feat: added components
68
CHANGELOG.md
Normal file
|
@ -0,0 +1,68 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Next
|
||||
### Changed
|
||||
- Switched to [Nuxt.js](//nuxtjs.org)
|
||||
- Server-Side rendered static app
|
||||
- Better SEO
|
||||
- Switched to Typescript using class components decorators from [nuxt-property-decorator](https://github.com/nuxt-community/nuxt-property-decorator)
|
||||
- UI and theme reworked
|
||||
- URL path changed
|
||||
- `/hash` -> [`/hash-text`](https://it-tools.tech/hash-text)
|
||||
- `/cypher` -> [`/cypher-uncyfer-text`](https://it-tools.tech/cypher-uncyfer-text)
|
||||
|
||||
### Added
|
||||
- Added [/how-to-report-bug-or-request](/how-to-report-bug-or-request) route to explain how to report bug and request features
|
||||
|
||||
## 1.7.0
|
||||
- [feat] [Crontab friendly generator](https://it-tools.tech/crontab-generator)
|
||||
|
||||
## 1.6.0
|
||||
- [feat] [BIP39 generator](https://it-tools.tech/bip39-generator)
|
||||
- [feat] [Base 64 converter](https://it-tools.tech/base64-string-converter)
|
||||
|
||||
## 1.5.2
|
||||
- [feat] [humans.txt](https://it-tools.tech/humans.txt)
|
||||
- [feat] pwa auto update on new changes
|
||||
|
||||
## 1.5.1
|
||||
- [feat] switched back to history mode (no more '#' in url)
|
||||
|
||||
## 1.5.0
|
||||
- [feat] added [qr-code generator](https://it-tools.tech/qrcode-generator)
|
||||
|
||||
## 1.4.0
|
||||
- [ui] condensed + colored sidenav
|
||||
- [feat] added [git memo](https://it-tools.tech/git-memo)
|
||||
- [refactor] changed app title
|
||||
|
||||
## 1.3.0
|
||||
- [fix] [GithubContributors] ordered contributors by contribution count
|
||||
- [refactor] used vue-typecasting for number inputs
|
||||
- [feat] lazy loading tools routes
|
||||
- [feat] added [markdown editor](https://it-tools.tech/markdown-editor)
|
||||
- [feat] added [lorem ipsum generator](https://it-tools.tech/lorem-ipsum-generator)
|
||||
|
||||
## 1.2.1
|
||||
- [fix] [UuidGenerator] added quantity validation rules
|
||||
- [refactor] better isInt checker
|
||||
|
||||
## 1.2.0
|
||||
- [feat] [UuidGenerator] can generate multiple uuids
|
||||
|
||||
## 1.1.0
|
||||
- [feat] 404 route + page
|
||||
- [feat] changelog in the About page
|
||||
- [feat] contributors list in the About page
|
||||
- [fix] [ColorConverter] color picker now updates fields
|
||||
|
||||
## 1.0.1
|
||||
- [chore] added changelog
|
||||
- [fix] [BaseConverter] prevented non-integer bases
|
||||
- [fix] remove history move (incompatible with vercel.com)
|
||||
|
||||
## 1.0.0
|
||||
- First release
|
|
@ -3,3 +3,4 @@
|
|||
// The variables you want to modify
|
||||
// $font-size-root: 20px;
|
||||
|
||||
$test: linear-gradient(90deg, rgba(37, 99, 108, 1) 0%, rgba(59, 149, 111, 1) 60%, rgba(71, 177, 113, 1) 100%)
|
||||
|
|
|
@ -2,14 +2,15 @@
|
|||
<v-autocomplete
|
||||
label="Search..."
|
||||
single-line
|
||||
append-icon="fa-search"
|
||||
append-icon="mdi-magnify"
|
||||
color="white"
|
||||
hide-details
|
||||
:items="items"
|
||||
item-text="text"
|
||||
:items="toolRoutesFlat"
|
||||
:item-text="item => item.config.title"
|
||||
item-value="path"
|
||||
solo-inverted
|
||||
:filter="filter"
|
||||
dense
|
||||
:filter="filterItems"
|
||||
clearable
|
||||
cache-items
|
||||
@change="choose"
|
||||
|
@ -24,23 +25,39 @@
|
|||
</v-autocomplete>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Component, Vue} from 'nuxt-property-decorator'
|
||||
import {ToolRoutes} from '~/mixins/tool-routes'
|
||||
<script lang="ts">
|
||||
import {Component, mixins} from 'nuxt-property-decorator'
|
||||
import {ToolRoutesMixin} from '@/mixins/tool-routes.mixin'
|
||||
import {ToolRouteConfig} from '~/types/ToolConfig'
|
||||
|
||||
@Component({
|
||||
mixins: [ToolRoutes]
|
||||
})
|
||||
export default class SearchBar extends Vue {
|
||||
title = 'IT - Tools'
|
||||
drawer = false
|
||||
items = []
|
||||
@Component
|
||||
export default class SearchBar extends mixins(ToolRoutesMixin) {
|
||||
choose(path:string) {
|
||||
this.$router.push({path})
|
||||
}
|
||||
|
||||
filterItems(item:ToolRouteConfig, queryText:string, itemText:string) {
|
||||
const query = queryText.trim().toLowerCase()
|
||||
const nameContainsText = itemText.toLowerCase().includes(query)
|
||||
const keywordContainsText = item?.config?.keywords.some((keyword:string) => keyword.toLowerCase().includes(query)) ?? false
|
||||
return nameContainsText || keywordContainsText
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
::v-deep .v-list-item__mask{
|
||||
color: inherit !important;
|
||||
background: inherit !important;
|
||||
::v-deep {
|
||||
.v-input__slot{
|
||||
background: var(--v-primary-base) !important;
|
||||
background: linear-gradient(90deg, rgba(37,99,108,1) 0%, rgba(59,149,111,1) 60%, rgba(71,177,113,1) 100%) !important;
|
||||
input {
|
||||
color: #ffffff !important;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.v-list{
|
||||
background: var(--v-foreground-base) !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="tool-wrapper">
|
||||
<v-row no-gutters justify="center" align="center">
|
||||
<v-col cols="12" lg="6">
|
||||
<v-col cols="12" xl="6" lg="8" md="10">
|
||||
<div class="tool-wrapper-info">
|
||||
<h1>{{ config.title }}</h1>
|
||||
<div class="spacer" />
|
||||
|
@ -50,9 +50,10 @@ export default class ToolWrapper extends Vue {
|
|||
}
|
||||
|
||||
.spacer{
|
||||
width: 130px;
|
||||
height: 1px;
|
||||
background-color: var(--v-primary-base);
|
||||
width: 200px;
|
||||
height: 2px;
|
||||
background: var(--v-primary-base);
|
||||
background: linear-gradient(90deg, rgba(71, 177, 113, 1) 0%, rgba(59, 149, 111, 1) 60%, rgba(37, 99, 108, 1) 200%);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<SearchBar class="hidden-sm-and-up" />
|
||||
|
||||
<v-list>
|
||||
<div v-for="(items, section) in toolRoutesSections" :key="section">
|
||||
<v-subheader class="mt-4 pl-4">
|
||||
|
@ -26,13 +28,15 @@
|
|||
<v-list-item
|
||||
v-for="(item, i) in items"
|
||||
:key="i"
|
||||
:to="items.path"
|
||||
:to="item.path"
|
||||
router
|
||||
exact
|
||||
dense
|
||||
>
|
||||
<v-list-item-action>
|
||||
<v-icon>{{ item.config.icon }}</v-icon>
|
||||
<v-icon color="primary">
|
||||
{{ item.config.icon }}
|
||||
</v-icon>
|
||||
</v-list-item-action>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="item.config.title" />
|
||||
|
@ -48,8 +52,24 @@
|
|||
height="60px"
|
||||
>
|
||||
<v-app-bar-nav-icon @click.stop="drawer = !drawer" />
|
||||
<v-toolbar-title v-if="!drawer" v-text="title" />
|
||||
<v-toolbar-title>
|
||||
<NuxtLink to="/" class="title">
|
||||
{{ title }}
|
||||
</NuxtLink>
|
||||
</v-toolbar-title>
|
||||
<v-spacer />
|
||||
<SearchBar class="hidden-sm-and-down" />
|
||||
<v-spacer />
|
||||
|
||||
<NuxtLink to="/how-to-report-bug-or-request">
|
||||
Bug / Request
|
||||
</NuxtLink>
|
||||
<NuxtLink to="/about">
|
||||
About
|
||||
</NuxtLink>
|
||||
<a href="https://github.com/CorentinTh/it-tools" target="_blank" class="github-link">
|
||||
<v-icon>mdi-github</v-icon>
|
||||
</a>
|
||||
</v-app-bar>
|
||||
|
||||
<v-main>
|
||||
|
@ -57,25 +77,27 @@
|
|||
<nuxt />
|
||||
</v-container>
|
||||
</v-main>
|
||||
<!-- <v-footer app>-->
|
||||
<!--<v-footer app>-->
|
||||
<!-- <span>© {{ new Date().getFullYear() }}</span>-->
|
||||
<!-- </v-footer>-->
|
||||
<!--</v-footer>-->
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {Component, mixins} from 'nuxt-property-decorator'
|
||||
import {ToolRoutes} from '~/mixins/tool-routes'
|
||||
import {ToolRoutesMixin} from '~/mixins/tool-routes.mixin'
|
||||
import LogoOutlined from '~/assets/logo-outlined.svg?inline'
|
||||
import HeroGradient from '~/assets/small-hero-gradient.svg?inline'
|
||||
import SearchBar from '~/components/SearchBar.vue'
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
LogoOutlined,
|
||||
HeroGradient
|
||||
HeroGradient,
|
||||
SearchBar
|
||||
}
|
||||
})
|
||||
export default class DefaultLayout extends mixins(ToolRoutes) {
|
||||
export default class DefaultLayout extends mixins(ToolRoutesMixin) {
|
||||
title = 'IT - Tools'
|
||||
drawer = false
|
||||
items = []
|
||||
|
@ -84,6 +106,40 @@ export default class DefaultLayout extends mixins(ToolRoutes) {
|
|||
|
||||
<style lang="less">
|
||||
|
||||
.v-toolbar__content {
|
||||
a {
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
transition: all ease 0.2s;
|
||||
margin: 0 10px;
|
||||
opacity: 0.5;
|
||||
font-size: 15px;
|
||||
|
||||
&.title{
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
color: var(--v-primary-base);
|
||||
}
|
||||
}
|
||||
|
||||
.github-link {
|
||||
border-bottom: none;
|
||||
margin-left: 10px;
|
||||
transition: all ease 0.2s;
|
||||
|
||||
.v-icon {
|
||||
font-size: 37px !important;
|
||||
color: var(--v-primary-base);
|
||||
transition: all ease 0.2s;
|
||||
transition: all ease 0.2s;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.small-hero {
|
||||
position: relative;
|
||||
|
||||
|
@ -96,18 +152,26 @@ export default class DefaultLayout extends mixins(ToolRoutes) {
|
|||
width: 100%;
|
||||
|
||||
.small-hero-content-logo {
|
||||
width: 30%;
|
||||
width: 25%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.small-hero-content-title {
|
||||
font-size: 30px;
|
||||
margin-top: 10px;
|
||||
font-size: 25px;
|
||||
font-weight: 600;
|
||||
font-family: Ubuntu, Roboto, sans-serif;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.v-navigation-drawer__content{
|
||||
.v-list-item--active{
|
||||
color: var(--v-anchor-base);
|
||||
border-left: 3px solid var(--v-primary-base);
|
||||
}
|
||||
}
|
||||
|
||||
.v-application {
|
||||
background-color: var(--v-background-base, #121212) !important;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ const copyToClipboard = (text: string) => {
|
|||
}
|
||||
|
||||
@Component
|
||||
export class Copyable extends Vue {
|
||||
export class CopyableMixin extends Vue {
|
||||
copy(text: string, toastText = 'Copied to clipboard !') {
|
||||
copyToClipboard(text)
|
||||
console.log(toastText)
|
|
@ -1,33 +1,36 @@
|
|||
import {Component, Vue} from 'nuxt-property-decorator'
|
||||
import {RouteConfig} from '@nuxt/types/config/router'
|
||||
import {ToolConfig} from '~/types/ToolConfig'
|
||||
import {ToolRouteConfig} from '~/types/ToolConfig'
|
||||
import {capitalise} from '~/utils/string'
|
||||
|
||||
export type ToolRouteConfig = RouteConfig & {config: ToolConfig}
|
||||
|
||||
@Component
|
||||
export class ToolRoutes extends Vue {
|
||||
export class ToolRoutesMixin extends Vue {
|
||||
toolRoutesFlat : ToolRouteConfig[] = []
|
||||
toolRoutesSections : {[key: string]: ToolRouteConfig[]} = {}
|
||||
|
||||
async mounted() {
|
||||
async created() {
|
||||
const routes = this.$router.options.routes?.filter(r => r.meta?.isTool) || []
|
||||
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
|
||||
this.toolRoutesFlat.push(routeConfig)
|
||||
flat.push(routeConfig)
|
||||
|
||||
const sectionKey = capitalise(route.meta.section).replace(/_/g, ' ')
|
||||
|
||||
if (!(sectionKey in this.toolRoutesSections)) {
|
||||
this.toolRoutesSections[sectionKey] = []
|
||||
if (!(sectionKey in sections)) {
|
||||
sections[sectionKey] = []
|
||||
}
|
||||
|
||||
this.toolRoutesSections[sectionKey].push(routeConfig)
|
||||
sections[sectionKey].push(routeConfig)
|
||||
}
|
||||
}
|
||||
|
||||
this.toolRoutesSections = sections
|
||||
this.toolRoutesFlat = flat
|
||||
}
|
||||
}
|
3534
package-lock.json
generated
|
@ -13,11 +13,13 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@nuxt/typescript-runtime": "^2.0.1",
|
||||
"@nuxtjs/axios": "^5.12.2",
|
||||
"@nuxtjs/axios": "^5.13.1",
|
||||
"@nuxtjs/pwa": "^3.0.2",
|
||||
"@nuxtjs/toast": "^3.3.1",
|
||||
"core-js": "^3.6.5",
|
||||
"crypto-js": "^4.0.0",
|
||||
"nuxt": "^2.14.12",
|
||||
"vuetify": "^2.4.5",
|
||||
"vuetify-toast-snackbar": "^0.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -28,11 +30,12 @@
|
|||
"@nuxtjs/eslint-module": "^2.0.0",
|
||||
"@nuxtjs/svg": "^0.1.12",
|
||||
"@nuxtjs/vuetify": "^1.11.2",
|
||||
"@types/crypto-js": "^4.0.1",
|
||||
"@vue/test-utils": "^1.1.0",
|
||||
"babel-core": "7.0.0-bridge.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-jest": "^26.5.0",
|
||||
"eslint": "^7.10.0",
|
||||
"eslint": "^7.20.0",
|
||||
"eslint-config-prettier": "^6.12.0",
|
||||
"eslint-plugin-nuxt": "^1.0.0",
|
||||
"eslint-plugin-prettier": "^3.1.4",
|
||||
|
@ -40,7 +43,7 @@
|
|||
"less": "^4.0.0",
|
||||
"less-loader": "^7.1.0",
|
||||
"nuxt-property-decorator": "^2.9.1",
|
||||
"ts-jest": "^26.4.1",
|
||||
"ts-jest": "^26.5.1",
|
||||
"vue-jest": "^3.0.4"
|
||||
}
|
||||
}
|
||||
|
|
20
pages/about.vue
Normal file
|
@ -0,0 +1,20 @@
|
|||
<template>
|
||||
<v-row justify="center" align="center">
|
||||
<v-col cols="12" sm="12" md="8">
|
||||
<h1>Yolo</h1>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Component, Vue} from 'nuxt-property-decorator'
|
||||
|
||||
@Component
|
||||
export default class About extends Vue {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
|
||||
</style>
|
20
pages/how-to-report-bug-or-request.vue
Normal file
|
@ -0,0 +1,20 @@
|
|||
<template>
|
||||
<v-row justify="center" align="center">
|
||||
<v-col cols="12" sm="12" md="8">
|
||||
<h1>How-to-report-bug-or-request</h1>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Component, Vue} from 'nuxt-property-decorator'
|
||||
|
||||
@Component
|
||||
export default class HowToReportBugOrRequest extends Vue {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
|
||||
</style>
|
|
@ -2,17 +2,57 @@
|
|||
<v-row justify="center" align="center">
|
||||
<v-col cols="12" sm="12" md="8">
|
||||
<h1>Yolo</h1>
|
||||
|
||||
<v-card v-for="(items, section) in toolRoutesSections" :key="section">
|
||||
<v-card-title>{{ section }}</v-card-title>
|
||||
<v-card-text>
|
||||
<v-list>
|
||||
<v-list-item
|
||||
v-for="(item, i) in items"
|
||||
:key="i"
|
||||
:to="item.path"
|
||||
router
|
||||
exact
|
||||
>
|
||||
<v-list-item-action>
|
||||
<v-icon>{{ item.config.icon }}</v-icon>
|
||||
</v-list-item-action>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="item.config.title" />
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Component, mixins} from 'nuxt-property-decorator'
|
||||
import {ToolRoutesMixin} from '@/mixins/tool-routes.mixin'
|
||||
|
||||
export default {
|
||||
components: {}
|
||||
@Component
|
||||
export default class Index extends mixins(ToolRoutesMixin) {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
<style scopedlang="less">
|
||||
.v-list{
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.v-card__title{
|
||||
background: var(--v-primary-base) !important;
|
||||
background: linear-gradient(90deg, rgba(37,99,108,1) 0%, rgba(59,149,111,1) 60%, rgba(71,177,113,1) 100%) !important;
|
||||
padding-left: 33px;
|
||||
}
|
||||
|
||||
.v-list-item{
|
||||
padding-left: 31px;
|
||||
}
|
||||
|
||||
.v-card__text{
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
106
pages/tools/crypto/cypher-uncyfer-text.vue
Normal file
|
@ -0,0 +1,106 @@
|
|||
<template>
|
||||
<ToolWrapper :config="config()">
|
||||
<v-row justify="center" align="center">
|
||||
<v-col cols="12" lg="8" md="12">
|
||||
<v-textarea
|
||||
v-model="key"
|
||||
outlined
|
||||
label="Encryption key"
|
||||
rows="1"
|
||||
@input="encrypt"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" lg="4" md="12">
|
||||
<v-select
|
||||
v-model="algorithm"
|
||||
:items="Object.keys(algorithms)"
|
||||
label="Algorithm"
|
||||
outlined
|
||||
@change="encrypt"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-textarea
|
||||
v-model="decrypted"
|
||||
outlined
|
||||
label="Clear text"
|
||||
@input="encrypt"
|
||||
/>
|
||||
|
||||
<v-textarea
|
||||
v-model="encrypted"
|
||||
outlined
|
||||
label="Cyphered text"
|
||||
@input="decrypt"
|
||||
/>
|
||||
<div class="text-center">
|
||||
<v-btn depressed @click="copy(encrypted)">
|
||||
Copy result
|
||||
</v-btn>
|
||||
</div>
|
||||
</ToolWrapper>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {Component} from 'nuxt-property-decorator'
|
||||
import {CopyableMixin} from '@/mixins/copyable.mixin'
|
||||
import Tool from '@/components/Tool'
|
||||
import {ToolConfig} from '@/types/ToolConfig'
|
||||
import CryptoJS from 'crypto-js'
|
||||
|
||||
const algos = {
|
||||
AES: CryptoJS.AES,
|
||||
TripleDES: CryptoJS.TripleDES,
|
||||
Rabbit: CryptoJS.Rabbit,
|
||||
RabbitLegacy: CryptoJS.RabbitLegacy,
|
||||
RC4: CryptoJS.RC4
|
||||
}
|
||||
|
||||
@Component({
|
||||
mixins: [CopyableMixin]
|
||||
})
|
||||
export default class CypherUncyferText extends Tool {
|
||||
algorithm: keyof typeof algos = 'AES'
|
||||
algorithms: typeof algos = algos
|
||||
key = 'sup3r s3cr3t k3y'
|
||||
decrypted = 'Lorem ipsum dolor sit amet.'
|
||||
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() {
|
||||
this.encrypt()
|
||||
}
|
||||
|
||||
encrypt() {
|
||||
try {
|
||||
this.encrypted = this.algorithms[this.algorithm]
|
||||
.encrypt(this.decrypted.trim(), this.key)
|
||||
.toString()
|
||||
} catch (ignored) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
decrypt() {
|
||||
try {
|
||||
this.decrypted = this.algorithms[this.algorithm]
|
||||
.decrypt(this.encrypted.trim(), this.key)
|
||||
.toString(CryptoJS.enc.Utf8)
|
||||
} catch (ignored) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
</style>
|
78
pages/tools/crypto/hash-text.vue
Normal file
|
@ -0,0 +1,78 @@
|
|||
<template>
|
||||
<ToolWrapper :config="config()">
|
||||
<v-textarea
|
||||
v-model="inputText"
|
||||
outlined
|
||||
label="Text to hash"
|
||||
/>
|
||||
|
||||
<v-select
|
||||
v-model="algorithm"
|
||||
:items="Object.keys(algorithms)"
|
||||
label="Algorithm"
|
||||
outlined
|
||||
/>
|
||||
|
||||
<v-textarea
|
||||
v-model="hashed"
|
||||
outlined
|
||||
readonly
|
||||
label="Hashed text"
|
||||
/>
|
||||
<div class="text-center">
|
||||
<v-btn depressed @click="copy(hashed)">
|
||||
Copy hash
|
||||
</v-btn>
|
||||
</div>
|
||||
</ToolWrapper>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {Component} from 'nuxt-property-decorator'
|
||||
import CryptoJS from 'crypto-js'
|
||||
import {CopyableMixin} from '~/mixins/copyable.mixin'
|
||||
import Tool from '~/components/Tool.vue'
|
||||
import {ToolConfig} from '~/types/ToolConfig'
|
||||
|
||||
const algos = {
|
||||
MD5: CryptoJS.MD5,
|
||||
SHA1: CryptoJS.SHA1,
|
||||
SHA256: CryptoJS.SHA256,
|
||||
SHA224: CryptoJS.SHA224,
|
||||
SHA512: CryptoJS.SHA512,
|
||||
SHA384: CryptoJS.SHA384,
|
||||
SHA3: CryptoJS.SHA3,
|
||||
RIPEMD160: CryptoJS.RIPEMD160
|
||||
}
|
||||
|
||||
@Component({
|
||||
mixins: [CopyableMixin]
|
||||
})
|
||||
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.'
|
||||
algorithm: keyof typeof algos = 'SHA256'
|
||||
algorithms: typeof algos = algos
|
||||
|
||||
get hashed() {
|
||||
if (this.algorithms[this.algorithm]) {
|
||||
return this.algorithms[this.algorithm](this.inputText).toString()
|
||||
} else {
|
||||
this.$toast.error('Invalid algorithm.')
|
||||
return ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
|
@ -11,7 +11,7 @@
|
|||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-slider v-model="length" :label="`Length (${length})`" min="1" max="256" />
|
||||
<v-slider v-model="length" :label="`Length (${length})`" min="1" max="512" />
|
||||
|
||||
<v-textarea v-model="token" outlined />
|
||||
|
||||
|
@ -30,16 +30,16 @@
|
|||
import {Component} from 'nuxt-property-decorator'
|
||||
import Tool from '~/components/Tool.vue'
|
||||
import {ToolConfig} from '~/types/ToolConfig'
|
||||
import {Copyable} from '~/mixins/copyable'
|
||||
import {CopyableMixin} from '~/mixins/copyable.mixin'
|
||||
import {shuffle} from '~/utils/string'
|
||||
|
||||
const shuffle = (s: string) => s.split('').sort(() => 0.5 - Math.random()).join('')
|
||||
const lowercase = 'abcdefghijklmopqrstuvwxyz'
|
||||
const uppercase = 'ABCDEFGHIJKLMOPQRSTUVWXYZ'
|
||||
const numbers = '0123456789'
|
||||
const specials = '.,;:!?./-"\'#{([-|\\@)]=}*+'
|
||||
|
||||
@Component({
|
||||
mixins: [Copyable]
|
||||
mixins: [CopyableMixin]
|
||||
})
|
||||
export default class TokenGenerator extends Tool {
|
||||
config(): ToolConfig {
|
||||
|
|
92
pages/tools/crypto/uuid-generator.vue
Normal file
|
@ -0,0 +1,92 @@
|
|||
<template>
|
||||
<ToolWrapper :config="config()">
|
||||
<v-text-field
|
||||
v-model.number="quantity"
|
||||
outlined
|
||||
type="number"
|
||||
label="Quantity"
|
||||
dense
|
||||
class="quantity"
|
||||
:rules="rules.quantity"
|
||||
/>
|
||||
<v-textarea
|
||||
v-model="token"
|
||||
outlined
|
||||
class="centered-input"
|
||||
:rows="quantity <= 10 ? quantity : 10"
|
||||
readonly
|
||||
/>
|
||||
|
||||
<div class="text-center">
|
||||
<v-btn depressed class="mr-4" @click="computeToken">
|
||||
Refresh
|
||||
</v-btn>
|
||||
<v-btn depressed @click="copy(token, `UUID${quantity > 1 ? 's' : ''} copied !`)">
|
||||
Copy UUID{{ quantity > 1 ? 's' : '' }}
|
||||
</v-btn>
|
||||
</div>
|
||||
</ToolWrapper>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import {Component, Ref, Watch} from 'nuxt-property-decorator'
|
||||
import {CopyableMixin} from '@/mixins/copyable.mixin'
|
||||
import {ToolConfig} from '@/types/ToolConfig'
|
||||
import { VTextField } from 'vuetify/lib'
|
||||
import Tool from '~/components/Tool.vue'
|
||||
|
||||
const generateUuid = () => '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, c => ((c as unknown as number) ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> (c as unknown as number) / 4).toString(16))
|
||||
|
||||
@Component({
|
||||
mixins: [CopyableMixin]
|
||||
})
|
||||
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
|
||||
token = ''
|
||||
quantity = 1
|
||||
rules = {
|
||||
quantity: [
|
||||
(v: any) => !!v || 'Quantity is required',
|
||||
(v: any) => (v > 0 && v <= 50) || 'Quantity should be > 0 and <= 50',
|
||||
(v: any) => Number.isInteger(v) || 'Quantity should be an integer'
|
||||
]
|
||||
}
|
||||
|
||||
mounted() {
|
||||
this.computeToken()
|
||||
}
|
||||
|
||||
@Watch('quantity')
|
||||
computeToken() {
|
||||
this.token = Array.from({length: this.quantity}, generateUuid).join('\n')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.quantity {
|
||||
width: 100px;
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
|
||||
::v-deep input {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .centered-input textarea {
|
||||
text-align: center;
|
||||
margin-top: 13px !important;
|
||||
font-family: Consolas, monospace;
|
||||
}
|
||||
</style>
|
BIN
static/android-chrome-192x192.png
Normal file
After Width: | Height: | Size: 7.7 KiB |
BIN
static/android-chrome-512x512.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
static/apple-touch-icon.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
9
static/browserconfig.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="/mstile-150x150.png"/>
|
||||
<TileColor>#2b5797</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
BIN
static/favicon-16x16.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
static/favicon-32x32.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 15 KiB |
BIN
static/icon.png
Before Width: | Height: | Size: 12 KiB |
BIN
static/mstile-150x150.png
Normal file
After Width: | Height: | Size: 4 KiB |
83
static/safari-pinned-tab.svg
Normal file
|
@ -0,0 +1,83 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="726.000000pt" height="726.000000pt" viewBox="0 0 726.000000 726.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.11, written by Peter Selinger 2001-2013
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,726.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M3255 7239 c-112 -39 -191 -120 -230 -238 -14 -43 -17 -88 -17 -237
|
||||
0 -144 -3 -186 -14 -195 -8 -6 -14 -9 -14 -6 0 3 -23 -1 -52 -9 -28 -9 -60
|
||||
-17 -71 -19 -10 -3 -28 -7 -40 -11 -12 -5 -26 -8 -32 -9 -5 -1 -17 -4 -25 -7
|
||||
-8 -3 -53 -19 -100 -34 -47 -15 -89 -31 -94 -36 -6 -4 -16 -8 -24 -8 -15 0
|
||||
-68 -22 -114 -46 -16 -9 -28 -12 -28 -7 0 4 -4 4 -8 -2 -6 -9 -103 -58 -109
|
||||
-56 -2 0 -46 -24 -99 -54 -53 -30 -100 -55 -105 -55 -5 0 -9 -3 -9 -7 0 -9
|
||||
-57 -43 -71 -43 -5 0 -69 60 -142 133 -132 130 -163 152 -264 185 -76 24 -223
|
||||
-4 -292 -57 -56 -42 -441 -432 -466 -471 -60 -96 -75 -246 -32 -325 6 -11 12
|
||||
-25 13 -32 4 -23 60 -88 177 -205 64 -64 117 -120 117 -123 0 -4 -13 -25 -29
|
||||
-48 -15 -23 -31 -52 -35 -64 -4 -13 -11 -23 -15 -23 -5 0 -14 -15 -22 -32 -7
|
||||
-18 -16 -35 -19 -38 -5 -4 -82 -157 -85 -170 -1 -3 -9 -23 -19 -45 -41 -92
|
||||
-103 -255 -111 -290 -1 -5 -5 -17 -8 -25 -9 -20 -47 -164 -59 -222 -6 -27 -13
|
||||
-48 -17 -49 -3 0 -91 -2 -196 -3 -105 -1 -208 -8 -231 -14 -120 -35 -230 -160
|
||||
-251 -287 -5 -27 -8 -185 -7 -350 1 -282 3 -303 23 -357 41 -106 113 -177 222
|
||||
-220 48 -18 77 -21 249 -22 l195 -1 13 -50 c7 -27 15 -58 17 -68 2 -10 7 -27
|
||||
10 -37 3 -10 7 -27 9 -37 15 -75 116 -345 128 -341 5 2 186 180 402 396 l393
|
||||
393 -8 44 c-24 126 -32 424 -15 550 5 33 9 71 10 85 10 99 86 364 138 480 70
|
||||
156 158 310 222 392 12 14 32 41 46 59 85 113 253 277 380 372 116 87 304 191
|
||||
440 244 120 47 141 55 155 58 6 2 35 10 65 19 30 8 73 18 95 22 22 3 44 8 48
|
||||
11 4 2 22 7 40 9 18 3 43 7 57 9 112 18 365 24 485 11 299 -32 547 -112 810
|
||||
-260 39 -22 72 -43 75 -46 3 -3 26 -19 52 -35 27 -17 48 -33 48 -37 0 -5 5 -8
|
||||
11 -8 11 0 84 -59 168 -135 41 -37 58 -54 141 -145 50 -54 142 -178 194 -258
|
||||
90 -142 216 -429 241 -552 2 -8 8 -33 13 -55 6 -22 13 -53 16 -70 3 -16 7 -41
|
||||
10 -55 7 -36 17 -109 21 -155 6 -61 6 -315 0 -360 -25 -201 -29 -221 -80 -405
|
||||
-31 -114 -117 -310 -183 -420 -12 -19 -29 -48 -38 -65 -9 -16 -20 -32 -23 -35
|
||||
-3 -3 -19 -24 -34 -48 -32 -50 -172 -217 -215 -259 -95 -90 -183 -165 -242
|
||||
-206 -154 -107 -272 -173 -410 -230 -79 -33 -223 -82 -266 -92 -228 -50 -308
|
||||
-60 -499 -59 -170 0 -297 10 -355 29 -14 4 -111 -87 -414 -390 -218 -218 -396
|
||||
-400 -396 -405 0 -4 24 -16 53 -26 28 -9 57 -20 62 -24 6 -4 57 -22 115 -39
|
||||
58 -18 116 -37 130 -41 14 -5 50 -14 80 -20 106 -23 97 -1 98 -223 0 -122 5
|
||||
-203 12 -216 6 -12 8 -21 5 -21 -3 0 6 -22 20 -49 27 -53 103 -141 123 -141 7
|
||||
0 12 -4 12 -9 0 -5 17 -15 38 -22 20 -6 43 -17 51 -23 10 -8 117 -11 350 -11
|
||||
307 0 341 2 394 20 31 10 57 23 57 27 0 4 6 8 14 8 20 0 112 96 131 137 36 75
|
||||
42 119 42 307 1 103 2 189 5 191 2 2 15 6 28 9 140 29 398 113 533 174 37 17
|
||||
67 28 67 24 0 -4 4 -2 8 3 4 6 43 28 87 49 44 22 82 42 85 45 3 4 17 12 32 18
|
||||
15 7 46 25 70 40 98 64 83 69 228 -76 138 -139 184 -172 270 -193 92 -23 172
|
||||
-12 265 36 40 21 440 412 487 476 77 107 85 261 19 386 -12 23 -83 103 -157
|
||||
178 l-136 137 19 26 c22 32 48 75 76 128 12 22 24 42 28 45 6 6 102 202 103
|
||||
211 1 3 12 30 25 60 13 30 27 63 32 74 17 42 71 203 85 255 19 69 45 170 48
|
||||
190 2 13 32 15 187 16 201 2 230 5 296 35 46 21 70 38 110 79 24 24 75 104 80
|
||||
125 1 5 7 31 13 56 12 49 9 646 -3 688 -33 117 -150 231 -262 257 -16 3 -115
|
||||
7 -219 8 -211 3 -199 -2 -216 83 -5 26 -19 80 -30 118 -12 39 -22 77 -25 85
|
||||
-2 8 -4 16 -5 18 -2 1 -3 5 -5 10 -1 4 -5 14 -8 22 -4 8 -14 38 -23 65 -9 28
|
||||
-21 61 -27 75 -5 14 -11 30 -12 36 -7 29 -149 311 -202 400 l-60 102 136 138
|
||||
c91 92 144 155 159 187 68 144 44 300 -63 415 -114 123 -402 403 -435 424 -95
|
||||
58 -234 73 -325 34 -22 -9 -42 -17 -45 -18 -13 -1 -86 -67 -191 -172 -64 -64
|
||||
-124 -116 -132 -116 -9 0 -25 10 -37 22 -11 12 -20 18 -20 12 0 -5 -4 -4 -8 2
|
||||
-9 13 -185 111 -277 154 -73 34 -263 111 -280 114 -5 1 -14 4 -20 7 -5 4 -37
|
||||
14 -70 24 -33 10 -87 26 -120 36 -33 10 -85 23 -115 29 l-55 12 0 207 -1 206
|
||||
-29 60 c-29 60 -125 165 -151 165 -8 0 -14 4 -14 8 0 5 -26 16 -57 25 -48 13
|
||||
-115 16 -373 16 -293 1 -319 -1 -375 -20z"/>
|
||||
<path d="M3577 5134 c-1 -1 -44 -4 -94 -8 -51 -4 -98 -8 -105 -11 -7 -2 -24
|
||||
-6 -38 -9 -106 -19 -283 -79 -375 -126 -65 -34 -177 -100 -185 -109 -3 -4 -23
|
||||
-18 -45 -33 -22 -15 -56 -42 -76 -60 -20 -18 -47 -43 -60 -55 -74 -66 -182
|
||||
-197 -237 -288 -56 -90 -130 -249 -152 -325 -13 -41 -27 -80 -31 -86 -5 -6 -7
|
||||
-13 -4 -16 3 -2 0 -20 -5 -39 -6 -19 -13 -52 -16 -74 -3 -22 -8 -51 -10 -65
|
||||
-3 -14 -6 -88 -8 -165 -3 -123 7 -245 28 -345 3 -14 8 -35 10 -48 3 -12 15
|
||||
-54 28 -92 l22 -71 -1037 -1037 c-570 -570 -1053 -1059 -1072 -1086 -19 -27
|
||||
-35 -55 -35 -63 0 -7 -3 -13 -8 -13 -8 0 -31 -48 -37 -79 -2 -12 -6 -25 -9
|
||||
-29 -21 -34 -29 -211 -14 -291 9 -51 55 -180 67 -191 3 -3 12 -17 19 -31 17
|
||||
-33 116 -137 162 -171 110 -80 245 -120 388 -114 110 5 176 22 277 74 65 33
|
||||
151 116 1128 1092 l1058 1058 49 -19 c27 -10 59 -20 72 -23 13 -3 32 -7 43
|
||||
-10 148 -34 189 -39 350 -39 150 -1 226 7 345 34 82 19 233 70 275 92 11 6 22
|
||||
12 25 12 23 4 240 133 260 155 3 3 25 21 50 41 134 108 265 260 348 404 49 86
|
||||
121 250 137 315 1 3 4 12 7 20 10 24 37 146 44 195 11 70 14 116 15 215 0 101
|
||||
-8 237 -16 250 -2 3 -6 26 -10 50 -22 151 -160 233 -287 171 -28 -14 -133
|
||||
-111 -303 -282 -143 -144 -282 -279 -309 -301 -131 -104 -308 -135 -469 -81
|
||||
-39 14 -74 28 -77 31 -3 4 -17 13 -32 21 -39 20 -109 89 -144 142 -106 157
|
||||
-115 340 -26 513 31 59 78 111 328 362 160 161 298 306 307 322 8 16 14 57 15
|
||||
90 0 63 -24 113 -73 154 -34 29 -172 62 -280 68 -69 4 -175 6 -178 4z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.6 KiB |
19
static/site.webmanifest
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "IT - Tools",
|
||||
"short_name": "IT Tools",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
|
@ -28,7 +28,8 @@
|
|||
"@types/node",
|
||||
"@nuxtjs/toast",
|
||||
"@nuxt/types",
|
||||
"~/types/custom.d.ts"
|
||||
"~/types/custom.d.ts",
|
||||
"vuetify"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import {RouteConfig} from '@nuxt/types/config/router';
|
||||
|
||||
interface ToolConfig {
|
||||
title: string;
|
||||
description: string;
|
||||
|
@ -6,5 +8,6 @@ interface ToolConfig {
|
|||
}
|
||||
|
||||
type ToolConfigMethod = () => ToolConfig;
|
||||
type ToolRouteConfig = RouteConfig & {config: ToolConfig}
|
||||
|
||||
export {ToolConfig, ToolConfigMethod}
|
||||
export {ToolConfig, ToolConfigMethod, ToolRouteConfig}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
function capitalise(s: string) {
|
||||
return s.charAt(0).toUpperCase() + s.slice(1)
|
||||
}
|
||||
const capitalise = (s: string) => s.charAt(0).toUpperCase() + s.slice(1)
|
||||
|
||||
export {capitalise}
|
||||
const shuffle = (s: string) => s.split('').sort(() => 0.5 - Math.random()).join('')
|
||||
|
||||
export {capitalise, shuffle}
|
||||
|
|