feat: first tool base

This commit is contained in:
Corentin Thomasset 2021-02-06 11:14:28 +01:00
parent b0e232bc77
commit 02dafd6a2f
No known key found for this signature in database
GPG key ID: DBD997E935996158
15 changed files with 326 additions and 168 deletions

View file

@ -10,6 +10,8 @@ module.exports = {
], ],
// add your custom rules here // add your custom rules here
rules: { rules: {
'space-before-function-paren': 'off' 'space-before-function-paren': 'off',
'object-curly-spacing': 'off',
'no-undef': 'off' // will be catch by the tsc compiler
} }
} }

View file

@ -2,3 +2,4 @@
// //
// The variables you want to modify // The variables you want to modify
// $font-size-root: 20px; // $font-size-root: 20px;

30
components/Tool.vue Normal file
View file

@ -0,0 +1,30 @@
<script lang="ts">
import {Component, Vue} from 'nuxt-property-decorator'
import ToolWrapper from '~/components/ToolWrapper.vue';
interface ToolConfig {
title: string;
description: string;
}
export {ToolConfig}
@Component({components: {ToolWrapper}})
export default class Tool extends Vue {
public isTool = true;
public config: ToolConfig = {
title: 'Tool',
description: 'Tool description'
}
public head() {
const {title, description} = this.config
return {
title,
description
}
}
}
</script>

View file

@ -0,0 +1,61 @@
<template>
<div class="tool-wrapper">
<v-row no-gutters justify="center" align="center">
<v-col cols="12" lg="6">
<div class="tool-wrapper-info">
<h1>{{ config.title }}</h1>
<div class="spacer"></div>
<div class="description">{{ config.description }}</div>
</div>
<v-card flat>
<v-card-text class="pa-10">
<slot></slot>
</v-card-text>
</v-card>
</v-col>
</v-row>
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'nuxt-property-decorator'
import {ToolConfig} from '~/components/Tool.vue'
@Component
export default class ToolWrapper extends Vue {
@Prop() config!: ToolConfig;
}
</script>
<style scoped lang="less">
.tool-wrapper {
height: 100%;
.tool-wrapper-info{
padding: 50px 0 30px;
}
.category {
color: #546167;
}
h1 {
font-weight: 300;
font-size: 50px;
margin: 0;
padding: 0;
}
.spacer{
width: 130px;
height: 1px;
background-color: var(--v-primary-base);
margin-bottom: 10px;
}
.description {
color: #829097;
}
}
</style>

View file

