feat: New layout system (#62)
This commit is contained in:
parent
08a0b2571b
commit
c776f49d8c
|
|
@ -34,6 +34,8 @@
|
|||
|
||||
- 🍍 [State Management via Pinia](https://pinia.vuejs.org)
|
||||
|
||||
- 📑 [Layout system](./src/layouts)
|
||||
|
||||
- 🎨 [UnoCSS](https://github.com/antfu/unocss) - the instant on-demand atomic CSS engine
|
||||
|
||||
- 🔥 Use the [new `<script setup>` syntax](https://github.com/vuejs/rfcs/pull/227)
|
||||
|
|
@ -79,6 +81,7 @@
|
|||
|
||||
- [Vue Router](https://github.com/vuejs/router)
|
||||
- [`unplugin-vue-router`](https://github.com/posva/unplugin-vue-router) - file system based routing
|
||||
- [`vite-plugin-vue-layouts`](https://github.com/JohnCampionJr/vite-plugin-vue-layouts) - layouts for pages
|
||||
- [Pinia](https://pinia.vuejs.org) - Intuitive, type safe, light and flexible Store for Vue using the composition api
|
||||
- [`pinia-plugin-persistedstate`](https://github.com/prazdevs/pinia-plugin-persistedstate) - Configurable persistence and rehydration of Pinia stores
|
||||
- [unplugin-vue-components](https://github.com/antfu/unplugin-vue-components) - components auto import
|
||||
|
|
@ -86,6 +89,9 @@
|
|||
- [vite-plugin-vconsole](https://github.com/vadxq/vite-plugin-vconsole) - A lightweight, extendable front-end developer tool for mobile web page
|
||||
- [vite-plugin-mock-dev-server](https://github.com/pengzhanbo/vite-plugin-mock-dev-server) - Vite Plugin for API mock dev server
|
||||
- [postcss-mobile-forever](https://github.com/wswmsword/postcss-mobile-forever) - To adapt different displays by one mobile viewport
|
||||
- [vite-plugin-vue-devtools](https://github.com/vuejs/devtools-next) - Designed to enhance the Vue developer experience
|
||||
- [vueuse](https://github.com/antfu/vueuse) - collection of useful composition APIs
|
||||
- [@unhead/vue](https://github.com/unjs/unhead) - manipulate document head reactively
|
||||
|
||||
### Coding Style
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@
|
|||
|
||||
- 🍍 [使用 Pinia 的状态管理](https://pinia.vuejs.org)
|
||||
|
||||
- 📑 [布局系统](./src/layouts)
|
||||
|
||||
- 🎨 [UnoCSS](https://github.com/antfu/unocss) - 高性能且极具灵活性的即时原子化 CSS 引擎
|
||||
|
||||
- 🔥 使用 [新的 `<script setup>` 语法](https://github.com/vuejs/rfcs/pull/227)
|
||||
|
|
@ -79,6 +81,7 @@
|
|||
|
||||
- [Vue Router](https://github.com/vuejs/router)
|
||||
- [`unplugin-vue-router`](https://github.com/posva/unplugin-vue-router) - 以文件系统为基础的路由
|
||||
- [`vite-plugin-vue-layouts`](https://github.com/JohnCampionJr/vite-plugin-vue-layouts) - 页面布局系统
|
||||
- [Pinia](https://pinia.vuejs.org) - 直接的, 类型安全的, 使用 Composition API 的轻便灵活的 Vue 状态管理库
|
||||
- [`pinia-plugin-persistedstate`](https://github.com/prazdevs/pinia-plugin-persistedstate) - 适用于 Pinia 的持久化存储插件
|
||||
- [unplugin-vue-components](https://github.com/antfu/unplugin-vue-components) - 自动加载组件
|
||||
|
|
@ -86,6 +89,9 @@
|
|||
- [vite-plugin-vconsole](https://github.com/vadxq/vite-plugin-vconsole) - vConsole 的 vite 插件
|
||||
- [vite-plugin-mock-dev-server](https://github.com/pengzhanbo/vite-plugin-mock-dev-server) - vite mock 开发服务(mock-dev-server)插件
|
||||
- [postcss-mobile-forever](https://github.com/wswmsword/postcss-mobile-forever) - 一款 PostCSS 插件,将固定尺寸的移动端视图转为具有最大宽度的可伸缩的移动端视图
|
||||
- [vite-plugin-vue-devtools](https://github.com/vuejs/devtools-next) - 旨在增强Vue开发者体验的Vite插件
|
||||
- [vueuse](https://github.com/antfu/vueuse) - 实用的 Composition API 工具合集
|
||||
- [@unhead/vue](https://github.com/unjs/unhead) - 响应式地操作文档头信息
|
||||
|
||||
### 编码风格
|
||||
|
||||
|
|
|
|||
|
|
@ -10,26 +10,28 @@ import { VantResolver } from 'unplugin-vue-components/resolvers'
|
|||
import { unheadVueComposablesImports } from '@unhead/vue'
|
||||
import VueDevTools from 'vite-plugin-vue-devtools'
|
||||
import mockDevServerPlugin from 'vite-plugin-mock-dev-server'
|
||||
import Layouts from 'vite-plugin-vue-layouts'
|
||||
import UnoCSS from 'unocss/vite'
|
||||
import { createViteVConsole } from './vconsole'
|
||||
|
||||
export function createVitePlugins() {
|
||||
return [
|
||||
// https://github.com/posva/unplugin-vue-router
|
||||
VueRouter({
|
||||
routesFolder: 'src/views',
|
||||
extensions: ['.vue'],
|
||||
routesFolder: 'src/pages',
|
||||
dts: 'src/typed-router.d.ts',
|
||||
}),
|
||||
|
||||
vue(),
|
||||
vueJsx(),
|
||||
visualizer(),
|
||||
UnoCSS(),
|
||||
|
||||
// https://github.com/JohnCampionJr/vite-plugin-vue-layouts
|
||||
Layouts(),
|
||||
|
||||
// https://github.com/pengzhanbo/vite-plugin-mock-dev-server
|
||||
mockDevServerPlugin(),
|
||||
|
||||
legacy({
|
||||
targets: ['defaults', 'not IE 11'],
|
||||
}),
|
||||
|
||||
// https://github.com/antfu/unplugin-vue-components
|
||||
Components({
|
||||
extensions: ['vue'],
|
||||
resolvers: [VantResolver()],
|
||||
|
|
@ -37,6 +39,7 @@ export function createVitePlugins() {
|
|||
dts: 'src/components.d.ts',
|
||||
}),
|
||||
|
||||
// https://github.com/antfu/unplugin-auto-import
|
||||
AutoImport({
|
||||
include: [
|
||||
/\.[tj]sx?$/,
|
||||
|
|
@ -59,8 +62,21 @@ export function createVitePlugins() {
|
|||
],
|
||||
}),
|
||||
|
||||
// https://github.com/antfu/unocss
|
||||
// see uno.config.ts for config
|
||||
UnoCSS(),
|
||||
|
||||
// https://github.com/vadxq/vite-plugin-vconsole
|
||||
createViteVConsole(),
|
||||
|
||||
// https://github.com/webfansplz/vite-plugin-vue-devtools
|
||||
VueDevTools(),
|
||||
|
||||
vueJsx(),
|
||||
visualizer(),
|
||||
|
||||
legacy({
|
||||
targets: ['defaults', 'not IE 11'],
|
||||
}),
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@
|
|||
"vite-plugin-mock-dev-server": "^1.4.7",
|
||||
"vite-plugin-vconsole": "^2.1.1",
|
||||
"vite-plugin-vue-devtools": "^7.0.14",
|
||||
"vite-plugin-vue-layouts": "^0.11.0",
|
||||
"vitest": "^1.2.2",
|
||||
"vue-tsc": "^1.8.27"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -154,6 +154,9 @@ devDependencies:
|
|||
vite-plugin-vue-devtools:
|
||||
specifier: ^7.0.14
|
||||
version: 7.0.14(rollup@4.9.6)(vite@5.0.12)
|
||||
vite-plugin-vue-layouts:
|
||||
specifier: ^0.11.0
|
||||
version: 0.11.0(vite@5.0.12)(vue-router@4.2.5)(vue@3.4.15)
|
||||
vitest:
|
||||
specifier: ^1.2.2
|
||||
version: 1.2.2(@types/node@20.11.16)(less@4.2.0)(terser@5.27.0)
|
||||
|
|
@ -7385,6 +7388,22 @@ packages:
|
|||
- supports-color
|
||||
dev: true
|
||||
|
||||
/vite-plugin-vue-layouts@0.11.0(vite@5.0.12)(vue-router@4.2.5)(vue@3.4.15):
|
||||
resolution: {integrity: sha512-uh6NW7lt+aOXujK4eHfiNbeo55K9OTuB7fnv+5RVc4OBn/cZull6ThXdYH03JzKanUfgt6QZ37NbbtJ0og59qw==}
|
||||
peerDependencies:
|
||||
vite: ^4.0.0 || ^5.0.0
|
||||
vue: ^3.2.4
|
||||
vue-router: ^4.0.11
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
fast-glob: 3.3.2
|
||||
vite: 5.0.12(@types/node@20.11.16)(less@4.2.0)(terser@5.27.0)
|
||||
vue: 3.4.15(typescript@5.3.3)
|
||||
vue-router: 4.2.5(vue@3.4.15)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/vite@5.0.12(@types/node@20.11.16)(less@4.2.0)(terser@5.27.0):
|
||||
resolution: {integrity: sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ declare module 'vue' {
|
|||
VanCellGroup: typeof import('vant/es')['CellGroup']
|
||||
VanConfigProvider: typeof import('vant/es')['ConfigProvider']
|
||||
VanEmpty: typeof import('vant/es')['Empty']
|
||||
VanIcon: typeof import('vant/es')['Icon']
|
||||
VanNavBar: typeof import('vant/es')['NavBar']
|
||||
VanSpace: typeof import('vant/es')['Space']
|
||||
VanSwitch: typeof import('vant/es')['Switch']
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<main class="h-full w-full p-16 py-60">
|
||||
<div class="p-16 py-60">
|
||||
<slot />
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
<script setup lang="ts">
|
||||
const router = useRouter()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main p="x4 y16" text-18 text="center gray-300 dark:gray-200">
|
||||
<van-icon name="warn-o" size="3em" />
|
||||
|
||||
<RouterView />
|
||||
|
||||
<div class="mt-10">
|
||||
<button van-haptics-feedback btn m="3 t8" @click="router.back()">
|
||||
Back
|
||||
</button>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
# Layouts
|
||||
|
||||
Vue components in this dir are used as layouts.
|
||||
|
||||
By default, `default.vue` will be used unless an alternative is specified in the route meta.
|
||||
|
||||
With [`unplugin-vue-router`](https://github.com/posva/unplugin-vue-router) and [`vite-plugin-vue-layouts`](https://github.com/JohnCampionJr/vite-plugin-vue-layouts), you can specify the layout in the page's SFCs like this:
|
||||
|
||||
```vue
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: home
|
||||
</route>
|
||||
```
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<template>
|
||||
<main text="gray-700 dark:gray-200">
|
||||
<RouterView />
|
||||
|
||||
<div mx-auto mt-15 text-center text-14 opacity-50>
|
||||
Default Layout
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<template>
|
||||
<main py-20 text="gray-700 dark:gray-200">
|
||||
<RouterView />
|
||||
|
||||
<div mx-auto mt-15 text-center text-14 opacity-50>
|
||||
Home Layout
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<template>
|
||||
<div>
|
||||
Not found
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: 404
|
||||
</route>
|
||||
|
|
@ -21,7 +21,7 @@ const onClickLeft = () => history.back()
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-full w-full">
|
||||
<div>
|
||||
<VanNavBar title="🍍 持久化 Pinia 状态" left-arrow fixed @click-left="onClickLeft" />
|
||||
|
||||
<Container>
|
||||
|
|
@ -35,7 +35,7 @@ const onClickLeft = () => history.back()
|
|||
<p class="mt-4">
|
||||
number:<strong class="text-green-500"> {{ counter }} </strong>
|
||||
</p>
|
||||
<button class="btn border-none btn-green" @click="add">
|
||||
<button class="btn" @click="add">
|
||||
Add
|
||||
</button>
|
||||
</Container>
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<script setup lang="ts">
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
|
||||
definePage({
|
||||
name: 'main',
|
||||
meta: {
|
||||
level: 1,
|
||||
},
|
||||
})
|
||||
|
||||
const appStore = useAppStore()
|
||||
const checked = ref<boolean>(isDark.value)
|
||||
|
||||
watch(
|
||||
() => isDark.value,
|
||||
(newMode) => {
|
||||
checked.value = newMode
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
function toggle() {
|
||||
toggleDark()
|
||||
appStore.swithMode(isDark.value ? 'dark' : 'light')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VanCellGroup inset>
|
||||
<VanCell center title="🌗 暗黑模式">
|
||||
<template #right-icon>
|
||||
<VanSwitch v-model="checked" size="20px" @click="toggle()" />
|
||||
</template>
|
||||
</VanCell>
|
||||
|
||||
<VanCell title="💿 Mock 指南" to="mock" is-link />
|
||||
<VanCell title="📊 Echarts 演示" to="charts" is-link />
|
||||
<VanCell title="🎨 Unocss 示例" to="unocss" is-link />
|
||||
<VanCell title="🍍 持久化 Pinia 状态" to="counter" is-link />
|
||||
<VanCell title="🙅 404 演示" to="unknown" is-link />
|
||||
|
||||
<VanCell center>
|
||||
<template #title>
|
||||
<span class="mr-4 v-middle">🚀 欢迎补充</span>
|
||||
<VanTag type="primary">
|
||||
PR
|
||||
</VanTag>
|
||||
</template>
|
||||
</VanCell>
|
||||
</VanCellGroup>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: home
|
||||
</route>
|
||||
|
|
@ -24,7 +24,7 @@ const onClickLeft = () => history.back()
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-full w-full">
|
||||
<div>
|
||||
<VanNavBar title="💿 Mock 指南" left-arrow fixed @click-left="onClickLeft" />
|
||||
|
||||
<Container>
|
||||
|
|
@ -11,7 +11,7 @@ const onClickLeft = () => history.back()
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-full w-full">
|
||||
<div>
|
||||
<VanNavBar title="🎨 Unocss" left-arrow fixed @click-left="onClickLeft" />
|
||||
|
||||
<Container>
|
||||
|
|
@ -21,8 +21,8 @@ const onClickLeft = () => history.back()
|
|||
<p class="mt-4 text-gray-700 dark:text-white">
|
||||
This is a simple example of Unocss in action.
|
||||
</p>
|
||||
<button class="btn border-none btn-green">
|
||||
Click me
|
||||
<button class="btn">
|
||||
Button
|
||||
</button>
|
||||
</Container>
|
||||
</div>
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
# `File-based Routing`
|
||||
|
||||
Routes will be auto-generated for Vue files in the **src/views** dir with the same file structure.
|
||||
Routes will be auto-generated for Vue files in the **src/pages** dir with the same file structure.
|
||||
Check out [`unplugin-vue-router`](https://github.com/posva/unplugin-vue-router) for more details.
|
||||
|
||||
在 **src/views** 目录下的 Vue 文件会自动生成相同结构的路由。
|
||||
在 **src/pages** 目录下的 Vue 文件会自动生成相同结构的路由。
|
||||
|
||||
查看[`unplugin-vue-router`](https://github.com/posva/unplugin-vue-router)了解更多细节。
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { createRouter, createWebHistory } from 'vue-router/auto'
|
||||
import { setupLayouts } from 'virtual:generated-layouts'
|
||||
import NProgress from 'nprogress'
|
||||
|
||||
import useRouteTransitionNameStore from '@/stores/modules/routeTransitionName'
|
||||
|
|
@ -8,6 +9,7 @@ NProgress.configure({ showSpinner: true, parent: '#app' })
|
|||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.VITE_APP_PUBLIC_PATH),
|
||||
extendRoutes: routes => setupLayouts(routes),
|
||||
})
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import type {
|
|||
declare module 'vue-router/auto/routes' {
|
||||
export interface RouteNamedMap {
|
||||
'main': RouteRecordInfo<'main', '/', Record<never, never>, Record<never, never>>,
|
||||
'/[...all]': RouteRecordInfo<'/[...all]', '/:all(.*)', { all: ParamValue<true> }, { all: ParamValue<false> }>,
|
||||
'charts': RouteRecordInfo<'charts', '/charts', Record<never, never>, Record<never, never>>,
|
||||
'counter': RouteRecordInfo<'counter', '/counter', Record<never, never>, Record<never, never>>,
|
||||
'mock': RouteRecordInfo<'mock', '/mock', Record<never, never>, Record<never, never>>,
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
|
||||
definePage({
|
||||
name: 'main',
|
||||
meta: {
|
||||
level: 1,
|
||||
},
|
||||
})
|
||||
|
||||
const appStore = useAppStore()
|
||||
const checked = ref<boolean>(isDark.value)
|
||||
|
||||
watch(
|
||||
() => isDark.value,
|
||||
(newMode) => {
|
||||
checked.value = newMode
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
function toggle() {
|
||||
toggleDark()
|
||||
appStore.swithMode(isDark.value ? 'dark' : 'light')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="h-full w-full py-30">
|
||||
<VanCellGroup inset>
|
||||
<VanCell center title="🌗 暗黑模式">
|
||||
<template #right-icon>
|
||||
<VanSwitch v-model="checked" size="20px" @click="toggle()" />
|
||||
</template>
|
||||
</VanCell>
|
||||
|
||||
<VanCell title="💿 Mock 指南" to="mock" is-link />
|
||||
<VanCell title="📊 Echarts 演示" to="charts" is-link />
|
||||
<VanCell title="🎨 Unocss 示例" to="unocss" is-link />
|
||||
<VanCell title="🍍 持久化 Pinia 状态" to="counter" is-link />
|
||||
|
||||
<VanCell center>
|
||||
<template #title>
|
||||
<span class="mr-4 v-middle">🚀 欢迎补充</span>
|
||||
<VanTag type="primary">
|
||||
PR
|
||||
</VanTag>
|
||||
</template>
|
||||
</VanCell>
|
||||
</VanCellGroup>
|
||||
</main>
|
||||
</template>
|
||||
|
|
@ -10,7 +10,11 @@
|
|||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
},
|
||||
"types": ["node"],
|
||||
"types": [
|
||||
"node",
|
||||
"unplugin-vue-router/client",
|
||||
"vite-plugin-vue-layouts/client"
|
||||
],
|
||||
"allowJs": true,
|
||||
"strictNullChecks": false,
|
||||
"noImplicitAny": false,
|
||||
|
|
|
|||
|
|
@ -15,18 +15,10 @@ export default defineConfig({
|
|||
// https://juejin.cn/post/7262975395620618298
|
||||
baseFontSize: 4,
|
||||
}),
|
||||
presetMini({
|
||||
dark: {
|
||||
dark: '.van-theme-dark',
|
||||
light: '.van-theme-light',
|
||||
},
|
||||
}),
|
||||
presetMini(),
|
||||
],
|
||||
shortcuts: {
|
||||
shortcuts: [
|
||||
// shortcuts to multiple utilities
|
||||
'btn': 'py-2 px-4 font-semibold rounded-lg shadow-md',
|
||||
'btn-green': 'text-white bg-green-500 hover:bg-green-700',
|
||||
'btn-blue': 'text-white bg-blue-500 hover:bg-blue-700',
|
||||
'centered': 'absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2',
|
||||
},
|
||||
['btn', 'px-6 py-3 rounded-3 border-none inline-block bg-green-400 text-white cursor-pointer !outline-none hover:bg-green-600 disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50'],
|
||||
],
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue