feat: externalized tool configuration

This commit is contained in:
Corentin Thomasset 2021-05-28 19:44:27 +02:00
parent c3adfe30ec
commit 690bd099ef
No known key found for this signature in database
GPG key ID: DBD997E935996158
31 changed files with 387 additions and 300 deletions

View file

@ -0,0 +1,85 @@
import {readdirSync, readFileSync} from 'fs'
import path, {join} from 'path'
import {Module} from '@nuxt/types'
import {NuxtRouteConfig} from '@nuxt/types/config/router'
import YAML from 'yaml'
import {capitalise} from '../../utils/string'
const toolDirName = 'tools'
const rootDir = join(__dirname, '..', '..')
const toolsDir = join(rootDir, toolDirName)
interface toolConfigModuleOptions {
}
function getTools() {
const categories = readdirSync(toolsDir)
const toolList: { [key: string]: any[] } = {}
for (const category of categories) {
const categoryDir = join(toolsDir, category)
const categoryFormatted = capitalise(category)
toolList[categoryFormatted] = readdirSync(categoryDir).map((toolFileName) => {
const toolPath = join(categoryDir, toolFileName)
const contentMatch = readFileSync(toolPath, 'utf8').match(/<tool(\s[^>\s]*)*>([\S\s.]*?)<\/tool>/)
return contentMatch
? {
...YAML.parse(contentMatch[2]),
componentPath: join(toolDirName, category, toolFileName)
}
: null
}).filter(v => v !== null)
}
return toolList
}
const toolConfigModule: Module<toolConfigModuleOptions> = function () {
const {nuxt, extendBuild, addPlugin} = this
const toolList = getTools()
const toolListFlat = Object.values(toolList).flat()
nuxt.hook('build:extendRoutes', (routes: NuxtRouteConfig[]) => {
toolListFlat.forEach((toolConfig) => {
const {path = '', title, componentPath} = toolConfig
const name = title.toLowerCase().split(/\s/).join('-').replace(/\.vue$/, '')
const newRoute: NuxtRouteConfig = {
name,
path,
component: join(rootDir, componentPath),
chunkName: componentPath.replace(/\.vue$/, '')
}
routes.push(newRoute)
})
nuxt.options.publicRuntimeConfig.toolList = toolList
})
extendBuild((config) => {
if (!config.module) {
// eslint-disable-next-line no-console
console.warn('Failed to register the tool-config module.')
return
}
config.module.rules.push({
resourceQuery: /blockType=tool/,
loader: require.resolve('./loader.js')
})
})
addPlugin({
src: path.resolve(__dirname, 'plugin.ts'),
fileName: 'tool-config/plugin.ts',
options: {
toolList,
toolListFlat
}
})
}
export default toolConfigModule

View file

@ -0,0 +1,13 @@
const YAML = require('yaml')
const loader = function (source, map) {
this.callback(
null,
`export default function (Component) {
Component.options.__toolConfig = ${JSON.stringify(YAML.parse(source))}
}`,
map
)
}
module.exports = loader

View file

@ -0,0 +1,16 @@
// @ts-nocheck
import {Plugin} from '@nuxt/types'
import type {ToolRouteConfig} from '~/types/ToolConfig';
declare module 'vue/types/vue' {
interface Vue {
$toolListFlat: ToolRouteConfig[]
$toolList: { [key: string]: ToolRouteConfig[] }
}
}
const plugin: Plugin = (_, inject) => {
inject('toolListFlat', <%= serialize(options.toolListFlat) %>)
inject('toolList', <%= serialize(options.toolList) %>)
}
export default plugin

View file

@ -1,6 +1,6 @@
<template> <template>
<div class="memo"> <div class="memo">
<ToolHeader :config="memoConfig" /> <ToolHeader :config="$toolConfig" />
Warning: le style/aspect est toujours en wip, so focus on content <br><br> Warning: le style/aspect est toujours en wip, so focus on content <br><br>

View file

