mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-05-05 13:57:10 -04:00
🔒 SSR UPDATE
This commit is contained in:
parent
23f82d956a
commit
cb44d3db8b
31 changed files with 991 additions and 210 deletions
|
@ -96,6 +96,7 @@
|
|||
"toReactive": true,
|
||||
"toRef": true,
|
||||
"toRefs": true,
|
||||
"toValue": true,
|
||||
"triggerRef": true,
|
||||
"tryOnBeforeMount": true,
|
||||
"tryOnBeforeUnmount": true,
|
||||
|
@ -285,7 +286,6 @@
|
|||
"watchThrottled": true,
|
||||
"watchTriggerable": true,
|
||||
"watchWithFilter": true,
|
||||
"whenever": true,
|
||||
"toValue": true
|
||||
"whenever": true
|
||||
}
|
||||
}
|
||||
|
|
29
components.d.ts
vendored
29
components.d.ts
vendored
|
@ -89,17 +89,28 @@ declare module '@vue/runtime-core' {
|
|||
HttpStatusCodes: typeof import('./src/tools/http-status-codes/http-status-codes.vue')['default']
|
||||
IbanValidatorAndParser: typeof import('./src/tools/iban-validator-and-parser/iban-validator-and-parser.vue')['default']
|
||||
'IconMdi:brushVariant': typeof import('~icons/mdi/brush-variant')['default']
|
||||
'IconMdi:contentCopy': typeof import('~icons/mdi/content-copy')['default']
|
||||
'IconMdi:kettleSteamOutline': typeof import('~icons/mdi/kettle-steam-outline')['default']
|
||||
IconMdiArrowDown: typeof import('~icons/mdi/arrow-down')['default']
|
||||
IconMdiArrowRightBottom: typeof import('~icons/mdi/arrow-right-bottom')['default']
|
||||
IconMdiCamera: typeof import('~icons/mdi/camera')['default']
|
||||
IconMdiChevronDown: typeof import('~icons/mdi/chevron-down')['default']
|
||||
IconMdiChevronRight: typeof import('~icons/mdi/chevron-right')['default']
|
||||
IconMdiClose: typeof import('~icons/mdi/close')['default']
|
||||
IconMdiContentCopy: typeof import('~icons/mdi/content-copy')['default']
|
||||
IconMdiDeleteOutline: typeof import('~icons/mdi/delete-outline')['default']
|
||||
IconMdiDownload: typeof import('~icons/mdi/download')['default']
|
||||
IconMdiEye: typeof import('~icons/mdi/eye')['default']
|
||||
IconMdiEyeOff: typeof import('~icons/mdi/eye-off')['default']
|
||||
IconMdiHeart: typeof import('~icons/mdi/heart')['default']
|
||||
IconMdiPause: typeof import('~icons/mdi/pause')['default']
|
||||
IconMdiPlay: typeof import('~icons/mdi/play')['default']
|
||||
IconMdiRecord: typeof import('~icons/mdi/record')['default']
|
||||
IconMdiRefresh: typeof import('~icons/mdi/refresh')['default']
|
||||
IconMdiSearch: typeof import('~icons/mdi/search')['default']
|
||||
IconMdiTranslate: typeof import('~icons/mdi/translate')['default']
|
||||
IconMdiTriangleDown: typeof import('~icons/mdi/triangle-down')['default']
|
||||
IconMdiVideo: typeof import('~icons/mdi/video')['default']
|
||||
InputCopyable: typeof import('./src/components/InputCopyable.vue')['default']
|
||||
IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default']
|
||||
Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default']
|
||||
|
@ -126,25 +137,40 @@ declare module '@vue/runtime-core' {
|
|||
MenuLayout: typeof import('./src/components/MenuLayout.vue')['default']
|
||||
MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default']
|
||||
MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default']
|
||||
NAlert: typeof import('naive-ui')['NAlert']
|
||||
NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default']
|
||||
NCheckbox: typeof import('naive-ui')['NCheckbox']
|
||||
NCode: typeof import('naive-ui')['NCode']
|
||||
NCollapseTransition: typeof import('naive-ui')['NCollapseTransition']
|
||||
NColorPicker: typeof import('naive-ui')['NColorPicker']
|
||||
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
|
||||
NDatePicker: typeof import('naive-ui')['NDatePicker']
|
||||
NDivider: typeof import('naive-ui')['NDivider']
|
||||
NDynamicInput: typeof import('naive-ui')['NDynamicInput']
|
||||
NEllipsis: typeof import('naive-ui')['NEllipsis']
|
||||
NForm: typeof import('naive-ui')['NForm']
|
||||
NFormItem: typeof import('naive-ui')['NFormItem']
|
||||
NGi: typeof import('naive-ui')['NGi']
|
||||
NGrid: typeof import('naive-ui')['NGrid']
|
||||
NH1: typeof import('naive-ui')['NH1']
|
||||
NH2: typeof import('naive-ui')['NH2']
|
||||
NH3: typeof import('naive-ui')['NH3']
|
||||
NIcon: typeof import('naive-ui')['NIcon']
|
||||
NImage: typeof import('naive-ui')['NImage']
|
||||
NInputGroup: typeof import('naive-ui')['NInputGroup']
|
||||
NInputGroupLabel: typeof import('naive-ui')['NInputGroupLabel']
|
||||
NInputNumber: typeof import('naive-ui')['NInputNumber']
|
||||
NLabel: typeof import('naive-ui')['NLabel']
|
||||
NLayout: typeof import('naive-ui')['NLayout']
|
||||
NLayoutSider: typeof import('naive-ui')['NLayoutSider']
|
||||
NMenu: typeof import('naive-ui')['NMenu']
|
||||
NProgress: typeof import('naive-ui')['NProgress']
|
||||
NScrollbar: typeof import('naive-ui')['NScrollbar']
|
||||
NSlider: typeof import('naive-ui')['NSlider']
|
||||
NSpin: typeof import('naive-ui')['NSpin']
|
||||
NStatistic: typeof import('naive-ui')['NStatistic']
|
||||
NSwitch: typeof import('naive-ui')['NSwitch']
|
||||
NTable: typeof import('naive-ui')['NTable']
|
||||
NTag: typeof import('naive-ui')['NTag']
|
||||
NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default']
|
||||
OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default']
|
||||
PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default']
|
||||
|
@ -159,6 +185,7 @@ declare module '@vue/runtime-core' {
|
|||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
RsaKeyPairGenerator: typeof import('./src/tools/rsa-key-pair-generator/rsa-key-pair-generator.vue')['default']
|
||||
SafelinkDecoder: typeof import('./src/tools/safelink-decoder/safelink-decoder.vue')['default']
|
||||
SlugifyString: typeof import('./src/tools/slugify-string/slugify-string.vue')['default']
|
||||
SpanCopyable: typeof import('./src/components/SpanCopyable.vue')['default']
|
||||
SqlPrettify: typeof import('./src/tools/sql-prettify/sql-prettify.vue')['default']
|
||||
|
|
13
index.html
13
index.html
|
@ -4,8 +4,8 @@
|
|||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>IT Tools - Handy online tools for developers</title>
|
||||
<meta itemprop="name" content="IT Tools - Handy online tools for developers" />
|
||||
<title>IT Tools</title>
|
||||
<meta itemprop="name" content="IT Tools" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Collection of handy online tools for developers, with great UX. IT Tools is a free and open-source collection of handy online tools for developers & people working in IT."
|
||||
|
@ -26,7 +26,7 @@
|
|||
|
||||
<meta property="og:url" content="https://it-tools.tech/" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:title" content="IT Tools - Handy online tools for developers" />
|
||||
<meta property="og:title" content="IT Tools" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Collection of handy online tools for developers, with great UX. IT Tools is a free and open-source collection of handy online tools for developers & people working in IT."
|
||||
|
@ -37,16 +37,17 @@
|
|||
<meta name="twitter:site" content="@ittoolsdottech" />
|
||||
<meta name="twitter:creator" content="@cthmsst" />
|
||||
|
||||
<meta name="twitter:title" content="IT Tools - Handy online tools for developers" />
|
||||
<meta name="twitter:title" content="IT Tools" />
|
||||
<meta
|
||||
name="twitter:description"
|
||||
content="Collection of handy online tools for developers, with great UX. IT Tools is a free and open-source collection of handy online tools for developers & people working in IT."
|
||||
/>
|
||||
<meta name="twitter:image" content="https://it-tools.tech/banner.png?v=2" />
|
||||
<meta name="twitter:image:alt" content="IT Tools - Handy online tools for developers" />
|
||||
<meta name="twitter:image:alt" content="IT Tools" />
|
||||
<style><!--app-css--></style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<div id="app"><!--app-html--></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"name": "it-tools",
|
||||
"version": "2023.12.21-5ed3693",
|
||||
"type": "module",
|
||||
"description": "Collection of handy online tools for developers, with great UX. ",
|
||||
"keywords": [
|
||||
"productivity",
|
||||
|
@ -22,6 +23,7 @@
|
|||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc --noEmit && NODE_OPTIONS=--max_old_space_size=4096 vite build",
|
||||
"build:ssr": "node server.js",
|
||||
"preview": "vite preview --port 5050",
|
||||
"test": "npm run test:unit",
|
||||
"test:unit": "vitest --environment jsdom",
|
||||
|
@ -35,6 +37,7 @@
|
|||
"release": "node ./scripts/release.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@css-render/vue3-ssr": "^0.15.12",
|
||||
"@it-tools/bip39": "^0.0.4",
|
||||
"@it-tools/oggen": "^1.3.0",
|
||||
"@sindresorhus/slugify": "^2.2.1",
|
||||
|
@ -44,6 +47,7 @@
|
|||
"@types/figlet": "^1.5.8",
|
||||
"@vicons/material": "^0.12.0",
|
||||
"@vicons/tabler": "^0.12.0",
|
||||
"@vue/server-renderer": "^3.4.23",
|
||||
"@vueuse/core": "^10.3.0",
|
||||
"@vueuse/head": "^1.0.0",
|
||||
"@vueuse/router": "^10.0.0",
|
||||
|
@ -58,6 +62,7 @@
|
|||
"date-fns": "^2.29.3",
|
||||
"dompurify": "^3.0.6",
|
||||
"emojilib": "^3.0.10",
|
||||
"express": "^4.19.2",
|
||||
"figlet": "^1.7.0",
|
||||
"figue": "^1.2.0",
|
||||
"fuse.js": "^6.6.2",
|
||||
|
@ -86,9 +91,11 @@
|
|||
"unicode-emoji-json": "^0.4.0",
|
||||
"unplugin-auto-import": "^0.16.4",
|
||||
"uuid": "^9.0.0",
|
||||
"vite-plugin-ssr": "^0.4.142",
|
||||
"vue": "^3.3.4",
|
||||
"vue-i18n": "^9.9.1",
|
||||
"vue-router": "^4.1.6",
|
||||
"vue-server-renderer": "^2.7.16",
|
||||
"vue-tsc": "^1.8.1",
|
||||
"xml-formatter": "^3.3.2",
|
||||
"yaml": "^2.2.1"
|
||||
|
|
828
pnpm-lock.yaml
generated
828
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
63
server.js
Normal file
63
server.js
Normal file
|
@ -0,0 +1,63 @@
|
|||
// server.js
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import express from 'express';
|
||||
import { createServer as createViteServer } from 'vite';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
async function startServer() {
|
||||
const app = express();
|
||||
|
||||
// 创建Vite服务器实例
|
||||
const vite = await createViteServer({
|
||||
server: { middlewareMode: true },
|
||||
});
|
||||
|
||||
// 使用Vite的中间件
|
||||
app.use(vite.middlewares);
|
||||
|
||||
app.use('*', async (req, res) => {
|
||||
try {
|
||||
// 读取index.html文件
|
||||
const indexProd = fs.readFileSync(path.resolve(__dirname, 'index.html'), 'utf-8');
|
||||
// 应用Vite HTML转换。重要:在生产环境中,这将由Vite自己处理。
|
||||
const indexHtml = await vite.transformIndexHtml(req.originalUrl, indexProd);
|
||||
|
||||
// 加载服务器入口。vite.ssrLoadModule会自动转换ECS模块为CommonJS,可直接被Node.js导入
|
||||
const { render } = await vite.ssrLoadModule('/src/entry-server.ts');
|
||||
const {
|
||||
app, router, pinia, i18n,
|
||||
cssHtml,
|
||||
appHtml,
|
||||
} = await render(req, res);
|
||||
|
||||
// 设置服务器端路由位置
|
||||
router.push(req.originalUrl);
|
||||
// 等待路由准备就绪
|
||||
await router.isReady();
|
||||
|
||||
// 注入应用内容到模板中
|
||||
const html = indexHtml
|
||||
.replace('<!--app-html-->', appHtml)
|
||||
.replace('<!--app-css-->', cssHtml);
|
||||
|
||||
// 发送渲染后的HTML回客户端
|
||||
res.status(200).set({ 'Content-Type': 'text/html' }).end(html);
|
||||
}
|
||||
catch (e) {
|
||||
// 如果捕获到错误,则使用Vite修复堆栈追踪,并发送500错误
|
||||
vite.ssrFixStacktrace(e);
|
||||
console.error(e);
|
||||
res.status(500).end(e.message);
|
||||
}
|
||||
});
|
||||
|
||||
app.listen(3000, () => {
|
||||
console.log('Server is running on http://localhost:3000');
|
||||
});
|
||||
}
|
||||
|
||||
startServer();
|
34
src/entry-client.ts
Normal file
34
src/entry-client.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
// // entry-client.js
|
||||
// import { createApp } from './main';
|
||||
//
|
||||
// const { app, router } = createApp();
|
||||
//
|
||||
// router.isReady().then(() => {
|
||||
// app.mount('#app', true);
|
||||
// });
|
||||
|
||||
// import 'uno.css'; // 确保这是你的 UnoCSS 生成的样式文件
|
||||
|
||||
import { createHead } from '@vueuse/head';
|
||||
|
||||
// src/entry-client.js
|
||||
import { createApp } from 'vue';
|
||||
import { createPinia } from 'pinia';
|
||||
import App from './App.vue';
|
||||
import router from '@/router';
|
||||
import { plausible } from '@/plugins/plausible.plugin';
|
||||
import { naive } from '@/plugins/naive.plugin';
|
||||
import { i18nPlugin } from '@/plugins/i18n.plugin';
|
||||
|
||||
const app = createApp(App);
|
||||
const pinia = createPinia();
|
||||
app.use(pinia);
|
||||
app.use(createHead());
|
||||
app.use(i18nPlugin);
|
||||
app.use(router);
|
||||
app.use(plausible);
|
||||
app.use(naive);
|
||||
|
||||
router.isReady().then(() => {
|
||||
app.mount('#app', true);
|
||||
});
|
22
src/entry-server.ts
Normal file
22
src/entry-server.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { renderToString } from '@vue/server-renderer';
|
||||
import { setup } from '@css-render/vue3-ssr';
|
||||
import { createApp } from './main';
|
||||
// import 'virtual:uno.css';
|
||||
|
||||
/**
|
||||
* Render page with naive ui
|
||||
*/
|
||||
export async function render() {
|
||||
const { app, router, pinia, i18n } = createApp();
|
||||
const { collect } = setup(app);
|
||||
const appHtml = await renderToString(app);
|
||||
const cssHtml = collect();
|
||||
return {
|
||||
cssHtml,
|
||||
appHtml,
|
||||
app,
|
||||
router,
|
||||
pinia,
|
||||
i18n,
|
||||
};
|
||||
}
|
27
src/main.ts
27
src/main.ts
|
@ -1,8 +1,8 @@
|
|||
import { createApp } from 'vue';
|
||||
import { createSSRApp } from 'vue';
|
||||
import { createPinia } from 'pinia';
|
||||
import { createHead } from '@vueuse/head';
|
||||
|
||||
import { registerSW } from 'virtual:pwa-register';
|
||||
// import { registerSW } from 'virtual:pwa-register';
|
||||
import { plausible } from './plugins/plausible.plugin';
|
||||
|
||||
import 'virtual:uno.css';
|
||||
|
@ -13,15 +13,28 @@ import App from './App.vue';
|
|||
import router from './router';
|
||||
import { i18nPlugin } from './plugins/i18n.plugin';
|
||||
|
||||
registerSW();
|
||||
// registerSW();
|
||||
|
||||
const app = createApp(App);
|
||||
// const app = createApp(App);
|
||||
|
||||
app.use(createPinia());
|
||||
// app.use(createPinia());
|
||||
// app.use(createHead());
|
||||
// app.use(i18nPlugin);
|
||||
// app.use(router);
|
||||
// app.use(naive);
|
||||
// // app.use(plausible);
|
||||
//
|
||||
// app.mount('#app');
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App);
|
||||
const pinia = createPinia();
|
||||
app.use(pinia);
|
||||
app.use(createHead());
|
||||
app.use(i18nPlugin);
|
||||
app.use(router);
|
||||
app.use(naive);
|
||||
app.use(plausible);
|
||||
app.use(naive);
|
||||
// 其他插件...
|
||||
|
||||
app.mount('#app');
|
||||
return { app, router, pinia, i18n: i18nPlugin };
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import type { PaletteOption } from './command-palette.types';
|
|||
const isModalOpen = ref(false);
|
||||
const inputRef = ref();
|
||||
const router = useRouter();
|
||||
const isMac = computed(() => window.navigator.userAgent.toLowerCase().includes('mac'));
|
||||
const isMac = computed(() => true);
|
||||
|
||||
const commandPaletteStore = useCommandPaletteStore();
|
||||
const { searchPrompt, filteredSearchResult } = storeToRefs(commandPaletteStore);
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import CSelect from '@/ui/c-select/c-select.vue';
|
||||
|
||||
const { availableLocales, locale } = useI18n();
|
||||
|
||||
const localesLong: Record<string, string> = {
|
||||
|
@ -21,7 +23,7 @@ const localeOptions = computed(() =>
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<c-select
|
||||
<CSelect
|
||||
v-model:value="locale"
|
||||
:options="localeOptions"
|
||||
placeholder="Select a language"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import _ from 'lodash';
|
||||
import type Plausible from 'plausible-tracker';
|
||||
// import type Plausible from 'plausible-tracker';
|
||||
import { inject } from 'vue';
|
||||
|
||||
export { createTrackerService, useTracker };
|
||||
|
@ -7,21 +7,21 @@ export { createTrackerService, useTracker };
|
|||
function createTrackerService({ plausible }: { plausible: ReturnType<typeof Plausible> }) {
|
||||
return {
|
||||
trackEvent({ eventName }: { eventName: string }) {
|
||||
plausible.trackEvent(eventName);
|
||||
// plausible.trackEvent(eventName);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function useTracker() {
|
||||
const plausible: ReturnType<typeof Plausible> | undefined = inject('plausible');
|
||||
// const plausible: ReturnType<any> | undefined = inject('plausible');
|
||||
//
|
||||
// if (_.isNil(plausible)) {
|
||||
// throw new TypeError('Plausible must be instantiated');
|
||||
// }
|
||||
|
||||
if (_.isNil(plausible)) {
|
||||
throw new TypeError('Plausible must be instantiated');
|
||||
}
|
||||
|
||||
const tracker = createTrackerService({ plausible });
|
||||
// const tracker = createTrackerService({ plausible });
|
||||
|
||||
return {
|
||||
tracker,
|
||||
tracker: () => {},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -3,18 +3,29 @@ import { get } from '@vueuse/core';
|
|||
import type { Plugin } from 'vue';
|
||||
import { createI18n } from 'vue-i18n';
|
||||
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: 'en',
|
||||
messages,
|
||||
});
|
||||
// const i18n = createI18n({
|
||||
// legacy: false,
|
||||
// locale: 'en',
|
||||
// messages,
|
||||
// });
|
||||
|
||||
export const i18nPlugin: Plugin = {
|
||||
install: (app) => {
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: 'zh',
|
||||
messages,
|
||||
});
|
||||
app.use(i18n);
|
||||
},
|
||||
};
|
||||
|
||||
export const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: 'zh',
|
||||
messages,
|
||||
});
|
||||
|
||||
export const translate = function (localeKey: string) {
|
||||
const hasKey = i18n.global.te(localeKey, get(i18n.global.locale));
|
||||
return hasKey ? i18n.global.t(localeKey) : localeKey;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { noop } from 'lodash';
|
||||
|
||||
import Plausible from 'plausible-tracker';
|
||||
// import Plausible from 'plausible-tracker';
|
||||
import type { App } from 'vue';
|
||||
import { config } from '@/config';
|
||||
|
||||
function createFakePlausibleInstance(): Pick<ReturnType<typeof Plausible>, 'trackEvent' | 'enableAutoPageviews'> {
|
||||
function createFakePlausibleInstance(): Pick<ReturnType<any>, 'trackEvent' | 'enableAutoPageviews'> {
|
||||
return {
|
||||
trackEvent: noop,
|
||||
enableAutoPageviews: () => noop,
|
||||
|
@ -22,7 +22,7 @@ function createPlausibleInstance({
|
|||
}
|
||||
}) {
|
||||
if (config.isTrackerEnabled) {
|
||||
return Plausible(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
return createFakePlausibleInstance();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { createRouter, createWebHistory } from 'vue-router';
|
||||
import { createMemoryHistory, createRouter } from 'vue-router';
|
||||
import { layouts } from './layouts/index';
|
||||
import HomePage from './pages/Home.page.vue';
|
||||
import NotFound from './pages/404.page.vue';
|
||||
|
@ -19,7 +19,7 @@ const toolsRedirectRoutes = tools
|
|||
);
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(config.app.baseUrl),
|
||||
history: createMemoryHistory(config.app.baseUrl),
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
sentenceCase,
|
||||
snakeCase,
|
||||
} from 'change-case';
|
||||
import InputCopyable from '../../components/InputCopyable.vue';
|
||||
import InputCopyable from '@/components/InputCopyable.vue';
|
||||
|
||||
const baseConfig = {
|
||||
stripRegexp: /[^A-Za-zÀ-ÖØ-öø-ÿ]+/gi,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { useThemeVars } from 'naive-ui';
|
||||
|
||||
import InputCopyable from '../../components/InputCopyable.vue';
|
||||
import InputCopyable from '@/components/InputCopyable.vue';
|
||||
import { computeChmodOctalRepresentation, computeChmodSymbolicRepresentation } from './chmod-calculator.service';
|
||||
|
||||
import type { Group, Scope } from './chmod-calculator.types';
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import type { lib } from 'crypto-js';
|
||||
import { MD5, RIPEMD160, SHA1, SHA224, SHA256, SHA3, SHA384, SHA512, enc } from 'crypto-js';
|
||||
|
||||
import InputCopyable from '../../components/InputCopyable.vue';
|
||||
import InputCopyable from '@/components/InputCopyable.vue';
|
||||
import { convertHexToBin } from './hash-text.service';
|
||||
import { useQueryParam } from '@/composable/queryParams';
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import CInputText from "@/ui/c-input-text/c-input-text.vue";
|
||||
import { extractIBAN, friendlyFormatIBAN, isQRIBAN, validateIBAN } from 'ibantools';
|
||||
import { getFriendlyErrors } from './iban-validator-and-parser.service';
|
||||
import type { CKeyValueListItems } from '@/ui/c-key-value-list/c-key-value-list.types';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import InputCopyable from '../../components/InputCopyable.vue';
|
||||
import InputCopyable from '@/components/InputCopyable.vue';
|
||||
import { convertBase } from './integer-base-converter.model';
|
||||
import { getErrorMessageIfThrows } from '@/utils/error';
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { stringify as stringifyToml } from 'iarna-toml-esm';
|
||||
import JSON5 from 'json5';
|
||||
import { withDefaultOnError } from '../../utils/defaults';
|
||||
import { withDefaultOnError } from '@/utils/defaults';
|
||||
import type { UseValidationRule } from '@/composable/validation';
|
||||
|
||||
const convertJsonToToml = (value: string) => [stringifyToml(JSON5.parse(value))].flat().join('\n').trim();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { useEventListener } from '@vueuse/core';
|
||||
|
||||
import InputCopyable from '../../components/InputCopyable.vue';
|
||||
import InputCopyable from '@/components/InputCopyable.vue';
|
||||
|
||||
const event = ref<KeyboardEvent>();
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import { parse as parseToml } from 'iarna-toml-esm';
|
||||
import { withDefaultOnError } from '../../utils/defaults';
|
||||
import { withDefaultOnError } from '@/utils/defaults';
|
||||
import { isValidToml } from './toml.services';
|
||||
import type { UseValidationRule } from '@/composable/validation';
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { parse as parseToml } from 'iarna-toml-esm';
|
||||
import { isNotThrowing } from '../../utils/boolean';
|
||||
import { isNotThrowing } from '@/utils/boolean';
|
||||
|
||||
export { isValidToml };
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { parse as parseToml } from 'iarna-toml-esm';
|
||||
import { stringify as stringifyToYaml } from 'yaml';
|
||||
import { withDefaultOnError } from '../../utils/defaults';
|
||||
import { withDefaultOnError } from '@/utils/defaults';
|
||||
import { isValidToml } from '../toml-to-json/toml.services';
|
||||
import type { UseValidationRule } from '@/composable/validation';
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import InputCopyable from '../../components/InputCopyable.vue';
|
||||
import InputCopyable from '@/components/InputCopyable.vue';
|
||||
import { isNotThrowing } from '@/utils/boolean';
|
||||
import { withDefaultOnError } from '@/utils/defaults';
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { stringify as stringifyToml } from 'iarna-toml-esm';
|
||||
import { parse as parseYaml } from 'yaml';
|
||||
import { withDefaultOnError } from '../../utils/defaults';
|
||||
import { withDefaultOnError } from '@/utils/defaults';
|
||||
import type { UseValidationRule } from '@/composable/validation';
|
||||
|
||||
const convertYamlToToml = (value: string) => [stringifyToml(parseYaml(value))].flat().join('\n').trim();
|
||||
|
|
|
@ -3,6 +3,7 @@ import { useAppTheme } from '../theme/themes';
|
|||
import type { CLabelProps } from '../c-label/c-label.types';
|
||||
import type { CSelectOption } from './c-select.types';
|
||||
import { useTheme } from './c-select.theme';
|
||||
import CLabel from '@/ui/c-label/c-label.vue';
|
||||
import { clamp } from '@/modules/shared/number.models';
|
||||
import { useFuzzySearch } from '@/composable/fuzzySearch';
|
||||
|
||||
|
@ -138,7 +139,7 @@ function onSearchInput() {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<c-label v-bind="props">
|
||||
<CLabel v-bind="props">
|
||||
<div ref="elementRef" relative class="c-select" w-full>
|
||||
<div
|
||||
flex flex-nowrap cursor-pointer items-center
|
||||
|
@ -190,7 +191,7 @@ function onSearchInput() {
|
|||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</c-label>
|
||||
</CLabel>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -14,8 +14,7 @@ export default defineConfig({
|
|||
transformers: [transformerDirectives(), transformerVariantGroup()],
|
||||
theme: {
|
||||
colors: {
|
||||
primary: '#1ea54c',
|
||||
|
||||
primary: '#9c1ea5',
|
||||
},
|
||||
},
|
||||
shortcuts: {
|
||||
|
|
|
@ -11,10 +11,11 @@ import Icons from 'unplugin-icons/vite';
|
|||
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers';
|
||||
import Components from 'unplugin-vue-components/vite';
|
||||
import { defineConfig } from 'vite';
|
||||
import { VitePWA } from 'vite-plugin-pwa';
|
||||
// import { VitePWA } from 'vite-plugin-pwa';
|
||||
import markdown from 'vite-plugin-vue-markdown';
|
||||
import svgLoader from 'vite-svg-loader';
|
||||
import { configDefaults } from 'vitest/config';
|
||||
import ssr from 'vite-plugin-ssr/plugin';
|
||||
|
||||
const baseUrl = process.env.BASE_URL ?? '/';
|
||||
|
||||
|
@ -53,43 +54,43 @@ export default defineConfig({
|
|||
vueJsx(),
|
||||
markdown(),
|
||||
svgLoader(),
|
||||
VitePWA({
|
||||
registerType: 'autoUpdate',
|
||||
strategies: 'generateSW',
|
||||
manifest: {
|
||||
name: 'IT Tools',
|
||||
description: 'Aggregated set of useful tools for developers.',
|
||||
display: 'standalone',
|
||||
lang: 'fr-FR',
|
||||
start_url: `${baseUrl}?utm_source=pwa&utm_medium=pwa`,
|
||||
orientation: 'any',
|
||||
theme_color: '#18a058',
|
||||
background_color: '#f1f5f9',
|
||||
icons: [
|
||||
{
|
||||
src: '/favicon-16x16.png',
|
||||
type: 'image/png',
|
||||
sizes: '16x16',
|
||||
},
|
||||
{
|
||||
src: '/favicon-32x32.png',
|
||||
type: 'image/png',
|
||||
sizes: '32x32',
|
||||
},
|
||||
{
|
||||
src: '/android-chrome-192x192.png',
|
||||
sizes: '192x192',
|
||||
type: 'image/png',
|
||||
},
|
||||
{
|
||||
src: '/android-chrome-512x512.png',
|
||||
sizes: '512x512',
|
||||
type: 'image/png',
|
||||
purpose: 'any maskable',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
// VitePWA({
|
||||
// registerType: 'autoUpdate',
|
||||
// strategies: 'generateSW',
|
||||
// manifest: {
|
||||
// name: 'IT Tools',
|
||||
// description: 'Aggregated set of useful tools for developers.',
|
||||
// display: 'standalone',
|
||||
// lang: 'fr-FR',
|
||||
// start_url: `${baseUrl}?utm_source=pwa&utm_medium=pwa`,
|
||||
// orientation: 'any',
|
||||
// theme_color: '#18a058',
|
||||
// background_color: '#f1f5f9',
|
||||
// icons: [
|
||||
// {
|
||||
// src: '/favicon-16x16.png',
|
||||
// type: 'image/png',
|
||||
// sizes: '16x16',
|
||||
// },
|
||||
// {
|
||||
// src: '/favicon-32x32.png',
|
||||
// type: 'image/png',
|
||||
// sizes: '32x32',
|
||||
// },
|
||||
// {
|
||||
// src: '/android-chrome-192x192.png',
|
||||
// sizes: '192x192',
|
||||
// type: 'image/png',
|
||||
// },
|
||||
// {
|
||||
// src: '/android-chrome-512x512.png',
|
||||
// sizes: '512x512',
|
||||
// type: 'image/png',
|
||||
// purpose: 'any maskable',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// }),
|
||||
Components({
|
||||
dirs: ['src/'],
|
||||
extensions: ['vue', 'md'],
|
||||
|
@ -97,6 +98,7 @@ export default defineConfig({
|
|||
resolvers: [NaiveUiResolver(), IconsResolver({ prefix: 'icon' })],
|
||||
}),
|
||||
Unocss(),
|
||||
ssr(),
|
||||
],
|
||||
base: baseUrl,
|
||||
resolve: {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue