diff --git a/apps/server/vitest.config.ts b/apps/server/vitest.config.ts index 9e551b734..2caa75aa8 100644 --- a/apps/server/vitest.config.ts +++ b/apps/server/vitest.config.ts @@ -9,7 +9,11 @@ export default defineConfig({ include: [ 'src/**/*.ts', ], - reporter: ['text', 'json', 'html'], + reporter: [ + 'text', + 'json', + 'html', + ], thresholds: { lines: 100, functions: 100, diff --git a/apps/ui-server-auth/index.html b/apps/ui-server-auth/index.html new file mode 100644 index 000000000..ef6ffd4da --- /dev/null +++ b/apps/ui-server-auth/index.html @@ -0,0 +1,57 @@ + + + + + AIRI + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + diff --git a/apps/ui-server-auth/package.json b/apps/ui-server-auth/package.json new file mode 100644 index 000000000..c7bc0114e --- /dev/null +++ b/apps/ui-server-auth/package.json @@ -0,0 +1,83 @@ +{ + "name": "@proj-airi/ui-server-auth", + "type": "module", + "private": true, + "description": "Auth UI for Project AIRI", + "author": { + "name": "Moeru AI Project AIRI Team", + "email": "airi@moeru.ai", + "url": "https://github.com/moeru-ai" + }, + "license": "MIT", + "scripts": { + "build": "vite build", + "dev": "vite --host", + "lint": "eslint .", + "preview": "vite preview", + "typecheck": "vue-tsc --noEmit" + }, + "dependencies": { + "@date-fns/utc": "^2.1.1", + "@fontsource-variable/nunito": "catalog:", + "@formkit/auto-animate": "^0.9.0", + "@huggingface/transformers": "^3.8.1", + "@moeru/eventa": "catalog:", + "@moeru/std": "catalog:", + "@proj-airi/font-chillroundm": "workspace:^", + "@proj-airi/font-cjkfonts-allseto": "workspace:^", + "@proj-airi/font-xiaolai": "workspace:^", + "@proj-airi/i18n": "workspace:^", + "@proj-airi/stage-layouts": "workspace:^", + "@proj-airi/stage-shared": "workspace:^", + "@proj-airi/stage-ui": "workspace:^", + "@proj-airi/ui": "workspace:^", + "@vueuse/core": "^14.2.1", + "@vueuse/shared": "^14.2.1", + "animejs": "^4.3.6", + "colorjs.io": "^0.6.1", + "culori": "^4.0.2", + "date-fns": "^4.1.0", + "nanoid": "^5.1.7", + "nprogress": "^0.2.0", + "pinia": "^3.0.4", + "posthog-js": "catalog:", + "uuid": "^13.0.0", + "vaul-vue": "^0.4.1", + "vue": "catalog:", + "vue-i18n": "^11.3.0", + "vue-router": "^5.0.4", + "vue-sonner": "^2.0.9" + }, + "devDependencies": { + "@iconify-json/carbon": "^1.2.19", + "@iconify-json/eos-icons": "^1.2.4", + "@iconify-json/logos": "catalog:", + "@iconify-json/lucide": "^1.2.98", + "@iconify-json/mingcute": "^1.2.7", + "@iconify-json/ph": "^1.2.2", + "@iconify-json/simple-icons": "^1.2.75", + "@iconify-json/solar": "^1.2.5", + "@iconify-json/svg-spinners": "^1.2.4", + "@iconify-json/tabler": "catalog:", + "@iconify-json/vscode-icons": "^1.2.45", + "@intlify/unplugin-vue-i18n": "^11.0.7", + "@proj-airi/iconify-meteocons": "catalog:", + "@proj-airi/lobe-icons": "^1.0.18", + "@shikijs/markdown-it": "^4.0.2", + "@types/culori": "^4.0.1", + "@types/nprogress": "^0.2.3", + "@types/splitpanes": "catalog:", + "@unocss/reset": "^66.6.7", + "@vitejs/plugin-vue": "^6.0.5", + "@vue-macros/volar": "^3.1.2", + "@vueuse/motion": "^3.0.3", + "unplugin-info": "^1.2.4", + "unplugin-vue-router": "^0.19.2", + "unplugin-yaml": "^4.0.1", + "vite": "catalog:", + "vite-plugin-vue-devtools": "^8.1.1", + "vite-plugin-vue-layouts": "^0.11.0", + "vue-macros": "^3.1.2", + "vue-tsc": "^3.2.6" + } +} diff --git a/apps/ui-server-auth/public/.assetsignore b/apps/ui-server-auth/public/.assetsignore new file mode 100644 index 000000000..421c66e16 --- /dev/null +++ b/apps/ui-server-auth/public/.assetsignore @@ -0,0 +1,3 @@ +**/node_modules +**/.DS_Store +**/.git diff --git a/apps/ui-server-auth/public/_headers b/apps/ui-server-auth/public/_headers new file mode 100644 index 000000000..7f40d0894 --- /dev/null +++ b/apps/ui-server-auth/public/_headers @@ -0,0 +1,4 @@ +/assets/* + cache-control: max-age=31536000 + cache-control: immutable + diff --git a/apps/ui-server-auth/public/apple-touch-icon.png b/apps/ui-server-auth/public/apple-touch-icon.png new file mode 100644 index 000000000..e3bfed969 Binary files /dev/null and b/apps/ui-server-auth/public/apple-touch-icon.png differ diff --git a/apps/ui-server-auth/public/favicon.ico b/apps/ui-server-auth/public/favicon.ico new file mode 100644 index 000000000..a47f8f675 Binary files /dev/null and b/apps/ui-server-auth/public/favicon.ico differ diff --git a/apps/ui-server-auth/public/favicon.svg b/apps/ui-server-auth/public/favicon.svg new file mode 100644 index 000000000..eae728aa1 --- /dev/null +++ b/apps/ui-server-auth/public/favicon.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/ui-server-auth/public/maskable_icon_x192.png b/apps/ui-server-auth/public/maskable_icon_x192.png new file mode 100644 index 000000000..9a1728ebd Binary files /dev/null and b/apps/ui-server-auth/public/maskable_icon_x192.png differ diff --git a/apps/ui-server-auth/public/maskable_icon_x512.png b/apps/ui-server-auth/public/maskable_icon_x512.png new file mode 100644 index 000000000..2a56ae126 Binary files /dev/null and b/apps/ui-server-auth/public/maskable_icon_x512.png differ diff --git a/apps/ui-server-auth/public/open-graph.png b/apps/ui-server-auth/public/open-graph.png new file mode 100644 index 000000000..a7d26580c Binary files /dev/null and b/apps/ui-server-auth/public/open-graph.png differ diff --git a/apps/ui-server-auth/public/web-app-manifest-192x192.png b/apps/ui-server-auth/public/web-app-manifest-192x192.png new file mode 100644 index 000000000..c046e5331 Binary files /dev/null and b/apps/ui-server-auth/public/web-app-manifest-192x192.png differ diff --git a/apps/ui-server-auth/public/web-app-manifest-512x512.png b/apps/ui-server-auth/public/web-app-manifest-512x512.png new file mode 100644 index 000000000..e92eb2fd7 Binary files /dev/null and b/apps/ui-server-auth/public/web-app-manifest-512x512.png differ diff --git a/apps/ui-server-auth/src/App.vue b/apps/ui-server-auth/src/App.vue new file mode 100644 index 000000000..9c133e140 --- /dev/null +++ b/apps/ui-server-auth/src/App.vue @@ -0,0 +1,34 @@ + + + diff --git a/apps/ui-server-auth/src/main.ts b/apps/ui-server-auth/src/main.ts new file mode 100644 index 000000000..80c73503d --- /dev/null +++ b/apps/ui-server-auth/src/main.ts @@ -0,0 +1,88 @@ +import type { Plugin } from 'vue' +import type { Router, RouteRecordRaw } from 'vue-router' + +import NProgress from 'nprogress' + +import { autoAnimatePlugin } from '@formkit/auto-animate/vue' +import { isEnvTruthy } from '@proj-airi/stage-shared' +import { MotionPlugin } from '@vueuse/motion' +import { createPinia } from 'pinia' +import { setupLayouts } from 'virtual:generated-layouts' +import { createApp } from 'vue' +import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router' +import { routes } from 'vue-router/auto-routes' + +import App from './App.vue' + +import { i18n } from './modules/i18n' + +import '@proj-airi/font-cjkfonts-allseto/index.css' +import '@proj-airi/font-xiaolai/index.css' +import '@unocss/reset/tailwind.css' +import 'vue-sonner/style.css' +import './styles/main.css' +import 'uno.css' + +const pinia = createPinia() + +// TODO: vite-plugin-vue-layouts is long deprecated, replace with another layout solution +const routeRecords = setupLayouts(routes as RouteRecordRaw[]) + +let router: Router +if (isEnvTruthy(import.meta.env.VITE_APP_TARGET_HUGGINGFACE_SPACE)) + router = createRouter({ routes: routeRecords, history: createWebHashHistory() }) +else + router = createRouter({ routes: routeRecords, history: createWebHistory() }) + +router.beforeEach((to, from) => { + if (to.path !== from.path) + NProgress.start() +}) + +router.afterEach(() => { + NProgress.done() +}) + +createApp(App) + .use(MotionPlugin) + // TODO: Fix autoAnimatePlugin type error + .use(autoAnimatePlugin as unknown as Plugin) + .use(router) + .use(pinia) + .use(i18n) + .mount('#app') + +if (import.meta.env.DEV && !import.meta.env.SSR) { + function captureEvents(el: HTMLElement) { + // Force `pointer-events: auto` as DismissableLayer in Reka UI adds + // `pointer-events: none` to document body. + el.style.pointerEvents = 'auto' + + // We need to capture events inside elements like devtools to prevent them + // from leaking to other layers (like DismissableLayer in Reka UI). + // + // See: https://github.com/unovue/reka-ui/blob/14866201d179b8bae3c8b4346a1ca8eff1c5eaa4/packages/radix-vue/src/DismissableLayer/DismissableLayer.vue#L186-L188 + el.addEventListener('focus', e => e.stopPropagation(), { capture: true }) + el.addEventListener('blur', e => e.stopPropagation(), { capture: true }) + el.addEventListener('pointerdown', e => e.stopPropagation(), { capture: true }) + } + + const observer = new MutationObserver((mutationsList, observer) => { + for (const mutation of mutationsList) { + if (mutation.type === 'childList') { + const devtoolsContainer = document.getElementById('__vue-devtools-container__') + + if (devtoolsContainer) { + captureEvents(devtoolsContainer) + observer.disconnect() + } + } + } + }) + + observer.observe(document.body, { childList: true, subtree: true }) + + // Disconnect on timeout in case the MutationObserver is left here forever. + // `observer.disconnect()` is idempotent, so it's safe to call it multiple times. + setTimeout(() => observer.disconnect(), 15 * 1000) +} diff --git a/apps/ui-server-auth/src/modules/i18n.ts b/apps/ui-server-auth/src/modules/i18n.ts new file mode 100644 index 000000000..438770ebe --- /dev/null +++ b/apps/ui-server-auth/src/modules/i18n.ts @@ -0,0 +1,22 @@ +import messages from '@proj-airi/i18n/locales' + +import { resolveSupportedLocale } from '@proj-airi/i18n' +import { createI18n } from 'vue-i18n' + +function getLocale() { + let language = localStorage.getItem('settings/language') + + if (!language) { + // Fallback to browser language + language = navigator.language || 'en' + } + + return resolveSupportedLocale(language, Object.keys(messages!)) +} + +export const i18n = createI18n({ + legacy: false, + locale: getLocale(), + fallbackLocale: 'en', + messages, +}) diff --git a/apps/ui-server-auth/src/pages/electron-callback.vue b/apps/ui-server-auth/src/pages/electron-callback.vue new file mode 100644 index 000000000..a78fb6fd3 --- /dev/null +++ b/apps/ui-server-auth/src/pages/electron-callback.vue @@ -0,0 +1,7 @@ + + + diff --git a/apps/ui-server-auth/src/pages/index.vue b/apps/ui-server-auth/src/pages/index.vue new file mode 100644 index 000000000..a78fb6fd3 --- /dev/null +++ b/apps/ui-server-auth/src/pages/index.vue @@ -0,0 +1,7 @@ + + + diff --git a/apps/ui-server-auth/src/pages/sign-in.vue b/apps/ui-server-auth/src/pages/sign-in.vue new file mode 100644 index 000000000..a78fb6fd3 --- /dev/null +++ b/apps/ui-server-auth/src/pages/sign-in.vue @@ -0,0 +1,7 @@ + + + diff --git a/apps/ui-server-auth/src/styles/main.css b/apps/ui-server-auth/src/styles/main.css new file mode 100755 index 000000000..6f8e46919 --- /dev/null +++ b/apps/ui-server-auth/src/styles/main.css @@ -0,0 +1,65 @@ +@import './transitions.css'; +@import './vue-transitions.css'; + +:root { + --bg-color-light: rgb(255 255 255); + --bg-color-dark: rgb(18 18 18); + --bg-color: var(--bg-color-light); +} + +/** + Disable double-tap "zoom" option in browser on touch devices + + https://stackoverflow.com/a/54207844 + https://stackoverflow.com/questions/10614481/disable-double-tap-zoom-option-in-browser-on-touch-devices + */ +* { + touch-action: manipulation; +} + +html, +body, +#app { + height: 100%; + margin: 0; + padding: 0; + overscroll-behavior: none; +} + +html { + background: var(--bg-color); + transition: all 0.3s ease-in-out; +} + +html.dark { + --bg-color: var(--bg-color-dark); + color-scheme: dark; +} + +#nprogress { + pointer-events: none; +} + +#nprogress .bar { + background: color-mix(in srgb, oklch(95% var(--chromatic-chroma-900) calc(var(--chromatic-hue) + ${0})) 70%, oklch(50% 0 360)); + opacity: 0.75; + position: fixed; + z-index: 1031; + top: 0; + left: 0; + width: 100%; + height: 2px; +} + +.dark #nprogress .bar { + background: `color-mix(in srgb, oklch(95% var(--chromatic-chroma-900) calc(var(--chromatic-hue) + ${0})) 90%, oklch(90% 0 360))`; +} + +@media (display-mode: standalone) { + #nprogress { + display: none; + } + #nprogress .bar { + display: none; + } +} diff --git a/apps/ui-server-auth/src/styles/transitions.css b/apps/ui-server-auth/src/styles/transitions.css new file mode 100644 index 000000000..82ae842e3 --- /dev/null +++ b/apps/ui-server-auth/src/styles/transitions.css @@ -0,0 +1,18 @@ +.slide-away-enter-active, +.slide-away-leave-active { + transition: + transform 0.3s ease-in-out, + opacity 0.3s ease-in-out; +} + +.slide-away-enter, +.slide-away-leave-to { + transform: translateY(-10px); + opacity: 0; +} + +.slide-away-enter-from, +.slide-away-leave { + transform: translateY(10px); + opacity: 0; +} diff --git a/apps/ui-server-auth/src/styles/vue-transitions.css b/apps/ui-server-auth/src/styles/vue-transitions.css new file mode 100644 index 000000000..2beab3d5c --- /dev/null +++ b/apps/ui-server-auth/src/styles/vue-transitions.css @@ -0,0 +1,48 @@ +.fade-slide-out-r-to-l-enter-active, +.fade-slide-out-r-to-l-leave-active { + transition: opacity 0.2s ease-in-out, transform 0.2s ease-in-out; +} + +.fade-slide-out-r-to-l-enter-from, +.fade-slide-out-r-to-l-leave-to { + opacity: 0; + transform: translateX(10px); +} + +.fade-slide-out-r-to-l-enter-to, +.fade-slide-out-r-to-l-leave-from { + opacity: 1; + transform: translateX(0); +} + +.fade-slide-out-l-to-r-enter-active, +.fade-slide-out-l-to-r-leave-active { + transition: opacity 0.2s ease-in-out, transform 0.2s ease-in-out; +} + +.fade-slide-out-l-to-r-enter-from, +.fade-slide-out-l-to-r-leave-to { + opacity: 0; + transform: translateX(-10px); +} + +.fade-slide-out-l-to-r-enter-to, +.fade-slide-out-l-to-r-leave-from { + opacity: 1; + transform: translateX(0); +} + +.fade-enter-active, +.fade-leave-active { + transition: opacity 0.2s ease-in-out; +} + +.fade-enter-from, +.fade-leave-to { + opacity: 0; +} + +.fade-enter-to, +.fade-leave-from { + opacity: 1; +} diff --git a/apps/ui-server-auth/tsconfig.json b/apps/ui-server-auth/tsconfig.json new file mode 100644 index 000000000..faa0d4ec4 --- /dev/null +++ b/apps/ui-server-auth/tsconfig.json @@ -0,0 +1,38 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "jsx": "preserve", + "lib": [ + "DOM", + "ESNext", + "DOM.Iterable", + "DOM.AsyncIterable" + ], + "paths": { + "@proj-airi/stage-ui/*": [ + "../../packages/stage-ui/src/*" + ], + "@proj-airi/stage-layouts/*": [ + "../../packages/stage-layouts/src/*" + ] + }, + "resolveJsonModule": true, + "types": [ + "vitest", + "vite/client", + "vite-plugin-vue-layouts/client", + "vue-macros/macros-global", + "unplugin-vue-router/client", + "unplugin-info/client" + ], + "allowJs": true, + "strict": true, + "skipLibCheck": true + }, + "vueCompilerOptions": { + "plugins": [ + "@vue-macros/volar/define-models", + "@vue-macros/volar/define-slots" + ] + } +} diff --git a/apps/ui-server-auth/uno.config.ts b/apps/ui-server-auth/uno.config.ts new file mode 100644 index 000000000..693fbd0ef --- /dev/null +++ b/apps/ui-server-auth/uno.config.ts @@ -0,0 +1,26 @@ +import { mergeConfigs, presetWebFonts } from 'unocss' + +import { presetWebFontsFonts, sharedUnoConfig } from '../../uno.config' + +export default mergeConfigs([ + sharedUnoConfig(), + { + presets: [ + presetWebFonts({ + fonts: { + ...presetWebFontsFonts('fontsource'), + }, + timeouts: { + warning: 5000, + failure: 10000, + }, + }), + ], + rules: [ + ['transition-colors-none', { + 'transition-property': 'color, background-color, border-color, text-color', + 'transition-duration': '0s', + }], + ], + }, +]) diff --git a/apps/ui-server-auth/vite-env.d.ts b/apps/ui-server-auth/vite-env.d.ts new file mode 100644 index 000000000..af271c835 --- /dev/null +++ b/apps/ui-server-auth/vite-env.d.ts @@ -0,0 +1,7 @@ +/// +/// + +interface ImportMetaEnv { + readonly VITE_APP_TARGET_HUGGINGFACE_SPACE: string + // more env variables... +} diff --git a/apps/ui-server-auth/vite.config.ts b/apps/ui-server-auth/vite.config.ts new file mode 100644 index 000000000..6f5e00cbe --- /dev/null +++ b/apps/ui-server-auth/vite.config.ts @@ -0,0 +1,105 @@ +import { join, resolve } from 'node:path' + +import VueI18n from '@intlify/unplugin-vue-i18n/vite' +import Vue from '@vitejs/plugin-vue' +import Unocss from 'unocss/vite' +import Info from 'unplugin-info/vite' +import VueRouter from 'unplugin-vue-router/vite' +import Yaml from 'unplugin-yaml/vite' +import VueDevTools from 'vite-plugin-vue-devtools' +import Layouts from 'vite-plugin-vue-layouts' +import VueMacros from 'vue-macros/vite' + +import { defineConfig } from 'vite' + +export default defineConfig({ + optimizeDeps: { + exclude: [ + // Internal Packages + '@proj-airi/stage-ui/*', + ], + }, + + resolve: { + alias: { + '@proj-airi/i18n': resolve(join(import.meta.dirname, '..', '..', 'packages', 'i18n', 'src')), + '@proj-airi/stage-ui': resolve(join(import.meta.dirname, '..', '..', 'packages', 'stage-ui', 'src')), + '@proj-airi/stage-shared': resolve(join(import.meta.dirname, '..', '..', 'packages', 'stage-shared', 'src')), + '@proj-airi/stage-layouts': resolve(join(import.meta.dirname, '..', '..', 'packages', 'stage-layouts', 'src')), + }, + }, + server: { + fs: { + // To mute errors like: + // The request id ".../node_modules/@fontsource/sniglet/files/sniglet-latin-400-normal.woff" is outside of Vite serving allow list. + // + // See: https://vite.dev/config/server-options#server-fs-strict + strict: false, + }, + warmup: { + clientFiles: [ + `${resolve(join(import.meta.dirname, '..', '..', 'packages', 'stage-ui', 'src'))}/*.vue`, + ], + }, + }, + build: { + sourcemap: true, + }, + worker: { + format: 'es', + rollupOptions: { + output: { + inlineDynamicImports: false, + }, + }, + }, + + plugins: [ + Info(), + + Yaml(), + + VueMacros({ + plugins: { + vue: Vue({ + include: [/\.vue$/, /\.md$/], + }), + vueJsx: false, + }, + betterDefine: false, + }), + + // https://github.com/posva/unplugin-vue-router + VueRouter({ + extensions: ['.vue', '.md'], + dts: resolve(import.meta.dirname, 'src/typed-router.d.ts'), + importMode: 'async', + routesFolder: [ + resolve(import.meta.dirname, 'src', 'pages'), + ], + exclude: ['**/components/**'], + }), + + // https://github.com/JohnCampionJr/vite-plugin-vue-layouts + Layouts({ + layoutsDirs: [ + resolve(import.meta.dirname, 'src', 'layouts'), + resolve(import.meta.dirname, '..', '..', 'packages', 'stage-layouts', 'src', 'layouts'), + ], + }), + + // https://github.com/antfu/unocss + // see uno.config.ts for config + Unocss(), + + // https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n + VueI18n({ + runtimeOnly: true, + compositionOnly: true, + fullInstall: true, + }), + + // https://github.com/webfansplz/vite-plugin-vue-devtools + VueDevTools(), + ], +}) diff --git a/package.json b/package.json index 61f8db771..eb86a78e9 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "dev:docs": "pnpm -rF @proj-airi/docs run dev", "dev:ui": "pnpm -rF @proj-airi/stage-ui run story:dev", "dev:web": "pnpm -rF @proj-airi/stage-web run dev", + "dev:server-auth": "pnpm -rF @proj-airi/ui-server-auth run dev", "dev:pocket:ios": "pnpm -rF @proj-airi/stage-pocket run dev:ios", "dev:pocket:android": "pnpm -rF @proj-airi/stage-pocket run dev:android", "dev:server": "pnpm -rF @proj-airi/server-runtime run dev", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5f1936dc8..36fd37bd1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1876,6 +1876,190 @@ importers: specifier: ^3.2.6 version: 3.2.6(typescript@5.9.3) + apps/ui-server-auth: + dependencies: + '@date-fns/utc': + specifier: ^2.1.1 + version: 2.1.1 + '@fontsource-variable/nunito': + specifier: 'catalog:' + version: 5.2.7 + '@formkit/auto-animate': + specifier: ^0.9.0 + version: 0.9.0(vue@3.5.30(typescript@5.9.3)) + '@huggingface/transformers': + specifier: ^3.8.1 + version: 3.8.1 + '@moeru/eventa': + specifier: 'catalog:' + version: 1.0.0-beta.3(electron@41.0.3) + '@moeru/std': + specifier: 'catalog:' + version: 0.1.0-beta.17 + '@proj-airi/font-chillroundm': + specifier: workspace:^ + version: link:../../packages/font-chillroundm + '@proj-airi/font-cjkfonts-allseto': + specifier: workspace:^ + version: link:../../packages/font-cjkfonts-allseto + '@proj-airi/font-xiaolai': + specifier: workspace:^ + version: link:../../packages/font-xiaolai + '@proj-airi/i18n': + specifier: workspace:^ + version: link:../../packages/i18n + '@proj-airi/stage-layouts': + specifier: workspace:^ + version: link:../../packages/stage-layouts + '@proj-airi/stage-shared': + specifier: workspace:^ + version: link:../../packages/stage-shared + '@proj-airi/stage-ui': + specifier: workspace:^ + version: link:../../packages/stage-ui + '@proj-airi/ui': + specifier: workspace:^ + version: link:../../packages/ui + '@vueuse/core': + specifier: ^14.2.1 + version: 14.2.1(vue@3.5.30(typescript@5.9.3)) + '@vueuse/shared': + specifier: ^14.2.1 + version: 14.2.1(vue@3.5.30(typescript@5.9.3)) + animejs: + specifier: ^4.3.6 + version: 4.3.6 + colorjs.io: + specifier: ^0.6.1 + version: 0.6.1 + culori: + specifier: ^4.0.2 + version: 4.0.2 + date-fns: + specifier: ^4.1.0 + version: 4.1.0 + nanoid: + specifier: ^5.1.7 + version: 5.1.7 + nprogress: + specifier: ^0.2.0 + version: 0.2.0 + pinia: + specifier: ^3.0.4 + version: 3.0.4(typescript@5.9.3)(vue@3.5.30(typescript@5.9.3)) + posthog-js: + specifier: 'catalog:' + version: 1.306.1 + uuid: + specifier: ^13.0.0 + version: 13.0.0 + vaul-vue: + specifier: ^0.4.1 + version: 0.4.1(reka-ui@2.9.2(vue@3.5.30(typescript@5.9.3)))(vue@3.5.30(typescript@5.9.3)) + vue: + specifier: 'catalog:' + version: 3.5.30(typescript@5.9.3) + vue-i18n: + specifier: ^11.3.0 + version: 11.3.0(vue@3.5.30(typescript@5.9.3)) + vue-router: + specifier: ^5.0.4 + version: 5.0.4(@vue/compiler-sfc@3.5.30)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.30(typescript@5.9.3)))(vue@3.5.30(typescript@5.9.3)) + vue-sonner: + specifier: ^2.0.9 + version: 2.0.9(vue@3.5.30(typescript@5.9.3)) + devDependencies: + '@iconify-json/carbon': + specifier: ^1.2.19 + version: 1.2.19 + '@iconify-json/eos-icons': + specifier: ^1.2.4 + version: 1.2.4 + '@iconify-json/logos': + specifier: 'catalog:' + version: 1.2.10 + '@iconify-json/lucide': + specifier: ^1.2.98 + version: 1.2.98 + '@iconify-json/mingcute': + specifier: ^1.2.7 + version: 1.2.7 + '@iconify-json/ph': + specifier: ^1.2.2 + version: 1.2.2 + '@iconify-json/simple-icons': + specifier: ^1.2.75 + version: 1.2.75 + '@iconify-json/solar': + specifier: ^1.2.5 + version: 1.2.5 + '@iconify-json/svg-spinners': + specifier: ^1.2.4 + version: 1.2.4 + '@iconify-json/tabler': + specifier: 'catalog:' + version: 1.2.32 + '@iconify-json/vscode-icons': + specifier: ^1.2.45 + version: 1.2.45 + '@intlify/unplugin-vue-i18n': + specifier: ^11.0.7 + version: 11.0.7(@vue/compiler-dom@3.5.30)(eslint@10.1.0(jiti@2.6.1))(rollup@4.60.0)(typescript@5.9.3)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-i18n@11.3.0(vue@3.5.30(typescript@5.9.3)))(vue@3.5.30(typescript@5.9.3)) + '@proj-airi/iconify-meteocons': + specifier: 'catalog:' + version: 0.1.4 + '@proj-airi/lobe-icons': + specifier: ^1.0.18 + version: 1.0.18 + '@shikijs/markdown-it': + specifier: ^4.0.2 + version: 4.0.2 + '@types/culori': + specifier: ^4.0.1 + version: 4.0.1 + '@types/nprogress': + specifier: ^0.2.3 + version: 0.2.3 + '@types/splitpanes': + specifier: 'catalog:' + version: 2.2.6 + '@unocss/reset': + specifier: ^66.6.7 + version: 66.6.7 + '@vitejs/plugin-vue': + specifier: ^6.0.5 + version: 6.0.5(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.30(typescript@5.9.3)) + '@vue-macros/volar': + specifier: ^3.1.2 + version: 3.1.2(typescript@5.9.3)(vue-tsc@3.2.6(typescript@5.9.3))(vue@3.5.30(typescript@5.9.3)) + '@vueuse/motion': + specifier: ^3.0.3 + version: 3.0.3(magicast@0.5.2)(vue@3.5.30(typescript@5.9.3)) + unplugin-info: + specifier: ^1.2.4 + version: 1.2.4(esbuild@0.27.2)(rollup@4.60.0)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + unplugin-vue-router: + specifier: ^0.19.2 + version: 0.19.2(@vue/compiler-sfc@3.5.30)(vue-router@5.0.4(@vue/compiler-sfc@3.5.30)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.30(typescript@5.9.3)))(vue@3.5.30(typescript@5.9.3)))(vue@3.5.30(typescript@5.9.3)) + unplugin-yaml: + specifier: ^4.0.1 + version: 4.0.1(@nuxt/kit@3.20.2(magicast@0.5.2))(esbuild@0.27.2)(rolldown@1.0.0-rc.9)(rollup@4.60.0)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + vite: + specifier: 'catalog:' + version: 8.0.2(@types/node@24.12.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vite-plugin-vue-devtools: + specifier: ^8.1.1 + version: 8.1.1(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.30(typescript@5.9.3)) + vite-plugin-vue-layouts: + specifier: ^0.11.0 + version: 0.11.0(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-router@5.0.4(@vue/compiler-sfc@3.5.30)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.30(typescript@5.9.3)))(vue@3.5.30(typescript@5.9.3)))(vue@3.5.30(typescript@5.9.3)) + vue-macros: + specifier: ^3.1.2 + version: 3.1.2(@vueuse/core@14.2.1(vue@3.5.30(typescript@5.9.3)))(esbuild@0.27.2)(rolldown@1.0.0-rc.9)(rollup@4.60.0)(typescript@5.9.3)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-tsc@3.2.6(typescript@5.9.3))(vue@3.5.30(typescript@5.9.3)) + vue-tsc: + specifier: ^3.2.6 + version: 3.2.6(typescript@5.9.3) + docs: dependencies: '@fontsource-variable/comfortaa':