@ -5,8 +5,8 @@
append-icon="mdi-magnify" append-icon="mdi-magnify"
color="white" color="white"
hide-details hide-details
:items="toolRoutesFlat" :items="$toolListFlat"
:item-text="item => item.config.title" :item-text="item => item.title"
item-value="path" item-value="path"
solo-inverted solo-inverted
dense dense
@ -26,12 +26,11 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import {Component, mixins} from 'nuxt-property-decorator' import {Component, Vue} from 'nuxt-property-decorator'
import {ToolRoutesMixin} from '@/mixins/tool-routes.mixin'
import {ToolRouteConfig} from '~/types/ToolConfig' import {ToolRouteConfig} from '~/types/ToolConfig'
@Component @Component
export default class SearchBar extends mixins(ToolRoutesMixin) { export default class SearchBar extends Vue {
choose(path:string) { choose(path:string) {
this.$router.push({path}) this.$router.push({path})
} }
@ -39,7 +38,7 @@ export default class SearchBar extends mixins(ToolRoutesMixin) {
filterItems(item:ToolRouteConfig, queryText:string, itemText:string) { filterItems(item:ToolRouteConfig, queryText:string, itemText:string) {
const query = queryText.trim().toLowerCase() const query = queryText.trim().toLowerCase()
const nameContainsText = itemText.toLowerCase().includes(query) const nameContainsText = itemText.toLowerCase().includes(query)
const keywordContainsText = item?.config?.keywords.join(' ').toLowerCase().includes(query) ?? false const keywordContainsText = item?.keywords.join(' ').toLowerCase().includes(query) ?? false
return nameContainsText || keywordContainsText return nameContainsText || keywordContainsText
} }
} }

View file

@ -1,16 +1,21 @@
<script lang="ts"> <script lang="ts">
import {Component, Vue} from 'nuxt-property-decorator' import {Component, mixins} from 'nuxt-property-decorator'
import ToolWrapper from '~/components/ToolWrapper.vue' import ToolWrapper from '~/components/ToolWrapper.vue'
import type {ToolConfig} from '~/types/ToolConfig' import type {ToolConfig} from '~/types/ToolConfig'
import {ToolConfigMixin} from '~/mixins/tool-config.mixin'
@Component({components: {ToolWrapper}}) @Component({
export default class Tool extends Vue { components: {ToolWrapper}
})
export default class Tool extends mixins(ToolConfigMixin) {
config(): ToolConfig { config(): ToolConfig {
throw new Error('You need to specify a config() method your custom Tool.') return {
title: 'ADD A <tool> TAG'
} as unknown as ToolConfig
}; };
public head() { public head() {
const {title, description, keywords} = this.config() const {title, description, keywords} = this.$toolConfig
const uniqueKeywordsCleaned = [...new Set([...keywords, ...title.split(/\s+/)].map(s => s.trim().toLowerCase()))] const uniqueKeywordsCleaned = [...new Set([...keywords, ...title.split(/\s+/)].map(s => s.trim().toLowerCase()))]

View file

@ -22,7 +22,7 @@
<SearchBar class="hidden-sm-and-up" /> <SearchBar class="hidden-sm-and-up" />
<v-list> <v-list>
<div v-for="(items, section) in toolRoutesSections" :key="section"> <div v-for="(items, section) in $toolList" :key="section">
<v-subheader class="mt-4 pl-4"> <v-subheader class="mt-4 pl-4">
{{ section }} {{ section }}
</v-subheader> </v-subheader>
@ -37,11 +37,11 @@
> >
<v-list-item-action> <v-list-item-action>
<v-icon color="primary"> <v-icon color="primary">
{{ item.config.icon }} {{ item.icon }}
</v-icon> </v-icon>
</v-list-item-action> </v-list-item-action>
<v-list-item-content> <v-list-item-content>
<v-list-item-title v-text="item.config.title" /> <v-list-item-title v-text="item.title" />
</v-list-item-content> </v-list-item-content>
</v-list-item> </v-list-item>
</div> </div>
@ -103,9 +103,8 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import {Component, mixins} from 'nuxt-property-decorator' import {Component, Vue} from 'nuxt-property-decorator'
import {version} from '../package.json' import {version} from '../package.json'
import {ToolRoutesMixin} from '~/mixins/tool-routes.mixin'
import LogoOutlined from '~/assets/logo-outlined.svg?inline' import LogoOutlined from '~/assets/logo-outlined.svg?inline'
import HeroGradient from '~/assets/small-hero-gradient.svg?inline' import HeroGradient from '~/assets/small-hero-gradient.svg?inline'
import SearchBar from '~/components/SearchBar.vue' import SearchBar from '~/components/SearchBar.vue'
@ -117,7 +116,7 @@ import SearchBar from '~/components/SearchBar.vue'
SearchBar SearchBar
} }
}) })
export default class DefaultLayout extends mixins(ToolRoutesMixin) { export default class DefaultLayout extends Vue {
title = 'IT - Tools' title = 'IT - Tools'
drawer = false drawer = false
items = [] items = []

View file

@ -0,0 +1,12 @@
import {Component, Vue} from 'nuxt-property-decorator'
import {ToolConfig} from '~/types/ToolConfig'
@Component
export class ToolConfigMixin extends Vue {
public $toolConfig!: ToolConfig;
beforeCreate() {
// @ts-ignore
this.$toolConfig = this.$options.__toolConfig
}
}

View file

@ -1,37 +0,0 @@
import {Component, Vue} from 'nuxt-property-decorator'
import {ToolRouteConfig} from '~/types/ToolConfig'
import {capitalise} from '~/utils/string'
@Component
export class ToolRoutesMixin extends Vue {
toolRoutesFlat : ToolRouteConfig[] = []
toolRoutesSections : {[key: string]: ToolRouteConfig[]} = {}
async created() {
const routes = this.$router.options.routes?.filter((r1, i, a) => r1.meta?.isTool && a.findIndex(r2 => r2.path.split('/').pop() === r1.path.split('/').pop()) === i) || []
const flat: ToolRouteConfig[] = []
const sections: { [key: string]: ToolRouteConfig[] } = {}
for (const route of routes) {
if ('component' in route) {
// @ts-ignore
const component = await route.component()
const routeConfig = {...route, config: component.options.methods.config()} as ToolRouteConfig
flat.push(routeConfig)
const sectionKey = capitalise(route.meta.section).replace(/_/g, ' ')
if (!(sectionKey in sections)) {
sections[sectionKey] = []
}
sections[sectionKey].push(routeConfig)
}
}
this.toolRoutesSections = sections
this.toolRoutesFlat = flat
}
}

View file

@ -36,7 +36,9 @@ export default {
// https://go.nuxtjs.dev/typescript // https://go.nuxtjs.dev/typescript
'@nuxt/typescript-build', '@nuxt/typescript-build',
// https://go.nuxtjs.dev/vuetify // https://go.nuxtjs.dev/vuetify
'@nuxtjs/vuetify' '@nuxtjs/vuetify',
// '@nuxtjs/router-extras'
'~/buildModules/tool-config'
], ],
// Modules (https://go.nuxtjs.dev/config-modules) // Modules (https://go.nuxtjs.dev/config-modules)
@ -48,6 +50,8 @@ export default {
'@nuxtjs/svg', '@nuxtjs/svg',
'nuxt-i18n', 'nuxt-i18n',
'@nuxtjs/markdownit' '@nuxtjs/markdownit'
// '~/buildModules/tool-config'
], ],
// Axios module configuration (https://go.nuxtjs.dev/config-axios) // Axios module configuration (https://go.nuxtjs.dev/config-axios)

92
package-lock.json generated
View file

