chore: components base

This commit is contained in:
Corentin Thomasset 2022-04-04 00:24:45 +02:00
parent 64c92a661c
commit 25a8659786
No known key found for this signature in database
GPG key ID: DBD997E935996158
13 changed files with 821 additions and 19 deletions

View file

@ -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>

15
src/composable/copy.ts Normal file
View file

@ -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);
},
};
}

View file

@ -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>

View file

@ -1,5 +1,7 @@
import BaseLayout from './base.layout.vue';
import ToolLayout from './tool.layout.vue';
export const layouts = {
base: BaseLayout,
toolLayout: ToolLayout,
};

View file

@ -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>

View file

@ -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);

View file

@ -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,

View file

@ -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 } })),
],
});

View file

@ -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[];
}

View file

@ -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);