Add home page tiles
This commit is contained in:
parent
faabc828d6
commit
1c5b0ba2ec
@ -1,12 +1,13 @@
|
||||
<template>
|
||||
<header class="flex">
|
||||
<span class="my-auto ml-2 font-bold">Tools</span>
|
||||
<header class="flex justify-between mx-2 mt-1">
|
||||
<span class="font-bold">Tools</span>
|
||||
<router-link :to="{name:'home'}" class="ml-4" tag="button">Home</router-link>
|
||||
</header>
|
||||
|
||||
<hr class="mt-2 mb-2">
|
||||
|
||||
<nav class="flex flex-col ml-2">
|
||||
<div v-for="[title, routes] of Object.entries(menuRoutes)" class="flex flex-col mb-2">
|
||||
<div v-for="[title, routes] of Object.entries(menuRoutes).sort((a, b) => a[0].localeCompare(b[0]))" class="flex flex-col mb-2">
|
||||
<p><i>{{ title }}</i></p>
|
||||
<router-link v-for="[key, value] of Object.entries(routes)" :to="{name:key}" class="ml-4" tag="button">{{ value }}</router-link>
|
||||
</div>
|
||||
@ -15,7 +16,7 @@
|
||||
|
||||
<div class="flex flex-col mb-2">
|
||||
<p><i>Other</i></p>
|
||||
<a href="https://gist.stuzer.link/" class="ml-4" tag="button">Gist</a>
|
||||
<a href="https://gist.stuzer.link/stuzer05/liked" class="ml-4" tag="button">Gist</a>
|
||||
<a href="https://cyberchef.tools.stuzer.link/" class="ml-4" tag="button">Cyberchef</a>
|
||||
<a href="https://pdf.tools.stuzer.link/" class="ml-4" tag="button">PDF tools</a>
|
||||
</div>
|
||||
@ -24,6 +25,8 @@
|
||||
|
||||
<script>
|
||||
|
||||
import { useToolsStore } from "@/stores/toolsStore";
|
||||
|
||||
export default {
|
||||
name: "Sidebar",
|
||||
components: {},
|
||||
@ -33,54 +36,7 @@ export default {
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.menuRoutes = {
|
||||
'General': {
|
||||
'home': 'Home',
|
||||
'explain_crontab': 'Explain crontab',
|
||||
'table_to_markdown_table': 'Table to Markdown table',
|
||||
'table_to_mediawiki_table': 'Table to Mediawiki table',
|
||||
'dummy_image': 'Dummy image',
|
||||
'humans_txt': 'humans.txt generator',
|
||||
'file_base64_encode_decode': 'File base64 encode/decode',
|
||||
'qr_code': 'QR code',
|
||||
'unix_timestamp': 'Unix timestamp',
|
||||
'sed_generator': 'Sed generator',
|
||||
'htaccess_generator': '.htaccess generator',
|
||||
},
|
||||
'Strings': {
|
||||
'fix_ru_en_keyboard': 'Fix ru-en keyboard',
|
||||
'str_length': 'Str length',
|
||||
'str_sort_lines': 'Str sort lines',
|
||||
'str_to_lower_upper': 'Str to lower/upper',
|
||||
'str_remove_duplicate_lines': 'Str remove duplicate lines',
|
||||
'str_pad': 'Str pad',
|
||||
'str_numeronym': 'Str numeronym (i18n)',
|
||||
'str_to_nato_alphabet': 'Str to NATO alphabet',
|
||||
'url_encode_decode': 'URL encode/decode',
|
||||
'url_query_viewer': 'URL query viewer',
|
||||
'iban_generator': 'IBAN generator',
|
||||
},
|
||||
'PHP': {
|
||||
'str_to_php_array': 'Str to PHP array',
|
||||
'php_array_to_json': 'PHP array to Json',
|
||||
'php_serialize': 'PHP serialize',
|
||||
},
|
||||
'Docker': {
|
||||
'docker_rename_volume': 'Rename volume',
|
||||
},
|
||||
'GO': {
|
||||
'go_json_to_struct': 'JSON to Go struct',
|
||||
// 'sql_tables_to_struct': 'SQL tables Go struct',
|
||||
},
|
||||
'JSON': {
|
||||
'json_minifier': 'JSON minifier',
|
||||
'json_formatter': 'JSON formatter',
|
||||
},
|
||||
'SQL': {
|
||||
'sql_formatter': 'SQL formatter',
|
||||
'sql_split_in': 'SQL split IN',
|
||||
},
|
||||
};
|
||||
this.menuRoutes = useToolsStore().tools;
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,196 +1,196 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { createRouter, createWebHistory } from "vue-router";
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
/**
|
||||
* General
|
||||
*/
|
||||
{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: () => import('../views/general/HomeView.vue'),
|
||||
},
|
||||
{
|
||||
path: '/explain_crontab',
|
||||
name: 'explain_crontab',
|
||||
component: () => import('../views/general/ExplainCrontab.vue'),
|
||||
},
|
||||
{
|
||||
path: '/table_to_markdown_table',
|
||||
name: 'table_to_markdown_table',
|
||||
component: () => import('../views/general/TableToMarkdownTable.vue'),
|
||||
},
|
||||
{
|
||||
path: '/table_to_mediawiki_table',
|
||||
name: 'table_to_mediawiki_table',
|
||||
component: () => import('../views/general/TableToMediawikiTable.vue'),
|
||||
},
|
||||
{
|
||||
path: '/dummy_image',
|
||||
name: 'dummy_image',
|
||||
component: () => import('../views/general/DummyImage.vue'),
|
||||
},
|
||||
{
|
||||
path: '/humans_txt',
|
||||
name: 'humans_txt',
|
||||
component: () => import('../views/general/HumansTxt.vue'),
|
||||
},
|
||||
{
|
||||
path: '/qr_code',
|
||||
name: 'qr_code',
|
||||
component: () => import('../views/general/QRCode.vue'),
|
||||
},
|
||||
{
|
||||
path: '/unix_timestamp',
|
||||
name: 'unix_timestamp',
|
||||
component: () => import('../views/general/UnixTimestamp.vue'),
|
||||
},
|
||||
{
|
||||
path: '/file_base64_encode_decode',
|
||||
name: 'file_base64_encode_decode',
|
||||
component: () => import('../views/general/FileBase64EncodeDecode.vue'),
|
||||
},
|
||||
{
|
||||
path: '/sed_generator',
|
||||
name: 'sed_generator',
|
||||
component: () => import('../views/general/SedGenerator.vue'),
|
||||
},
|
||||
{
|
||||
path: '/htaccess_generator',
|
||||
name: 'htaccess_generator',
|
||||
component: () => import('../views/general/HtaccessGenerator.vue'),
|
||||
},
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
/**
|
||||
* General
|
||||
*/
|
||||
{
|
||||
path: "/",
|
||||
name: "home",
|
||||
component: () => import("../views/HomeView.vue")
|
||||
},
|
||||
{
|
||||
path: "/explain_crontab",
|
||||
name: "explain_crontab",
|
||||
component: () => import("../views/general/ExplainCrontab.vue")
|
||||
},
|
||||
{
|
||||
path: "/table_to_markdown_table",
|
||||
name: "table_to_markdown_table",
|
||||
component: () => import("../views/general/TableToMarkdownTable.vue")
|
||||
},
|
||||
{
|
||||
path: "/table_to_mediawiki_table",
|
||||
name: "table_to_mediawiki_table",
|
||||
component: () => import("../views/general/TableToMediawikiTable.vue")
|
||||
},
|
||||
{
|
||||
path: "/dummy_image",
|
||||
name: "dummy_image",
|
||||
component: () => import("../views/generators/DummyImage.vue")
|
||||
},
|
||||
{
|
||||
path: "/humans_txt",
|
||||
name: "humans_txt",
|
||||
component: () => import("../views/general/HumansTxt.vue")
|
||||
},
|
||||
{
|
||||
path: "/qr_code",
|
||||
name: "qr_code",
|
||||
component: () => import("../views/generators/QRCode.vue")
|
||||
},
|
||||
{
|
||||
path: "/unix_timestamp",
|
||||
name: "unix_timestamp",
|
||||
component: () => import("../views/general/UnixTimestamp.vue")
|
||||
},
|
||||
{
|
||||
path: "/file_base64_encode_decode",
|
||||
name: "file_base64_encode_decode",
|
||||
component: () => import("../views/general/FileBase64EncodeDecode.vue")
|
||||
},
|
||||
{
|
||||
path: "/sed_generator",
|
||||
name: "sed_generator",
|
||||
component: () => import("../views/general/SedGenerator.vue")
|
||||
},
|
||||
{
|
||||
path: "/htaccess_generator",
|
||||
name: "htaccess_generator",
|
||||
component: () => import("../views/general/HtaccessGenerator.vue")
|
||||
},
|
||||
|
||||
/**
|
||||
* String manipulation
|
||||
*/
|
||||
{
|
||||
path: '/str_length',
|
||||
name: 'str_length',
|
||||
component: () => import('../views/strings/Length.vue'),
|
||||
},
|
||||
{
|
||||
path: '/str_sort_lines',
|
||||
name: 'str_sort_lines',
|
||||
component: () => import('../views/strings/SortLines.vue'),
|
||||
},
|
||||
{
|
||||
path: '/str_to_lower_upper',
|
||||
name: 'str_to_lower_upper',
|
||||
component: () => import('../views/strings/ToLowerUppper.vue'),
|
||||
},
|
||||
{
|
||||
path: '/str_remove_duplicate_lines',
|
||||
name: 'str_remove_duplicate_lines',
|
||||
component: () => import('../views/strings/RemoveDuplicateLines.vue'),
|
||||
},
|
||||
{
|
||||
path: '/str_pad',
|
||||
name: 'str_pad',
|
||||
component: () => import('../views/strings/Pad.vue'),
|
||||
},
|
||||
{
|
||||
path: '/str_numeronym',
|
||||
name: 'str_numeronym',
|
||||
component: () => import('../views/strings/Numeronym.vue'),
|
||||
},
|
||||
{
|
||||
path: '/str_to_nato_alphabet',
|
||||
name: 'str_to_nato_alphabet',
|
||||
component: () => import('../views/strings/NATOAlphabet.vue'),
|
||||
},
|
||||
{
|
||||
path: '/url_encode_decode',
|
||||
name: 'url_encode_decode',
|
||||
component: () => import('../views/strings/UrlEncodeDecode.vue'),
|
||||
},
|
||||
{
|
||||
path: '/url_query_viewer',
|
||||
name: 'url_query_viewer',
|
||||
component: () => import('../views/strings/UrlQueryViewer.vue'),
|
||||
},
|
||||
{
|
||||
path: '/fix_ru_en_keyboard',
|
||||
name: 'fix_ru_en_keyboard',
|
||||
component: () => import('../views/strings/FixRuEnKeyboard.vue'),
|
||||
},
|
||||
{
|
||||
path: '/iban_generator',
|
||||
name: 'iban_generator',
|
||||
component: () => import('../views/strings/IbanGenerator.vue'),
|
||||
},
|
||||
/**
|
||||
* String manipulation
|
||||
*/
|
||||
{
|
||||
path: "/str_length",
|
||||
name: "str_length",
|
||||
component: () => import("../views/strings/Length.vue")
|
||||
},
|
||||
{
|
||||
path: "/str_sort_lines",
|
||||
name: "str_sort_lines",
|
||||
component: () => import("../views/strings/SortLines.vue")
|
||||
},
|
||||
{
|
||||
path: "/str_to_lower_upper",
|
||||
name: "str_to_lower_upper",
|
||||
component: () => import("../views/strings/ToLowerUppper.vue")
|
||||
},
|
||||
{
|
||||
path: "/str_remove_duplicate_lines",
|
||||
name: "str_remove_duplicate_lines",
|
||||
component: () => import("../views/strings/RemoveDuplicateLines.vue")
|
||||
},
|
||||
{
|
||||
path: "/str_pad",
|
||||
name: "str_pad",
|
||||
component: () => import("../views/strings/Pad.vue")
|
||||
},
|
||||
{
|
||||
path: "/str_numeronym",
|
||||
name: "str_numeronym",
|
||||
component: () => import("../views/strings/Numeronym.vue")
|
||||
},
|
||||
{
|
||||
path: "/str_to_nato_alphabet",
|
||||
name: "str_to_nato_alphabet",
|
||||
component: () => import("../views/strings/NATOAlphabet.vue")
|
||||
},
|
||||
{
|
||||
path: "/url_encode_decode",
|
||||
name: "url_encode_decode",
|
||||
component: () => import("../views/strings/UrlEncodeDecode.vue")
|
||||
},
|
||||
{
|
||||
path: "/url_query_viewer",
|
||||
name: "url_query_viewer",
|
||||
component: () => import("../views/strings/UrlQueryViewer.vue")
|
||||
},
|
||||
{
|
||||
path: "/fix_ru_en_keyboard",
|
||||
name: "fix_ru_en_keyboard",
|
||||
component: () => import("../views/strings/FixRuEnKeyboard.vue")
|
||||
},
|
||||
{
|
||||
path: "/iban_generator",
|
||||
name: "iban_generator",
|
||||
component: () => import("../views/generators/IbanGenerator.vue")
|
||||
},
|
||||
|
||||
/**
|
||||
* PHP
|
||||
*/
|
||||
{
|
||||
path: '/str_to_php_array',
|
||||
name: 'str_to_php_array',
|
||||
component: () => import('../views/php/StrToPHPArray.vue'),
|
||||
},
|
||||
{
|
||||
path: '/php_array_to_json',
|
||||
name: 'php_array_to_json',
|
||||
component: () => import('../views/php/PHPArrayToJson.vue'),
|
||||
},
|
||||
{
|
||||
path: '/php_serialize',
|
||||
name: 'php_serialize',
|
||||
component: () => import('../views/php/Serialize.vue'),
|
||||
},
|
||||
/**
|
||||
* PHP
|
||||
*/
|
||||
{
|
||||
path: "/str_to_php_array",
|
||||
name: "str_to_php_array",
|
||||
component: () => import("../views/php/StrToPHPArray.vue")
|
||||
},
|
||||
{
|
||||
path: "/php_array_to_json",
|
||||
name: "php_array_to_json",
|
||||
component: () => import("../views/php/PHPArrayToJson.vue")
|
||||
},
|
||||
{
|
||||
path: "/php_serialize",
|
||||
name: "php_serialize",
|
||||
component: () => import("../views/php/Serialize.vue")
|
||||
},
|
||||
|
||||
/**
|
||||
* JSON manipulation
|
||||
*/
|
||||
{
|
||||
path: '/json_formatter',
|
||||
name: 'json_formatter',
|
||||
component: () => import('../views/json/JSONFormatter.vue'),
|
||||
},
|
||||
{
|
||||
path: '/json_minifier',
|
||||
name: 'json_minifier',
|
||||
component: () => import('../views/json/JSONMinifier.vue'),
|
||||
},
|
||||
/**
|
||||
* JSON manipulation
|
||||
*/
|
||||
{
|
||||
path: "/json_formatter",
|
||||
name: "json_formatter",
|
||||
component: () => import("../views/json/JSONFormatter.vue")
|
||||
},
|
||||
{
|
||||
path: "/json_minifier",
|
||||
name: "json_minifier",
|
||||
component: () => import("../views/json/JSONMinifier.vue")
|
||||
},
|
||||
|
||||
/**
|
||||
* Golang
|
||||
*/
|
||||
{
|
||||
path: '/go_json_to_struct',
|
||||
name: 'go_json_to_struct',
|
||||
component: () => import('../views/go/JSONToStruct.vue'),
|
||||
},
|
||||
{
|
||||
path: '/sql_tables_to_struct',
|
||||
name: 'sql_tables_to_struct',
|
||||
component: () => import('../views/go/SQLTablesToStruct.vue'),
|
||||
},
|
||||
/**
|
||||
* Golang
|
||||
*/
|
||||
{
|
||||
path: "/go_json_to_struct",
|
||||
name: "go_json_to_struct",
|
||||
component: () => import("../views/go/JSONToStruct.vue")
|
||||
},
|
||||
{
|
||||
path: "/sql_tables_to_struct",
|
||||
name: "sql_tables_to_struct",
|
||||
component: () => import("../views/go/SQLTablesToStruct.vue")
|
||||
},
|
||||
|
||||
/**
|
||||
* Docker
|
||||
*/
|
||||
{
|
||||
path: '/docker_rename_volume',
|
||||
name: 'docker_rename_volume',
|
||||
component: () => import('../views/docker/RenameVolume.vue'),
|
||||
},
|
||||
/**
|
||||
* Docker
|
||||
*/
|
||||
{
|
||||
path: "/docker_rename_volume",
|
||||
name: "docker_rename_volume",
|
||||
component: () => import("../views/docker/RenameVolume.vue")
|
||||
},
|
||||
|
||||
/**
|
||||
* SQL manipulation
|
||||
*/
|
||||
{
|
||||
path: '/sql_split_in',
|
||||
name: 'sql_split_in',
|
||||
component: () => import('../views/sql/SplitInView.vue'),
|
||||
},
|
||||
{
|
||||
path: '/sql_formatter',
|
||||
name: 'sql_formatter',
|
||||
component: () => import('../views/sql/Formatter.vue'),
|
||||
},
|
||||
],
|
||||
})
|
||||
/**
|
||||
* SQL manipulation
|
||||
*/
|
||||
{
|
||||
path: "/sql_split_in",
|
||||
name: "sql_split_in",
|
||||
component: () => import("../views/sql/SplitInView.vue")
|
||||
},
|
||||
{
|
||||
path: "/sql_formatter",
|
||||
name: "sql_formatter",
|
||||
component: () => import("../views/sql/Formatter.vue")
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
export default router
|
||||
export default router;
|
||||
|
77
src/stores/toolsStore.js
Normal file
77
src/stores/toolsStore.js
Normal file
@ -0,0 +1,77 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
function sortMenuRoutes(routes) {
|
||||
const sortedRoutes = {};
|
||||
const sortedKeys = Object.keys(routes).sort();
|
||||
|
||||
for (const key of sortedKeys) {
|
||||
const innerRoutes = routes[key];
|
||||
const sortedInnerKeys = Object.keys(innerRoutes).sort();
|
||||
sortedRoutes[key] = {};
|
||||
|
||||
for (const innerKey of sortedInnerKeys) {
|
||||
sortedRoutes[key][innerKey] = innerRoutes[innerKey];
|
||||
}
|
||||
}
|
||||
|
||||
return sortedRoutes;
|
||||
}
|
||||
|
||||
export const useToolsStore = defineStore('tools', {
|
||||
state: () => ({
|
||||
tools: sortMenuRoutes({
|
||||
'-': {
|
||||
'table_to_markdown_table': 'Table to Markdown table',
|
||||
'table_to_mediawiki_table': 'Table to Mediawiki table',
|
||||
'humans_txt': 'humans.txt generator',
|
||||
},
|
||||
'Docker': {
|
||||
'docker_rename_volume': 'Rename volume',
|
||||
},
|
||||
'GO': {
|
||||
'go_json_to_struct': 'JSON to Go struct',
|
||||
// 'sql_tables_to_struct': 'SQL tables Go struct',
|
||||
},
|
||||
'JSON': {
|
||||
'json_minifier': 'JSON minifier',
|
||||
'json_formatter': 'JSON formatter',
|
||||
},
|
||||
'PHP': {
|
||||
'str_to_php_array': 'Str to PHP array',
|
||||
'php_array_to_json': 'PHP array to Json',
|
||||
'php_serialize': 'PHP serialize',
|
||||
},
|
||||
'SQL': {
|
||||
'sql_formatter': 'SQL formatter',
|
||||
'sql_split_in': 'SQL split IN',
|
||||
},
|
||||
'Strings': {
|
||||
'fix_ru_en_keyboard': 'Fix ru-en keyboard',
|
||||
'str_length': 'Str length',
|
||||
'str_sort_lines': 'Str sort lines',
|
||||
'str_to_lower_upper': 'Str to lower/upper',
|
||||
'str_remove_duplicate_lines': 'Str remove duplicate lines',
|
||||
'str_pad': 'Str pad',
|
||||
'str_numeronym': 'Str numeronym (i18n)',
|
||||
'str_to_nato_alphabet': 'Str to NATO alphabet',
|
||||
'url_encode_decode': 'URL encode/decode',
|
||||
'url_query_viewer': 'URL query viewer',
|
||||
},
|
||||
'Unix': {
|
||||
'explain_crontab': 'Explain crontab',
|
||||
'file_base64_encode_decode': 'File base64 encode/decode',
|
||||
'unix_timestamp': 'Unix timestamp',
|
||||
'sed_generator': 'Sed generator',
|
||||
'htaccess_generator': '.htaccess generator',
|
||||
},
|
||||
'Generators': {
|
||||
'qr_code': 'QR code',
|
||||
'iban_generator': 'IBAN generator',
|
||||
'dummy_image': 'Dummy image',
|
||||
},
|
||||
}),
|
||||
actions: {
|
||||
// You can add actions here if needed, e.g., to update the tools
|
||||
},
|
||||
}),
|
||||
})
|
50
src/views/HomeView.vue
Normal file
50
src/views/HomeView.vue
Normal file
@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<div class="container mx-auto p-4">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-5">
|
||||
<div v-for="(category, categoryName) in tools" :key="categoryName" class="bg-white rounded-lg shadow-md p-4">
|
||||
<h2 class="text-xl font-semibold mb-3">{{ categoryName }}</h2>
|
||||
<div class="max-h-80 overflow-y-auto">
|
||||
<ul class="space-y-2">
|
||||
<li
|
||||
v-for="(value, key) in category"
|
||||
:key="key"
|
||||
@click="navigateTo(key)"
|
||||
class="bg-gray-100 rounded p-2 hover:bg-gray-200 transition-colors duration-200 cursor-pointer"
|
||||
>
|
||||
{{ value }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useToolsStore } from "@/stores/toolsStore";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
tools: {},
|
||||
}
|
||||
},
|
||||
setup() {
|
||||
const router = useRouter();
|
||||
|
||||
const navigateTo = (routeName) => {
|
||||
router.push({ name: routeName });
|
||||
};
|
||||
|
||||
return { navigateTo };
|
||||
},
|
||||
mounted() {
|
||||
this.tools = useToolsStore().tools;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
@ -1,7 +0,0 @@
|
||||
<template>
|
||||
/home
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
@ -28,7 +28,7 @@
|
||||
|
||||
<div>
|
||||
<input id="inputTimestamp" type="number" v-model="toolData.inputTimestamp" :placeholder="currentTimestamp">
|
||||
<button @click="convertFromUnix">Convert</button>
|
||||
<button @click="convertFromUnix">Convert ↓</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -57,7 +57,7 @@
|
||||
<td><input type="number" v-model="toolData.inputMinute"></td>
|
||||
<td><input type="number" v-model="toolData.inputSecond"></td>
|
||||
<td>
|
||||
<button @click="convertToUnix">Convert →</button>
|
||||
<button @click="convertToUnix">Convert ↑</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
Loading…
Reference in New Issue
Block a user