@ -3583,15 +3583,6 @@
"typescript": "~4.2" "typescript": "~4.2"
} }
}, },
"@nuxt/typescript-runtime": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@nuxt/typescript-runtime/-/typescript-runtime-2.1.0.tgz",
"integrity": "sha512-quzxXiWq+jGdnCedDIYuBiExrfIJL3VL9o4gJyq6QzthKLYSvLzB6w4RiH6UbLtnNJyDoO9ywyNSI2+RUJr/Ng==",
"requires": {
"ts-node": "^9.1.1",
"typescript": "~4.2"
}
},
"@nuxt/utils": { "@nuxt/utils": {
"version": "2.15.6", "version": "2.15.6",
"resolved": "https://registry.npmjs.org/@nuxt/utils/-/utils-2.15.6.tgz", "resolved": "https://registry.npmjs.org/@nuxt/utils/-/utils-2.15.6.tgz",
@ -4499,6 +4490,16 @@
"workbox-cdn": "^5.1.4" "workbox-cdn": "^5.1.4"
} }
}, },
"@nuxtjs/router-extras": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@nuxtjs/router-extras/-/router-extras-1.1.1.tgz",
"integrity": "sha512-WUBT6ig0MweXZVC3bYbhQ6cxvIRLBCCcIy/nZxUEw1zAWwrPWX12l3b5zRTLDFVhGUQfio25GWkNh8UWHWK7kw==",
"dev": true,
"requires": {
"chokidar": "^3.4.3",
"gray-matter": "^4.0.2"
}
},
"@nuxtjs/svg": { "@nuxtjs/svg": {
"version": "0.1.12", "version": "0.1.12",
"resolved": "https://registry.npmjs.org/@nuxtjs/svg/-/svg-0.1.12.tgz", "resolved": "https://registry.npmjs.org/@nuxtjs/svg/-/svg-0.1.12.tgz",
@ -5842,11 +5843,6 @@
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
}, },
"arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="
},
"argparse": { "argparse": {
"version": "1.0.10", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@ -8302,11 +8298,6 @@
"resolved": "https://registry.npmjs.org/devalue/-/devalue-2.0.1.tgz", "resolved": "https://registry.npmjs.org/devalue/-/devalue-2.0.1.tgz",
"integrity": "sha512-I2TiqT5iWBEyB8GRfTDP0hiLZ0YeDJZ+upDxjBfOC2lebO5LezQMv7QvIUTzdb64jQyAKLf1AHADtGN+jw6v8Q==" "integrity": "sha512-I2TiqT5iWBEyB8GRfTDP0hiLZ0YeDJZ+upDxjBfOC2lebO5LezQMv7QvIUTzdb64jQyAKLf1AHADtGN+jw6v8Q=="
}, },
"diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A=="
},
"diff-sequences": { "diff-sequences": {
"version": "26.6.2", "version": "26.6.2",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz",
@ -10251,6 +10242,18 @@
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
"integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ=="
}, },
"gray-matter": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz",
"integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==",
"dev": true,
"requires": {
"js-yaml": "^3.13.1",
"kind-of": "^6.0.2",
"section-matter": "^1.0.0",
"strip-bom-string": "^1.0.0"
}
},
"growly": { "growly": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
@ -13152,7 +13155,8 @@
"make-error": { "make-error": {
"version": "1.3.6", "version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
}, },
"makeerror": { "makeerror": {
"version": "1.0.11", "version": "1.0.11",
@ -16775,6 +16779,27 @@
"resolved": "https://registry.npmjs.org/scule/-/scule-0.2.1.tgz", "resolved": "https://registry.npmjs.org/scule/-/scule-0.2.1.tgz",
"integrity": "sha512-M9gnWtn3J0W+UhJOHmBxBTwv8mZCan5i1Himp60t6vvZcor0wr+IM0URKmIglsWJ7bRujNAVVN77fp+uZaWoKg==" "integrity": "sha512-M9gnWtn3J0W+UhJOHmBxBTwv8mZCan5i1Himp60t6vvZcor0wr+IM0URKmIglsWJ7bRujNAVVN77fp+uZaWoKg=="
}, },
"section-matter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
"integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==",
"dev": true,
"requires": {
"extend-shallow": "^2.0.1",
"kind-of": "^6.0.0"
},
"dependencies": {
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"dev": true,
"requires": {
"is-extendable": "^0.1.0"
}
}
}
},
"semver": { "semver": {
"version": "6.3.0", "version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
@ -17427,6 +17452,12 @@
"integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
"dev": true "dev": true
}, },
"strip-bom-string": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
"integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=",
"dev": true
},
"strip-eof": { "strip-eof": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
@ -18021,19 +18052,6 @@
} }
} }
}, },
"ts-node": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz",
"integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==",
"requires": {
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"source-map-support": "^0.5.17",
"yn": "3.1.1"
}
},
"ts-pnp": { "ts-pnp": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz", "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz",
@ -18161,7 +18179,8 @@
"typescript": { "typescript": {
"version": "4.2.4", "version": "4.2.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz",
"integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==" "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==",
"dev": true
}, },
"ua-parser-js": { "ua-parser-js": {
"version": "0.7.28", "version": "0.7.28",
@ -19811,11 +19830,6 @@
"decamelize": "^1.2.0" "decamelize": "^1.2.0"
} }
}, },
"yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q=="
},
"yocto-queue": { "yocto-queue": {
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",

View file

@ -3,17 +3,16 @@
"version": "2.0.0-beta.0", "version": "2.0.0-beta.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "nuxt-ts", "dev": "nuxt",
"build": "npm run generate", "build": "npm run generate",
"start": "nuxt-ts start", "start": "nuxt start",
"generate": "nuxt-ts generate", "generate": "nuxt generate",
"lint:commit": "commitlint --from $(git rev-list --max-parents=0 HEAD)", "lint:commit": "commitlint --from $(git rev-list --max-parents=0 HEAD)",
"lint:js": "eslint --ext .js,.vue --ignore-path=.gitignore --max-warnings=0 .", "lint:js": "eslint --ext .js,.vue --ignore-path=.gitignore --max-warnings=0 .",
"lint": "npm run lint:js && npm run lint:commit", "lint": "npm run lint:js && npm run lint:commit",
"test": "jest" "test": "jest"
}, },
"dependencies": { "dependencies": {
"@nuxt/typescript-runtime": "^2.1.0",
"@nuxtjs/axios": "^5.13.5", "@nuxtjs/axios": "^5.13.5",
"@nuxtjs/markdownit": "^2.0.0", "@nuxtjs/markdownit": "^2.0.0",
"@nuxtjs/pwa": "^3.0.2", "@nuxtjs/pwa": "^3.0.2",
@ -57,6 +56,7 @@
"less-loader": "^7.1.0", "less-loader": "^7.1.0",
"nuxt-property-decorator": "^2.9.1", "nuxt-property-decorator": "^2.9.1",
"ts-jest": "^26.5.6", "ts-jest": "^26.5.6",
"vue-jest": "^3.0.4" "vue-jest": "^3.0.4",
"yaml": "^1.10.2"
} }
} }

View file

@ -5,7 +5,7 @@
<v-row> <v-row>
<v-col <v-col
v-for="(items, section) in toolRoutesSections" v-for="(items, section) in $toolList"
:key="section" :key="section"
cols="12" cols="12"
sm="12" sm="12"
@ -24,10 +24,10 @@
exact exact
> >
<v-list-item-action> <v-list-item-action>
<v-icon>{{ item.config.icon }}</v-icon> <v-icon>{{ item.icon }}</v-icon>
</v-list-item-action> </v-list-item-action>
<v-list-item-content> <v-list-item-content>
<v-list-item-title v-text="item.config.title" /> <v-list-item-title v-text="item.title" />
</v-list-item-content> </v-list-item-content>
</v-list-item> </v-list-item>
</v-list> </v-list>
@ -40,11 +40,10 @@
</template> </template>
<script> <script>
import {Component, mixins} from 'nuxt-property-decorator' import {Component, Vue} from 'nuxt-property-decorator'
import {ToolRoutesMixin} from '@/mixins/tool-routes.mixin'
@Component @Component
export default class Index extends mixins(ToolRoutesMixin) { export default class Index extends Vue {
} }
</script> </script>

BIN
static/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -1,5 +1,5 @@
<template> <template>
<ToolWrapper :config="config()"> <ToolWrapper :config="$toolConfig">
<v-row> <v-row>
<v-col cols="12" sm="4"> <v-col cols="12" sm="4">
<v-text-field <v-text-field
@ -50,12 +50,19 @@
</ToolWrapper> </ToolWrapper>
</template> </template>
<tool>
title: 'Base converter'
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.'
icon: 'mdi-swap-horizontal'
keywords: ['base', 'converter']
path: '/color-picker-converter'
</tool>
<script lang="ts"> <script lang="ts">
import {Component, Ref} from 'nuxt-property-decorator' import {Component, Ref} from 'nuxt-property-decorator'
import {CopyableMixin} from '~/mixins/copyable.mixin' import {CopyableMixin} from '~/mixins/copyable.mixin'
import Tool from '~/components/Tool.vue' import Tool from '~/components/Tool.vue'
import {ToolConfig} from '~/types/ToolConfig'
import type {VForm} from '~/types/VForm' import type {VForm} from '~/types/VForm'
const convertBase = (value: string, fromBase: number, toBase: number) => { const convertBase = (value: string, fromBase: number, toBase: number) => {
@ -83,15 +90,6 @@ const convertBase = (value: string, fromBase: number, toBase: number) => {
mixins: [CopyableMixin] mixins: [CopyableMixin]
}) })
export default class BaseConverter extends Tool { export default class BaseConverter extends Tool {
config(): ToolConfig {
return {
title: 'Base converter',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.',
icon: 'mdi-swap-horizontal',
keywords: ['base', 'converter']
}
}
@Ref() readonly inputBaseRef!: VForm @Ref() readonly inputBaseRef!: VForm
@Ref() readonly outputBaseRef!: VForm @Ref() readonly outputBaseRef!: VForm

View file

@ -1,5 +1,5 @@
<template> <template>
<ToolWrapper :config="config()"> <ToolWrapper :config="$toolConfig">
<v-textarea <v-textarea
v-model="clearText" v-model="clearText"
outlined outlined
@ -23,26 +23,24 @@
</ToolWrapper> </ToolWrapper>
</template> </template>
<tool>
title: 'Base64 string converter'
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.'
icon: 'mdi-text-box-outline'
keywords: ['base64', 'base', '64', 'converter']
path: '/base64-string-converter'
</tool>
<script lang="ts"> <script lang="ts">
import {Component} from 'nuxt-property-decorator' import {Component} from 'nuxt-property-decorator'
import {CopyableMixin} from '~/mixins/copyable.mixin' import {CopyableMixin} from '~/mixins/copyable.mixin'
import Tool from '~/components/Tool.vue' import Tool from '~/components/Tool.vue'
import type {ToolConfig} from '~/types/ToolConfig'
import {base64ToString, stringToBase64} from '~/utils/convert' import {base64ToString, stringToBase64} from '~/utils/convert'
@Component({ @Component({
mixins: [CopyableMixin] mixins: [CopyableMixin]
}) })
export default class Base64StringConverter extends Tool { export default class Base64StringConverter extends Tool {
config(): ToolConfig {
return {
title: 'Base64 string converter',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.',
icon: 'mdi-text-box-outline',
keywords: ['base64', 'base', '64', 'converter']
}
}
clearText = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' clearText = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.'
get base64Text() { get base64Text() {

View file

@ -1,5 +1,5 @@
<template> <template>
<ToolWrapper :config="config()"> <ToolWrapper :config="$toolConfig">
<v-row no-gutters align="center" align-content="center" justify="center"> <v-row no-gutters align="center" align-content="center" justify="center">
<v-col cols="12" sm="6" align="center"> <v-col cols="12" sm="6" align="center">
<v-color-picker <v-color-picker
@ -59,6 +59,14 @@
</ToolWrapper> </ToolWrapper>
</template> </template>
<tool>
title: 'Color picker/converter'
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.'
icon: 'mdi-palette'
keywords: ['rgb', 'hsl', 'hex', 'keyword', 'css', 'picker']
path: '/color-picker-converter'
</tool>
<script lang="ts"> <script lang="ts">
import {Component} from 'nuxt-property-decorator' import {Component} from 'nuxt-property-decorator'
@ -66,7 +74,6 @@ import colors from 'color-name'
import convert from 'color-convert' import convert from 'color-convert'
import {CopyableMixin} from '~/mixins/copyable.mixin' import {CopyableMixin} from '~/mixins/copyable.mixin'
import Tool from '~/components/Tool.vue' import Tool from '~/components/Tool.vue'
import {ToolConfig} from '~/types/ToolConfig'
import type {VForm} from '~/types/VForm' import type {VForm} from '~/types/VForm'
const required = (v: unknown) => !!v || 'A value is required' const required = (v: unknown) => !!v || 'A value is required'
@ -75,15 +82,6 @@ const required = (v: unknown) => !!v || 'A value is required'
mixins: [CopyableMixin] mixins: [CopyableMixin]
}) })
export default class ColorPickerConverter extends Tool { export default class ColorPickerConverter extends Tool {
config(): ToolConfig {
return {
title: 'Color picker/converter',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.',
icon: 'mdi-palette',
keywords: ['rgb', 'hsl', 'hex', 'keyword', 'css', 'picker']
}
}
rgbPicker = { rgbPicker = {
r: 76, r: 76,
g: 175, g: 175,

View file

@ -1,5 +1,5 @@
<template> <template>
<ToolWrapper :config="config()"> <ToolWrapper :config="$toolConfig">
<v-row> <v-row>
<v-col md="3" sm="12" class="pt-0 pb-0"> <v-col md="3" sm="12" class="pt-0 pb-0">
<div class="text-center"> <div class="text-center">
@ -49,26 +49,24 @@
</ToolWrapper> </ToolWrapper>
</template> </template>
<tool>
title: 'Date/Time converter'
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.'
icon: 'mdi-calendar-range'
keywords: ['date', 'time', 'converter', 'iso']
path: '/date-converter'
</tool>
<script lang="ts"> <script lang="ts">
import {Component} from 'nuxt-property-decorator' import {Component} from 'nuxt-property-decorator'
import {CopyableMixin} from '@/mixins/copyable.mixin' import {CopyableMixin} from '@/mixins/copyable.mixin'
import Tool from '@/components/Tool.vue' import Tool from '@/components/Tool.vue'
import {ToolConfig} from '@/types/ToolConfig'
@Component({ @Component({
mixins: [CopyableMixin] mixins: [CopyableMixin]
}) })
export default class DateConverter extends Tool { export default class DateConverter extends Tool {
config(): ToolConfig {
return {
title: 'Date/Time converter',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.',
icon: 'mdi-calendar-range',
keywords: ['date', 'time', 'converter', 'iso']
}
}
inputString = '' inputString = ''
inputFormatterTitle: string | null = null inputFormatterTitle: string | null = null
useCurrentDate = true useCurrentDate = true

View file

@ -1,5 +1,5 @@
<template> <template>
<ToolWrapper :config="config()"> <ToolWrapper :config="$toolConfig">
<v-select <v-select
v-model="language" v-model="language"
outlined outlined
@ -33,13 +33,20 @@
</ToolWrapper> </ToolWrapper>
</template> </template>
<tool>
title: 'BIP39 passphrase generator'
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.'
icon: 'mdi-message-text-lock-outline'
keywords: ['BIP39', 'passphrase', 'generator']
path: '/bip39-generator'
</tool>
<script lang="ts"> <script lang="ts">
import * as bip39 from 'bip39' import * as bip39 from 'bip39'
import {shuffle} from '@/utils/string' import {shuffle} from '@/utils/string'
import {Component, Ref} from 'nuxt-property-decorator' import {Component, Ref} from 'nuxt-property-decorator'
import {CopyableMixin} from '@/mixins/copyable.mixin' import {CopyableMixin} from '@/mixins/copyable.mixin'
import Tool from '@/components/Tool.vue' import Tool from '@/components/Tool.vue'
import {ToolConfig} from '@/types/ToolConfig'
import type {VForm} from '~/types/VForm' import type {VForm} from '~/types/VForm'
const getRandomBuffer = () => Buffer.from(shuffle('0123456789abcdef'.repeat(16)).substring(0, 32), 'hex') const getRandomBuffer = () => Buffer.from(shuffle('0123456789abcdef'.repeat(16)).substring(0, 32), 'hex')
@ -48,15 +55,6 @@ const getRandomBuffer = () => Buffer.from(shuffle('0123456789abcdef'.repeat(16))
mixins: [CopyableMixin] mixins: [CopyableMixin]
}) })
export default class Bip39Generator extends Tool { export default class Bip39Generator extends Tool {
config(): ToolConfig {
return {
title: 'BIP39 passphrase generator',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.',
icon: 'mdi-message-text-lock-outline',
keywords: ['BIP39', 'passphrase', 'generator']
}
}
@Ref() readonly entropyRef!: VForm @Ref() readonly entropyRef!: VForm
@Ref() readonly passphraseRef!: VForm @Ref() readonly passphraseRef!: VForm
buffer = getRandomBuffer() buffer = getRandomBuffer()

View file

@ -1,5 +1,5 @@
<template> <template>
<ToolWrapper :config="config()"> <ToolWrapper :config="$toolConfig">
<v-row justify="center" align="center"> <v-row justify="center" align="center">
<v-col cols="12" lg="8" md="12"> <v-col cols="12" lg="8" md="12">
<v-textarea <v-textarea
@ -42,11 +42,18 @@
</ToolWrapper> </ToolWrapper>
</template> </template>
<tool>
title: 'Cypher / uncypher text'
description: 'Cypher and uncyfer text.'
icon: 'mdi-lock-open'
keywords: ['cypher', 'uncypher', 'text', 'AES', 'TripleDES', 'Rabbit', 'RabbitLegacy', 'RC4']
path: '/cypher-uncyfer-text'
</tool>
<script lang="ts"> <script lang="ts">
import {Component} from 'nuxt-property-decorator' import {Component} from 'nuxt-property-decorator'
import {CopyableMixin} from '@/mixins/copyable.mixin' import {CopyableMixin} from '@/mixins/copyable.mixin'
import Tool from '@/components/Tool.vue' import Tool from '@/components/Tool.vue'
import type {ToolConfig} from '@/types/ToolConfig'
import CryptoJS from 'crypto-js' import CryptoJS from 'crypto-js'
const algos = { const algos = {
@ -67,15 +74,6 @@ export default class CypherUncyferText extends Tool {
decrypted = 'Lorem ipsum dolor sit amet.' decrypted = 'Lorem ipsum dolor sit amet.'
encrypted = '' encrypted = ''
config(): ToolConfig {
return {
title: 'Cypher / uncypher text',
description: 'Cypher and uncyfer text.',
icon: 'mdi-lock-open',
keywords: ['cypher', 'uncypher', 'text', ...Object.keys(algos).map(s => s.toLowerCase())]
}
}
mounted() { mounted() {
this.encrypt() this.encrypt()
} }

View file

@ -1,5 +1,5 @@
<template> <template>
<ToolWrapper :config="config()"> <ToolWrapper :config="$toolConfig">
<v-textarea <v-textarea
v-model="inputText" v-model="inputText"
outlined outlined
@ -27,12 +27,20 @@
</ToolWrapper> </ToolWrapper>
</template> </template>
<tool>
title: 'Hash text'
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.'
icon: 'mdi-script-text-play'
keywords: ['hash', 'text', 'MD5', 'SHA1', 'SHA256', 'SHA224', 'SHA512', 'SHA384', 'SHA3', 'RIPEMD160']
path: '/hash-text'
</tool>
<script lang="ts"> <script lang="ts">
import {Component} from 'nuxt-property-decorator' import {Component} from 'nuxt-property-decorator'
import CryptoJS from 'crypto-js' import CryptoJS from 'crypto-js'
import {CopyableMixin} from '~/mixins/copyable.mixin' import {CopyableMixin} from '~/mixins/copyable.mixin'
import Tool from '~/components/Tool.vue' import Tool from '~/components/Tool.vue'
import type {ToolConfig} from '~/types/ToolConfig'
const algos = { const algos = {
MD5: CryptoJS.MD5, MD5: CryptoJS.MD5,
SHA1: CryptoJS.SHA1, SHA1: CryptoJS.SHA1,
@ -48,15 +56,6 @@ const algos = {
mixins: [CopyableMixin] mixins: [CopyableMixin]
}) })
export default class HashText extends Tool { export default class HashText extends Tool {
config(): ToolConfig {
return {
title: 'Hash text',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.',
icon: 'mdi-script-text-play',
keywords: ['hash', 'text', ...Object.keys(algos).map(s => s.toLowerCase())]
}
}
inputText = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' inputText = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.'
algorithm: keyof typeof algos = 'SHA256' algorithm: keyof typeof algos = 'SHA256'
algorithms: typeof algos = algos algorithms: typeof algos = algos

View file

@ -1,5 +1,5 @@
<template> <template>
<ToolWrapper :config="config()"> <ToolWrapper :config="$toolConfig">
<v-row no-gutters> <v-row no-gutters>
<v-col lg="6" md="12"> <v-col lg="6" md="12">
<v-switch v-model="withLowercase" label="Lowercase (abc...)" /> <v-switch v-model="withLowercase" label="Lowercase (abc...)" />
@ -26,10 +26,17 @@
</ToolWrapper> </ToolWrapper>
</template> </template>
<tool>
title: 'Token generator'
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.'
icon: 'mdi-key-chain-variant'
keywords: ['token', 'random', 'string', 'alphanumeric', 'symbols']
path: '/token-generator'
</tool>
<script lang="ts"> <script lang="ts">
import {Component} from 'nuxt-property-decorator' import {Component} from 'nuxt-property-decorator'
import Tool from '~/components/Tool.vue' import Tool from '~/components/Tool.vue'
import type {ToolConfig} from '~/types/ToolConfig'
import {CopyableMixin} from '~/mixins/copyable.mixin' import {CopyableMixin} from '~/mixins/copyable.mixin'
import {shuffle} from '~/utils/string' import {shuffle} from '~/utils/string'
@ -42,15 +49,6 @@ const specials = '.,;:!?./-"\'#{([-|\\@)]=}*+'
mixins: [CopyableMixin] mixins: [CopyableMixin]
}) })
export default class TokenGenerator extends Tool { export default class TokenGenerator extends Tool {
config(): ToolConfig {
return {
title: 'Token generator',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.',
icon: 'mdi-key-chain-variant',
keywords: ['token', 'random', 'string', 'alphanumeric', 'symbols']
}
}
withNumbers = true; withNumbers = true;
withLowercase = true; withLowercase = true;
withUppercase = true; withUppercase = true;

View file

@ -1,5 +1,5 @@
<template> <template>
<ToolWrapper :config="config()"> <ToolWrapper :config="$toolConfig">
<v-text-field <v-text-field
v-model.number="quantity" v-model.number="quantity"
outlined outlined
@ -28,11 +28,18 @@
</ToolWrapper> </ToolWrapper>
</template> </template>
<tool>
title: 'UUIDs generator'
description: 'A universally unique identifier (UUID) is a 128-bit number used to identify information in computer systems. '
icon: 'mdi-fingerprint'
keywords: ['uuid', 'v4', 'random', 'id', 'alphanumeric', 'identity']
path: '/uuid-generator'
</tool>
<script lang="ts"> <script lang="ts">
import {Component, Ref, Watch} from 'nuxt-property-decorator' import {Component, Ref, Watch} from 'nuxt-property-decorator'
import {CopyableMixin} from '@/mixins/copyable.mixin' import {CopyableMixin} from '@/mixins/copyable.mixin'
import type {ToolConfig} from '@/types/ToolConfig'
import { VTextField } from 'vuetify/lib' import { VTextField } from 'vuetify/lib'
import Tool from '~/components/Tool.vue' import Tool from '~/components/Tool.vue'
@ -42,15 +49,6 @@ const generateUuid = () => '10000000-1000-4000-8000-100000000000'.replace(/[018]
mixins: [CopyableMixin] mixins: [CopyableMixin]
}) })
export default class UuidGenerator extends Tool { export default class UuidGenerator extends Tool {
config(): ToolConfig {
return {
title: 'UUIDs generator',
description: 'A universally unique identifier (UUID) is a 128-bit number used to identify information in computer systems. ',
icon: 'mdi-fingerprint',
keywords: ['uuid', 'v4', 'random', 'id', 'alphanumeric', 'identity']
}
}
@Ref() readonly quantityEl! : typeof VTextField @Ref() readonly quantityEl! : typeof VTextField
token = '' token = ''
quantity = 1 quantity = 1

View file

@ -1,18 +1,17 @@
<tool>
title: 'Git memo'
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.'
icon: 'mdi-git'
keywords: ['git', 'memo', 'cheat', 'sheet']
path: '/git-memo'
</tool>
<script lang="ts"> <script lang="ts">
import {Component} from 'nuxt-property-decorator' import {Component} from 'nuxt-property-decorator'
import type {ToolConfig} from '@/types/ToolConfig'
import Memo from '~/components/Memo.vue' import Memo from '~/components/Memo.vue'
@Component @Component
export default class GitMemo extends Memo { export default class GitMemo extends Memo {
config(): ToolConfig {
return {
title: 'Git memo',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.',
icon: 'mdi-git',
keywords: ['git', 'memo', 'cheat', 'sheet']
}
}
} }
</script> </script>

View file

@ -1,5 +1,5 @@
<template> <template>
<ToolWrapper :config="config()"> <ToolWrapper :config="$toolConfig">
<div class="result"> <div class="result">
{{ cronString }} {{ cronString }}
</div> </div>
@ -162,27 +162,25 @@
</ToolWrapper> </ToolWrapper>
</template> </template>
<tool>
title: 'Crontab generator'
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.'
icon: 'mdi-calendar-clock'
keywords: ['year', 'month', 'week', 'day', 'minute', 'second']
path: '/crontab-generator'
</tool>
<script lang="ts"> <script lang="ts">
import {Component} from 'nuxt-property-decorator' import {Component} from 'nuxt-property-decorator'
import cronstrue from 'cronstrue' import cronstrue from 'cronstrue'
import {isValidCron} from 'cron-validator' import {isValidCron} from 'cron-validator'
import {CopyableMixin} from '~/mixins/copyable.mixin' import {CopyableMixin} from '~/mixins/copyable.mixin'
import Tool from '~/components/Tool.vue' import Tool from '~/components/Tool.vue'
import type {ToolConfig} from '~/types/ToolConfig'
@Component({ @Component({
mixins: [CopyableMixin] mixins: [CopyableMixin]
}) })
export default class CrontabGenerator extends Tool { export default class CrontabGenerator extends Tool {
config(): ToolConfig {
return {
title: 'Crontab generator',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.',
icon: 'mdi-calendar-clock',
keywords: ['year', 'month', 'week', 'day', 'minute', 'second']
}
}
cron = '* * * * *' cron = '* * * * *'
cronstrueConfig = { cronstrueConfig = {
verbose: true, verbose: true,

View file

@ -1,5 +1,5 @@
<template> <template>
<ToolWrapper :config="config()"> <ToolWrapper :config="$toolConfig">
<v-text-field <v-text-field
v-model="port" v-model="port"
outlined outlined
@ -18,11 +18,18 @@
</ToolWrapper> </ToolWrapper>
</template> </template>
<tool>
title: 'Random port generator'
description: 'Random port generator without the range of "known" ports (0-1023).'
icon: 'mdi-lan-pending'
keywords: ['system', 'port', 'lan']
path: '/random-port-generator'
</tool>
<script lang="ts"> <script lang="ts">
import {Component} from 'nuxt-property-decorator' import {Component} from 'nuxt-property-decorator'
import {CopyableMixin} from '@/mixins/copyable.mixin' import {CopyableMixin} from '@/mixins/copyable.mixin'
import type {ToolConfig} from '@/types/ToolConfig'
import Tool from '~/components/Tool.vue' import Tool from '~/components/Tool.vue'
import {randIntFromInterval} from '~/utils/random' import {randIntFromInterval} from '~/utils/random'
@ -32,15 +39,6 @@ const generatePort = () => randIntFromInterval(1024, 65535)
mixins: [CopyableMixin] mixins: [CopyableMixin]
}) })
export default class RandomPortGenerator extends Tool { export default class RandomPortGenerator extends Tool {
config(): ToolConfig {
return {
title: 'Random port generator',
description: 'Random port generator without the range of "known" ports (0-1023).',
icon: 'mdi-lan-pending',
keywords: ['system', 'port', 'lan']
}
}
port!: number port!: number
created() { created() {

View file

@ -1,5 +1,5 @@
<template> <template>
<ToolWrapper :config="config()"> <ToolWrapper :config="$toolConfig">
<v-slider v-model="paragraphs" min="1" max="20" label="Paragraphs" thumb-label /> <v-slider v-model="paragraphs" min="1" max="20" label="Paragraphs" thumb-label />
<v-range-slider <v-range-slider
v-model="sentencePerParagraph" v-model="sentencePerParagraph"
@ -35,11 +35,18 @@
</ToolWrapper> </ToolWrapper>
</template> </template>
<tool>
title: 'Lorem ipsum generator'
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.'
icon: 'mdi-comment-text'
keywords: ['Lorem', 'ipsum', 'dolor', 'sit', 'amet']
path: '/lorem-ipsum-generator'
</tool>
<script lang="ts"> <script lang="ts">
import {Component} from 'nuxt-property-decorator' import {Component} from 'nuxt-property-decorator'
import {CopyableMixin} from '~/mixins/copyable.mixin' import {CopyableMixin} from '~/mixins/copyable.mixin'
import Tool from '~/components/Tool.vue' import Tool from '~/components/Tool.vue'
import type {ToolConfig} from '~/types/ToolConfig'
import {randFromArray, randIntFromInterval} from '~/utils/random' import {randFromArray, randIntFromInterval} from '~/utils/random'
const vocabulary = ['a', 'ac', 'accumsan', 'ad', 'adipiscing', 'aenean', 'aliquam', 'aliquet', 'amet', 'ante', 'aptent', 'arcu', 'at', 'auctor', 'bibendum', 'blandit', 'class', 'commodo', 'condimentum', 'congue', 'consectetur', 'consequat', 'conubia', 'convallis', 'cras', 'cubilia', 'cum', 'curabitur', 'curae', 'dapibus', 'diam', 'dictum', 'dictumst', 'dignissim', 'dolor', 'donec', 'dui', 'duis', 'egestas', 'eget', 'eleifend', 'elementum', 'elit', 'enim', 'erat', 'eros', 'est', 'et', 'etiam', 'eu', 'euismod', 'facilisi', 'faucibus', 'felis', 'fermentum', 'feugiat', 'fringilla', 'fusce', 'gravida', 'habitant', 'habitasse', 'hac', 'hendrerit', 'himenaeos', 'iaculis', 'id', 'imperdiet', 'in', 'inceptos', 'integer', 'interdum', 'ipsum', 'justo', 'lacinia', 'lacus', 'laoreet', 'lectus', 'leo', 'ligula', 'litora', 'lobortis', 'lorem', 'luctus', 'maecenas', 'magna', 'magnis', 'malesuada', 'massa', 'mattis', 'mauris', 'metus', 'mi', 'molestie', 'mollis', 'montes', 'morbi', 'mus', 'nam', 'nascetur', 'natoque', 'nec', 'neque', 'netus', 'nisi', 'nisl', 'non', 'nostra', 'nulla', 'nullam', 'nunc', 'odio', 'orci', 'ornare', 'parturient', 'pellentesque', 'penatibus', 'per', 'pharetra', 'phasellus', 'placerat', 'platea', 'porta', 'porttitor', 'posuere', 'potenti', 'praesent', 'pretium', 'primis', 'proin', 'pulvinar', 'purus', 'quam', 'quis', 'quisque', 'rhoncus', 'ridiculus', 'risus', 'rutrum', 'sagittis', 'sapien', 'scelerisque', 'sed', 'sem', 'semper', 'senectus', 'sit', 'sociis', 'sociosqu', 'sodales', 'sollicitudin', 'suscipit', 'suspendisse', 'taciti', 'tellus', 'tempor', 'tempus', 'tincidunt', 'torquent', 'tortor', 'turpis', 'ullamcorper', 'ultrices', 'ultricies', 'urna', 'varius', 'vehicula', 'vel', 'velit', 'venenatis', 'vestibulum', 'vitae', 'vivamus', 'viverra', 'volutpat', 'vulputate'] const vocabulary = ['a', 'ac', 'accumsan', 'ad', 'adipiscing', 'aenean', 'aliquam', 'aliquet', 'amet', 'ante', 'aptent', 'arcu', 'at', 'auctor', 'bibendum', 'blandit', 'class', 'commodo', 'condimentum', 'congue', 'consectetur', 'consequat', 'conubia', 'convallis', 'cras', 'cubilia', 'cum', 'curabitur', 'curae', 'dapibus', 'diam', 'dictum', 'dictumst', 'dignissim', 'dolor', 'donec', 'dui', 'duis', 'egestas', 'eget', 'eleifend', 'elementum', 'elit', 'enim', 'erat', 'eros', 'est', 'et', 'etiam', 'eu', 'euismod', 'facilisi', 'faucibus', 'felis', 'fermentum', 'feugiat', 'fringilla', 'fusce', 'gravida', 'habitant', 'habitasse', 'hac', 'hendrerit', 'himenaeos', 'iaculis', 'id', 'imperdiet', 'in', 'inceptos', 'integer', 'interdum', 'ipsum', 'justo', 'lacinia', 'lacus', 'laoreet', 'lectus', 'leo', 'ligula', 'litora', 'lobortis', 'lorem', 'luctus', 'maecenas', 'magna', 'magnis', 'malesuada', 'massa', 'mattis', 'mauris', 'metus', 'mi', 'molestie', 'mollis', 'montes', 'morbi', 'mus', 'nam', 'nascetur', 'natoque', 'nec', 'neque', 'netus', 'nisi', 'nisl', 'non', 'nostra', 'nulla', 'nullam', 'nunc', 'odio', 'orci', 'ornare', 'parturient', 'pellentesque', 'penatibus', 'per', 'pharetra', 'phasellus', 'placerat', 'platea', 'porta', 'porttitor', 'posuere', 'potenti', 'praesent', 'pretium', 'primis', 'proin', 'pulvinar', 'purus', 'quam', 'quis', 'quisque', 'rhoncus', 'ridiculus', 'risus', 'rutrum', 'sagittis', 'sapien', 'scelerisque', 'sed', 'sem', 'semper', 'senectus', 'sit', 'sociis', 'sociosqu', 'sodales', 'sollicitudin', 'suscipit', 'suspendisse', 'taciti', 'tellus', 'tempor', 'tempus', 'tincidunt', 'torquent', 'tortor', 'turpis', 'ullamcorper', 'ultrices', 'ultricies', 'urna', 'varius', 'vehicula', 'vel', 'velit', 'venenatis', 'vestibulum', 'vitae', 'vivamus', 'viverra', 'volutpat', 'vulputate']
@ -54,15 +61,6 @@ const generateSentence = (length: number) => {
mixins: [CopyableMixin] mixins: [CopyableMixin]
}) })
export default class LoremIpsumGenerator extends Tool { export default class LoremIpsumGenerator extends Tool {
config(): ToolConfig {
return {
title: 'Lorem ipsum generator',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.',
icon: 'mdi-comment-text',
keywords: ['Lorem', 'ipsum', 'dolor', 'sit', 'amet']
}
}
paragraphs = 1 paragraphs = 1
sentencePerParagraph = [3, 8] sentencePerParagraph = [3, 8]
wordPerSentence = [8, 15] wordPerSentence = [8, 15]

View file

@ -1,5 +1,5 @@
<template> <template>
<ToolWrapper :config="config()"> <ToolWrapper :config="$toolConfig">
<v-textarea <v-textarea
v-model="text" v-model="text"
outlined outlined
@ -8,49 +8,54 @@
auto-grow auto-grow
/> />
<div>{{ $toolListFlat }}</div>
<table> <table>
<tr> <tbody>
<td><strong>Character count:</strong></td> <tr>
<td>{{ textLength }}</td> <td><strong>Character count:</strong></td>
</tr> <td>{{ textLength }}</td>
<tr> </tr>
<td><strong>Word count:</strong></td> <tr>
<td>{{ textWordCount }}</td> <td><strong>Word count:</strong></td>
</tr> <td>{{ textWordCount }}</td>
<tr> </tr>
<td><strong>Line count:</strong></td> <tr>
<td>{{ textLineCount }}</td> <td><strong>Line count:</strong></td>
</tr> <td>{{ textLineCount }}</td>
<tr> </tr>
<td><strong>Byte size:</strong></td> <tr>
<td>{{ textSize }}</td> <td><strong>Byte size:</strong></td>
</tr> <td>{{ textSize }}</td>
</tr>
</tbody>
</table> </table>
</ToolWrapper> </ToolWrapper>
</template> </template>
<tool>
title: 'Text stats'
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.'
icon: mdi-text
keywords: [ length, character, count ]
path: '/text-stats'
</tool>
<script lang="ts"> <script lang="ts">
import {Component} from 'nuxt-property-decorator' import {Component} from 'nuxt-property-decorator'
import {CopyableMixin} from '~/mixins/copyable.mixin' import {CopyableMixin} from '~/mixins/copyable.mixin'
import Tool from '~/components/Tool.vue' import Tool from '~/components/Tool.vue'
import type {ToolConfig} from '~/types/ToolConfig'
import {formatBytes} from '~/utils/convert' import {formatBytes} from '~/utils/convert'
@Component({ @Component({
mixins: [CopyableMixin] mixins: [CopyableMixin]
}) })
export default class TextStats extends Tool { export default class TextStats extends Tool {
config(): ToolConfig {
return {
title: 'Text stats',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.',
icon: 'mdi-text',
keywords: ['length', 'character', 'count']
}
}
text = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.' text = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.'
created() {
}
get textLength() { get textLength() {
return this.text.length return this.text.length
} }

View file

@ -1,5 +1,5 @@
<template> <template>
<ToolWrapper :config="config()" no-card="true"> <ToolWrapper :config="$toolConfig" no-card="true">
<FileUploader v-model="file" /> <FileUploader v-model="file" />
<div v-if="base64 || loading" class="mt-10"> <div v-if="base64 || loading" class="mt-10">
@ -25,11 +25,18 @@
</ToolWrapper> </ToolWrapper>
</template> </template>
<tool>
title: 'File to base64'
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.'
icon: 'mdi-file-link-outline'
keywords: ['file', 'base64']
path: '/file-to-base64'
</tool>
<script lang="ts"> <script lang="ts">
import {Component, Watch} from 'nuxt-property-decorator' import {Component, Watch} from 'nuxt-property-decorator'
import {CopyableMixin} from '@/mixins/copyable.mixin' import {CopyableMixin} from '@/mixins/copyable.mixin'
import Tool from '@/components/Tool.vue' import Tool from '@/components/Tool.vue'
import type {ToolConfig} from '@/types/ToolConfig'
import FileUploader from '~/components/FileUploader.vue' import FileUploader from '~/components/FileUploader.vue'
@Component({ @Component({
@ -37,15 +44,6 @@ import FileUploader from '~/components/FileUploader.vue'
components: {FileUploader} components: {FileUploader}
}) })
export default class FileToBase64 extends Tool { export default class FileToBase64 extends Tool {
config(): ToolConfig {
return {
title: 'File to base64',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.',
icon: 'mdi-file-link-outline',
keywords: ['file', 'base64']
}
}
file: Blob | null = null file: Blob | null = null
loading = false loading = false
base64 = '' base64 = ''

View file

@ -1,5 +1,5 @@
<template> <template>
<ToolWrapper :config="config()"> <ToolWrapper :config="$toolConfig">
<v-row justify="center" align="center"> <v-row justify="center" align="center">
<v-col cols="12" lg="6" sm="12"> <v-col cols="12" lg="6" sm="12">
<v-text-field <v-text-field
@ -49,13 +49,20 @@
</ToolWrapper> </ToolWrapper>
</template> </template>
<tool>
title: 'QR-code generator'
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.'
icon: 'mdi-qrcode'
keywords: ['editor']
path: '/qrcode-generator'
</tool>
<script lang="ts"> <script lang="ts">
import {Component} from 'nuxt-property-decorator' import {Component} from 'nuxt-property-decorator'
import QrcodeVue from 'qrcode.vue' import QrcodeVue from 'qrcode.vue'
import colors from 'color-name' import colors from 'color-name'
import {CopyableMixin} from '~/mixins/copyable.mixin' import {CopyableMixin} from '~/mixins/copyable.mixin'
import Tool from '~/components/Tool.vue' import Tool from '~/components/Tool.vue'
import type {ToolConfig} from '~/types/ToolConfig'
import {downloadBase64File} from '~/utils/file' import {downloadBase64File} from '~/utils/file'
import {stringToBase64} from '~/utils/convert' import {stringToBase64} from '~/utils/convert'
import ColorInput from '~/components/ColorInput.vue' import ColorInput from '~/components/ColorInput.vue'
@ -65,15 +72,6 @@ import ColorInput from '~/components/ColorInput.vue'
mixins: [CopyableMixin] mixins: [CopyableMixin]
}) })
export default class QrcodeGenerator extends Tool { export default class QrcodeGenerator extends Tool {
config(): ToolConfig {
return {
title: 'QR-code generator',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus distinctio dolor dolorum eaque eligendi, facilis impedit laboriosam odit placeat.',
icon: 'mdi-qrcode',
keywords: ['editor']
}
}
value = 'https://it-tools.tech' value = 'https://it-tools.tech'
size = 300 size = 300
level = 'M' level = 'M'

View file

@ -1,13 +1,14 @@
import {RouteConfig} from '@nuxt/types/config/router';
interface ToolConfig { interface ToolConfig {
title: string; title: string;
description: string; description: string;
icon: string; icon: string;
keywords: string[]; keywords: string[];
path?: string
} }
type ToolConfigMethod = () => ToolConfig; interface ToolRouteConfig extends ToolConfig{
type ToolRouteConfig = RouteConfig & {config: ToolConfig} componentPath: string
}
export {ToolConfig, ToolConfigMethod, ToolRouteConfig} export {ToolConfig, ToolRouteConfig}