@ -2,11 +2,21 @@
<v-app dark> <v-app dark>
<v-navigation-drawer <v-navigation-drawer
v-model="drawer" v-model="drawer"
:mini-variant="miniVariant"
:clipped="clipped"
fixed fixed
app app
> >
<div>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis corporis cumque dolore esse eveniet
exercitationem explicabo ipsa libero necessitatibus numquam optio pariatur, perferendis placeat porro ullam vel
velit voluptas voluptates?
</div>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 320">
<path fill="#eee" fill-opacity="1"
d="M0,160L26.7,133.3C53.3,107,107,53,160,58.7C213.3,64,267,128,320,176C373.3,224,427,256,480,250.7C533.3,245,587,203,640,186.7C693.3,171,747,181,800,186.7C853.3,192,907,192,960,186.7C1013.3,181,1067,171,1120,176C1173.3,181,1227,203,1280,192C1333.3,181,1387,139,1413,117.3L1440,96L1440,0L1413.3,0C1386.7,0,1333,0,1280,0C1226.7,0,1173,0,1120,0C1066.7,0,1013,0,960,0C906.7,0,853,0,800,0C746.7,0,693,0,640,0C586.7,0,533,0,480,0C426.7,0,373,0,320,0C266.7,0,213,0,160,0C106.7,0,53,0,27,0L0,0Z"></path>
<path fill="#05e677" fill-opacity="1"
d="M0,224L26.7,218.7C53.3,213,107,203,160,213.3C213.3,224,267,256,320,266.7C373.3,277,427,267,480,256C533.3,245,587,235,640,208C693.3,181,747,139,800,106.7C853.3,75,907,53,960,69.3C1013.3,85,1067,139,1120,181.3C1173.3,224,1227,256,1280,266.7C1333.3,277,1387,267,1413,261.3L1440,256L1440,0L1413.3,0C1386.7,0,1333,0,1280,0C1226.7,0,1173,0,1120,0C1066.7,0,1013,0,960,0C906.7,0,853,0,800,0C746.7,0,693,0,640,0C586.7,0,533,0,480,0C426.7,0,373,0,320,0C266.7,0,213,0,160,0C106.7,0,53,0,27,0L0,0Z"></path>
</svg>
<v-list> <v-list>
<v-list-item <v-list-item
v-for="(item, i) in items" v-for="(item, i) in items"
@ -14,6 +24,7 @@
:to="item.to" :to="item.to"
router router
exact exact
dense
> >
<v-list-item-action> <v-list-item-action>
<v-icon>{{ item.icon }}</v-icon> <v-icon>{{ item.icon }}</v-icon>
@ -24,70 +35,76 @@
</v-list-item> </v-list-item>
</v-list> </v-list>
</v-navigation-drawer> </v-navigation-drawer>
<v-app-bar :clipped-left="clipped" fixed app>
<v-app-bar
app
flat
height="60px"
>
<v-app-bar-nav-icon @click.stop="drawer = !drawer"/> <v-app-bar-nav-icon @click.stop="drawer = !drawer"/>
<v-btn icon @click.stop="miniVariant = !miniVariant">
<v-icon>mdi-{{ `chevron-${miniVariant ? 'right' : 'left'}` }}</v-icon>
</v-btn>
<v-btn icon @click.stop="clipped = !clipped">
<v-icon>mdi-application</v-icon>
</v-btn>
<v-btn icon @click.stop="fixed = !fixed">
<v-icon>mdi-minus</v-icon>
</v-btn>
<v-toolbar-title v-text="title"/> <v-toolbar-title v-text="title"/>
<v-spacer/> <v-spacer/>
<v-btn icon @click.stop="rightDrawer = !rightDrawer">
<v-icon>mdi-menu</v-icon>
</v-btn>
</v-app-bar> </v-app-bar>
<v-main> <v-main>
<v-container> <v-container>
<nuxt/> <nuxt/>
</v-container> </v-container>
</v-main> </v-main>
<v-navigation-drawer v-model="rightDrawer" :right="right" temporary fixed> <!-- <v-footer app>-->
<v-list> <!-- <span>&copy; {{ new Date().getFullYear() }}</span>-->
<v-list-item @click.native="right = !right"> <!-- </v-footer>-->
<v-list-item-action>
<v-icon light>
mdi-repeat
</v-icon>
</v-list-item-action>
<v-list-item-title>Switch drawer (click me)</v-list-item-title>
</v-list-item>
</v-list>
</v-navigation-drawer>
<v-footer :absolute="!fixed" app>
<span>&copy; {{ new Date().getFullYear() }}</span>
</v-footer>
</v-app> </v-app>
</template> </template>
<script> <script lang="ts">
export default { import {Component, Vue} from 'nuxt-property-decorator';
data() {
return { @Component
clipped: false, export default class DefaultLayout extends Vue {
drawer: false, title = 'IT - Tools'
fixed: false, drawer = false
items: [ items = [
{ {
icon: 'mdi-apps', icon: 'mdi-apps',
title: 'Welcome', title: 'Welcome',
to: '/' to: '/'
}, },
{
icon: 'mdi-apps',
title: 'Token generator',
to: '/crypto/TokenGenerator'
},
{ {
icon: 'mdi-chart-bubble', icon: 'mdi-chart-bubble',
title: 'Inspire', title: 'Inspire',
to: '/inspire' to: '/inspire'
} }
], ]
miniVariant: false,
right: true, created() {
rightDrawer: false,
title: 'Vuetify.js'
}
} }
} }
</script> </script>
<style lang="less">
.v-application {
background-color: var(--v-background-base, #121212) !important;
}
.theme--dark {
.v-card,
.v-footer,
.v-navigation-drawer,
.v-app-bar.v-toolbar.v-sheet {
background-color: var(--v-foreground-base, #121212) !important;
}
.v-footer,
.v-app-bar.v-toolbar.v-sheet {
background-color: var(--v-toolbar-base, #121212) !important;
}
}
</style>

18
mixins/copyable.ts Normal file
View file

@ -0,0 +1,18 @@
const copyToClipboard = (text: string) => {
const input = document.createElement('textarea')
input.innerHTML = text
document.body.appendChild(input)
input.select()
const result = document.execCommand('copy')
document.body.removeChild(input)
return result
}
export const copyable = {
methods: {
copy(text: string, toastText = 'Copied to clipboard !') {
copyToClipboard(text)
this.$toast.success(toastText)
}
}
}

View file

@ -1,8 +1,8 @@
import colors from 'vuetify/es5/util/colors' import colors from 'vuetify/es5/util/colors'
export default { export default {
// Disable server-side rendering (https://go.nuxtjs.dev/ssr-mode) // Enable server-side rendering (https://go.nuxtjs.dev/ssr-mode)
ssr: false, ssr: true,
// Target (https://go.nuxtjs.dev/config-target) // Target (https://go.nuxtjs.dev/config-target)
target: 'static', target: 'static',
@ -50,17 +50,22 @@ export default {
// Vuetify module configuration (https://go.nuxtjs.dev/config-vuetify) // Vuetify module configuration (https://go.nuxtjs.dev/config-vuetify)
vuetify: { vuetify: {
customVariables: ['~/assets/variables.scss'], customVariables: ['~/assets/variables.scss'],
treeShake: true,
theme: { theme: {
dark: true, dark: true,
options: { customProperties: true },
themes: { themes: {
dark: { dark: {
primary: colors.blue.darken2, primary: '#05e677',
accent: colors.grey.darken3, accent: colors.grey.darken3,
secondary: colors.amber.darken3, secondary: colors.amber.darken3,
info: colors.teal.lighten1, info: colors.teal.lighten1,
warning: colors.amber.base, warning: colors.amber.base,
error: colors.deepOrange.accent4, error: colors.deepOrange.accent4,
success: colors.green.accent3 success: colors.green.accent3,
background: '#324148',
foreground: '#28353b',
toolbar: '#243137'
} }
} }
} }

41
package-lock.json generated
View file

@ -3968,9 +3968,9 @@
"dev": true "dev": true
}, },
"axios": { "axios": {
"version": "0.21.0", "version": "0.21.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.0.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
"integrity": "sha512-fmkJBknJKoZwem3/IKSSLpkdNXZeBu5Q7GA/aRsr2btgrptmSCxi2oFjZHqGdK9DoTil9PIHlPIZw2EcRJXRvw==", "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
"requires": { "requires": {
"follow-redirects": "^1.10.0" "follow-redirects": "^1.10.0"
} }
@ -11612,6 +11612,18 @@
"@nuxt/webpack": "2.14.12" "@nuxt/webpack": "2.14.12"
} }
}, },
"nuxt-property-decorator": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/nuxt-property-decorator/-/nuxt-property-decorator-2.9.1.tgz",
"integrity": "sha512-dE2GrrGKZMhv0dHAr+Lmj+JOQfjIouINgF58QNRDFNOZXMJrXxKO5zGqvCRwmx3hxqqwht7TXHdz9w1AnvL2IA==",
"dev": true,
"requires": {
"vue-class-component": "^7.2.6",
"vue-property-decorator": "^9.0.0",
"vuex-class": "^0.3.2",
"vuex-module-decorators": "^1.0.1"
}
},
"nwsapi": { "nwsapi": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz",
@ -15823,6 +15835,12 @@
"resolved": "https://registry.npmjs.org/vue/-/vue-2.6.12.tgz", "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.12.tgz",
"integrity": "sha512-uhmLFETqPPNyuLLbsKz6ioJ4q7AZHzD8ZVFNATNyICSZouqP2Sz0rotWQC8UNBF6VGSCs5abnKJoStA6JbCbfg==" "integrity": "sha512-uhmLFETqPPNyuLLbsKz6ioJ4q7AZHzD8ZVFNATNyICSZouqP2Sz0rotWQC8UNBF6VGSCs5abnKJoStA6JbCbfg=="
}, },
"vue-class-component": {
"version": "7.2.6",
"resolved": "https://registry.npmjs.org/vue-class-component/-/vue-class-component-7.2.6.tgz",
"integrity": "sha512-+eaQXVrAm/LldalI272PpDe3+i4mPis0ORiMYxF6Ae4hyuCh15W8Idet7wPUEs4N4YptgFHGys4UrgNQOMyO6w==",
"dev": true
},
"vue-client-only": { "vue-client-only": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/vue-client-only/-/vue-client-only-2.0.0.tgz", "resolved": "https://registry.npmjs.org/vue-client-only/-/vue-client-only-2.0.0.tgz",
@ -16071,11 +16089,28 @@
"loader-utils": "^1.2.0" "loader-utils": "^1.2.0"
} }
}, },
"vuetify-toast-snackbar": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/vuetify-toast-snackbar/-/vuetify-toast-snackbar-0.6.1.tgz",
"integrity": "sha512-F2bLPMXiw7qQgX68adSu0zQrMTKODN5JAzCP8AP/HGhz/Bz1z24QbvYcX0fyHnG/yP6PAPkpMCXsLQSq6HV0Ag=="
},
"vuex": { "vuex": {
"version": "3.6.0", "version": "3.6.0",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.0.tgz", "resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.0.tgz",
"integrity": "sha512-W74OO2vCJPs9/YjNjW8lLbj+jzT24waTo2KShI8jLvJW8OaIkgb3wuAMA7D+ZiUxDOx3ubwSZTaJBip9G8a3aQ==" "integrity": "sha512-W74OO2vCJPs9/YjNjW8lLbj+jzT24waTo2KShI8jLvJW8OaIkgb3wuAMA7D+ZiUxDOx3ubwSZTaJBip9G8a3aQ=="
}, },
"vuex-class": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/vuex-class/-/vuex-class-0.3.2.tgz",
"integrity": "sha512-m0w7/FMsNcwJgunJeM+wcNaHzK2KX1K1rw2WUQf7Q16ndXHo7pflRyOV/E8795JO/7fstyjH3EgqBI4h4n4qXQ==",
"dev": true
},
"vuex-module-decorators": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/vuex-module-decorators/-/vuex-module-decorators-1.0.1.tgz",
"integrity": "sha512-FLWZsXV5XAtl/bcKUyQFpnSBtpc3wK/7zSdy9oKbyp71mZd4ut5y2zSd219wWW9OG7WUOlVwac4rXFFDVnq7ug==",
"dev": true
},
"w3c-hr-time": { "w3c-hr-time": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",

View file

@ -16,7 +16,8 @@
"@nuxtjs/axios": "^5.12.2", "@nuxtjs/axios": "^5.12.2",
"@nuxtjs/pwa": "^3.0.2", "@nuxtjs/pwa": "^3.0.2",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"nuxt": "^2.14.6" "nuxt": "^2.14.6",
"vuetify-toast-snackbar": "^0.6.1"
}, },
"devDependencies": { "devDependencies": {
"@nuxt/types": "^2.14.6", "@nuxt/types": "^2.14.6",
@ -36,8 +37,8 @@
"jest": "^26.5.0", "jest": "^26.5.0",
"less": "^4.0.0", "less": "^4.0.0",
"less-loader": "^7.1.0", "less-loader": "^7.1.0",
"nuxt-property-decorator": "^2.9.1",
"ts-jest": "^26.4.1", "ts-jest": "^26.4.1",
"vue-jest": "^3.0.4", "vue-jest": "^3.0.4"
"vue-property-decorator": "^9.1.2"
} }
} }

