mirror of
https://github.com/xiangshu233/vue3-vant4-mobile.git
synced 2026-04-29 23:23:15 +08:00
Compare commits
5 Commits
6e776c52e2
...
b47617226e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b47617226e | ||
|
|
b01e46b64f | ||
|
|
1019242a0c | ||
|
|
23e3c9d369 | ||
|
|
fbc12f02f9 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -23,4 +23,5 @@ dist-ssr
|
|||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
/components.d.ts
|
/components.d.ts
|
||||||
/components.d.ts
|
.agents/
|
||||||
|
skills-lock.json
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
## 介绍
|
## 介绍
|
||||||
|
|
||||||
👋👋👋 Vue3 Vant4 Mobile 使用了最新的 `Vue3.4`、`Vite5`、`Vant4`、`Pinia`、`TypeScript`、`UnoCSS` 等主流技术开发,集成 `Dark Mode`(暗黑)模式和系统主题色,并且持久化保存,集成 `Mock` 数据,顺便写了登录/注册/找回密码 页面(包括逻辑),只需替换你的 API 即可,另外页面均可以 `<keep-alive>`,随便写了个包含 `NavBar`、`TabBar` 的 Layout,集成了 `Axios`、`useECharts`、`IconSvg`。
|
👋👋👋 Vue3 Vant4 Mobile 使用了最新的 `Vue3.5`、`Vite8`、`Vant4`、`Pinia`、`TypeScript`、`UnoCSS` 等主流技术开发,集成 `Dark Mode`(暗黑)模式和系统主题色,并且持久化保存,集成 `Mock` 数据,顺便写了登录/注册/找回密码 页面(包括逻辑),只需替换你的 API 即可,另外页面均可以 `<keep-alive>`,随便写了个包含 `NavBar`、`TabBar` 的 Layout,集成了 `Axios`、`useECharts`、`IconSvg`。
|
||||||
|
|
||||||
项目使用了 [antfu](https://github.com/antfu) 大佬的 [antfu/eslint-config](https://github.com/antfu/eslint-config) 作为代码规范检查工具,摆脱繁琐无聊的 Eslint 配置,配合 `cz-git`、 `lint-staged`、`simple-git-hooks`可对暂存区代码提交校验,代码风格不合格可打断提交,保证多人协作开发时上游 Git 库的干净。
|
项目使用了 [antfu](https://github.com/antfu) 大佬的 [antfu/eslint-config](https://github.com/antfu/eslint-config) 作为代码规范检查工具,摆脱繁琐无聊的 Eslint 配置,配合 `cz-git`、 `lint-staged`、`simple-git-hooks`可对暂存区代码提交校验,代码风格不合格可打断提交,保证多人协作开发时上游 Git 库的干净。
|
||||||
|
|
||||||
|
|||||||
48
package.json
48
package.json
@ -18,7 +18,7 @@
|
|||||||
"url": "https://github.com/xiangshu233/vue3-vant4-mobile/issues"
|
"url": "https://github.com/xiangshu233/vue3-vant4-mobile/issues"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^20.9.0 || >=21.7.1",
|
"node": "^20.19.0 || >=22.12.0",
|
||||||
"pnpm": ">=8.15.4"
|
"pnpm": ">=8.15.4"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -40,44 +40,44 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@unocss/reset": "^0.58.5",
|
"@vueuse/core": "^14.2.1",
|
||||||
"@vueuse/core": "^10.7.0",
|
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"date-fns": "^3.0.6",
|
"date-fns": "^3.0.6",
|
||||||
"echarts": "^5.4.3",
|
"echarts": "^5.4.3",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"mockjs": "^1.1.0",
|
"mockjs": "^1.1.0",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^3.0.4",
|
||||||
"pinia-plugin-persist": "^1.0.0",
|
"pinia-plugin-persistedstate": "^4.7.1",
|
||||||
"qs": "^6.11.2",
|
"qs": "^6.11.2",
|
||||||
"vant": "^4.8.1",
|
"vant": "^4.9.22",
|
||||||
"vue": "^3.3.13",
|
"vue": "^3.5.30",
|
||||||
"vue-router": "4.2.5"
|
"vue-router": "^5.0.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@antfu/eslint-config": "^2.6.3",
|
"@antfu/eslint-config": "^2.6.3",
|
||||||
"@commitlint/cli": "^18.4.3",
|
"@commitlint/cli": "^18.4.3",
|
||||||
"@commitlint/config-conventional": "^18.4.3",
|
"@commitlint/config-conventional": "^18.4.3",
|
||||||
"@iconify/json": "^2.2.188",
|
"@iconify/json": "^2.2.188",
|
||||||
|
"@oxc-parser/binding-win32-x64-msvc": "0.115.0",
|
||||||
"@types/fs-extra": "^11.0.4",
|
"@types/fs-extra": "^11.0.4",
|
||||||
"@types/mockjs": "^1.0.10",
|
"@types/mockjs": "^1.0.10",
|
||||||
"@types/node": "^20.10.5",
|
"@types/node": "^25.5.0",
|
||||||
"@types/nprogress": "^0.2.3",
|
"@types/nprogress": "^0.2.3",
|
||||||
"@types/qs": "^6.9.11",
|
"@types/qs": "^6.9.11",
|
||||||
"@unocss/eslint-plugin": "^0.58.4",
|
"@unocss/eslint-plugin": "^66.6.7",
|
||||||
"@unocss/preset-icons": "^0.58.5",
|
"@unocss/preset-icons": "^66.6.7",
|
||||||
"@unocss/preset-rem-to-px": "^0.58.5",
|
"@unocss/preset-rem-to-px": "^66.6.7",
|
||||||
"@unocss/transformer-directives": "^0.58.4",
|
"@unocss/reset": "^66.6.7",
|
||||||
"@unocss/transformer-variant-group": "^0.58.4",
|
"@unocss/transformer-directives": "^66.6.7",
|
||||||
"@vitejs/plugin-vue": "^5.0.0",
|
"@unocss/transformer-variant-group": "^66.6.7",
|
||||||
|
"@vitejs/plugin-vue": "^6.0.5",
|
||||||
"autoprefixer": "^10.4.16",
|
"autoprefixer": "^10.4.16",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"cz-git": "^1.8.0",
|
"cz-git": "^1.8.0",
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
"eslint": "^8.56.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-plugin-format": "^0.1.0",
|
"eslint-plugin-format": "^0.1.0",
|
||||||
"tsx": "^3.0.0",
|
|
||||||
"fs-extra": "^11.2.0",
|
"fs-extra": "^11.2.0",
|
||||||
"less": "^4.2.0",
|
"less": "^4.2.0",
|
||||||
"lint-staged": "^15.2.0",
|
"lint-staged": "^15.2.0",
|
||||||
@ -89,16 +89,18 @@
|
|||||||
"rollup": "^4.9.1",
|
"rollup": "^4.9.1",
|
||||||
"rollup-plugin-visualizer": "^5.11.0",
|
"rollup-plugin-visualizer": "^5.11.0",
|
||||||
"simple-git-hooks": "^2.9.0",
|
"simple-git-hooks": "^2.9.0",
|
||||||
"typescript": "^5.3.3",
|
"terser": "^5.46.1",
|
||||||
"unocss": "^0.58.5",
|
"tsx": "^4.21.0",
|
||||||
"unplugin-auto-import": "^0.17.5",
|
"typescript": "^5.9.3",
|
||||||
"unplugin-vue-components": "^0.26.0",
|
"unocss": "^66.6.7",
|
||||||
"vite": "^5.0.10",
|
"unplugin-auto-import": "^21.0.0",
|
||||||
|
"unplugin-vue-components": "^32.0.0",
|
||||||
|
"vite": "^8.0.2",
|
||||||
"vite-plugin-compression": "^0.5.1",
|
"vite-plugin-compression": "^0.5.1",
|
||||||
"vite-plugin-html": "^3.2.2",
|
"vite-plugin-html": "^3.2.2",
|
||||||
"vite-plugin-mock": "^2.9.8",
|
"vite-plugin-mock": "^2.9.8",
|
||||||
"vite-plugin-svg-icons": "^2.0.1",
|
"vite-plugin-svg-icons": "^2.0.1",
|
||||||
"vue-tsc": "^1.8.27"
|
"vue-tsc": "^3.2.6"
|
||||||
},
|
},
|
||||||
"simple-git-hooks": {
|
"simple-git-hooks": {
|
||||||
"pre-commit": "pnpm lint-staged",
|
"pre-commit": "pnpm lint-staged",
|
||||||
|
|||||||
3795
pnpm-lock.yaml
generated
3795
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -1,14 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<vanConfigProvider :theme="getDarkMode" :theme-vars="getThemeVars()">
|
<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">
|
<div class="absolute bottom-0 top-0 w-full overflow-hidden">
|
||||||
<transition :name="getTransitionName" mode="out-in" appear>
|
<transition :name="getTransitionName" mode="out-in" appear>
|
||||||
<keep-alive v-if="keepAliveComponents" :include="keepAliveComponents">
|
<KeepAlive v-if="keepAliveComponents" :include="keepAliveComponents">
|
||||||
<component :is="Component" />
|
<component :is="Component" />
|
||||||
</keep-alive>
|
</KeepAlive>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
</routerView>
|
</RouterView>
|
||||||
</vanConfigProvider>
|
</vanConfigProvider>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@ -4,44 +4,35 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script setup lang="ts">
|
||||||
import type { CSSProperties } from 'vue'
|
import type { CSSProperties } from 'vue'
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'SvgIcon' })
|
||||||
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}`)
|
|
||||||
|
|
||||||
const getStyle = computed((): CSSProperties => {
|
const props = withDefaults(
|
||||||
const { size } = props
|
defineProps<{
|
||||||
let s = `${size}`
|
prefix?: string
|
||||||
s = `${s.replace('px', '')}px`
|
name: string
|
||||||
return {
|
size?: number | string
|
||||||
width: s,
|
color?: string
|
||||||
height: s,
|
}>(),
|
||||||
}
|
{
|
||||||
})
|
prefix: 'icon',
|
||||||
|
size: 16,
|
||||||
return { symbolId, getStyle }
|
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>
|
</script>
|
||||||
|
|
||||||
|
|||||||
548
src/layout/components/FloatingNavBar.vue
Normal file
548
src/layout/components/FloatingNavBar.vue
Normal file
@ -0,0 +1,548 @@
|
|||||||
|
<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 { NavigationFailureType, isNavigationFailure, 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`,
|
||||||
|
'--toolbar-max-width': toolbarColumns.value >= 5 ? '430px' : '340px',
|
||||||
|
'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 normalizePath(path: string) {
|
||||||
|
return path.replace(/\/+$/, '') || '/'
|
||||||
|
}
|
||||||
|
|
||||||
|
function goNav(path: string) {
|
||||||
|
// Avoid redundant navigation warnings when clicking current tab.
|
||||||
|
if (normalizePath(currentRoute.path) === normalizePath(path)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
router.push(path).catch((err) => {
|
||||||
|
if (!isNavigationFailure(err, NavigationFailureType.duplicated)) {
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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(94vw, var(--toolbar-max-width));
|
||||||
|
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: 62px;
|
||||||
|
height: 38px;
|
||||||
|
margin-top: -19px;
|
||||||
|
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: 20px;
|
||||||
|
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>
|
||||||
@ -1,66 +1,59 @@
|
|||||||
<!-- eslint-disable prettier/prettier -->
|
|
||||||
<template>
|
<template>
|
||||||
<div class="h-screen flex flex-col">
|
<div
|
||||||
<van-nav-bar v-if="getShowHeader" placeholder fixed :title="getTitle" />
|
class="layout-shell h-screen flex flex-col"
|
||||||
<routerView class="flex-1 overflow-x-hidden">
|
:class="{ dark: designStore.darkMode === 'dark' }"
|
||||||
|
>
|
||||||
|
<RouterView class="flex-1 overflow-x-hidden">
|
||||||
<template #default="{ Component, route }">
|
<template #default="{ Component, route }">
|
||||||
<!--
|
<KeepAlive v-if="keepAliveComponents" :include="keepAliveComponents">
|
||||||
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">
|
|
||||||
<component :is="Component" :key="route.fullPath" />
|
<component :is="Component" :key="route.fullPath" />
|
||||||
</keep-alive>
|
</KeepAlive>
|
||||||
<component :is="Component" v-else :key="route.fullPath" />
|
<component :is="Component" v-else :key="route.fullPath" />
|
||||||
</template>
|
</template>
|
||||||
</routerView>
|
</RouterView>
|
||||||
<van-tabbar route class="tabbar">
|
|
||||||
<van-tabbar-item
|
<!--
|
||||||
v-for="menu in getMenus"
|
<van-tabbar route>
|
||||||
:key="menu.name"
|
<van-tabbar-item icon="home-o" to="/dashboard/index">
|
||||||
replace
|
首页
|
||||||
:to="menu.path"
|
</van-tabbar-item>
|
||||||
>
|
<van-tabbar-item icon="search" to="/message/index">
|
||||||
<template #icon>
|
消息
|
||||||
<i :class="menu.meta?.icon" />
|
</van-tabbar-item>
|
||||||
</template>
|
<van-tabbar-item icon="user-o" to="/my/index">
|
||||||
{{ menu.meta?.title }}
|
我的
|
||||||
</van-tabbar-item>
|
</van-tabbar-item>
|
||||||
</van-tabbar>
|
</van-tabbar>
|
||||||
|
-->
|
||||||
|
<FloatingNavBar :items="tabbarItems" :show-dark-mode-toggle="true" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ComputedRef } from 'vue'
|
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import FloatingNavBar from './components/FloatingNavBar.vue'
|
||||||
import type { RouteRecordRaw } from 'vue-router'
|
|
||||||
import { useRouteStore } from '@/store/modules/route'
|
import { useRouteStore } from '@/store/modules/route'
|
||||||
|
import { useDesignSettingStore } from '@/store/modules/designSetting'
|
||||||
|
|
||||||
const routeStore = useRouteStore()
|
const routeStore = useRouteStore()
|
||||||
// 需要缓存的路由组件
|
const designStore = useDesignSettingStore()
|
||||||
|
|
||||||
const keepAliveComponents = computed(() => routeStore.keepAliveComponents)
|
const keepAliveComponents = computed(() => routeStore.keepAliveComponents)
|
||||||
const currentRoute = useRoute()
|
|
||||||
|
|
||||||
const getTitle = computed(() => currentRoute.meta.title as string)
|
const tabbarItems = [
|
||||||
|
{ label: 'Home', path: '/dashboard/index', icon: 'i-ph:house-line' },
|
||||||
// 菜单
|
{ label: 'Example', path: '/example/index', icon: 'i-ph:flask' },
|
||||||
const getMenus: ComputedRef<RouteRecordRaw[]> = computed(() =>
|
{ label: 'Search', path: '/message/index', icon: 'i-ph:magnifying-glass' },
|
||||||
routeStore.menus.filter((item) => {
|
{ label: 'User', path: '/my/index', icon: 'i-ph:user-circle' },
|
||||||
return !item.meta?.innerPage
|
]
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
const getShowHeader = computed(() => !currentRoute.meta.hiddenHeader)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.tabbar {
|
.layout-shell {
|
||||||
bottom: 0;
|
background: #f7f8fa;
|
||||||
width: 100%;
|
}
|
||||||
position: relative;
|
|
||||||
|
.layout-shell.dark {
|
||||||
|
background: #000000;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -10,7 +10,7 @@ const routeModuleList: Array<RouteRecordRaw> = [
|
|||||||
component: Layout,
|
component: Layout,
|
||||||
meta: {
|
meta: {
|
||||||
title: '主控台',
|
title: '主控台',
|
||||||
icon: 'i-simple-icons:atlassian',
|
icon: 'i-ph:house',
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
@ -30,7 +30,7 @@ const routeModuleList: Array<RouteRecordRaw> = [
|
|||||||
component: Layout,
|
component: Layout,
|
||||||
meta: {
|
meta: {
|
||||||
title: '图表',
|
title: '图表',
|
||||||
icon: 'i-simple-icons:soundcharts',
|
icon: 'i-ph:chart-line',
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
@ -50,7 +50,7 @@ const routeModuleList: Array<RouteRecordRaw> = [
|
|||||||
component: Layout,
|
component: Layout,
|
||||||
meta: {
|
meta: {
|
||||||
title: '示例',
|
title: '示例',
|
||||||
icon: 'i-material-symbols:award-star',
|
icon: 'i-ph:code',
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
@ -70,7 +70,7 @@ const routeModuleList: Array<RouteRecordRaw> = [
|
|||||||
component: Layout,
|
component: Layout,
|
||||||
meta: {
|
meta: {
|
||||||
title: '我的',
|
title: '我的',
|
||||||
icon: 'i-simple-icons:docsify',
|
icon: 'i-ph:user',
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -15,29 +15,26 @@ const LOGIN_PATH = PageEnum.BASE_LOGIN
|
|||||||
const whitePathList = [LOGIN_PATH] // no redirect whitelist
|
const whitePathList = [LOGIN_PATH] // no redirect whitelist
|
||||||
|
|
||||||
export function createRouterGuards(router: Router) {
|
export function createRouterGuards(router: Router) {
|
||||||
router.beforeEach(async (to, from, next) => {
|
router.beforeEach(async (to, from) => {
|
||||||
// to: 即将要进入的目标
|
// to: 即将要进入的目标
|
||||||
// from: 当前导航正要离开的路由
|
// from: 当前导航正要离开的路由
|
||||||
NProgress.start()
|
NProgress.start()
|
||||||
const userStore = useUserStoreWithOut()
|
const userStore = useUserStoreWithOut()
|
||||||
|
|
||||||
if (from.path === LOGIN_PATH && to.name === PageEnum.ERROR_PAGE_NAME) {
|
if (from.path === LOGIN_PATH && to.name === PageEnum.ERROR_PAGE_NAME) {
|
||||||
next(PageEnum.BASE_HOME)
|
return PageEnum.BASE_HOME
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Whitelist can be directly entered
|
// Whitelist can be directly entered
|
||||||
if (whitePathList.includes(to.path as PageEnum)) {
|
if (whitePathList.includes(to.path as PageEnum)) {
|
||||||
next()
|
return true
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = storage.get(ACCESS_TOKEN)
|
const token = storage.get(ACCESS_TOKEN)
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
// redirect login page
|
// redirect login page
|
||||||
next(LOGIN_PATH)
|
return LOGIN_PATH
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 当上次更新时间为空时获取用户信息
|
// 当上次更新时间为空时获取用户信息
|
||||||
@ -46,12 +43,11 @@ export function createRouterGuards(router: Router) {
|
|||||||
await userStore.GetUserInfo()
|
await userStore.GetUserInfo()
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
next()
|
return true
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
next()
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
// 进入某个路由之后触发的钩子
|
// 进入某个路由之后触发的钩子
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import type { App } from 'vue'
|
import type { App } from 'vue'
|
||||||
import { createPinia } from 'pinia'
|
import { createPinia } from 'pinia'
|
||||||
import piniaPersist from 'pinia-plugin-persist'
|
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
||||||
|
|
||||||
const store = createPinia()
|
const store = createPinia()
|
||||||
store.use(piniaPersist)
|
store.use(piniaPluginPersistedstate)
|
||||||
|
|
||||||
export function setupStore(app: App<Element>) {
|
export function setupStore(app: App<Element>) {
|
||||||
app.use(store)
|
app.use(store)
|
||||||
|
|||||||
@ -5,8 +5,7 @@ import type { DesignSettingState } from '@/settings/designSetting'
|
|||||||
|
|
||||||
const { darkMode, appTheme, appThemeList, isPageAnimate, pageAnimateType } = designSetting
|
const { darkMode, appTheme, appThemeList, isPageAnimate, pageAnimateType } = designSetting
|
||||||
|
|
||||||
export const useDesignSettingStore = defineStore({
|
export const useDesignSettingStore = defineStore('app-design-setting', {
|
||||||
id: 'app-design-setting',
|
|
||||||
state: (): DesignSettingState => ({
|
state: (): DesignSettingState => ({
|
||||||
darkMode,
|
darkMode,
|
||||||
appTheme,
|
appTheme,
|
||||||
@ -41,13 +40,8 @@ export const useDesignSettingStore = defineStore({
|
|||||||
},
|
},
|
||||||
// 持久化
|
// 持久化
|
||||||
persist: {
|
persist: {
|
||||||
enabled: true,
|
key: 'DESIGN-SETTING',
|
||||||
strategies: [
|
storage: localStorage,
|
||||||
{
|
|
||||||
key: 'DESIGN-SETTING',
|
|
||||||
storage: localStorage,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -8,8 +8,7 @@ export interface IRouteState {
|
|||||||
keepAliveComponents: string[]
|
keepAliveComponents: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useRouteStore = defineStore({
|
export const useRouteStore = defineStore('app-route', {
|
||||||
id: 'app-route',
|
|
||||||
state: (): IRouteState => ({
|
state: (): IRouteState => ({
|
||||||
menus: [],
|
menus: [],
|
||||||
routers: [],
|
routers: [],
|
||||||
|
|||||||
@ -33,8 +33,7 @@ interface LoginParams {
|
|||||||
password: string
|
password: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useUserStore = defineStore({
|
export const useUserStore = defineStore('app-user', {
|
||||||
id: 'app-user',
|
|
||||||
state: (): IUserState => ({
|
state: (): IUserState => ({
|
||||||
userInfo: null,
|
userInfo: null,
|
||||||
token: undefined,
|
token: undefined,
|
||||||
|
|||||||
@ -17,8 +17,8 @@ html.dark {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-color: #121212;
|
background-color: #000000;
|
||||||
color: var(--van-text-color) !important;
|
color: rgba(255, 255, 255, 0.9) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,15 +93,37 @@ a:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
html.light {
|
html.light {
|
||||||
|
body {
|
||||||
|
background-color: #f5f6fa;
|
||||||
|
}
|
||||||
|
|
||||||
.my-card {
|
.my-card {
|
||||||
backdrop-filter: blur(10px);
|
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 {
|
html.dark {
|
||||||
.my-card {
|
.my-card {
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(12px);
|
||||||
background: rgba(30, 30, 30, 70%);
|
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 {
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="h-screen flex flex-col items-center justify-center p-60px">
|
<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">
|
<div class="wel-box w-full flex flex-col items-center justify-between">
|
||||||
<Logo class="!h-30 !w-30" />
|
<div class="page-title mb-4 mt-12 text-center">
|
||||||
<div class="text-darkBlue dark:text-garyWhite mb-4 mt-12 text-center text-2xl font-black">
|
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-6 mt-4 w-full">
|
<div class="mb-6 mt-4 w-full">
|
||||||
@ -10,12 +9,12 @@
|
|||||||
<van-swipe-item
|
<van-swipe-item
|
||||||
v-for="(text, index) in getSwipeText"
|
v-for="(text, index) in getSwipeText"
|
||||||
:key="index"
|
: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 }}
|
{{ text.title }}
|
||||||
</p>
|
</p>
|
||||||
<p class="text-sm">
|
<p class="swipe-details">
|
||||||
{{ text.details }}
|
{{ text.details }}
|
||||||
</p>
|
</p>
|
||||||
</van-swipe-item>
|
</van-swipe-item>
|
||||||
@ -28,7 +27,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useDesignSettingStore } from '@/store/modules/designSetting'
|
import { useDesignSettingStore } from '@/store/modules/designSetting'
|
||||||
import { useGlobSetting } from '@/hooks/setting'
|
import { useGlobSetting } from '@/hooks/setting'
|
||||||
import Logo from '@/components/Logo.vue'
|
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'DashboardPage',
|
name: 'DashboardPage',
|
||||||
@ -77,4 +75,56 @@ const getSwipeText = computed(() => {
|
|||||||
})
|
})
|
||||||
</script>
|
</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>
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="my-4">
|
<div class="example-page my-4 pb-24">
|
||||||
<van-cell-group inset>
|
<van-cell-group inset>
|
||||||
<van-cell center title="🌓 暗黑模式">
|
<van-cell center title="🌓 暗黑模式">
|
||||||
<template #right-icon>
|
<template #right-icon>
|
||||||
<i inline-block align-middle i="dark:carbon-moon carbon-sun" />
|
<i inline-block align-middle i="dark:carbon-moon carbon-sun" />
|
||||||
<span class="ml-2">{{ isDark ? 'Dark' : 'Light' }}</span>
|
<span class="mx-2">{{ isDark ? 'Dark' : 'Light' }}</span>
|
||||||
<span class="mx-2">{{ isDark }}</span>
|
<van-switch v-model="darkSwitch" size="22" />
|
||||||
<van-switch v-model="checked" size="22" @click="toggle()" />
|
|
||||||
</template>
|
</template>
|
||||||
</van-cell>
|
</van-cell>
|
||||||
<template v-for="item in menuItems" :key="item.route">
|
<template v-for="item in menuItems" :key="item.route">
|
||||||
@ -17,7 +16,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useDark, useToggle } from '@vueuse/core'
|
import { useDark } from '@vueuse/core'
|
||||||
import { useDesignSettingStore } from '@/store/modules/designSetting'
|
import { useDesignSettingStore } from '@/store/modules/designSetting'
|
||||||
|
|
||||||
const designStore = useDesignSettingStore()
|
const designStore = useDesignSettingStore()
|
||||||
@ -25,16 +24,16 @@ const designStore = useDesignSettingStore()
|
|||||||
const isDark = useDark({
|
const isDark = useDark({
|
||||||
valueDark: 'dark',
|
valueDark: 'dark',
|
||||||
valueLight: 'light',
|
valueLight: 'light',
|
||||||
|
disableTransition: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
const checked = ref(isDark.value)
|
const darkSwitch = computed({
|
||||||
|
get: () => isDark.value,
|
||||||
const toggleDark = useToggle(isDark)
|
set: (value: boolean) => {
|
||||||
|
isDark.value = value
|
||||||
function toggle() {
|
designStore.setDarkMode(value ? 'dark' : 'light')
|
||||||
toggleDark()
|
},
|
||||||
designStore.setDarkMode(isDark.value ? 'dark' : 'light')
|
})
|
||||||
}
|
|
||||||
|
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
{ title: '🐗 keep-alive', route: '/editNickname' },
|
{ title: '🐗 keep-alive', route: '/editNickname' },
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="login-page">
|
||||||
<div class="h-screen flex justify-center p-8">
|
<div class="login-scroll px-8 pt-8">
|
||||||
<div class="w-full flex flex-col">
|
<div class="w-full flex flex-col">
|
||||||
<LoginTitle />
|
<LoginTitle />
|
||||||
<LoginForm />
|
<LoginForm />
|
||||||
@ -21,6 +21,22 @@ import LoginWave from './LoginWave.vue'
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
.login-page {
|
||||||
|
position: relative;
|
||||||
|
height: 100dvh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-scroll {
|
||||||
|
min-height: 100%;
|
||||||
|
padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 120px);
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.wave-wrapper) {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
:deep(.van-field__left-icon) {
|
:deep(.van-field__left-icon) {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<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 ref="chartRef" :style="{ height: '350px' }" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -7,11 +7,16 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { EChartsOption } from 'echarts'
|
import type { EChartsOption } from 'echarts'
|
||||||
import { useECharts } from '@/hooks/web/useECharts'
|
import { useECharts } from '@/hooks/web/useECharts'
|
||||||
|
import { useDesignSettingStore } from '@/store/modules/designSetting'
|
||||||
|
|
||||||
const chartRef = ref<HTMLDivElement | null>(null)
|
const chartRef = ref<HTMLDivElement | null>(null)
|
||||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>)
|
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>)
|
||||||
|
const designStore = useDesignSettingStore()
|
||||||
|
|
||||||
|
const chartColors = [designStore.appTheme, '#4a9eff', '#5dd9a8', '#ff9f7a', '#7ec8e3', '#b8a9e0']
|
||||||
|
|
||||||
const chartOptions: EChartsOption = {
|
const chartOptions: EChartsOption = {
|
||||||
|
color: chartColors,
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
axisPointer: {
|
axisPointer: {
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="message-page pb-24">
|
||||||
|
<div class="section-title">
|
||||||
|
数据概览
|
||||||
|
</div>
|
||||||
<lineChart />
|
<lineChart />
|
||||||
<barChart />
|
<barChart />
|
||||||
<pieChart />
|
<pieChart />
|
||||||
@ -12,4 +15,29 @@ import barChart from './barChart.vue'
|
|||||||
import pieChart from './pieChart.vue'
|
import pieChart from './pieChart.vue'
|
||||||
</script>
|
</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>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<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 ref="chartRef" :style="{ height: '350px' }" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -7,11 +7,16 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { EChartsOption } from 'echarts'
|
import type { EChartsOption } from 'echarts'
|
||||||
import { useECharts } from '@/hooks/web/useECharts'
|
import { useECharts } from '@/hooks/web/useECharts'
|
||||||
|
import { useDesignSettingStore } from '@/store/modules/designSetting'
|
||||||
|
|
||||||
const chartRef = ref<HTMLDivElement | null>(null)
|
const chartRef = ref<HTMLDivElement | null>(null)
|
||||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>)
|
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>)
|
||||||
|
const designStore = useDesignSettingStore()
|
||||||
|
|
||||||
|
const chartColors = [designStore.appTheme, '#4a9eff', '#5dd9a8', '#ff9f7a', '#7ec8e3']
|
||||||
|
|
||||||
const chartOptions: EChartsOption = {
|
const chartOptions: EChartsOption = {
|
||||||
|
color: chartColors,
|
||||||
title: {
|
title: {
|
||||||
text: 'Stacked Area Chart',
|
text: 'Stacked Area Chart',
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<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 ref="chartRef" :style="{ height: '350px' }" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -7,11 +7,16 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { EChartsOption } from 'echarts'
|
import type { EChartsOption } from 'echarts'
|
||||||
import { useECharts } from '@/hooks/web/useECharts'
|
import { useECharts } from '@/hooks/web/useECharts'
|
||||||
|
import { useDesignSettingStore } from '@/store/modules/designSetting'
|
||||||
|
|
||||||
const chartRef = ref<HTMLDivElement | null>(null)
|
const chartRef = ref<HTMLDivElement | null>(null)
|
||||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>)
|
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>)
|
||||||
|
const designStore = useDesignSettingStore()
|
||||||
|
|
||||||
|
const chartColors = [designStore.appTheme, '#4a9eff', '#5dd9a8', '#ff9f7a', '#7ec8e3', '#b8a9e0']
|
||||||
|
|
||||||
const chartOptions: EChartsOption = {
|
const chartOptions: EChartsOption = {
|
||||||
|
color: chartColors,
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'item',
|
trigger: 'item',
|
||||||
},
|
},
|
||||||
|
|||||||
@ -68,7 +68,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useDark, useToggle } from '@vueuse/core'
|
import { useDark } from '@vueuse/core'
|
||||||
import NavBar from './components/NavBar.vue'
|
import NavBar from './components/NavBar.vue'
|
||||||
import { useDesignSettingStore } from '@/store/modules/designSetting'
|
import { useDesignSettingStore } from '@/store/modules/designSetting'
|
||||||
import { animates as animateOptions } from '@/settings/animateSetting'
|
import { animates as animateOptions } from '@/settings/animateSetting'
|
||||||
@ -78,15 +78,14 @@ const designStore = useDesignSettingStore()
|
|||||||
const isDark = useDark({
|
const isDark = useDark({
|
||||||
valueDark: 'dark',
|
valueDark: 'dark',
|
||||||
valueLight: 'light',
|
valueLight: 'light',
|
||||||
|
disableTransition: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
const toggleDark = useToggle(isDark)
|
|
||||||
|
|
||||||
const getDarkMode = computed({
|
const getDarkMode = computed({
|
||||||
get: () => isDark.value,
|
get: () => isDark.value,
|
||||||
set: () => {
|
set: (value: boolean) => {
|
||||||
toggleDark()
|
isDark.value = value
|
||||||
designStore.setDarkMode(isDark.value ? 'dark' : 'light')
|
designStore.setDarkMode(value ? 'dark' : 'light')
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="my-page">
|
||||||
<div :style="getUserCoverBg" class="my-bg h-70" />
|
<div :style="getUserCoverBg" class="my-bg h-70" />
|
||||||
<div
|
<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
|
<van-image
|
||||||
class="h-22 w-22 border-2 border-solid !absolute -top-10"
|
class="h-22 w-22 border-2 border-solid !absolute -top-10"
|
||||||
@ -11,42 +11,42 @@
|
|||||||
:src="avatar"
|
:src="avatar"
|
||||||
/>
|
/>
|
||||||
<div class="mt-14 flex flex-col items-center">
|
<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 }}
|
{{ nickname }}
|
||||||
</p>
|
</p>
|
||||||
<p class="text-4">
|
<p class="profile-sign text-4">
|
||||||
{{ sign }}
|
{{ sign }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<van-divider class="w-full" />
|
<van-divider class="profile-divider w-full" />
|
||||||
|
|
||||||
<van-cell :border="false" title="个人信息" is-link to="/editUserInfo">
|
<van-cell :border="false" title="个人信息" is-link to="/editUserInfo">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<i class="i-mingcute:idcard-fill mr-2 text-xl" />
|
<i class="i-ph:user-circle mr-2 text-xl" />
|
||||||
</template>
|
</template>
|
||||||
</van-cell>
|
</van-cell>
|
||||||
|
|
||||||
<van-cell :border="false" title="账号与安全" is-link to="/accountSetting">
|
<van-cell :border="false" title="账号与安全" is-link to="/accountSetting">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<i class="i-material-symbols:account-box mr-2 text-xl" />
|
<i class="i-ph:shield-check mr-2 text-xl" />
|
||||||
</template>
|
</template>
|
||||||
</van-cell>
|
</van-cell>
|
||||||
|
|
||||||
<van-cell :border="false" title="主题设置" is-link to="/themeSetting">
|
<van-cell :border="false" title="主题设置" is-link to="/themeSetting">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<i class="i-material-symbols:palette mr-2 text-xl" />
|
<i class="i-ph:palette mr-2 text-xl" />
|
||||||
</template>
|
</template>
|
||||||
</van-cell>
|
</van-cell>
|
||||||
|
|
||||||
<van-cell :border="false" title="隐私政策" is-link>
|
<van-cell :border="false" title="隐私政策" is-link>
|
||||||
<template #icon>
|
<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>
|
</template>
|
||||||
</van-cell>
|
</van-cell>
|
||||||
|
|
||||||
<van-cell :border="false" title="退出登录" is-link @click="showLogoutAction = true">
|
<van-cell :border="false" title="退出登录" is-link @click="showLogoutAction = true">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<i class="i-solar:logout-3-bold mr-2 text-xl" />
|
<i class="i-ph:sign-out mr-2 text-xl" />
|
||||||
</template>
|
</template>
|
||||||
</van-cell>
|
</van-cell>
|
||||||
|
|
||||||
@ -88,6 +88,11 @@ const getUserCoverBg = computed(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
.my-page {
|
||||||
|
min-height: 100%;
|
||||||
|
padding-bottom: calc(110px + env(safe-area-inset-bottom));
|
||||||
|
}
|
||||||
|
|
||||||
.my-bg {
|
.my-bg {
|
||||||
clip-path: inset(0 -55% 0 -55% round 0 0 100% 100%);
|
clip-path: inset(0 -55% 0 -55% round 0 0 100% 100%);
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
@ -100,10 +105,22 @@ const getUserCoverBg = computed(() => {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-image: linear-gradient(180deg, rgba(0, 0, 0, 0), #000);
|
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 {
|
.van-cell {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -112,4 +129,16 @@ const getUserCoverBg = computed(() => {
|
|||||||
background-color: var(--van-cell-active-color);
|
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>
|
</style>
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
"useDefineForClassFields": true,
|
"useDefineForClassFields": true,
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"moduleResolution": "Node",
|
"moduleResolution": "bundler",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["src/*"],
|
"@/*": ["src/*"],
|
||||||
"#/*": ["types/*"]
|
"#/*": ["types/*"]
|
||||||
|
|||||||
595
types/auto-imports.d.ts
vendored
595
types/auto-imports.d.ts
vendored
@ -3,302 +3,317 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
// noinspection JSUnusedGlobalSymbols
|
// noinspection JSUnusedGlobalSymbols
|
||||||
// Generated by unplugin-auto-import
|
// Generated by unplugin-auto-import
|
||||||
|
// biome-ignore lint: disable
|
||||||
export {}
|
export {}
|
||||||
declare global {
|
declare global {
|
||||||
const EffectScope: typeof import('vue')['EffectScope']
|
const EffectScope: typeof import('vue').EffectScope
|
||||||
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
|
const acceptHMRUpdate: typeof import('pinia').acceptHMRUpdate
|
||||||
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
|
const asyncComputed: typeof import('@vueuse/core').asyncComputed
|
||||||
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
|
const autoResetRef: typeof import('@vueuse/core').autoResetRef
|
||||||
const computed: typeof import('vue')['computed']
|
const computed: typeof import('vue').computed
|
||||||
const computedAsync: typeof import('@vueuse/core')['computedAsync']
|
const computedAsync: typeof import('@vueuse/core').computedAsync
|
||||||
const computedEager: typeof import('@vueuse/core')['computedEager']
|
const computedEager: typeof import('@vueuse/core').computedEager
|
||||||
const computedInject: typeof import('@vueuse/core')['computedInject']
|
const computedInject: typeof import('@vueuse/core').computedInject
|
||||||
const computedWithControl: typeof import('@vueuse/core')['computedWithControl']
|
const computedWithControl: typeof import('@vueuse/core').computedWithControl
|
||||||
const controlledComputed: typeof import('@vueuse/core')['controlledComputed']
|
const controlledComputed: typeof import('@vueuse/core').controlledComputed
|
||||||
const controlledRef: typeof import('@vueuse/core')['controlledRef']
|
const controlledRef: typeof import('@vueuse/core').controlledRef
|
||||||
const createApp: typeof import('vue')['createApp']
|
const createApp: typeof import('vue').createApp
|
||||||
const createEventHook: typeof import('@vueuse/core')['createEventHook']
|
const createEventHook: typeof import('@vueuse/core').createEventHook
|
||||||
const createGlobalState: typeof import('@vueuse/core')['createGlobalState']
|
const createGlobalState: typeof import('@vueuse/core').createGlobalState
|
||||||
const createInjectionState: typeof import('@vueuse/core')['createInjectionState']
|
const createInjectionState: typeof import('@vueuse/core').createInjectionState
|
||||||
const createPinia: typeof import('pinia')['createPinia']
|
const createPinia: typeof import('pinia').createPinia
|
||||||
const createReactiveFn: typeof import('@vueuse/core')['createReactiveFn']
|
const createReactiveFn: typeof import('@vueuse/core').createReactiveFn
|
||||||
const createReusableTemplate: typeof import('@vueuse/core')['createReusableTemplate']
|
const createRef: typeof import('@vueuse/core').createRef
|
||||||
const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable']
|
const createReusableTemplate: typeof import('@vueuse/core').createReusableTemplate
|
||||||
const createTemplatePromise: typeof import('@vueuse/core')['createTemplatePromise']
|
const createSharedComposable: typeof import('@vueuse/core').createSharedComposable
|
||||||
const createUnrefFn: typeof import('@vueuse/core')['createUnrefFn']
|
const createTemplatePromise: typeof import('@vueuse/core').createTemplatePromise
|
||||||
const customRef: typeof import('vue')['customRef']
|
const createUnrefFn: typeof import('@vueuse/core').createUnrefFn
|
||||||
const debouncedRef: typeof import('@vueuse/core')['debouncedRef']
|
const customRef: typeof import('vue').customRef
|
||||||
const debouncedWatch: typeof import('@vueuse/core')['debouncedWatch']
|
const debouncedRef: typeof import('@vueuse/core').debouncedRef
|
||||||
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
const debouncedWatch: typeof import('@vueuse/core').debouncedWatch
|
||||||
const defineComponent: typeof import('vue')['defineComponent']
|
const defineAsyncComponent: typeof import('vue').defineAsyncComponent
|
||||||
const defineStore: typeof import('pinia')['defineStore']
|
const defineComponent: typeof import('vue').defineComponent
|
||||||
const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
|
const defineStore: typeof import('pinia').defineStore
|
||||||
const effectScope: typeof import('vue')['effectScope']
|
const eagerComputed: typeof import('@vueuse/core').eagerComputed
|
||||||
const extendRef: typeof import('@vueuse/core')['extendRef']
|
const effectScope: typeof import('vue').effectScope
|
||||||
const getActivePinia: typeof import('pinia')['getActivePinia']
|
const extendRef: typeof import('@vueuse/core').extendRef
|
||||||
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
const getActivePinia: typeof import('pinia').getActivePinia
|
||||||
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
const getCurrentInstance: typeof import('vue').getCurrentInstance
|
||||||
const h: typeof import('vue')['h']
|
const getCurrentScope: typeof import('vue').getCurrentScope
|
||||||
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
|
const getCurrentWatcher: typeof import('vue').getCurrentWatcher
|
||||||
const inject: typeof import('vue')['inject']
|
const h: typeof import('vue').h
|
||||||
const injectLocal: typeof import('@vueuse/core')['injectLocal']
|
const ignorableWatch: typeof import('@vueuse/core').ignorableWatch
|
||||||
const isDefined: typeof import('@vueuse/core')['isDefined']
|
const inject: typeof import('vue').inject
|
||||||
const isProxy: typeof import('vue')['isProxy']
|
const injectLocal: typeof import('@vueuse/core').injectLocal
|
||||||
const isReactive: typeof import('vue')['isReactive']
|
const isDefined: typeof import('@vueuse/core').isDefined
|
||||||
const isReadonly: typeof import('vue')['isReadonly']
|
const isProxy: typeof import('vue').isProxy
|
||||||
const isRef: typeof import('vue')['isRef']
|
const isReactive: typeof import('vue').isReactive
|
||||||
const makeDestructurable: typeof import('@vueuse/core')['makeDestructurable']
|
const isReadonly: typeof import('vue').isReadonly
|
||||||
const mapActions: typeof import('pinia')['mapActions']
|
const isRef: typeof import('vue').isRef
|
||||||
const mapGetters: typeof import('pinia')['mapGetters']
|
const isShallow: typeof import('vue').isShallow
|
||||||
const mapState: typeof import('pinia')['mapState']
|
const makeDestructurable: typeof import('@vueuse/core').makeDestructurable
|
||||||
const mapStores: typeof import('pinia')['mapStores']
|
const mapActions: typeof import('pinia').mapActions
|
||||||
const mapWritableState: typeof import('pinia')['mapWritableState']
|
const mapGetters: typeof import('pinia').mapGetters
|
||||||
const markRaw: typeof import('vue')['markRaw']
|
const mapState: typeof import('pinia').mapState
|
||||||
const nextTick: typeof import('vue')['nextTick']
|
const mapStores: typeof import('pinia').mapStores
|
||||||
const onActivated: typeof import('vue')['onActivated']
|
const mapWritableState: typeof import('pinia').mapWritableState
|
||||||
const onBeforeMount: typeof import('vue')['onBeforeMount']
|
const markRaw: typeof import('vue').markRaw
|
||||||
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
|
const nextTick: typeof import('vue').nextTick
|
||||||
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
|
const onActivated: typeof import('vue').onActivated
|
||||||
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
|
const onBeforeMount: typeof import('vue').onBeforeMount
|
||||||
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
|
const onBeforeRouteLeave: typeof import('vue-router').onBeforeRouteLeave
|
||||||
const onClickOutside: typeof import('@vueuse/core')['onClickOutside']
|
const onBeforeRouteUpdate: typeof import('vue-router').onBeforeRouteUpdate
|
||||||
const onDeactivated: typeof import('vue')['onDeactivated']
|
const onBeforeUnmount: typeof import('vue').onBeforeUnmount
|
||||||
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
|
const onBeforeUpdate: typeof import('vue').onBeforeUpdate
|
||||||
const onKeyStroke: typeof import('@vueuse/core')['onKeyStroke']
|
const onClickOutside: typeof import('@vueuse/core').onClickOutside
|
||||||
const onLongPress: typeof import('@vueuse/core')['onLongPress']
|
const onDeactivated: typeof import('vue').onDeactivated
|
||||||
const onMounted: typeof import('vue')['onMounted']
|
const onElementRemoval: typeof import('@vueuse/core').onElementRemoval
|
||||||
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
const onErrorCaptured: typeof import('vue').onErrorCaptured
|
||||||
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
const onKeyStroke: typeof import('@vueuse/core').onKeyStroke
|
||||||
const onScopeDispose: typeof import('vue')['onScopeDispose']
|
const onLongPress: typeof import('@vueuse/core').onLongPress
|
||||||
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
const onMounted: typeof import('vue').onMounted
|
||||||
const onStartTyping: typeof import('@vueuse/core')['onStartTyping']
|
const onRenderTracked: typeof import('vue').onRenderTracked
|
||||||
const onUnmounted: typeof import('vue')['onUnmounted']
|
const onRenderTriggered: typeof import('vue').onRenderTriggered
|
||||||
const onUpdated: typeof import('vue')['onUpdated']
|
const onScopeDispose: typeof import('vue').onScopeDispose
|
||||||
const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
|
const onServerPrefetch: typeof import('vue').onServerPrefetch
|
||||||
const provide: typeof import('vue')['provide']
|
const onStartTyping: typeof import('@vueuse/core').onStartTyping
|
||||||
const provideLocal: typeof import('@vueuse/core')['provideLocal']
|
const onUnmounted: typeof import('vue').onUnmounted
|
||||||
const reactify: typeof import('@vueuse/core')['reactify']
|
const onUpdated: typeof import('vue').onUpdated
|
||||||
const reactifyObject: typeof import('@vueuse/core')['reactifyObject']
|
const onWatcherCleanup: typeof import('vue').onWatcherCleanup
|
||||||
const reactive: typeof import('vue')['reactive']
|
const pausableWatch: typeof import('@vueuse/core').pausableWatch
|
||||||
const reactiveComputed: typeof import('@vueuse/core')['reactiveComputed']
|
const provide: typeof import('vue').provide
|
||||||
const reactiveOmit: typeof import('@vueuse/core')['reactiveOmit']
|
const provideLocal: typeof import('@vueuse/core').provideLocal
|
||||||
const reactivePick: typeof import('@vueuse/core')['reactivePick']
|
const reactify: typeof import('@vueuse/core').reactify
|
||||||
const readonly: typeof import('vue')['readonly']
|
const reactifyObject: typeof import('@vueuse/core').reactifyObject
|
||||||
const ref: typeof import('vue')['ref']
|
const reactive: typeof import('vue').reactive
|
||||||
const refAutoReset: typeof import('@vueuse/core')['refAutoReset']
|
const reactiveComputed: typeof import('@vueuse/core').reactiveComputed
|
||||||
const refDebounced: typeof import('@vueuse/core')['refDebounced']
|
const reactiveOmit: typeof import('@vueuse/core').reactiveOmit
|
||||||
const refDefault: typeof import('@vueuse/core')['refDefault']
|
const reactivePick: typeof import('@vueuse/core').reactivePick
|
||||||
const refThrottled: typeof import('@vueuse/core')['refThrottled']
|
const readonly: typeof import('vue').readonly
|
||||||
const refWithControl: typeof import('@vueuse/core')['refWithControl']
|
const ref: typeof import('vue').ref
|
||||||
const resolveComponent: typeof import('vue')['resolveComponent']
|
const refAutoReset: typeof import('@vueuse/core').refAutoReset
|
||||||
const resolveRef: typeof import('@vueuse/core')['resolveRef']
|
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 resolveUnref: typeof import('@vueuse/core')['resolveUnref']
|
||||||
const setActivePinia: typeof import('pinia')['setActivePinia']
|
const setActivePinia: typeof import('pinia').setActivePinia
|
||||||
const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix']
|
const setMapStoreSuffix: typeof import('pinia').setMapStoreSuffix
|
||||||
const shallowReactive: typeof import('vue')['shallowReactive']
|
const shallowReactive: typeof import('vue').shallowReactive
|
||||||
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
const shallowReadonly: typeof import('vue').shallowReadonly
|
||||||
const shallowRef: typeof import('vue')['shallowRef']
|
const shallowRef: typeof import('vue').shallowRef
|
||||||
const storeToRefs: typeof import('pinia')['storeToRefs']
|
const storeToRefs: typeof import('pinia').storeToRefs
|
||||||
const syncRef: typeof import('@vueuse/core')['syncRef']
|
const syncRef: typeof import('@vueuse/core').syncRef
|
||||||
const syncRefs: typeof import('@vueuse/core')['syncRefs']
|
const syncRefs: typeof import('@vueuse/core').syncRefs
|
||||||
const templateRef: typeof import('@vueuse/core')['templateRef']
|
const templateRef: typeof import('@vueuse/core').templateRef
|
||||||
const throttledRef: typeof import('@vueuse/core')['throttledRef']
|
const throttledRef: typeof import('@vueuse/core').throttledRef
|
||||||
const throttledWatch: typeof import('@vueuse/core')['throttledWatch']
|
const throttledWatch: typeof import('@vueuse/core').throttledWatch
|
||||||
const toRaw: typeof import('vue')['toRaw']
|
const toRaw: typeof import('vue').toRaw
|
||||||
const toReactive: typeof import('@vueuse/core')['toReactive']
|
const toReactive: typeof import('@vueuse/core').toReactive
|
||||||
const toRef: typeof import('vue')['toRef']
|
const toRef: typeof import('vue').toRef
|
||||||
const toRefs: typeof import('vue')['toRefs']
|
const toRefs: typeof import('vue').toRefs
|
||||||
const toValue: typeof import('vue')['toValue']
|
const toValue: typeof import('vue').toValue
|
||||||
const triggerRef: typeof import('vue')['triggerRef']
|
const triggerRef: typeof import('vue').triggerRef
|
||||||
const tryOnBeforeMount: typeof import('@vueuse/core')['tryOnBeforeMount']
|
const tryOnBeforeMount: typeof import('@vueuse/core').tryOnBeforeMount
|
||||||
const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount']
|
const tryOnBeforeUnmount: typeof import('@vueuse/core').tryOnBeforeUnmount
|
||||||
const tryOnMounted: typeof import('@vueuse/core')['tryOnMounted']
|
const tryOnMounted: typeof import('@vueuse/core').tryOnMounted
|
||||||
const tryOnScopeDispose: typeof import('@vueuse/core')['tryOnScopeDispose']
|
const tryOnScopeDispose: typeof import('@vueuse/core').tryOnScopeDispose
|
||||||
const tryOnUnmounted: typeof import('@vueuse/core')['tryOnUnmounted']
|
const tryOnUnmounted: typeof import('@vueuse/core').tryOnUnmounted
|
||||||
const unref: typeof import('vue')['unref']
|
const unref: typeof import('vue').unref
|
||||||
const unrefElement: typeof import('@vueuse/core')['unrefElement']
|
const unrefElement: typeof import('@vueuse/core').unrefElement
|
||||||
const until: typeof import('@vueuse/core')['until']
|
const until: typeof import('@vueuse/core').until
|
||||||
const useActiveElement: typeof import('@vueuse/core')['useActiveElement']
|
const useActiveElement: typeof import('@vueuse/core').useActiveElement
|
||||||
const useAnimate: typeof import('@vueuse/core')['useAnimate']
|
const useAnimate: typeof import('@vueuse/core').useAnimate
|
||||||
const useArrayDifference: typeof import('@vueuse/core')['useArrayDifference']
|
const useArrayDifference: typeof import('@vueuse/core').useArrayDifference
|
||||||
const useArrayEvery: typeof import('@vueuse/core')['useArrayEvery']
|
const useArrayEvery: typeof import('@vueuse/core').useArrayEvery
|
||||||
const useArrayFilter: typeof import('@vueuse/core')['useArrayFilter']
|
const useArrayFilter: typeof import('@vueuse/core').useArrayFilter
|
||||||
const useArrayFind: typeof import('@vueuse/core')['useArrayFind']
|
const useArrayFind: typeof import('@vueuse/core').useArrayFind
|
||||||
const useArrayFindIndex: typeof import('@vueuse/core')['useArrayFindIndex']
|
const useArrayFindIndex: typeof import('@vueuse/core').useArrayFindIndex
|
||||||
const useArrayFindLast: typeof import('@vueuse/core')['useArrayFindLast']
|
const useArrayFindLast: typeof import('@vueuse/core').useArrayFindLast
|
||||||
const useArrayIncludes: typeof import('@vueuse/core')['useArrayIncludes']
|
const useArrayIncludes: typeof import('@vueuse/core').useArrayIncludes
|
||||||
const useArrayJoin: typeof import('@vueuse/core')['useArrayJoin']
|
const useArrayJoin: typeof import('@vueuse/core').useArrayJoin
|
||||||
const useArrayMap: typeof import('@vueuse/core')['useArrayMap']
|
const useArrayMap: typeof import('@vueuse/core').useArrayMap
|
||||||
const useArrayReduce: typeof import('@vueuse/core')['useArrayReduce']
|
const useArrayReduce: typeof import('@vueuse/core').useArrayReduce
|
||||||
const useArraySome: typeof import('@vueuse/core')['useArraySome']
|
const useArraySome: typeof import('@vueuse/core').useArraySome
|
||||||
const useArrayUnique: typeof import('@vueuse/core')['useArrayUnique']
|
const useArrayUnique: typeof import('@vueuse/core').useArrayUnique
|
||||||
const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue']
|
const useAsyncQueue: typeof import('@vueuse/core').useAsyncQueue
|
||||||
const useAsyncState: typeof import('@vueuse/core')['useAsyncState']
|
const useAsyncState: typeof import('@vueuse/core').useAsyncState
|
||||||
const useAttrs: typeof import('vue')['useAttrs']
|
const useAttrs: typeof import('vue').useAttrs
|
||||||
const useBase64: typeof import('@vueuse/core')['useBase64']
|
const useBase64: typeof import('@vueuse/core').useBase64
|
||||||
const useBattery: typeof import('@vueuse/core')['useBattery']
|
const useBattery: typeof import('@vueuse/core').useBattery
|
||||||
const useBluetooth: typeof import('@vueuse/core')['useBluetooth']
|
const useBluetooth: typeof import('@vueuse/core').useBluetooth
|
||||||
const useBreakpoints: typeof import('@vueuse/core')['useBreakpoints']
|
const useBreakpoints: typeof import('@vueuse/core').useBreakpoints
|
||||||
const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel']
|
const useBroadcastChannel: typeof import('@vueuse/core').useBroadcastChannel
|
||||||
const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation']
|
const useBrowserLocation: typeof import('@vueuse/core').useBrowserLocation
|
||||||
const useCached: typeof import('@vueuse/core')['useCached']
|
const useCached: typeof import('@vueuse/core').useCached
|
||||||
const useClipboard: typeof import('@vueuse/core')['useClipboard']
|
const useClipboard: typeof import('@vueuse/core').useClipboard
|
||||||
const useClipboardItems: typeof import('@vueuse/core')['useClipboardItems']
|
const useClipboardItems: typeof import('@vueuse/core').useClipboardItems
|
||||||
const useCloned: typeof import('@vueuse/core')['useCloned']
|
const useCloned: typeof import('@vueuse/core').useCloned
|
||||||
const useColorMode: typeof import('@vueuse/core')['useColorMode']
|
const useColorMode: typeof import('@vueuse/core').useColorMode
|
||||||
const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog']
|
const useConfirmDialog: typeof import('@vueuse/core').useConfirmDialog
|
||||||
const useCounter: typeof import('@vueuse/core')['useCounter']
|
const useCountdown: typeof import('@vueuse/core').useCountdown
|
||||||
const useCssModule: typeof import('vue')['useCssModule']
|
const useCounter: typeof import('@vueuse/core').useCounter
|
||||||
const useCssVar: typeof import('@vueuse/core')['useCssVar']
|
const useCssModule: typeof import('vue').useCssModule
|
||||||
const useCssVars: typeof import('vue')['useCssVars']
|
const useCssSupports: typeof import('@vueuse/core').useCssSupports
|
||||||
const useCurrentElement: typeof import('@vueuse/core')['useCurrentElement']
|
const useCssVar: typeof import('@vueuse/core').useCssVar
|
||||||
const useCycleList: typeof import('@vueuse/core')['useCycleList']
|
const useCssVars: typeof import('vue').useCssVars
|
||||||
const useDark: typeof import('@vueuse/core')['useDark']
|
const useCurrentElement: typeof import('@vueuse/core').useCurrentElement
|
||||||
const useDateFormat: typeof import('@vueuse/core')['useDateFormat']
|
const useCycleList: typeof import('@vueuse/core').useCycleList
|
||||||
const useDebounce: typeof import('@vueuse/core')['useDebounce']
|
const useDark: typeof import('@vueuse/core').useDark
|
||||||
const useDebounceFn: typeof import('@vueuse/core')['useDebounceFn']
|
const useDateFormat: typeof import('@vueuse/core').useDateFormat
|
||||||
const useDebouncedRefHistory: typeof import('@vueuse/core')['useDebouncedRefHistory']
|
const useDebounce: typeof import('@vueuse/core').useDebounce
|
||||||
const useDeviceMotion: typeof import('@vueuse/core')['useDeviceMotion']
|
const useDebounceFn: typeof import('@vueuse/core').useDebounceFn
|
||||||
const useDeviceOrientation: typeof import('@vueuse/core')['useDeviceOrientation']
|
const useDebouncedRefHistory: typeof import('@vueuse/core').useDebouncedRefHistory
|
||||||
const useDevicePixelRatio: typeof import('@vueuse/core')['useDevicePixelRatio']
|
const useDeviceMotion: typeof import('@vueuse/core').useDeviceMotion
|
||||||
const useDevicesList: typeof import('@vueuse/core')['useDevicesList']
|
const useDeviceOrientation: typeof import('@vueuse/core').useDeviceOrientation
|
||||||
const useDisplayMedia: typeof import('@vueuse/core')['useDisplayMedia']
|
const useDevicePixelRatio: typeof import('@vueuse/core').useDevicePixelRatio
|
||||||
const useDocumentVisibility: typeof import('@vueuse/core')['useDocumentVisibility']
|
const useDevicesList: typeof import('@vueuse/core').useDevicesList
|
||||||
const useDraggable: typeof import('@vueuse/core')['useDraggable']
|
const useDisplayMedia: typeof import('@vueuse/core').useDisplayMedia
|
||||||
const useDropZone: typeof import('@vueuse/core')['useDropZone']
|
const useDocumentVisibility: typeof import('@vueuse/core').useDocumentVisibility
|
||||||
const useElementBounding: typeof import('@vueuse/core')['useElementBounding']
|
const useDraggable: typeof import('@vueuse/core').useDraggable
|
||||||
const useElementByPoint: typeof import('@vueuse/core')['useElementByPoint']
|
const useDropZone: typeof import('@vueuse/core').useDropZone
|
||||||
const useElementHover: typeof import('@vueuse/core')['useElementHover']
|
const useElementBounding: typeof import('@vueuse/core').useElementBounding
|
||||||
const useElementSize: typeof import('@vueuse/core')['useElementSize']
|
const useElementByPoint: typeof import('@vueuse/core').useElementByPoint
|
||||||
const useElementVisibility: typeof import('@vueuse/core')['useElementVisibility']
|
const useElementHover: typeof import('@vueuse/core').useElementHover
|
||||||
const useEventBus: typeof import('@vueuse/core')['useEventBus']
|
const useElementSize: typeof import('@vueuse/core').useElementSize
|
||||||
const useEventListener: typeof import('@vueuse/core')['useEventListener']
|
const useElementVisibility: typeof import('@vueuse/core').useElementVisibility
|
||||||
const useEventSource: typeof import('@vueuse/core')['useEventSource']
|
const useEventBus: typeof import('@vueuse/core').useEventBus
|
||||||
const useEyeDropper: typeof import('@vueuse/core')['useEyeDropper']
|
const useEventListener: typeof import('@vueuse/core').useEventListener
|
||||||
const useFavicon: typeof import('@vueuse/core')['useFavicon']
|
const useEventSource: typeof import('@vueuse/core').useEventSource
|
||||||
const useFetch: typeof import('@vueuse/core')['useFetch']
|
const useEyeDropper: typeof import('@vueuse/core').useEyeDropper
|
||||||
const useFileDialog: typeof import('@vueuse/core')['useFileDialog']
|
const useFavicon: typeof import('@vueuse/core').useFavicon
|
||||||
const useFileSystemAccess: typeof import('@vueuse/core')['useFileSystemAccess']
|
const useFetch: typeof import('@vueuse/core').useFetch
|
||||||
const useFocus: typeof import('@vueuse/core')['useFocus']
|
const useFileDialog: typeof import('@vueuse/core').useFileDialog
|
||||||
const useFocusWithin: typeof import('@vueuse/core')['useFocusWithin']
|
const useFileSystemAccess: typeof import('@vueuse/core').useFileSystemAccess
|
||||||
const useFps: typeof import('@vueuse/core')['useFps']
|
const useFocus: typeof import('@vueuse/core').useFocus
|
||||||
const useFullscreen: typeof import('@vueuse/core')['useFullscreen']
|
const useFocusWithin: typeof import('@vueuse/core').useFocusWithin
|
||||||
const useGamepad: typeof import('@vueuse/core')['useGamepad']
|
const useFps: typeof import('@vueuse/core').useFps
|
||||||
const useGeolocation: typeof import('@vueuse/core')['useGeolocation']
|
const useFullscreen: typeof import('@vueuse/core').useFullscreen
|
||||||
const useIdle: typeof import('@vueuse/core')['useIdle']
|
const useGamepad: typeof import('@vueuse/core').useGamepad
|
||||||
const useImage: typeof import('@vueuse/core')['useImage']
|
const useGeolocation: typeof import('@vueuse/core').useGeolocation
|
||||||
const useInfiniteScroll: typeof import('@vueuse/core')['useInfiniteScroll']
|
const useId: typeof import('vue').useId
|
||||||
const useIntersectionObserver: typeof import('@vueuse/core')['useIntersectionObserver']
|
const useIdle: typeof import('@vueuse/core').useIdle
|
||||||
const useInterval: typeof import('@vueuse/core')['useInterval']
|
const useImage: typeof import('@vueuse/core').useImage
|
||||||
const useIntervalFn: typeof import('@vueuse/core')['useIntervalFn']
|
const useInfiniteScroll: typeof import('@vueuse/core').useInfiniteScroll
|
||||||
const useKeyModifier: typeof import('@vueuse/core')['useKeyModifier']
|
const useIntersectionObserver: typeof import('@vueuse/core').useIntersectionObserver
|
||||||
const useLastChanged: typeof import('@vueuse/core')['useLastChanged']
|
const useInterval: typeof import('@vueuse/core').useInterval
|
||||||
const useLink: typeof import('vue-router')['useLink']
|
const useIntervalFn: typeof import('@vueuse/core').useIntervalFn
|
||||||
const useLocalStorage: typeof import('@vueuse/core')['useLocalStorage']
|
const useKeyModifier: typeof import('@vueuse/core').useKeyModifier
|
||||||
const useMagicKeys: typeof import('@vueuse/core')['useMagicKeys']
|
const useLastChanged: typeof import('@vueuse/core').useLastChanged
|
||||||
const useManualRefHistory: typeof import('@vueuse/core')['useManualRefHistory']
|
const useLink: typeof import('vue-router').useLink
|
||||||
const useMediaControls: typeof import('@vueuse/core')['useMediaControls']
|
const useLocalStorage: typeof import('@vueuse/core').useLocalStorage
|
||||||
const useMediaQuery: typeof import('@vueuse/core')['useMediaQuery']
|
const useMagicKeys: typeof import('@vueuse/core').useMagicKeys
|
||||||
const useMemoize: typeof import('@vueuse/core')['useMemoize']
|
const useManualRefHistory: typeof import('@vueuse/core').useManualRefHistory
|
||||||
const useMemory: typeof import('@vueuse/core')['useMemory']
|
const useMediaControls: typeof import('@vueuse/core').useMediaControls
|
||||||
const useMounted: typeof import('@vueuse/core')['useMounted']
|
const useMediaQuery: typeof import('@vueuse/core').useMediaQuery
|
||||||
const useMouse: typeof import('@vueuse/core')['useMouse']
|
const useMemoize: typeof import('@vueuse/core').useMemoize
|
||||||
const useMouseInElement: typeof import('@vueuse/core')['useMouseInElement']
|
const useMemory: typeof import('@vueuse/core').useMemory
|
||||||
const useMousePressed: typeof import('@vueuse/core')['useMousePressed']
|
const useModel: typeof import('vue').useModel
|
||||||
const useMutationObserver: typeof import('@vueuse/core')['useMutationObserver']
|
const useMounted: typeof import('@vueuse/core').useMounted
|
||||||
const useNavigatorLanguage: typeof import('@vueuse/core')['useNavigatorLanguage']
|
const useMouse: typeof import('@vueuse/core').useMouse
|
||||||
const useNetwork: typeof import('@vueuse/core')['useNetwork']
|
const useMouseInElement: typeof import('@vueuse/core').useMouseInElement
|
||||||
const useNow: typeof import('@vueuse/core')['useNow']
|
const useMousePressed: typeof import('@vueuse/core').useMousePressed
|
||||||
const useObjectUrl: typeof import('@vueuse/core')['useObjectUrl']
|
const useMutationObserver: typeof import('@vueuse/core').useMutationObserver
|
||||||
const useOffsetPagination: typeof import('@vueuse/core')['useOffsetPagination']
|
const useNavigatorLanguage: typeof import('@vueuse/core').useNavigatorLanguage
|
||||||
const useOnline: typeof import('@vueuse/core')['useOnline']
|
const useNetwork: typeof import('@vueuse/core').useNetwork
|
||||||
const usePageLeave: typeof import('@vueuse/core')['usePageLeave']
|
const useNow: typeof import('@vueuse/core').useNow
|
||||||
const useParallax: typeof import('@vueuse/core')['useParallax']
|
const useObjectUrl: typeof import('@vueuse/core').useObjectUrl
|
||||||
const useParentElement: typeof import('@vueuse/core')['useParentElement']
|
const useOffsetPagination: typeof import('@vueuse/core').useOffsetPagination
|
||||||
const usePerformanceObserver: typeof import('@vueuse/core')['usePerformanceObserver']
|
const useOnline: typeof import('@vueuse/core').useOnline
|
||||||
const usePermission: typeof import('@vueuse/core')['usePermission']
|
const usePageLeave: typeof import('@vueuse/core').usePageLeave
|
||||||
const usePointer: typeof import('@vueuse/core')['usePointer']
|
const useParallax: typeof import('@vueuse/core').useParallax
|
||||||
const usePointerLock: typeof import('@vueuse/core')['usePointerLock']
|
const useParentElement: typeof import('@vueuse/core').useParentElement
|
||||||
const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe']
|
const usePerformanceObserver: typeof import('@vueuse/core').usePerformanceObserver
|
||||||
const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme']
|
const usePermission: typeof import('@vueuse/core').usePermission
|
||||||
const usePreferredContrast: typeof import('@vueuse/core')['usePreferredContrast']
|
const usePointer: typeof import('@vueuse/core').usePointer
|
||||||
const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark']
|
const usePointerLock: typeof import('@vueuse/core').usePointerLock
|
||||||
const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages']
|
const usePointerSwipe: typeof import('@vueuse/core').usePointerSwipe
|
||||||
const usePreferredReducedMotion: typeof import('@vueuse/core')['usePreferredReducedMotion']
|
const usePreferredColorScheme: typeof import('@vueuse/core').usePreferredColorScheme
|
||||||
const usePrevious: typeof import('@vueuse/core')['usePrevious']
|
const usePreferredContrast: typeof import('@vueuse/core').usePreferredContrast
|
||||||
const useRafFn: typeof import('@vueuse/core')['useRafFn']
|
const usePreferredDark: typeof import('@vueuse/core').usePreferredDark
|
||||||
const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
|
const usePreferredLanguages: typeof import('@vueuse/core').usePreferredLanguages
|
||||||
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
|
const usePreferredReducedMotion: typeof import('@vueuse/core').usePreferredReducedMotion
|
||||||
const useRoute: typeof import('vue-router')['useRoute']
|
const usePreferredReducedTransparency: typeof import('@vueuse/core').usePreferredReducedTransparency
|
||||||
const useRouter: typeof import('vue-router')['useRouter']
|
const usePrevious: typeof import('@vueuse/core').usePrevious
|
||||||
const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation']
|
const useRafFn: typeof import('@vueuse/core').useRafFn
|
||||||
const useScreenSafeArea: typeof import('@vueuse/core')['useScreenSafeArea']
|
const useRefHistory: typeof import('@vueuse/core').useRefHistory
|
||||||
const useScriptTag: typeof import('@vueuse/core')['useScriptTag']
|
const useResizeObserver: typeof import('@vueuse/core').useResizeObserver
|
||||||
const useScroll: typeof import('@vueuse/core')['useScroll']
|
const useRoute: typeof import('vue-router').useRoute
|
||||||
const useScrollLock: typeof import('@vueuse/core')['useScrollLock']
|
const useRouter: typeof import('vue-router').useRouter
|
||||||
const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage']
|
const useSSRWidth: typeof import('@vueuse/core').useSSRWidth
|
||||||
const useShare: typeof import('@vueuse/core')['useShare']
|
const useScreenOrientation: typeof import('@vueuse/core').useScreenOrientation
|
||||||
const useSlots: typeof import('vue')['useSlots']
|
const useScreenSafeArea: typeof import('@vueuse/core').useScreenSafeArea
|
||||||
const useSorted: typeof import('@vueuse/core')['useSorted']
|
const useScriptTag: typeof import('@vueuse/core').useScriptTag
|
||||||
const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition']
|
const useScroll: typeof import('@vueuse/core').useScroll
|
||||||
const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis']
|
const useScrollLock: typeof import('@vueuse/core').useScrollLock
|
||||||
const useStepper: typeof import('@vueuse/core')['useStepper']
|
const useSessionStorage: typeof import('@vueuse/core').useSessionStorage
|
||||||
const useStorage: typeof import('@vueuse/core')['useStorage']
|
const useShare: typeof import('@vueuse/core').useShare
|
||||||
const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync']
|
const useSlots: typeof import('vue').useSlots
|
||||||
const useStyleTag: typeof import('@vueuse/core')['useStyleTag']
|
const useSorted: typeof import('@vueuse/core').useSorted
|
||||||
const useSupported: typeof import('@vueuse/core')['useSupported']
|
const useSpeechRecognition: typeof import('@vueuse/core').useSpeechRecognition
|
||||||
const useSwipe: typeof import('@vueuse/core')['useSwipe']
|
const useSpeechSynthesis: typeof import('@vueuse/core').useSpeechSynthesis
|
||||||
const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList']
|
const useStepper: typeof import('@vueuse/core').useStepper
|
||||||
const useTextDirection: typeof import('@vueuse/core')['useTextDirection']
|
const useStorage: typeof import('@vueuse/core').useStorage
|
||||||
const useTextSelection: typeof import('@vueuse/core')['useTextSelection']
|
const useStorageAsync: typeof import('@vueuse/core').useStorageAsync
|
||||||
const useTextareaAutosize: typeof import('@vueuse/core')['useTextareaAutosize']
|
const useStyleTag: typeof import('@vueuse/core').useStyleTag
|
||||||
const useThrottle: typeof import('@vueuse/core')['useThrottle']
|
const useSupported: typeof import('@vueuse/core').useSupported
|
||||||
const useThrottleFn: typeof import('@vueuse/core')['useThrottleFn']
|
const useSwipe: typeof import('@vueuse/core').useSwipe
|
||||||
const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory']
|
const useTemplateRef: typeof import('vue').useTemplateRef
|
||||||
const useTimeAgo: typeof import('@vueuse/core')['useTimeAgo']
|
const useTemplateRefsList: typeof import('@vueuse/core').useTemplateRefsList
|
||||||
const useTimeout: typeof import('@vueuse/core')['useTimeout']
|
const useTextDirection: typeof import('@vueuse/core').useTextDirection
|
||||||
const useTimeoutFn: typeof import('@vueuse/core')['useTimeoutFn']
|
const useTextSelection: typeof import('@vueuse/core').useTextSelection
|
||||||
const useTimeoutPoll: typeof import('@vueuse/core')['useTimeoutPoll']
|
const useTextareaAutosize: typeof import('@vueuse/core').useTextareaAutosize
|
||||||
const useTimestamp: typeof import('@vueuse/core')['useTimestamp']
|
const useThrottle: typeof import('@vueuse/core').useThrottle
|
||||||
const useTitle: typeof import('@vueuse/core')['useTitle']
|
const useThrottleFn: typeof import('@vueuse/core').useThrottleFn
|
||||||
const useToNumber: typeof import('@vueuse/core')['useToNumber']
|
const useThrottledRefHistory: typeof import('@vueuse/core').useThrottledRefHistory
|
||||||
const useToString: typeof import('@vueuse/core')['useToString']
|
const useTimeAgo: typeof import('@vueuse/core').useTimeAgo
|
||||||
const useToggle: typeof import('@vueuse/core')['useToggle']
|
const useTimeAgoIntl: typeof import('@vueuse/core').useTimeAgoIntl
|
||||||
const useTransition: typeof import('@vueuse/core')['useTransition']
|
const useTimeout: typeof import('@vueuse/core').useTimeout
|
||||||
const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams']
|
const useTimeoutFn: typeof import('@vueuse/core').useTimeoutFn
|
||||||
const useUserMedia: typeof import('@vueuse/core')['useUserMedia']
|
const useTimeoutPoll: typeof import('@vueuse/core').useTimeoutPoll
|
||||||
const useVModel: typeof import('@vueuse/core')['useVModel']
|
const useTimestamp: typeof import('@vueuse/core').useTimestamp
|
||||||
const useVModels: typeof import('@vueuse/core')['useVModels']
|
const useTitle: typeof import('@vueuse/core').useTitle
|
||||||
const useVibrate: typeof import('@vueuse/core')['useVibrate']
|
const useToNumber: typeof import('@vueuse/core').useToNumber
|
||||||
const useVirtualList: typeof import('@vueuse/core')['useVirtualList']
|
const useToString: typeof import('@vueuse/core').useToString
|
||||||
const useWakeLock: typeof import('@vueuse/core')['useWakeLock']
|
const useToggle: typeof import('@vueuse/core').useToggle
|
||||||
const useWebNotification: typeof import('@vueuse/core')['useWebNotification']
|
const useTransition: typeof import('@vueuse/core').useTransition
|
||||||
const useWebSocket: typeof import('@vueuse/core')['useWebSocket']
|
const useUrlSearchParams: typeof import('@vueuse/core').useUrlSearchParams
|
||||||
const useWebWorker: typeof import('@vueuse/core')['useWebWorker']
|
const useUserMedia: typeof import('@vueuse/core').useUserMedia
|
||||||
const useWebWorkerFn: typeof import('@vueuse/core')['useWebWorkerFn']
|
const useVModel: typeof import('@vueuse/core').useVModel
|
||||||
const useWindowFocus: typeof import('@vueuse/core')['useWindowFocus']
|
const useVModels: typeof import('@vueuse/core').useVModels
|
||||||
const useWindowScroll: typeof import('@vueuse/core')['useWindowScroll']
|
const useVibrate: typeof import('@vueuse/core').useVibrate
|
||||||
const useWindowSize: typeof import('@vueuse/core')['useWindowSize']
|
const useVirtualList: typeof import('@vueuse/core').useVirtualList
|
||||||
const watch: typeof import('vue')['watch']
|
const useWakeLock: typeof import('@vueuse/core').useWakeLock
|
||||||
const watchArray: typeof import('@vueuse/core')['watchArray']
|
const useWebNotification: typeof import('@vueuse/core').useWebNotification
|
||||||
const watchAtMost: typeof import('@vueuse/core')['watchAtMost']
|
const useWebSocket: typeof import('@vueuse/core').useWebSocket
|
||||||
const watchDebounced: typeof import('@vueuse/core')['watchDebounced']
|
const useWebWorker: typeof import('@vueuse/core').useWebWorker
|
||||||
const watchDeep: typeof import('@vueuse/core')['watchDeep']
|
const useWebWorkerFn: typeof import('@vueuse/core').useWebWorkerFn
|
||||||
const watchEffect: typeof import('vue')['watchEffect']
|
const useWindowFocus: typeof import('@vueuse/core').useWindowFocus
|
||||||
const watchIgnorable: typeof import('@vueuse/core')['watchIgnorable']
|
const useWindowScroll: typeof import('@vueuse/core').useWindowScroll
|
||||||
const watchImmediate: typeof import('@vueuse/core')['watchImmediate']
|
const useWindowSize: typeof import('@vueuse/core').useWindowSize
|
||||||
const watchOnce: typeof import('@vueuse/core')['watchOnce']
|
const watch: typeof import('vue').watch
|
||||||
const watchPausable: typeof import('@vueuse/core')['watchPausable']
|
const watchArray: typeof import('@vueuse/core').watchArray
|
||||||
const watchPostEffect: typeof import('vue')['watchPostEffect']
|
const watchAtMost: typeof import('@vueuse/core').watchAtMost
|
||||||
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
|
const watchDebounced: typeof import('@vueuse/core').watchDebounced
|
||||||
const watchThrottled: typeof import('@vueuse/core')['watchThrottled']
|
const watchDeep: typeof import('@vueuse/core').watchDeep
|
||||||
const watchTriggerable: typeof import('@vueuse/core')['watchTriggerable']
|
const watchEffect: typeof import('vue').watchEffect
|
||||||
const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter']
|
const watchIgnorable: typeof import('@vueuse/core').watchIgnorable
|
||||||
const whenever: typeof import('@vueuse/core')['whenever']
|
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
|
// for type re-export
|
||||||
declare global {
|
declare global {
|
||||||
// @ts-ignore
|
// @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')
|
import('vue')
|
||||||
}
|
}
|
||||||
|
|||||||
@ -75,9 +75,9 @@ export default defineConfig({
|
|||||||
// 因此无法生成对应的 CSS。为了解决这个问题,你可以使用 UnoCSS 的 safelist 选项来指定一些始终需要生成的 CSS 类。
|
// 因此无法生成对应的 CSS。为了解决这个问题,你可以使用 UnoCSS 的 safelist 选项来指定一些始终需要生成的 CSS 类。
|
||||||
// https://unocss.dev/guide/advanced#safelist
|
// https://unocss.dev/guide/advanced#safelist
|
||||||
safelist: [
|
safelist: [
|
||||||
'i-simple-icons:atlassian',
|
'i-ph:house',
|
||||||
'i-simple-icons:soundcharts',
|
'i-ph:chart-line',
|
||||||
'i-simple-icons:docsify',
|
'i-ph:code',
|
||||||
'i-material-symbols:award-star',
|
'i-ph:user',
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|||||||
@ -69,16 +69,17 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
|||||||
__APP_INFO__: JSON.stringify(__APP_INFO__),
|
__APP_INFO__: JSON.stringify(__APP_INFO__),
|
||||||
},
|
},
|
||||||
|
|
||||||
esbuild: {
|
|
||||||
// 使用 esbuild 压缩 剔除 console.log
|
|
||||||
drop: VITE_DROP_CONSOLE ? ['debugger', 'console'] : [],
|
|
||||||
// minify: true, // minify: true, 等于 minify: 'esbuild',
|
|
||||||
},
|
|
||||||
|
|
||||||
build: {
|
build: {
|
||||||
// 设置最终构建的浏览器兼容目标
|
// 设置最终构建的浏览器兼容目标
|
||||||
target: 'es2015',
|
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 文件(用于线上报错代码报错映射对应代码)
|
// 构建后是否生成 source map 文件(用于线上报错代码报错映射对应代码)
|
||||||
sourcemap: false,
|
sourcemap: false,
|
||||||
cssTarget: 'chrome80',
|
cssTarget: 'chrome80',
|
||||||
@ -98,8 +99,8 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
|||||||
reportCompressedSize: true,
|
reportCompressedSize: true,
|
||||||
// chunk 大小警告的限制(以 kbs 为单位)
|
// chunk 大小警告的限制(以 kbs 为单位)
|
||||||
chunkSizeWarningLimit: 2000,
|
chunkSizeWarningLimit: 2000,
|
||||||
// 自定义底层的 Rollup 打包配置
|
// 自定义底层的 Rolldown 打包配置
|
||||||
rollupOptions: {
|
rolldownOptions: {
|
||||||
// 静态资源分类打包
|
// 静态资源分类打包
|
||||||
output: {
|
output: {
|
||||||
chunkFileNames: 'js/[name]-[hash].js', // 引入文件名的名称
|
chunkFileNames: 'js/[name]-[hash].js', // 引入文件名的名称
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user