diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/App.vue | 8 | ||||
-rw-r--r-- | src/composable/copy.ts | 15 | ||||
-rw-r--r-- | src/layouts/base.layout.vue | 88 | ||||
-rw-r--r-- | src/layouts/index.ts | 2 | ||||
-rw-r--r-- | src/layouts/tool.layout.vue | 68 | ||||
-rw-r--r-- | src/main.ts | 2 | ||||
-rw-r--r-- | src/plugins/naive.plugin.ts | 10 | ||||
-rw-r--r-- | src/router.ts | 3 | ||||
-rw-r--r-- | src/tools/Tool.ts | 7 | ||||
-rw-r--r-- | src/tools/index.ts | 8 |
10 files changed, 192 insertions, 19 deletions
diff --git a/src/App.vue b/src/App.vue index c7c24ef..abbb362 100644 --- a/src/App.vue +++ b/src/App.vue @@ -16,9 +16,11 @@ const layout = computed(() => route?.meta?.layout ?? layouts.base) <template> <n-config-provider> <n-global-style /> - <component :is="layout"> - <router-view /> - </component> + <n-message-provider placement="bottom"> + <component :is="layout"> + <router-view /> + </component> + </n-message-provider> </n-config-provider> </template> diff --git a/src/composable/copy.ts b/src/composable/copy.ts new file mode 100644 index 0000000..fb29be5 --- /dev/null +++ b/src/composable/copy.ts @@ -0,0 +1,15 @@ +import { useClipboard } from '@vueuse/core'; +import { useMessage } from 'naive-ui'; +import type { Ref } from 'vue'; + +export function useCopy({ source, text = 'Copied to the clipboard' }: { source: Ref; text?: string }) { + const { copy } = useClipboard({ source }); + const message = useMessage(); + + return { + async copy() { + await copy(); + message.success(text); + }, + }; +} diff --git a/src/layouts/base.layout.vue b/src/layouts/base.layout.vue index bfbe5da..f2c601b 100644 --- a/src/layouts/base.layout.vue +++ b/src/layouts/base.layout.vue @@ -1,19 +1,85 @@ -<script lang="ts"> -export default { - name: 'base-layout' -} +<script lang="ts" setup> +import { NIcon } from 'naive-ui'; +import { h, ref, type Component } from 'vue'; +import { RouterLink, useRoute } from 'vue-router'; +import { User } from '@vicons/tabler' +import { tools } from '@/tools'; + +const collapsed = ref(false) +const activeKey = ref(null) +const route = useRoute() + +const makeLabel = (text: string, to: string) => () => h(RouterLink, { to }, { default: () => text }) +const makeIcon = (icon: Component) => () => h(NIcon, null, { default: () => h(icon) }) + +const menuOptions = tools.map(({ name, path, icon }) => ({ + label: makeLabel(name, path), + key: name, + icon: makeIcon(icon) +})) </script> <template> - <div class="base-layout"> - <slot /> - </div> + <n-layout has-sider> + <n-layout-sider + bordered + collapse-mode="width" + :collapsed-width="64" + :width="240" + :collapsed="collapsed" + show-trigger + @collapse="collapsed = true" + @expand="collapsed = false" + > + <router-link + to="/" + style="text-decoration: none; color: grey; display: block; text-align: center; margin:25px 0; font-size: 25px;" + > + <strong>IT-Tools</strong> + </router-link> + + <n-menu + :value="route.name" + class="menu" + :collapsed="collapsed" + :collapsed-width="64" + :collapsed-icon-size="22" + :options="menuOptions" + v-model:value="activeKey" + /> + </n-layout-sider> + <n-layout class="content"> + <div class="bar-wrapper"> + <n-input /> + <n-button secondary circle> + <n-icon size="large"> + <user /> + </n-icon> + </n-button> + </div> + <slot /> + </n-layout> + </n-layout> </template> <style lang="less" scoped> -.base-layout { - width: 100%; - min-height: 100vh; - background-color: #f4f6fa; +.bar-wrapper { + display: flex; + & > *:not(:first-child) { + margin-left: 15px; + } + & > :first-child { + flex-grow: 1; + } +} + +.content { + background-color: #f1f5f9; + ::v-deep(.n-layout-scroll-container) { + padding: 26px; + } +} +.n-layout { + height: 100vh; } </style>
\ No newline at end of file diff --git a/src/layouts/index.ts b/src/layouts/index.ts index 736164a..8f52b62 100644 --- a/src/layouts/index.ts +++ b/src/layouts/index.ts @@ -1,5 +1,7 @@ import BaseLayout from './base.layout.vue'; +import ToolLayout from './tool.layout.vue'; export const layouts = { base: BaseLayout, + toolLayout: ToolLayout, }; diff --git a/src/layouts/tool.layout.vue b/src/layouts/tool.layout.vue new file mode 100644 index 0000000..01c8cc1 --- /dev/null +++ b/src/layouts/tool.layout.vue @@ -0,0 +1,68 @@ +<script lang="ts" setup> +import { useRoute } from 'vue-router'; +import BaseLayout from './base.layout.vue'; +import { useHead } from '@vueuse/head' +import type { HeadObject } from '@vueuse/head' +import { reactive } from 'vue'; + +const route = useRoute() + +const head = reactive<HeadObject>({ + title: `${route.meta.name} - IT Tools`, + meta: [ + { + name: 'description', + content: route.meta.description + }, + { + name: 'keywords', + content: route.meta.keywords + } + ] +}) +useHead(head) +</script> + +<template> + <base-layout> + <div class="tool-layout"> + <div class="tool-header"> + <n-h1>{{ route.meta.name }}</n-h1> + <div class="separator" /> + <div class="description">{{ route.meta.description }}</div> + </div> + + <slot /> + </div> + </base-layout> +</template> + +<style lang="less" scoped> +.tool-layout { + max-width: 700px; + margin: 0 auto; + box-sizing: border-box; + + .tool-header { + padding: 40px 0; + .n-h1 { + opacity: 0.9; + font-size: 40px; + font-weight: 400; + margin: 0; + } + .separator { + width: 200px; + height: 2px; + background: rgb(161, 161, 161); + + margin-bottom: 10px; + } + .description { + margin: 0; + + opacity: 0.7; + } + } +} +</style>
\ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 36230d2..7377786 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,6 @@ import { createApp } from 'vue'; import { createPinia } from 'pinia'; +import { createHead } from '@vueuse/head'; import { naive } from './plugins/naive.plugin'; @@ -9,6 +10,7 @@ import router from './router'; const app = createApp(App); app.use(createPinia()); +app.use(createHead()); app.use(router); app.use(naive); diff --git a/src/plugins/naive.plugin.ts b/src/plugins/naive.plugin.ts index 5d36387..50bb9b5 100644 --- a/src/plugins/naive.plugin.ts +++ b/src/plugins/naive.plugin.ts @@ -33,9 +33,19 @@ import { NP, NH2, NDropdown, + NLayout, + NLayoutSider, + NMenu, + NMessageProvider, + NPageHeader, } from 'naive-ui'; const components = [ + NPageHeader, + NMessageProvider, + NLayout, + NLayoutSider, + NMenu, NDropdown, NH2, NP, diff --git a/src/router.ts b/src/router.ts index 30565bb..00f39c8 100644 --- a/src/router.ts +++ b/src/router.ts @@ -1,3 +1,4 @@ +import { layouts } from './layouts/index'; import { createRouter, createWebHistory } from 'vue-router'; import HomePage from './pages/Home.page.vue'; import { tools } from './tools'; @@ -10,7 +11,7 @@ const router = createRouter({ name: 'home', component: HomePage, }, - ...Object.values(tools).flat(), + ...tools.map(({ path, name, component, ...config }) => ({ path, name, component, meta: { isTool: true, layout: layouts.toolLayout, name, ...config } })), ], }); diff --git a/src/tools/Tool.ts b/src/tools/Tool.ts index e452fdd..9ccd2d7 100644 --- a/src/tools/Tool.ts +++ b/src/tools/Tool.ts @@ -6,4 +6,11 @@ export interface ITool { description: string; keywords: string[]; component: () => Promise<Component>; + icon: Component; +} + +export interface ToolCategory { + name: string; + icon: Component; + components: ITool[]; } diff --git a/src/tools/index.ts b/src/tools/index.ts index 0db7d63..1bcd931 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -1,5 +1,5 @@ -import { tool as tokenGenerator } from './token-generator'; +import type { ToolCategory } from './Tool'; -export const tools = { - crypto: [tokenGenerator], -}; +export const toolsByCategory: ToolCategory[] = []; + +export const tools = toolsByCategory.flatMap(({ components }) => components); |