View file

@ -0,0 +1,79 @@
<template>
<ToolWrapper :config="config">
<v-row no-gutters>
<v-col lg="6" md="12">
<v-switch v-model="withLowercase" label="Lowercase (abc...)" />
<v-switch v-model="withUppercase" label="Uppercase (ABC...)" />
</v-col>
<v-col lg="6" md="12">
<v-switch v-model="withNumbers" label="Numbers (123...)" />
<v-switch v-model="withSpecials" label="Specials (#]-...)" />
</v-col>
</v-row>
<v-slider v-model="length" :label="`Length (${length})`" min="1" max="256" />
<v-textarea v-model="token" outlined />
<div class="text-center">
<v-btn depressed class="mr-4" @click="refreshToken()">
Refresh
</v-btn>
<!-- <v-btn @click="copyToken()" depressed>Copy token</v-btn>-->
</div>
</ToolWrapper>
</template>
<script lang="ts">
import {Component} from 'nuxt-property-decorator'
import Tool, {ToolConfig} from '~/components/Tool.vue'
const shuffle = (s: string) => s.split('').sort(() => 0.5 - Math.random()).join('')
const lowercase = 'abcdefghijklmopqrstuvwxyz'
const uppercase = 'ABCDEFGHIJKLMOPQRSTUVWXYZ'
const numbers = '0123456789'
const specials = '.,;:!?./-"\'#{([-|\\@)]=}*+'
@Component
export default class TokenGenerator extends Tool {
config: ToolConfig = {
title: 'Token generator',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.'
}
withNumbers = true;
withLowercase = true;
withUppercase = true;
withSpecials = false;
length = 64;
refreshBool = true;
refreshToken() {
this.refreshBool = !this.refreshBool
}
get token() {
if (this.refreshBool) { (() => {})() } // To force recomputation
let result = ''
if (this.withLowercase) {
result += lowercase
}
if (this.withUppercase) {
result += uppercase
}
if (this.withNumbers) {
result += numbers
}
if (this.withSpecials) {
result += specials
}
return shuffle(result.repeat(this.length)).substring(0, this.length)
}
}
</script>
<style scoped>
</style>

