refactor: ♻️ 升级依赖并重构导航与主题交互

升级核心依赖与构建链路(Vite/Vue/Pinia/VueUse/Vant 等)并完成兼容调整

Vibe Coding 了一个导航组件 FloatingNavBar

修复暗黑模式 switch 动画异常:统一 useDark 行为并设置 disableTransition: false,恢复 Vant Switch 过渡动画

调整亮色模式下页面背景与卡片层次(以边框+轻阴影为主),降低过强对比并提升一致性

我的页面入口 icon 统一为线性风格
This commit is contained in:
xiangshu233 2026-03-24 20:36:10 +08:00
parent 6e776c52e2
commit fbc12f02f9
25 changed files with 3284 additions and 2132 deletions

3
.gitignore vendored
View File

@ -23,4 +23,5 @@ dist-ssr
*.sln
*.sw?
/components.d.ts
/components.d.ts
.agents/
skills-lock.json

View File

@ -18,7 +18,7 @@
"url": "https://github.com/xiangshu233/vue3-vant4-mobile/issues"
},
"engines": {
"node": "^20.9.0 || >=21.7.1",
"node": "^20.19.0 || >=22.12.0",
"pnpm": ">=8.15.4"
},
"scripts": {
@ -40,44 +40,44 @@
},
"dependencies": {
"@types/lodash-es": "^4.17.12",
"@unocss/reset": "^0.58.5",
"@vueuse/core": "^10.7.0",
"@vueuse/core": "^14.2.1",
"axios": "^1.4.0",
"date-fns": "^3.0.6",
"echarts": "^5.4.3",
"lodash-es": "^4.17.21",
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
"pinia": "^2.1.7",
"pinia-plugin-persist": "^1.0.0",
"pinia": "^3.0.4",
"pinia-plugin-persistedstate": "^4.7.1",
"qs": "^6.11.2",
"vant": "^4.8.1",
"vue": "^3.3.13",
"vue-router": "4.2.5"
"vant": "^4.9.22",
"vue": "^3.5.30",
"vue-router": "^5.0.4"
},
"devDependencies": {
"@antfu/eslint-config": "^2.6.3",
"@commitlint/cli": "^18.4.3",
"@commitlint/config-conventional": "^18.4.3",
"@iconify/json": "^2.2.188",
"@oxc-parser/binding-win32-x64-msvc": "0.115.0",
"@types/fs-extra": "^11.0.4",
"@types/mockjs": "^1.0.10",
"@types/node": "^20.10.5",
"@types/node": "^25.5.0",
"@types/nprogress": "^0.2.3",
"@types/qs": "^6.9.11",
"@unocss/eslint-plugin": "^0.58.4",
"@unocss/preset-icons": "^0.58.5",
"@unocss/preset-rem-to-px": "^0.58.5",
"@unocss/transformer-directives": "^0.58.4",
"@unocss/transformer-variant-group": "^0.58.4",
"@vitejs/plugin-vue": "^5.0.0",
"@unocss/eslint-plugin": "^66.6.7",
"@unocss/preset-icons": "^66.6.7",
"@unocss/preset-rem-to-px": "^66.6.7",
"@unocss/reset": "^66.6.7",
"@unocss/transformer-directives": "^66.6.7",
"@unocss/transformer-variant-group": "^66.6.7",
"@vitejs/plugin-vue": "^6.0.5",
"autoprefixer": "^10.4.16",
"cross-env": "^7.0.3",
"cz-git": "^1.8.0",
"dotenv": "^16.3.1",
"eslint": "^8.56.0",
"eslint": "^8.57.0",
"eslint-plugin-format": "^0.1.0",
"tsx": "^3.0.0",
"fs-extra": "^11.2.0",
"less": "^4.2.0",
"lint-staged": "^15.2.0",
@ -89,16 +89,18 @@
"rollup": "^4.9.1",
"rollup-plugin-visualizer": "^5.11.0",
"simple-git-hooks": "^2.9.0",
"typescript": "^5.3.3",
"unocss": "^0.58.5",
"unplugin-auto-import": "^0.17.5",
"unplugin-vue-components": "^0.26.0",
"vite": "^5.0.10",
"terser": "^5.46.1",
"tsx": "^4.21.0",
"typescript": "^5.9.3",
"unocss": "^66.6.7",
"unplugin-auto-import": "^21.0.0",
"unplugin-vue-components": "^32.0.0",
"vite": "^8.0.2",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-html": "^3.2.2",
"vite-plugin-mock": "^2.9.8",
"vite-plugin-svg-icons": "^2.0.1",
"vue-tsc": "^1.8.27"
"vue-tsc": "^3.2.6"
},
"simple-git-hooks": {
"pre-commit": "pnpm lint-staged",

3795
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,14 @@
<template>
<vanConfigProvider :theme="getDarkMode" :theme-vars="getThemeVars()">
<routerView v-slot="{ Component }">
<RouterView v-slot="{ Component }">
<div class="absolute bottom-0 top-0 w-full overflow-hidden">
<transition :name="getTransitionName" mode="out-in" appear>
<keep-alive v-if="keepAliveComponents" :include="keepAliveComponents">
<KeepAlive v-if="keepAliveComponents" :include="keepAliveComponents">
<component :is="Component" />
</keep-alive>
</KeepAlive>
</transition>
</div>
</routerView>
</RouterView>
</vanConfigProvider>
</template>

View File

@ -4,44 +4,35 @@
</svg>
</template>
<script lang="ts">
<script setup lang="ts">
import type { CSSProperties } from 'vue'
export default defineComponent({
name: 'SvgIcon',
props: {
prefix: {
type: String,
default: 'icon',
},
name: {
type: String,
required: true,
},
size: {
type: [Number, String],
default: 16,
},
color: {
type: String,
default: '#333',
},
},
setup(props) {
const symbolId = computed(() => `#${props.prefix}-${props.name}`)
defineOptions({ name: 'SvgIcon' })
const getStyle = computed((): CSSProperties => {
const { size } = props
let s = `${size}`
s = `${s.replace('px', '')}px`
return {
width: s,
height: s,
}
})
return { symbolId, getStyle }
const props = withDefaults(
defineProps<{
prefix?: string
name: string
size?: number | string
color?: string
}>(),
{
prefix: 'icon',
size: 16,
color: '#333',
},
)
const symbolId = computed(() => `#${props.prefix}-${props.name}`)
const getStyle = computed((): CSSProperties => {
const { size } = props
let s = `${size}`
s = `${s.replace('px', '')}px`
return {
width: s,
height: s,
}
})
</script>

View File

@ -0,0 +1,535 @@
<template>
<div class="floating-toolbar-wrap">
<nav
ref="toolbarRef"
class="floating-toolbar"
:class="{ dark: isDarkTheme }"
:style="toolbarCssVars"
aria-label="主导航"
>
<div class="ambient-glow" />
<div class="film-grain" />
<div
ref="indicatorRef"
class="active-indicator"
:style="{
transform: `translateX(${indicatorX}px)`,
opacity: activeNavIndex >= 0 ? 1 : 0,
}"
>
<div class="ring-glow" />
<div class="ring-clip">
<div class="ring-spin" />
</div>
<div class="inner-plate" />
</div>
<button
v-for="(item, idx) in navItems"
:key="item.path"
:ref="(el) => setNavRef(el, idx)"
type="button"
class="nav-btn"
:class="{
'active': idx === activeNavIndex,
'with-divider': idx < navItems.length - 1,
'nav-bounce': navBounceIndex === idx,
}"
:aria-label="item.label"
@click="handleNavClick(idx, item.path)"
>
<i :class="item.icon" />
</button>
<button
v-if="props.showDarkModeToggle"
type="button"
class="nav-btn toggle-btn"
:class="{ bounce: toggleBouncing }"
aria-label="切换主题"
@click="toggleTheme"
>
<span class="toggle-icon-wrap">
<i class="i-ph:sun-dim sun-icon" :class="{ hidden: darkModel }" />
<i class="i-ph:moon moon-icon" :class="{ show: darkModel }" />
</span>
</button>
</nav>
</div>
</template>
<script setup lang="ts">
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { useDark } from '@vueuse/core'
import { useRoute, useRouter } from 'vue-router'
import { useDesignSettingStore } from '@/store/modules/designSetting'
interface NavItem {
label: string
path: string
icon: string
}
interface Props {
items?: NavItem[]
showDarkModeToggle?: boolean
}
const props = withDefaults(defineProps<Props>(), {
items: () => [
{ label: 'Home', path: '/dashboard/index', icon: 'i-ph:house-line' },
{ label: 'Search', path: '/message/index', icon: 'i-ph:magnifying-glass' },
{ label: 'User', path: '/my/index', icon: 'i-ph:user-circle' },
],
showDarkModeToggle: true,
})
const designStore = useDesignSettingStore()
const currentRoute = useRoute()
const router = useRouter()
const navItems = computed(() => props.items)
const activeNavIndex = computed(() => {
const path = currentRoute.path
const items = navItems.value
if (items.length === 0) {
return -1
}
const index = items.findIndex((item) => {
const basePath = item.path.replace(/\/index$/, '')
return path === item.path || path.startsWith(basePath)
})
return index >= 0 ? index : 0
})
const toolbarRef = ref<HTMLElement | null>(null)
const indicatorRef = ref<HTMLElement | null>(null)
const navRefs = ref<(HTMLElement | null)[]>([])
const indicatorX = ref(0)
const isDark = useDark({
valueDark: 'dark',
valueLight: 'light',
disableTransition: false,
})
const darkModel = computed({
get: () => isDark.value || designStore.darkMode === 'dark',
set: (value: boolean) => {
isDark.value = value
designStore.setDarkMode(value ? 'dark' : 'light')
},
})
const isDarkTheme = computed(() => darkModel.value)
const toolbarColumns = computed(() => Math.max(1, navItems.value.length + (props.showDarkModeToggle ? 1 : 0)))
const toolbarCssVars = computed(() => ({
'--accent-color': designStore.appTheme,
'--accent-soft-color': `${designStore.appTheme}33`,
'gridTemplateColumns': `repeat(${toolbarColumns.value}, 1fr)`,
}))
const toggleBouncing = ref(false)
const navBounceIndex = ref<number | null>(null)
let toggleTimer: number | null = null
let navBounceTimer: number | null = null
let resizeObserver: ResizeObserver | null = null
function setNavRef(el: Element | { $el?: Element } | null, index: number) {
if (!el) {
navRefs.value[index] = null
return
}
const element = el instanceof HTMLElement
? el
: ('$el' in el ? (el.$el as HTMLElement | undefined) : undefined)
navRefs.value[index] = element ?? null
}
function updateIndicatorPosition() {
const indicator = indicatorRef.value
const target = navRefs.value[activeNavIndex.value]
if (!indicator || !target) {
return
}
const indicatorWidth = indicator.offsetWidth || 48
indicatorX.value = target.offsetLeft + target.offsetWidth / 2 - indicatorWidth / 2
}
function scheduleIndicatorUpdate() {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
updateIndicatorPosition()
})
})
}
function bindResizeObserver() {
if (typeof ResizeObserver === 'undefined') {
return
}
if (resizeObserver) {
resizeObserver.disconnect()
}
resizeObserver = new ResizeObserver(() => {
scheduleIndicatorUpdate()
})
if (toolbarRef.value) {
resizeObserver.observe(toolbarRef.value)
}
if (indicatorRef.value) {
resizeObserver.observe(indicatorRef.value)
}
for (const navEl of navRefs.value) {
if (navEl) {
resizeObserver.observe(navEl)
}
}
}
function goNav(path: string) {
router.push(path)
}
function handleNavClick(index: number, path: string) {
navBounceIndex.value = null
if (navBounceTimer) {
window.clearTimeout(navBounceTimer)
}
void nextTick(() => {
navBounceIndex.value = index
navBounceTimer = window.setTimeout(() => {
navBounceIndex.value = null
}, 420)
})
goNav(path)
}
function toggleTheme() {
if (!props.showDarkModeToggle) {
return
}
toggleBouncing.value = false
if (toggleTimer) {
window.clearTimeout(toggleTimer)
}
void nextTick(() => {
toggleBouncing.value = true
toggleTimer = window.setTimeout(() => {
toggleBouncing.value = false
}, 420)
})
darkModel.value = !darkModel.value
}
watch(
() => currentRoute.path,
async () => {
await nextTick()
bindResizeObserver()
scheduleIndicatorUpdate()
},
{ immediate: false },
)
watch(activeNavIndex, async () => {
await nextTick()
scheduleIndicatorUpdate()
})
onMounted(async () => {
await nextTick()
bindResizeObserver()
scheduleIndicatorUpdate()
window.addEventListener('resize', scheduleIndicatorUpdate)
const storeDark = designStore.darkMode === 'dark'
if (isDark.value !== storeDark) {
isDark.value = storeDark
}
})
onBeforeUnmount(() => {
if (toggleTimer) {
window.clearTimeout(toggleTimer)
}
if (navBounceTimer) {
window.clearTimeout(navBounceTimer)
}
if (resizeObserver) {
resizeObserver.disconnect()
resizeObserver = null
}
window.removeEventListener('resize', scheduleIndicatorUpdate as () => void)
})
</script>
<style scoped lang="less">
.floating-toolbar-wrap {
pointer-events: none;
position: fixed;
z-index: 20;
left: 0;
right: 0;
bottom: calc(14px + env(safe-area-inset-bottom));
display: flex;
justify-content: center;
}
.floating-toolbar {
pointer-events: auto;
position: relative;
width: min(92vw, 340px);
height: 62px;
display: grid;
grid-template-columns: repeat(4, 1fr);
align-items: center;
padding: 6px;
border-radius: 31px;
background: rgba(16, 20, 30, 0.86);
border: 1px solid rgba(255, 255, 255, 0.08);
backdrop-filter: blur(20px) saturate(140%);
box-shadow: 0 8px 28px rgba(0, 0, 0, 0.35);
overflow: hidden;
}
.floating-toolbar.dark {
background: rgba(16, 20, 30, 0.86);
border-color: rgba(255, 255, 255, 0.08);
}
.floating-toolbar:not(.dark) {
background: rgba(255, 255, 255, 0.9);
border-color: rgba(24, 39, 75, 0.12);
box-shadow: 0 6px 16px rgba(41, 58, 88, 0.08);
}
.ambient-glow {
position: absolute;
inset: -18px;
background: radial-gradient(
72% 100% at 50% 112%,
var(--accent-soft-color),
transparent 70%
);
pointer-events: none;
}
.film-grain {
position: absolute;
inset: 0;
opacity: 0.06;
pointer-events: none;
mix-blend-mode: soft-light;
background-image: radial-gradient(
circle at 22% 28%,
rgba(255, 255, 255, 0.38) 0.35px,
transparent 1px
),
radial-gradient(
circle at 78% 72%,
rgba(255, 255, 255, 0.26) 0.4px,
transparent 1px
);
background-size:
4px 4px,
5px 5px;
}
.active-indicator {
position: absolute;
left: 0;
top: 50%;
width: 70px;
height: 44px;
margin-top: -22px;
transition: transform 0.28s ease;
pointer-events: none;
}
.ring-glow {
position: absolute;
inset: 0;
border-radius: 22px;
background: var(--accent-soft-color);
opacity: 0.22;
filter: none;
box-shadow: none;
}
.ring-clip {
position: absolute;
inset: 0;
border-radius: 22px;
overflow: visible;
}
.ring-spin {
position: absolute;
inset: 0;
border-radius: 22px;
border: 1px solid var(--accent-color);
opacity: 0.35;
animation: none;
background: transparent;
}
.inner-plate {
position: absolute;
inset: 0;
border-radius: 22px;
background: transparent;
}
.floating-toolbar:not(.dark) .inner-plate {
background: rgba(255, 255, 255, 0.92);
border: 1px solid rgba(24, 39, 75, 0.1);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.8),
0 2px 8px rgba(31, 41, 55, 0.12);
}
.nav-btn {
position: relative;
z-index: 2;
width: 100%;
height: 100%;
border: none;
background: transparent;
display: grid;
place-items: center;
color: rgba(255, 255, 255, 0.45);
font-size: 22px;
cursor: pointer;
transition: color 0.25s ease;
}
.floating-toolbar:not(.dark) .nav-btn {
color: rgba(44, 59, 88, 0.72);
}
.nav-btn.active {
color: var(--accent-color);
}
.floating-toolbar:not(.dark) .nav-btn.active {
color: #1f2937;
}
.nav-btn.with-divider::after {
content: '';
position: absolute;
right: 0;
top: 15px;
width: 1px;
height: 30px;
background: linear-gradient(
180deg,
transparent,
rgba(255, 255, 255, 0.14),
transparent
);
}
.floating-toolbar:not(.dark) .nav-btn.with-divider::after {
background: linear-gradient(
180deg,
transparent,
rgba(36, 54, 88, 0.12),
transparent
);
}
.theme-switch-wrap {
position: relative;
z-index: 2;
display: grid;
place-items: center;
}
.toggle-btn {
color: rgba(255, 255, 255, 0.6);
}
.floating-toolbar:not(.dark) .toggle-btn {
color: rgba(44, 59, 88, 0.78);
}
.floating-toolbar:not(.dark) .ring-glow {
background: rgba(255, 255, 255, 0.95);
opacity: 0.75;
}
.floating-toolbar:not(.dark) .ring-spin {
border-color: rgba(24, 39, 75, 0.14);
opacity: 1;
}
.toggle-icon-wrap {
position: relative;
width: 22px;
height: 22px;
}
.sun-icon,
.moon-icon {
position: absolute;
inset: 0;
transition:
opacity 0.28s ease,
transform 0.32s ease;
}
.sun-icon.hidden {
opacity: 0;
transform: rotate(90deg) scale(0.6);
}
.moon-icon {
opacity: 0;
transform: rotate(-90deg) scale(0.6);
}
.moon-icon.show {
opacity: 1;
transform: rotate(0deg) scale(1);
}
.toggle-btn.bounce {
animation: toggle-bounce 0.42s cubic-bezier(0.34, 1.2, 0.64, 1);
}
.nav-btn.nav-bounce i {
animation: nav-icon-bounce 0.42s cubic-bezier(0.34, 1.2, 0.64, 1);
}
@keyframes toggle-bounce {
0% {
transform: scale(1);
}
35% {
transform: scale(1.25);
}
70% {
transform: scale(0.95);
}
100% {
transform: scale(1);
}
}
@keyframes nav-icon-bounce {
0% {
transform: scale(1);
}
35% {
transform: scale(1.2);
}
70% {
transform: scale(0.92);
}
100% {
transform: scale(1);
}
}
</style>

View File

@ -1,66 +1,58 @@
<!-- eslint-disable prettier/prettier -->
<template>
<div class="h-screen flex flex-col">
<van-nav-bar v-if="getShowHeader" placeholder fixed :title="getTitle" />
<routerView class="flex-1 overflow-x-hidden">
<div
class="layout-shell h-screen flex flex-col"
:class="{ dark: designStore.darkMode === 'dark' }"
>
<RouterView class="flex-1 overflow-x-hidden">
<template #default="{ Component, route }">
<!--
keep-alive 标签的 include 属性是根据组件的 name 判断的
所以 index.vue list.vue 等页面 vue 文件里一定要写上 name
并且与 router 路由表中使用的 name 属性 一致否则无效
Vue 3.3 中新引入了 defineOptions 宏声明 name 属性
https://gist.github.com/sxzz/3995fc7251567c7c95de35f45539b9c2
-->
<keep-alive v-if="keepAliveComponents" :include="keepAliveComponents">
<KeepAlive v-if="keepAliveComponents" :include="keepAliveComponents">
<component :is="Component" :key="route.fullPath" />
</keep-alive>
</KeepAlive>
<component :is="Component" v-else :key="route.fullPath" />
</template>
</routerView>
<van-tabbar route class="tabbar">
<van-tabbar-item
v-for="menu in getMenus"
:key="menu.name"
replace
:to="menu.path"
>
<template #icon>
<i :class="menu.meta?.icon" />
</template>
{{ menu.meta?.title }}
</van-tabbar-item>
</van-tabbar>
</RouterView>
<!--
<van-tabbar route>
<van-tabbar-item icon="home-o" to="/dashboard/index">
首页
</van-tabbar-item>
<van-tabbar-item icon="search" to="/message/index">
消息
</van-tabbar-item>
<van-tabbar-item icon="user-o" to="/my/index">
我的
</van-tabbar-item>
</van-tabbar>
-->
<FloatingNavBar :items="tabbarItems" :show-dark-mode-toggle="true" />
</div>
</template>
<script setup lang="ts">
import type { ComputedRef } from 'vue'
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import type { RouteRecordRaw } from 'vue-router'
import FloatingNavBar from './components/FloatingNavBar.vue'
import { useRouteStore } from '@/store/modules/route'
import { useDesignSettingStore } from '@/store/modules/designSetting'
const routeStore = useRouteStore()
//
const designStore = useDesignSettingStore()
const keepAliveComponents = computed(() => routeStore.keepAliveComponents)
const currentRoute = useRoute()
const getTitle = computed(() => currentRoute.meta.title as string)
//
const getMenus: ComputedRef<RouteRecordRaw[]> = computed(() =>
routeStore.menus.filter((item) => {
return !item.meta?.innerPage
}),
)
const getShowHeader = computed(() => !currentRoute.meta.hiddenHeader)
const tabbarItems = [
{ label: 'Home', path: '/dashboard/index', icon: 'i-ph:house-line' },
{ label: 'Search', path: '/message/index', icon: 'i-ph:magnifying-glass' },
{ label: 'User', path: '/my/index', icon: 'i-ph:user-circle' },
]
</script>
<style scoped lang="less">
.tabbar {
bottom: 0;
width: 100%;
position: relative;
.layout-shell {
background: #f7f8fa;
}
.layout-shell.dark {
background: #000000;
}
</style>

View File

@ -10,7 +10,7 @@ const routeModuleList: Array<RouteRecordRaw> = [
component: Layout,
meta: {
title: '主控台',
icon: 'i-simple-icons:atlassian',
icon: 'i-ph:house',
},
children: [
{
@ -30,7 +30,7 @@ const routeModuleList: Array<RouteRecordRaw> = [
component: Layout,
meta: {
title: '图表',
icon: 'i-simple-icons:soundcharts',
icon: 'i-ph:chart-line',
},
children: [
{
@ -50,7 +50,7 @@ const routeModuleList: Array<RouteRecordRaw> = [
component: Layout,
meta: {
title: '示例',
icon: 'i-material-symbols:award-star',
icon: 'i-ph:code',
},
children: [
{
@ -70,7 +70,7 @@ const routeModuleList: Array<RouteRecordRaw> = [
component: Layout,
meta: {
title: '我的',
icon: 'i-simple-icons:docsify',
icon: 'i-ph:user',
},
children: [
{

View File

@ -1,9 +1,9 @@
import type { App } from 'vue'
import { createPinia } from 'pinia'
import piniaPersist from 'pinia-plugin-persist'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const store = createPinia()
store.use(piniaPersist)
store.use(piniaPluginPersistedstate)
export function setupStore(app: App<Element>) {
app.use(store)

View File

@ -5,8 +5,7 @@ import type { DesignSettingState } from '@/settings/designSetting'
const { darkMode, appTheme, appThemeList, isPageAnimate, pageAnimateType } = designSetting
export const useDesignSettingStore = defineStore({
id: 'app-design-setting',
export const useDesignSettingStore = defineStore('app-design-setting', {
state: (): DesignSettingState => ({
darkMode,
appTheme,
@ -41,13 +40,8 @@ export const useDesignSettingStore = defineStore({
},
// 持久化
persist: {
enabled: true,
strategies: [
{
key: 'DESIGN-SETTING',
storage: localStorage,
},
],
key: 'DESIGN-SETTING',
storage: localStorage,
},
})

View File

@ -8,8 +8,7 @@ export interface IRouteState {
keepAliveComponents: string[]
}
export const useRouteStore = defineStore({
id: 'app-route',
export const useRouteStore = defineStore('app-route', {
state: (): IRouteState => ({
menus: [],
routers: [],

View File

@ -33,8 +33,7 @@ interface LoginParams {
password: string
}
export const useUserStore = defineStore({
id: 'app-user',
export const useUserStore = defineStore('app-user', {
state: (): IUserState => ({
userInfo: null,
token: undefined,

View File

@ -17,8 +17,8 @@ html.dark {
}
body {
background-color: #121212;
color: var(--van-text-color) !important;
background-color: #000000;
color: rgba(255, 255, 255, 0.9) !important;
}
}
@ -93,15 +93,38 @@ a:hover {
}
html.light {
body {
background-color: #f5f6fa;
}
.my-card {
backdrop-filter: blur(10px);
background: rgba(255, 255, 255, 70%);
background: rgba(255, 255, 255, 0.9);
border: 1px solid rgba(24, 39, 75, 0.1);
box-shadow: 0 4px 10px rgba(41, 58, 88, 0.05);
}
}
html.dark {
.my-card {
backdrop-filter: blur(10px);
background: rgba(30, 30, 30, 70%);
backdrop-filter: blur(12px);
background: rgba(18, 18, 18, 0.85);
border: 1px solid rgba(255, 255, 255, 0.08);
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4);
}
.van-cell-group--inset {
margin: 16px;
border-radius: 14px;
overflow: hidden;
border: 1px solid rgba(255, 255, 255, 0.08);
}
.van-cell-group--inset .van-cell {
background: rgba(18, 18, 18, 0.6);
}
.van-cell-group .van-cell::after {
border-color: rgba(255, 255, 255, 0.08);
}
}

View File

@ -1,8 +1,7 @@
<template>
<div class="h-screen flex flex-col items-center justify-center p-60px">
<div class="wel-box w-full flex flex-col items-center justify-between">
<Logo class="!h-30 !w-30" />
<div class="text-darkBlue dark:text-garyWhite mb-4 mt-12 text-center text-2xl font-black">
<div class="page-title mb-4 mt-12 text-center">
{{ title }}
</div>
<div class="mb-6 mt-4 w-full">
@ -10,12 +9,12 @@
<van-swipe-item
v-for="(text, index) in getSwipeText"
:key="index"
class="text-center text-gray-700 leading-relaxed dark:text-gray-400"
class="swipe-item text-center leading-relaxed"
>
<p class="text-lg">
<p class="swipe-title">
{{ text.title }}
</p>
<p class="text-sm">
<p class="swipe-details">
{{ text.details }}
</p>
</van-swipe-item>
@ -28,7 +27,6 @@
<script setup lang="ts">
import { useDesignSettingStore } from '@/store/modules/designSetting'
import { useGlobSetting } from '@/hooks/setting'
import Logo from '@/components/Logo.vue'
defineOptions({
name: 'DashboardPage',
@ -77,4 +75,56 @@ const getSwipeText = computed(() => {
})
</script>
<style scoped lang="less"></style>
<style scoped lang="less">
.page-title {
font-size: 1.25rem;
font-weight: 600;
letter-spacing: 0.12em;
text-transform: uppercase;
}
html.light .page-title {
color: #1a1a2e;
}
html.dark .page-title {
color: rgba(255, 255, 255, 0.95);
}
html.light .page-title::after,
html.dark .page-title::after {
content: '';
display: block;
width: 40px;
height: 2px;
margin: 8px auto 0;
background: linear-gradient(
90deg,
transparent,
v-bind('designStore.appTheme'),
transparent
);
border-radius: 1px;
}
.swipe-item {
padding: 0 8px;
}
html.light .swipe-title {
color: #333;
}
html.dark .swipe-title {
color: rgba(255, 255, 255, 0.88);
}
html.light .swipe-details {
color: #666;
}
html.dark .swipe-details {
color: rgba(255, 255, 255, 0.5);
font-size: 13px;
}
</style>

View File

@ -1,12 +1,11 @@
<template>
<div class="my-4">
<div class="example-page my-4 pb-24">
<van-cell-group inset>
<van-cell center title="🌓 暗黑模式">
<template #right-icon>
<i inline-block align-middle i="dark:carbon-moon carbon-sun" />
<span class="ml-2">{{ isDark ? 'Dark' : 'Light' }}</span>
<span class="mx-2">{{ isDark }}</span>
<van-switch v-model="checked" size="22" @click="toggle()" />
<van-switch v-model="darkSwitch" size="22" />
</template>
</van-cell>
<template v-for="item in menuItems" :key="item.route">
@ -17,7 +16,7 @@
</template>
<script setup lang="ts">
import { useDark, useToggle } from '@vueuse/core'
import { useDark } from '@vueuse/core'
import { useDesignSettingStore } from '@/store/modules/designSetting'
const designStore = useDesignSettingStore()
@ -25,16 +24,16 @@ const designStore = useDesignSettingStore()
const isDark = useDark({
valueDark: 'dark',
valueLight: 'light',
disableTransition: false,
})
const checked = ref(isDark.value)
const toggleDark = useToggle(isDark)
function toggle() {
toggleDark()
designStore.setDarkMode(isDark.value ? 'dark' : 'light')
}
const darkSwitch = computed({
get: () => isDark.value,
set: (value: boolean) => {
isDark.value = value
designStore.setDarkMode(value ? 'dark' : 'light')
},
})
const menuItems = [
{ title: '🐗 keep-alive', route: '/editNickname' },

View File

@ -1,5 +1,5 @@
<template>
<div class="my-card m-40px rounded-2xl p-30px shadow-xl">
<div class="my-card m-16px rounded-2xl p-24px">
<div ref="chartRef" :style="{ height: '350px' }" />
</div>
</template>
@ -7,11 +7,16 @@
<script setup lang="ts">
import type { EChartsOption } from 'echarts'
import { useECharts } from '@/hooks/web/useECharts'
import { useDesignSettingStore } from '@/store/modules/designSetting'
const chartRef = ref<HTMLDivElement | null>(null)
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>)
const designStore = useDesignSettingStore()
const chartColors = [designStore.appTheme, '#4a9eff', '#5dd9a8', '#ff9f7a', '#7ec8e3', '#b8a9e0']
const chartOptions: EChartsOption = {
color: chartColors,
tooltip: {
trigger: 'axis',
axisPointer: {

View File

@ -1,5 +1,8 @@
<template>
<div>
<div class="message-page pb-24">
<div class="section-title">
数据概览
</div>
<lineChart />
<barChart />
<pieChart />
@ -12,4 +15,29 @@ import barChart from './barChart.vue'
import pieChart from './pieChart.vue'
</script>
<style scoped></style>
<style scoped lang="less">
.section-title {
padding: 24px 16px 16px;
font-size: 0.7rem;
font-weight: 600;
letter-spacing: 0.15em;
text-transform: uppercase;
}
html.light .section-title {
color: #555;
}
html.dark .section-title {
color: rgba(255, 255, 255, 0.5);
}
html.dark .section-title::after {
content: '';
display: block;
width: 24px;
height: 1px;
margin-top: 6px;
background: var(--van-primary-color);
}
</style>

View File

@ -1,5 +1,5 @@
<template>
<div class="my-card m-40px rounded-2xl p-30px shadow-xl">
<div class="my-card m-16px rounded-2xl p-24px">
<div ref="chartRef" :style="{ height: '350px' }" />
</div>
</template>
@ -7,11 +7,16 @@
<script setup lang="ts">
import type { EChartsOption } from 'echarts'
import { useECharts } from '@/hooks/web/useECharts'
import { useDesignSettingStore } from '@/store/modules/designSetting'
const chartRef = ref<HTMLDivElement | null>(null)
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>)
const designStore = useDesignSettingStore()
const chartColors = [designStore.appTheme, '#4a9eff', '#5dd9a8', '#ff9f7a', '#7ec8e3']
const chartOptions: EChartsOption = {
color: chartColors,
title: {
text: 'Stacked Area Chart',
},

View File

@ -1,5 +1,5 @@
<template>
<div class="my-card m-40px rounded-2xl p-30px shadow-xl">
<div class="my-card m-16px rounded-2xl p-24px">
<div ref="chartRef" :style="{ height: '350px' }" />
</div>
</template>
@ -7,11 +7,16 @@
<script setup lang="ts">
import type { EChartsOption } from 'echarts'
import { useECharts } from '@/hooks/web/useECharts'
import { useDesignSettingStore } from '@/store/modules/designSetting'
const chartRef = ref<HTMLDivElement | null>(null)
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>)
const designStore = useDesignSettingStore()
const chartColors = [designStore.appTheme, '#4a9eff', '#5dd9a8', '#ff9f7a', '#7ec8e3', '#b8a9e0']
const chartOptions: EChartsOption = {
color: chartColors,
tooltip: {
trigger: 'item',
},

View File

@ -68,7 +68,7 @@
</template>
<script setup lang="ts">
import { useDark, useToggle } from '@vueuse/core'
import { useDark } from '@vueuse/core'
import NavBar from './components/NavBar.vue'
import { useDesignSettingStore } from '@/store/modules/designSetting'
import { animates as animateOptions } from '@/settings/animateSetting'
@ -78,15 +78,14 @@ const designStore = useDesignSettingStore()
const isDark = useDark({
valueDark: 'dark',
valueLight: 'light',
disableTransition: false,
})
const toggleDark = useToggle(isDark)
const getDarkMode = computed({
get: () => isDark.value,
set: () => {
toggleDark()
designStore.setDarkMode(isDark.value ? 'dark' : 'light')
set: (value: boolean) => {
isDark.value = value
designStore.setDarkMode(value ? 'dark' : 'light')
},
})

View File

@ -1,8 +1,8 @@
<template>
<div>
<div class="my-page">
<div :style="getUserCoverBg" class="my-bg h-70" />
<div
class="my-card relative mx-6 flex flex-col items-center rounded-2xl pb-2 shadow-xl -top-18"
class="my-card relative mx-5 flex flex-col items-center rounded-2xl pb-2 -top-18"
>
<van-image
class="h-22 w-22 border-2 border-solid !absolute -top-10"
@ -11,42 +11,42 @@
:src="avatar"
/>
<div class="mt-14 flex flex-col items-center">
<p class="mb-2 text-5 font-black">
<p class="profile-name mb-2 text-5 font-semibold">
{{ nickname }}
</p>
<p class="text-4">
<p class="profile-sign text-4">
{{ sign }}
</p>
</div>
<van-divider class="w-full" />
<van-divider class="profile-divider w-full" />
<van-cell :border="false" title="个人信息" is-link to="/editUserInfo">
<template #icon>
<i class="i-mingcute:idcard-fill mr-2 text-xl" />
<i class="i-ph:user-circle mr-2 text-xl" />
</template>
</van-cell>
<van-cell :border="false" title="账号与安全" is-link to="/accountSetting">
<template #icon>
<i class="i-material-symbols:account-box mr-2 text-xl" />
<i class="i-ph:shield-check mr-2 text-xl" />
</template>
</van-cell>
<van-cell :border="false" title="主题设置" is-link to="/themeSetting">
<template #icon>
<i class="i-material-symbols:palette mr-2 text-xl" />
<i class="i-ph:palette mr-2 text-xl" />
</template>
</van-cell>
<van-cell :border="false" title="隐私政策" is-link>
<template #icon>
<i class="i-material-symbols:list-alt-rounded mr-2 text-xl" />
<i class="i-ph:file-text mr-2 text-xl" />
</template>
</van-cell>
<van-cell :border="false" title="退出登录" is-link @click="showLogoutAction = true">
<template #icon>
<i class="i-solar:logout-3-bold mr-2 text-xl" />
<i class="i-ph:sign-out mr-2 text-xl" />
</template>
</van-cell>
@ -100,10 +100,22 @@ const getUserCoverBg = computed(() => {
width: 100%;
height: 100%;
background-image: linear-gradient(180deg, rgba(0, 0, 0, 0), #000);
opacity: 0.9;
opacity: 0.92;
}
}
html.dark .profile-name {
color: rgba(255, 255, 255, 0.95);
}
html.dark .profile-sign {
color: rgba(255, 255, 255, 0.5);
}
html.dark .profile-divider {
border-color: rgba(255, 255, 255, 0.12);
}
.van-cell {
align-items: center;
background: transparent;
@ -112,4 +124,16 @@ const getUserCoverBg = computed(() => {
background-color: var(--van-cell-active-color);
}
}
html.dark .van-cell {
color: rgba(255, 255, 255, 0.85);
}
html.dark .van-cell__right-icon {
color: rgba(255, 255, 255, 0.5);
}
html.dark .van-cell:active {
background-color: rgba(255, 255, 255, 0.08);
}
</style>

View File

@ -6,7 +6,7 @@
"useDefineForClassFields": true,
"baseUrl": ".",
"module": "ESNext",
"moduleResolution": "Node",
"moduleResolution": "bundler",
"paths": {
"@/*": ["src/*"],
"#/*": ["types/*"]

View File

@ -3,302 +3,317 @@
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
// biome-ignore lint: disable
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
const computed: typeof import('vue')['computed']
const computedAsync: typeof import('@vueuse/core')['computedAsync']
const computedEager: typeof import('@vueuse/core')['computedEager']
const computedInject: typeof import('@vueuse/core')['computedInject']
const computedWithControl: typeof import('@vueuse/core')['computedWithControl']
const controlledComputed: typeof import('@vueuse/core')['controlledComputed']
const controlledRef: typeof import('@vueuse/core')['controlledRef']
const createApp: typeof import('vue')['createApp']
const createEventHook: typeof import('@vueuse/core')['createEventHook']
const createGlobalState: typeof import('@vueuse/core')['createGlobalState']
const createInjectionState: typeof import('@vueuse/core')['createInjectionState']
const createPinia: typeof import('pinia')['createPinia']
const createReactiveFn: typeof import('@vueuse/core')['createReactiveFn']
const createReusableTemplate: typeof import('@vueuse/core')['createReusableTemplate']
const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable']
const createTemplatePromise: typeof import('@vueuse/core')['createTemplatePromise']
const createUnrefFn: typeof import('@vueuse/core')['createUnrefFn']
const customRef: typeof import('vue')['customRef']
const debouncedRef: typeof import('@vueuse/core')['debouncedRef']
const debouncedWatch: typeof import('@vueuse/core')['debouncedWatch']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const defineStore: typeof import('pinia')['defineStore']
const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
const effectScope: typeof import('vue')['effectScope']
const extendRef: typeof import('@vueuse/core')['extendRef']
const getActivePinia: typeof import('pinia')['getActivePinia']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
const inject: typeof import('vue')['inject']
const injectLocal: typeof import('@vueuse/core')['injectLocal']
const isDefined: typeof import('@vueuse/core')['isDefined']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const makeDestructurable: typeof import('@vueuse/core')['makeDestructurable']
const mapActions: typeof import('pinia')['mapActions']
const mapGetters: typeof import('pinia')['mapGetters']
const mapState: typeof import('pinia')['mapState']
const mapStores: typeof import('pinia')['mapStores']
const mapWritableState: typeof import('pinia')['mapWritableState']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onClickOutside: typeof import('@vueuse/core')['onClickOutside']
const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onKeyStroke: typeof import('@vueuse/core')['onKeyStroke']
const onLongPress: typeof import('@vueuse/core')['onLongPress']
const onMounted: typeof import('vue')['onMounted']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onStartTyping: typeof import('@vueuse/core')['onStartTyping']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
const provide: typeof import('vue')['provide']
const provideLocal: typeof import('@vueuse/core')['provideLocal']
const reactify: typeof import('@vueuse/core')['reactify']
const reactifyObject: typeof import('@vueuse/core')['reactifyObject']
const reactive: typeof import('vue')['reactive']
const reactiveComputed: typeof import('@vueuse/core')['reactiveComputed']
const reactiveOmit: typeof import('@vueuse/core')['reactiveOmit']
const reactivePick: typeof import('@vueuse/core')['reactivePick']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const refAutoReset: typeof import('@vueuse/core')['refAutoReset']
const refDebounced: typeof import('@vueuse/core')['refDebounced']
const refDefault: typeof import('@vueuse/core')['refDefault']
const refThrottled: typeof import('@vueuse/core')['refThrottled']
const refWithControl: typeof import('@vueuse/core')['refWithControl']
const resolveComponent: typeof import('vue')['resolveComponent']
const resolveRef: typeof import('@vueuse/core')['resolveRef']
const EffectScope: typeof import('vue').EffectScope
const acceptHMRUpdate: typeof import('pinia').acceptHMRUpdate
const asyncComputed: typeof import('@vueuse/core').asyncComputed
const autoResetRef: typeof import('@vueuse/core').autoResetRef
const computed: typeof import('vue').computed
const computedAsync: typeof import('@vueuse/core').computedAsync
const computedEager: typeof import('@vueuse/core').computedEager
const computedInject: typeof import('@vueuse/core').computedInject
const computedWithControl: typeof import('@vueuse/core').computedWithControl
const controlledComputed: typeof import('@vueuse/core').controlledComputed
const controlledRef: typeof import('@vueuse/core').controlledRef
const createApp: typeof import('vue').createApp
const createEventHook: typeof import('@vueuse/core').createEventHook
const createGlobalState: typeof import('@vueuse/core').createGlobalState
const createInjectionState: typeof import('@vueuse/core').createInjectionState
const createPinia: typeof import('pinia').createPinia
const createReactiveFn: typeof import('@vueuse/core').createReactiveFn
const createRef: typeof import('@vueuse/core').createRef
const createReusableTemplate: typeof import('@vueuse/core').createReusableTemplate
const createSharedComposable: typeof import('@vueuse/core').createSharedComposable
const createTemplatePromise: typeof import('@vueuse/core').createTemplatePromise
const createUnrefFn: typeof import('@vueuse/core').createUnrefFn
const customRef: typeof import('vue').customRef
const debouncedRef: typeof import('@vueuse/core').debouncedRef
const debouncedWatch: typeof import('@vueuse/core').debouncedWatch
const defineAsyncComponent: typeof import('vue').defineAsyncComponent
const defineComponent: typeof import('vue').defineComponent
const defineStore: typeof import('pinia').defineStore
const eagerComputed: typeof import('@vueuse/core').eagerComputed
const effectScope: typeof import('vue').effectScope
const extendRef: typeof import('@vueuse/core').extendRef
const getActivePinia: typeof import('pinia').getActivePinia
const getCurrentInstance: typeof import('vue').getCurrentInstance
const getCurrentScope: typeof import('vue').getCurrentScope
const getCurrentWatcher: typeof import('vue').getCurrentWatcher
const h: typeof import('vue').h
const ignorableWatch: typeof import('@vueuse/core').ignorableWatch
const inject: typeof import('vue').inject
const injectLocal: typeof import('@vueuse/core').injectLocal
const isDefined: typeof import('@vueuse/core').isDefined
const isProxy: typeof import('vue').isProxy
const isReactive: typeof import('vue').isReactive
const isReadonly: typeof import('vue').isReadonly
const isRef: typeof import('vue').isRef
const isShallow: typeof import('vue').isShallow
const makeDestructurable: typeof import('@vueuse/core').makeDestructurable
const mapActions: typeof import('pinia').mapActions
const mapGetters: typeof import('pinia').mapGetters
const mapState: typeof import('pinia').mapState
const mapStores: typeof import('pinia').mapStores
const mapWritableState: typeof import('pinia').mapWritableState
const markRaw: typeof import('vue').markRaw
const nextTick: typeof import('vue').nextTick
const onActivated: typeof import('vue').onActivated
const onBeforeMount: typeof import('vue').onBeforeMount
const onBeforeRouteLeave: typeof import('vue-router').onBeforeRouteLeave
const onBeforeRouteUpdate: typeof import('vue-router').onBeforeRouteUpdate
const onBeforeUnmount: typeof import('vue').onBeforeUnmount
const onBeforeUpdate: typeof import('vue').onBeforeUpdate
const onClickOutside: typeof import('@vueuse/core').onClickOutside
const onDeactivated: typeof import('vue').onDeactivated
const onElementRemoval: typeof import('@vueuse/core').onElementRemoval
const onErrorCaptured: typeof import('vue').onErrorCaptured
const onKeyStroke: typeof import('@vueuse/core').onKeyStroke
const onLongPress: typeof import('@vueuse/core').onLongPress
const onMounted: typeof import('vue').onMounted
const onRenderTracked: typeof import('vue').onRenderTracked
const onRenderTriggered: typeof import('vue').onRenderTriggered
const onScopeDispose: typeof import('vue').onScopeDispose
const onServerPrefetch: typeof import('vue').onServerPrefetch
const onStartTyping: typeof import('@vueuse/core').onStartTyping
const onUnmounted: typeof import('vue').onUnmounted
const onUpdated: typeof import('vue').onUpdated
const onWatcherCleanup: typeof import('vue').onWatcherCleanup
const pausableWatch: typeof import('@vueuse/core').pausableWatch
const provide: typeof import('vue').provide
const provideLocal: typeof import('@vueuse/core').provideLocal
const reactify: typeof import('@vueuse/core').reactify
const reactifyObject: typeof import('@vueuse/core').reactifyObject
const reactive: typeof import('vue').reactive
const reactiveComputed: typeof import('@vueuse/core').reactiveComputed
const reactiveOmit: typeof import('@vueuse/core').reactiveOmit
const reactivePick: typeof import('@vueuse/core').reactivePick
const readonly: typeof import('vue').readonly
const ref: typeof import('vue').ref
const refAutoReset: typeof import('@vueuse/core').refAutoReset
const refDebounced: typeof import('@vueuse/core').refDebounced
const refDefault: typeof import('@vueuse/core').refDefault
const refManualReset: typeof import('@vueuse/core').refManualReset
const refThrottled: typeof import('@vueuse/core').refThrottled
const refWithControl: typeof import('@vueuse/core').refWithControl
const resolveComponent: typeof import('vue').resolveComponent
const resolveRef: typeof import('@vueuse/core').resolveRef
const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
const setActivePinia: typeof import('pinia')['setActivePinia']
const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const storeToRefs: typeof import('pinia')['storeToRefs']
const syncRef: typeof import('@vueuse/core')['syncRef']
const syncRefs: typeof import('@vueuse/core')['syncRefs']
const templateRef: typeof import('@vueuse/core')['templateRef']
const throttledRef: typeof import('@vueuse/core')['throttledRef']
const throttledWatch: typeof import('@vueuse/core')['throttledWatch']
const toRaw: typeof import('vue')['toRaw']
const toReactive: typeof import('@vueuse/core')['toReactive']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const toValue: typeof import('vue')['toValue']
const triggerRef: typeof import('vue')['triggerRef']
const tryOnBeforeMount: typeof import('@vueuse/core')['tryOnBeforeMount']
const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount']
const tryOnMounted: typeof import('@vueuse/core')['tryOnMounted']
const tryOnScopeDispose: typeof import('@vueuse/core')['tryOnScopeDispose']
const tryOnUnmounted: typeof import('@vueuse/core')['tryOnUnmounted']
const unref: typeof import('vue')['unref']
const unrefElement: typeof import('@vueuse/core')['unrefElement']
const until: typeof import('@vueuse/core')['until']
const useActiveElement: typeof import('@vueuse/core')['useActiveElement']
const useAnimate: typeof import('@vueuse/core')['useAnimate']
const useArrayDifference: typeof import('@vueuse/core')['useArrayDifference']
const useArrayEvery: typeof import('@vueuse/core')['useArrayEvery']
const useArrayFilter: typeof import('@vueuse/core')['useArrayFilter']
const useArrayFind: typeof import('@vueuse/core')['useArrayFind']
const useArrayFindIndex: typeof import('@vueuse/core')['useArrayFindIndex']
const useArrayFindLast: typeof import('@vueuse/core')['useArrayFindLast']
const useArrayIncludes: typeof import('@vueuse/core')['useArrayIncludes']
const useArrayJoin: typeof import('@vueuse/core')['useArrayJoin']
const useArrayMap: typeof import('@vueuse/core')['useArrayMap']
const useArrayReduce: typeof import('@vueuse/core')['useArrayReduce']
const useArraySome: typeof import('@vueuse/core')['useArraySome']
const useArrayUnique: typeof import('@vueuse/core')['useArrayUnique']
const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue']
const useAsyncState: typeof import('@vueuse/core')['useAsyncState']
const useAttrs: typeof import('vue')['useAttrs']
const useBase64: typeof import('@vueuse/core')['useBase64']
const useBattery: typeof import('@vueuse/core')['useBattery']
const useBluetooth: typeof import('@vueuse/core')['useBluetooth']
const useBreakpoints: typeof import('@vueuse/core')['useBreakpoints']
const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel']
const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation']
const useCached: typeof import('@vueuse/core')['useCached']
const useClipboard: typeof import('@vueuse/core')['useClipboard']
const useClipboardItems: typeof import('@vueuse/core')['useClipboardItems']
const useCloned: typeof import('@vueuse/core')['useCloned']
const useColorMode: typeof import('@vueuse/core')['useColorMode']
const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog']
const useCounter: typeof import('@vueuse/core')['useCounter']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVar: typeof import('@vueuse/core')['useCssVar']
const useCssVars: typeof import('vue')['useCssVars']
const useCurrentElement: typeof import('@vueuse/core')['useCurrentElement']
const useCycleList: typeof import('@vueuse/core')['useCycleList']
const useDark: typeof import('@vueuse/core')['useDark']
const useDateFormat: typeof import('@vueuse/core')['useDateFormat']
const useDebounce: typeof import('@vueuse/core')['useDebounce']
const useDebounceFn: typeof import('@vueuse/core')['useDebounceFn']
const useDebouncedRefHistory: typeof import('@vueuse/core')['useDebouncedRefHistory']
const useDeviceMotion: typeof import('@vueuse/core')['useDeviceMotion']
const useDeviceOrientation: typeof import('@vueuse/core')['useDeviceOrientation']
const useDevicePixelRatio: typeof import('@vueuse/core')['useDevicePixelRatio']
const useDevicesList: typeof import('@vueuse/core')['useDevicesList']
const useDisplayMedia: typeof import('@vueuse/core')['useDisplayMedia']
const useDocumentVisibility: typeof import('@vueuse/core')['useDocumentVisibility']
const useDraggable: typeof import('@vueuse/core')['useDraggable']
const useDropZone: typeof import('@vueuse/core')['useDropZone']
const useElementBounding: typeof import('@vueuse/core')['useElementBounding']
const useElementByPoint: typeof import('@vueuse/core')['useElementByPoint']
const useElementHover: typeof import('@vueuse/core')['useElementHover']
const useElementSize: typeof import('@vueuse/core')['useElementSize']
const useElementVisibility: typeof import('@vueuse/core')['useElementVisibility']
const useEventBus: typeof import('@vueuse/core')['useEventBus']
const useEventListener: typeof import('@vueuse/core')['useEventListener']
const useEventSource: typeof import('@vueuse/core')['useEventSource']
const useEyeDropper: typeof import('@vueuse/core')['useEyeDropper']
const useFavicon: typeof import('@vueuse/core')['useFavicon']
const useFetch: typeof import('@vueuse/core')['useFetch']
const useFileDialog: typeof import('@vueuse/core')['useFileDialog']
const useFileSystemAccess: typeof import('@vueuse/core')['useFileSystemAccess']
const useFocus: typeof import('@vueuse/core')['useFocus']
const useFocusWithin: typeof import('@vueuse/core')['useFocusWithin']
const useFps: typeof import('@vueuse/core')['useFps']
const useFullscreen: typeof import('@vueuse/core')['useFullscreen']
const useGamepad: typeof import('@vueuse/core')['useGamepad']
const useGeolocation: typeof import('@vueuse/core')['useGeolocation']
const useIdle: typeof import('@vueuse/core')['useIdle']
const useImage: typeof import('@vueuse/core')['useImage']
const useInfiniteScroll: typeof import('@vueuse/core')['useInfiniteScroll']
const useIntersectionObserver: typeof import('@vueuse/core')['useIntersectionObserver']
const useInterval: typeof import('@vueuse/core')['useInterval']
const useIntervalFn: typeof import('@vueuse/core')['useIntervalFn']
const useKeyModifier: typeof import('@vueuse/core')['useKeyModifier']
const useLastChanged: typeof import('@vueuse/core')['useLastChanged']
const useLink: typeof import('vue-router')['useLink']
const useLocalStorage: typeof import('@vueuse/core')['useLocalStorage']
const useMagicKeys: typeof import('@vueuse/core')['useMagicKeys']
const useManualRefHistory: typeof import('@vueuse/core')['useManualRefHistory']
const useMediaControls: typeof import('@vueuse/core')['useMediaControls']
const useMediaQuery: typeof import('@vueuse/core')['useMediaQuery']
const useMemoize: typeof import('@vueuse/core')['useMemoize']
const useMemory: typeof import('@vueuse/core')['useMemory']
const useMounted: typeof import('@vueuse/core')['useMounted']
const useMouse: typeof import('@vueuse/core')['useMouse']
const useMouseInElement: typeof import('@vueuse/core')['useMouseInElement']
const useMousePressed: typeof import('@vueuse/core')['useMousePressed']
const useMutationObserver: typeof import('@vueuse/core')['useMutationObserver']
const useNavigatorLanguage: typeof import('@vueuse/core')['useNavigatorLanguage']
const useNetwork: typeof import('@vueuse/core')['useNetwork']
const useNow: typeof import('@vueuse/core')['useNow']
const useObjectUrl: typeof import('@vueuse/core')['useObjectUrl']
const useOffsetPagination: typeof import('@vueuse/core')['useOffsetPagination']
const useOnline: typeof import('@vueuse/core')['useOnline']
const usePageLeave: typeof import('@vueuse/core')['usePageLeave']
const useParallax: typeof import('@vueuse/core')['useParallax']
const useParentElement: typeof import('@vueuse/core')['useParentElement']
const usePerformanceObserver: typeof import('@vueuse/core')['usePerformanceObserver']
const usePermission: typeof import('@vueuse/core')['usePermission']
const usePointer: typeof import('@vueuse/core')['usePointer']
const usePointerLock: typeof import('@vueuse/core')['usePointerLock']
const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe']
const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme']
const usePreferredContrast: typeof import('@vueuse/core')['usePreferredContrast']
const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark']
const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages']
const usePreferredReducedMotion: typeof import('@vueuse/core')['usePreferredReducedMotion']
const usePrevious: typeof import('@vueuse/core')['usePrevious']
const useRafFn: typeof import('@vueuse/core')['useRafFn']
const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter']
const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation']
const useScreenSafeArea: typeof import('@vueuse/core')['useScreenSafeArea']
const useScriptTag: typeof import('@vueuse/core')['useScriptTag']
const useScroll: typeof import('@vueuse/core')['useScroll']
const useScrollLock: typeof import('@vueuse/core')['useScrollLock']
const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage']
const useShare: typeof import('@vueuse/core')['useShare']
const useSlots: typeof import('vue')['useSlots']
const useSorted: typeof import('@vueuse/core')['useSorted']
const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition']
const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis']
const useStepper: typeof import('@vueuse/core')['useStepper']
const useStorage: typeof import('@vueuse/core')['useStorage']
const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync']
const useStyleTag: typeof import('@vueuse/core')['useStyleTag']
const useSupported: typeof import('@vueuse/core')['useSupported']
const useSwipe: typeof import('@vueuse/core')['useSwipe']
const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList']
const useTextDirection: typeof import('@vueuse/core')['useTextDirection']
const useTextSelection: typeof import('@vueuse/core')['useTextSelection']
const useTextareaAutosize: typeof import('@vueuse/core')['useTextareaAutosize']
const useThrottle: typeof import('@vueuse/core')['useThrottle']
const useThrottleFn: typeof import('@vueuse/core')['useThrottleFn']
const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory']
const useTimeAgo: typeof import('@vueuse/core')['useTimeAgo']
const useTimeout: typeof import('@vueuse/core')['useTimeout']
const useTimeoutFn: typeof import('@vueuse/core')['useTimeoutFn']
const useTimeoutPoll: typeof import('@vueuse/core')['useTimeoutPoll']
const useTimestamp: typeof import('@vueuse/core')['useTimestamp']
const useTitle: typeof import('@vueuse/core')['useTitle']
const useToNumber: typeof import('@vueuse/core')['useToNumber']
const useToString: typeof import('@vueuse/core')['useToString']
const useToggle: typeof import('@vueuse/core')['useToggle']
const useTransition: typeof import('@vueuse/core')['useTransition']
const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams']
const useUserMedia: typeof import('@vueuse/core')['useUserMedia']
const useVModel: typeof import('@vueuse/core')['useVModel']
const useVModels: typeof import('@vueuse/core')['useVModels']
const useVibrate: typeof import('@vueuse/core')['useVibrate']
const useVirtualList: typeof import('@vueuse/core')['useVirtualList']
const useWakeLock: typeof import('@vueuse/core')['useWakeLock']
const useWebNotification: typeof import('@vueuse/core')['useWebNotification']
const useWebSocket: typeof import('@vueuse/core')['useWebSocket']
const useWebWorker: typeof import('@vueuse/core')['useWebWorker']
const useWebWorkerFn: typeof import('@vueuse/core')['useWebWorkerFn']
const useWindowFocus: typeof import('@vueuse/core')['useWindowFocus']
const useWindowScroll: typeof import('@vueuse/core')['useWindowScroll']
const useWindowSize: typeof import('@vueuse/core')['useWindowSize']
const watch: typeof import('vue')['watch']
const watchArray: typeof import('@vueuse/core')['watchArray']
const watchAtMost: typeof import('@vueuse/core')['watchAtMost']
const watchDebounced: typeof import('@vueuse/core')['watchDebounced']
const watchDeep: typeof import('@vueuse/core')['watchDeep']
const watchEffect: typeof import('vue')['watchEffect']
const watchIgnorable: typeof import('@vueuse/core')['watchIgnorable']
const watchImmediate: typeof import('@vueuse/core')['watchImmediate']
const watchOnce: typeof import('@vueuse/core')['watchOnce']
const watchPausable: typeof import('@vueuse/core')['watchPausable']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
const watchThrottled: typeof import('@vueuse/core')['watchThrottled']
const watchTriggerable: typeof import('@vueuse/core')['watchTriggerable']
const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter']
const whenever: typeof import('@vueuse/core')['whenever']
const setActivePinia: typeof import('pinia').setActivePinia
const setMapStoreSuffix: typeof import('pinia').setMapStoreSuffix
const shallowReactive: typeof import('vue').shallowReactive
const shallowReadonly: typeof import('vue').shallowReadonly
const shallowRef: typeof import('vue').shallowRef
const storeToRefs: typeof import('pinia').storeToRefs
const syncRef: typeof import('@vueuse/core').syncRef
const syncRefs: typeof import('@vueuse/core').syncRefs
const templateRef: typeof import('@vueuse/core').templateRef
const throttledRef: typeof import('@vueuse/core').throttledRef
const throttledWatch: typeof import('@vueuse/core').throttledWatch
const toRaw: typeof import('vue').toRaw
const toReactive: typeof import('@vueuse/core').toReactive
const toRef: typeof import('vue').toRef
const toRefs: typeof import('vue').toRefs
const toValue: typeof import('vue').toValue
const triggerRef: typeof import('vue').triggerRef
const tryOnBeforeMount: typeof import('@vueuse/core').tryOnBeforeMount
const tryOnBeforeUnmount: typeof import('@vueuse/core').tryOnBeforeUnmount
const tryOnMounted: typeof import('@vueuse/core').tryOnMounted
const tryOnScopeDispose: typeof import('@vueuse/core').tryOnScopeDispose
const tryOnUnmounted: typeof import('@vueuse/core').tryOnUnmounted
const unref: typeof import('vue').unref
const unrefElement: typeof import('@vueuse/core').unrefElement
const until: typeof import('@vueuse/core').until
const useActiveElement: typeof import('@vueuse/core').useActiveElement
const useAnimate: typeof import('@vueuse/core').useAnimate
const useArrayDifference: typeof import('@vueuse/core').useArrayDifference
const useArrayEvery: typeof import('@vueuse/core').useArrayEvery
const useArrayFilter: typeof import('@vueuse/core').useArrayFilter
const useArrayFind: typeof import('@vueuse/core').useArrayFind
const useArrayFindIndex: typeof import('@vueuse/core').useArrayFindIndex
const useArrayFindLast: typeof import('@vueuse/core').useArrayFindLast
const useArrayIncludes: typeof import('@vueuse/core').useArrayIncludes
const useArrayJoin: typeof import('@vueuse/core').useArrayJoin
const useArrayMap: typeof import('@vueuse/core').useArrayMap
const useArrayReduce: typeof import('@vueuse/core').useArrayReduce
const useArraySome: typeof import('@vueuse/core').useArraySome
const useArrayUnique: typeof import('@vueuse/core').useArrayUnique
const useAsyncQueue: typeof import('@vueuse/core').useAsyncQueue
const useAsyncState: typeof import('@vueuse/core').useAsyncState
const useAttrs: typeof import('vue').useAttrs
const useBase64: typeof import('@vueuse/core').useBase64
const useBattery: typeof import('@vueuse/core').useBattery
const useBluetooth: typeof import('@vueuse/core').useBluetooth
const useBreakpoints: typeof import('@vueuse/core').useBreakpoints
const useBroadcastChannel: typeof import('@vueuse/core').useBroadcastChannel
const useBrowserLocation: typeof import('@vueuse/core').useBrowserLocation
const useCached: typeof import('@vueuse/core').useCached
const useClipboard: typeof import('@vueuse/core').useClipboard
const useClipboardItems: typeof import('@vueuse/core').useClipboardItems
const useCloned: typeof import('@vueuse/core').useCloned
const useColorMode: typeof import('@vueuse/core').useColorMode
const useConfirmDialog: typeof import('@vueuse/core').useConfirmDialog
const useCountdown: typeof import('@vueuse/core').useCountdown
const useCounter: typeof import('@vueuse/core').useCounter
const useCssModule: typeof import('vue').useCssModule
const useCssSupports: typeof import('@vueuse/core').useCssSupports
const useCssVar: typeof import('@vueuse/core').useCssVar
const useCssVars: typeof import('vue').useCssVars
const useCurrentElement: typeof import('@vueuse/core').useCurrentElement
const useCycleList: typeof import('@vueuse/core').useCycleList
const useDark: typeof import('@vueuse/core').useDark
const useDateFormat: typeof import('@vueuse/core').useDateFormat
const useDebounce: typeof import('@vueuse/core').useDebounce
const useDebounceFn: typeof import('@vueuse/core').useDebounceFn
const useDebouncedRefHistory: typeof import('@vueuse/core').useDebouncedRefHistory
const useDeviceMotion: typeof import('@vueuse/core').useDeviceMotion
const useDeviceOrientation: typeof import('@vueuse/core').useDeviceOrientation
const useDevicePixelRatio: typeof import('@vueuse/core').useDevicePixelRatio
const useDevicesList: typeof import('@vueuse/core').useDevicesList
const useDisplayMedia: typeof import('@vueuse/core').useDisplayMedia
const useDocumentVisibility: typeof import('@vueuse/core').useDocumentVisibility
const useDraggable: typeof import('@vueuse/core').useDraggable
const useDropZone: typeof import('@vueuse/core').useDropZone
const useElementBounding: typeof import('@vueuse/core').useElementBounding
const useElementByPoint: typeof import('@vueuse/core').useElementByPoint
const useElementHover: typeof import('@vueuse/core').useElementHover
const useElementSize: typeof import('@vueuse/core').useElementSize
const useElementVisibility: typeof import('@vueuse/core').useElementVisibility
const useEventBus: typeof import('@vueuse/core').useEventBus
const useEventListener: typeof import('@vueuse/core').useEventListener
const useEventSource: typeof import('@vueuse/core').useEventSource
const useEyeDropper: typeof import('@vueuse/core').useEyeDropper
const useFavicon: typeof import('@vueuse/core').useFavicon
const useFetch: typeof import('@vueuse/core').useFetch
const useFileDialog: typeof import('@vueuse/core').useFileDialog
const useFileSystemAccess: typeof import('@vueuse/core').useFileSystemAccess
const useFocus: typeof import('@vueuse/core').useFocus
const useFocusWithin: typeof import('@vueuse/core').useFocusWithin
const useFps: typeof import('@vueuse/core').useFps
const useFullscreen: typeof import('@vueuse/core').useFullscreen
const useGamepad: typeof import('@vueuse/core').useGamepad
const useGeolocation: typeof import('@vueuse/core').useGeolocation
const useId: typeof import('vue').useId
const useIdle: typeof import('@vueuse/core').useIdle
const useImage: typeof import('@vueuse/core').useImage
const useInfiniteScroll: typeof import('@vueuse/core').useInfiniteScroll
const useIntersectionObserver: typeof import('@vueuse/core').useIntersectionObserver
const useInterval: typeof import('@vueuse/core').useInterval
const useIntervalFn: typeof import('@vueuse/core').useIntervalFn
const useKeyModifier: typeof import('@vueuse/core').useKeyModifier
const useLastChanged: typeof import('@vueuse/core').useLastChanged
const useLink: typeof import('vue-router').useLink
const useLocalStorage: typeof import('@vueuse/core').useLocalStorage
const useMagicKeys: typeof import('@vueuse/core').useMagicKeys
const useManualRefHistory: typeof import('@vueuse/core').useManualRefHistory
const useMediaControls: typeof import('@vueuse/core').useMediaControls
const useMediaQuery: typeof import('@vueuse/core').useMediaQuery
const useMemoize: typeof import('@vueuse/core').useMemoize
const useMemory: typeof import('@vueuse/core').useMemory
const useModel: typeof import('vue').useModel
const useMounted: typeof import('@vueuse/core').useMounted
const useMouse: typeof import('@vueuse/core').useMouse
const useMouseInElement: typeof import('@vueuse/core').useMouseInElement
const useMousePressed: typeof import('@vueuse/core').useMousePressed
const useMutationObserver: typeof import('@vueuse/core').useMutationObserver
const useNavigatorLanguage: typeof import('@vueuse/core').useNavigatorLanguage
const useNetwork: typeof import('@vueuse/core').useNetwork
const useNow: typeof import('@vueuse/core').useNow
const useObjectUrl: typeof import('@vueuse/core').useObjectUrl
const useOffsetPagination: typeof import('@vueuse/core').useOffsetPagination
const useOnline: typeof import('@vueuse/core').useOnline
const usePageLeave: typeof import('@vueuse/core').usePageLeave
const useParallax: typeof import('@vueuse/core').useParallax
const useParentElement: typeof import('@vueuse/core').useParentElement
const usePerformanceObserver: typeof import('@vueuse/core').usePerformanceObserver
const usePermission: typeof import('@vueuse/core').usePermission
const usePointer: typeof import('@vueuse/core').usePointer
const usePointerLock: typeof import('@vueuse/core').usePointerLock
const usePointerSwipe: typeof import('@vueuse/core').usePointerSwipe
const usePreferredColorScheme: typeof import('@vueuse/core').usePreferredColorScheme
const usePreferredContrast: typeof import('@vueuse/core').usePreferredContrast
const usePreferredDark: typeof import('@vueuse/core').usePreferredDark
const usePreferredLanguages: typeof import('@vueuse/core').usePreferredLanguages
const usePreferredReducedMotion: typeof import('@vueuse/core').usePreferredReducedMotion
const usePreferredReducedTransparency: typeof import('@vueuse/core').usePreferredReducedTransparency
const usePrevious: typeof import('@vueuse/core').usePrevious
const useRafFn: typeof import('@vueuse/core').useRafFn
const useRefHistory: typeof import('@vueuse/core').useRefHistory
const useResizeObserver: typeof import('@vueuse/core').useResizeObserver
const useRoute: typeof import('vue-router').useRoute
const useRouter: typeof import('vue-router').useRouter
const useSSRWidth: typeof import('@vueuse/core').useSSRWidth
const useScreenOrientation: typeof import('@vueuse/core').useScreenOrientation
const useScreenSafeArea: typeof import('@vueuse/core').useScreenSafeArea
const useScriptTag: typeof import('@vueuse/core').useScriptTag
const useScroll: typeof import('@vueuse/core').useScroll
const useScrollLock: typeof import('@vueuse/core').useScrollLock
const useSessionStorage: typeof import('@vueuse/core').useSessionStorage
const useShare: typeof import('@vueuse/core').useShare
const useSlots: typeof import('vue').useSlots
const useSorted: typeof import('@vueuse/core').useSorted
const useSpeechRecognition: typeof import('@vueuse/core').useSpeechRecognition
const useSpeechSynthesis: typeof import('@vueuse/core').useSpeechSynthesis
const useStepper: typeof import('@vueuse/core').useStepper
const useStorage: typeof import('@vueuse/core').useStorage
const useStorageAsync: typeof import('@vueuse/core').useStorageAsync
const useStyleTag: typeof import('@vueuse/core').useStyleTag
const useSupported: typeof import('@vueuse/core').useSupported
const useSwipe: typeof import('@vueuse/core').useSwipe
const useTemplateRef: typeof import('vue').useTemplateRef
const useTemplateRefsList: typeof import('@vueuse/core').useTemplateRefsList
const useTextDirection: typeof import('@vueuse/core').useTextDirection
const useTextSelection: typeof import('@vueuse/core').useTextSelection
const useTextareaAutosize: typeof import('@vueuse/core').useTextareaAutosize
const useThrottle: typeof import('@vueuse/core').useThrottle
const useThrottleFn: typeof import('@vueuse/core').useThrottleFn
const useThrottledRefHistory: typeof import('@vueuse/core').useThrottledRefHistory
const useTimeAgo: typeof import('@vueuse/core').useTimeAgo
const useTimeAgoIntl: typeof import('@vueuse/core').useTimeAgoIntl
const useTimeout: typeof import('@vueuse/core').useTimeout
const useTimeoutFn: typeof import('@vueuse/core').useTimeoutFn
const useTimeoutPoll: typeof import('@vueuse/core').useTimeoutPoll
const useTimestamp: typeof import('@vueuse/core').useTimestamp
const useTitle: typeof import('@vueuse/core').useTitle
const useToNumber: typeof import('@vueuse/core').useToNumber
const useToString: typeof import('@vueuse/core').useToString
const useToggle: typeof import('@vueuse/core').useToggle
const useTransition: typeof import('@vueuse/core').useTransition
const useUrlSearchParams: typeof import('@vueuse/core').useUrlSearchParams
const useUserMedia: typeof import('@vueuse/core').useUserMedia
const useVModel: typeof import('@vueuse/core').useVModel
const useVModels: typeof import('@vueuse/core').useVModels
const useVibrate: typeof import('@vueuse/core').useVibrate
const useVirtualList: typeof import('@vueuse/core').useVirtualList
const useWakeLock: typeof import('@vueuse/core').useWakeLock
const useWebNotification: typeof import('@vueuse/core').useWebNotification
const useWebSocket: typeof import('@vueuse/core').useWebSocket
const useWebWorker: typeof import('@vueuse/core').useWebWorker
const useWebWorkerFn: typeof import('@vueuse/core').useWebWorkerFn
const useWindowFocus: typeof import('@vueuse/core').useWindowFocus
const useWindowScroll: typeof import('@vueuse/core').useWindowScroll
const useWindowSize: typeof import('@vueuse/core').useWindowSize
const watch: typeof import('vue').watch
const watchArray: typeof import('@vueuse/core').watchArray
const watchAtMost: typeof import('@vueuse/core').watchAtMost
const watchDebounced: typeof import('@vueuse/core').watchDebounced
const watchDeep: typeof import('@vueuse/core').watchDeep
const watchEffect: typeof import('vue').watchEffect
const watchIgnorable: typeof import('@vueuse/core').watchIgnorable
const watchImmediate: typeof import('@vueuse/core').watchImmediate
const watchOnce: typeof import('@vueuse/core').watchOnce
const watchPausable: typeof import('@vueuse/core').watchPausable
const watchPostEffect: typeof import('vue').watchPostEffect
const watchSyncEffect: typeof import('vue').watchSyncEffect
const watchThrottled: typeof import('@vueuse/core').watchThrottled
const watchTriggerable: typeof import('@vueuse/core').watchTriggerable
const watchWithFilter: typeof import('@vueuse/core').watchWithFilter
const whenever: typeof import('@vueuse/core').whenever
}
// for type re-export
declare global {
// @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, ShallowRef, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
import('vue')
}

View File

@ -75,9 +75,9 @@ export default defineConfig({
// 因此无法生成对应的 CSS。为了解决这个问题你可以使用 UnoCSS 的 safelist 选项来指定一些始终需要生成的 CSS 类。
// https://unocss.dev/guide/advanced#safelist
safelist: [
'i-simple-icons:atlassian',
'i-simple-icons:soundcharts',
'i-simple-icons:docsify',
'i-material-symbols:award-star',
'i-ph:house',
'i-ph:chart-line',
'i-ph:code',
'i-ph:user',
],
})

View File

@ -69,16 +69,17 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
__APP_INFO__: JSON.stringify(__APP_INFO__),
},
esbuild: {
// 使用 esbuild 压缩 剔除 console.log
drop: VITE_DROP_CONSOLE ? ['debugger', 'console'] : [],
// minify: true, // minify: true, 等于 minify: 'esbuild',
},
build: {
// 设置最终构建的浏览器兼容目标
target: 'es2015',
minify: 'esbuild',
// Vite 8 的 oxc 不支持 drop 选项,按需切换到 terser 去除 console/debugger
minify: VITE_DROP_CONSOLE ? 'terser' : 'oxc',
terserOptions: {
compress: {
drop_console: VITE_DROP_CONSOLE,
drop_debugger: VITE_DROP_CONSOLE,
},
},
// 构建后是否生成 source map 文件(用于线上报错代码报错映射对应代码)
sourcemap: false,
cssTarget: 'chrome80',
@ -98,8 +99,8 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
reportCompressedSize: true,
// chunk 大小警告的限制(以 kbs 为单位)
chunkSizeWarningLimit: 2000,
// 自定义底层的 Rollup 打包配置
rollupOptions: {
// 自定义底层的 Rolldown 打包配置
rolldownOptions: {
// 静态资源分类打包
output: {
chunkFileNames: 'js/[name]-[hash].js', // 引入文件名的名称