View file

@ -1,78 +1,7 @@
<template> <template>
<v-row justify="center" align="center"> <v-row justify="center" align="center">
<v-col cols="12" sm="8" md="6"> <v-col cols="12" sm="12" md="8">
<div class="text-center"/> <h1>Yolo</h1>
<v-card>
<v-card-title class="headline">
Welcome to the Vuetify + Nuxt.js template
</v-card-title>
<v-card-text>
<p>
Vuetify is a progressive Material Design component framework for
Vue.js. It was designed to empower developers to create amazing
applications.
</p>
<p>
For more information on Vuetify, check out the
<a
href="https://vuetifyjs.com"
target="_blank"
rel="noopener noreferrer"
>
documentation </a>.
</p>
<p>
If you have questions, please join the official
<a
href="https://chat.vuetifyjs.com/"
target="_blank"
rel="noopener noreferrer"
title="chat"
>
discord </a>.
</p>
<p>
Find a bug? Report it on the github
<a
href="https://github.com/vuetifyjs/vuetify/issues"
target="_blank"
rel="noopener noreferrer"
title="contribute"
>
issue board </a>.
</p>
<p>
Thank you for developing with Vuetify and I look forward to bringing
more exciting features in the future.
</p>
<div class="text-xs-right">
<em><small>&mdash; John Leider</small></em>
</div>
<hr class="my-3">
<a
href="https://nuxtjs.org/"
target="_blank"
rel="noopener noreferrer"
>
Nuxt Documentation
</a>
<br>
<a
href="https://github.com/nuxt/nuxt.js"
target="_blank"
rel="noopener noreferrer"
>
Nuxt GitHub
</a>
</v-card-text>
<v-card-actions>
<v-spacer/>
<v-btn color="primary" nuxt to="/inspire">
Continue
</v-btn>
</v-card-actions>
</v-card>
</v-col> </v-col>
</v-row> </v-row>
</template> </template>

View file

@ -1,15 +0,0 @@
<template>
<v-row>
<v-col class="text-center">
<img src="/v.png" alt="Vuetify.js" class="mb-5">
<blockquote class="blockquote">
&#8220;First, solve the problem. Then, write the code.&#8221;
<footer>
<small>
<em>&mdash;John Johnson</em>
</small>
</footer>
</blockquote>
</v-col>
</v-row>
</template>

View file

@ -1,11 +0,0 @@
# STATIC
**This directory is not required, you can delete it if you don't want to use it.**
This directory contains your static files.
Each file inside this directory is mapped to `/`.
Thus you'd want to delete this README.md before deploying to production.
Example: `/static/robots.txt` is mapped as `/robots.txt`.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#static).

4
static/humans.txt Normal file
View file

@ -0,0 +1,4 @@
/* TEAM */
Developer: Corentin Thomasset
Site: https://github.com/CorentinTh
Twitter: @cthmsst

2
static/robots.txt Normal file
View file

@ -0,0 +1,2 @@
User-agent: *
Disallow: