Compare commits
10 Commits
fb5991f355
...
1156ef497b
| Author | SHA1 | Date |
|---|---|---|
|
|
1156ef497b | |
|
|
831732c719 | |
|
|
24f15fde5c | |
|
|
dd4d5e83f0 | |
|
|
637360f8dc | |
|
|
c489b81c4b | |
|
|
e9913758ba | |
|
|
9157e69046 | |
|
|
131d4e38d4 | |
|
|
0ad1afb26f |
|
|
@ -1 +0,0 @@
|
|||
node scripts/verifyCommit.js
|
||||
|
|
@ -1 +0,0 @@
|
|||
pnpm lint
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
import type { UserConfig } from '@commitlint/types'
|
||||
import { RuleConfigSeverity } from '@commitlint/types'
|
||||
|
||||
const Configuration: UserConfig = {
|
||||
extends: ['@commitlint/config-conventional'],
|
||||
formatter: '@commitlint/format',
|
||||
rules: {
|
||||
'type-enum': [
|
||||
RuleConfigSeverity.Error,
|
||||
'always',
|
||||
[
|
||||
'feat',
|
||||
'fix',
|
||||
'perf',
|
||||
'style',
|
||||
'docs',
|
||||
'test',
|
||||
'refactor',
|
||||
'build',
|
||||
'ci',
|
||||
'chore',
|
||||
'revert',
|
||||
'wip',
|
||||
'workflow',
|
||||
'types',
|
||||
'release',
|
||||
],
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
export default Configuration
|
||||
79
package.json
79
package.json
|
|
@ -1,92 +1,97 @@
|
|||
{
|
||||
"name": "vue3-vant-mobile",
|
||||
"type": "module",
|
||||
"version": "3.5.1",
|
||||
"version": "3.6.0",
|
||||
"packageManager": "pnpm@9.15.4",
|
||||
"description": "An mobile web apps template based on the Vue 3 ecosystem",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"dev": "cross-env MOCK_SERVER_PORT=8086 vite",
|
||||
"build": "vue-tsc --noEmit && vite build",
|
||||
"build:dev": "vue-tsc --noEmit && vite build --mode=development",
|
||||
"preview": "vite preview",
|
||||
"test": "vitest",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix",
|
||||
"test": "vitest",
|
||||
"release": "bumpp --commit --push --tag",
|
||||
"prepare": "husky",
|
||||
"typecheck": "vue-tsc --noEmit"
|
||||
"typecheck": "vue-tsc --noEmit",
|
||||
"commitlint": "commitlint --edit",
|
||||
"prepare": "simple-git-hooks"
|
||||
},
|
||||
"dependencies": {
|
||||
"@unhead/vue": "^1.11.18",
|
||||
"@unhead/vue": "~1.11.19",
|
||||
"@vant/touch-emulator": "^1.4.0",
|
||||
"@vant/use": "^1.6.0",
|
||||
"@vueuse/core": "^12.5.0",
|
||||
"@vueuse/core": "^12.7.0",
|
||||
"axios": "^1.7.9",
|
||||
"echarts": "^5.6.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^2.3.1",
|
||||
"pinia": "^3.0.1",
|
||||
"pinia-plugin-persistedstate": "^4.2.0",
|
||||
"resize-detector": "^0.3.0",
|
||||
"vant": "^4.9.16",
|
||||
"vant": "^4.9.17",
|
||||
"vconsole": "^3.15.1",
|
||||
"vue": "^3.5.13",
|
||||
"vue-i18n": "^11.0.1",
|
||||
"vue-i18n": "^11.1.1",
|
||||
"vue-router": "^4.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "4.1.0",
|
||||
"@iconify-json/carbon": "^1.2.5",
|
||||
"@antfu/eslint-config": "4.3.0",
|
||||
"@commitlint/cli": "^19.7.1",
|
||||
"@commitlint/config-conventional": "^19.7.1",
|
||||
"@commitlint/types": "^19.5.0",
|
||||
"@iconify-json/carbon": "^1.2.7",
|
||||
"@intlify/unplugin-vue-i18n": "^6.0.3",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/node": "^22.10.10",
|
||||
"@types/node": "^22.13.4",
|
||||
"@types/nprogress": "^0.2.3",
|
||||
"@unocss/eslint-plugin": "65.4.3",
|
||||
"@unocss/preset-rem-to-px": "65.4.3",
|
||||
"@unocss/eslint-plugin": "66.0.0",
|
||||
"@unocss/preset-rem-to-px": "66.0.0",
|
||||
"@vant/auto-import-resolver": "^1.2.1",
|
||||
"@vitejs/plugin-legacy": "^6.0.0",
|
||||
"@vitejs/plugin-legacy": "^6.0.1",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"bumpp": "^10.0.1",
|
||||
"bumpp": "^10.0.3",
|
||||
"consola": "^3.4.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^9.19.0",
|
||||
"eslint": "^9.20.1",
|
||||
"eslint-plugin-format": "^1.0.1",
|
||||
"husky": "^9.1.7",
|
||||
"less": "^4.2.2",
|
||||
"lint-staged": "^15.4.3",
|
||||
"mockjs": "^1.1.0",
|
||||
"postcss-mobile-forever": "^4.3.2",
|
||||
"rollup": "^4.32.0",
|
||||
"terser": "^5.37.0",
|
||||
"postcss-mobile-forever": "^4.4.0",
|
||||
"rollup": "^4.34.8",
|
||||
"simple-git-hooks": "^2.11.1",
|
||||
"terser": "^5.39.0",
|
||||
"typescript": "^5.7.3",
|
||||
"unocss": "65.4.3",
|
||||
"unplugin-auto-import": "^19.0.0",
|
||||
"unplugin-vue-components": "^28.0.0",
|
||||
"unocss": "66.0.0",
|
||||
"unplugin-auto-import": "^19.1.0",
|
||||
"unplugin-vue-components": "^28.2.0",
|
||||
"unplugin-vue-router": "^0.11.2",
|
||||
"vite": "^6.0.11",
|
||||
"vite-plugin-mock-dev-server": "^1.8.3",
|
||||
"vite": "^6.1.0",
|
||||
"vite-plugin-mock-dev-server": "^1.8.4",
|
||||
"vite-plugin-pwa": "^0.21.1",
|
||||
"vite-plugin-sitemap": "^0.7.1",
|
||||
"vite-plugin-vconsole": "^2.1.1",
|
||||
"vite-plugin-vue-devtools": "^7.7.1",
|
||||
"vitest": "^3.0.4",
|
||||
"vue-tsc": "^2.2.0"
|
||||
"vite-plugin-vue-devtools": "^7.7.2",
|
||||
"vitest": "^3.0.6",
|
||||
"vue-tsc": "^2.2.2"
|
||||
},
|
||||
"pnpm": {
|
||||
"allowedDeprecatedVersions": {
|
||||
"glob": "7.2.3",
|
||||
"inflight": "1.0.6",
|
||||
"sourcemap-codec": "1.4.8"
|
||||
},
|
||||
"peerDependencyRules": {
|
||||
"allowedVersions": {
|
||||
"@intlify/shared": "^11.x",
|
||||
"vue-i18n": "^11.x"
|
||||
}
|
||||
}
|
||||
},
|
||||
"resolutions": {
|
||||
"vite": "^6.0.11"
|
||||
"vite": "^6.1.0"
|
||||
},
|
||||
"simple-git-hooks": {
|
||||
"pre-commit": "pnpm lint-staged",
|
||||
"commit-msg": "pnpm commitlint $1"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*": "eslint --fix"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
4055
pnpm-lock.yaml
4055
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
|
@ -1,18 +0,0 @@
|
|||
import fs from 'node:fs'
|
||||
import process from 'node:process'
|
||||
|
||||
const msg = fs.readFileSync('.git/COMMIT_EDITMSG', 'utf-8').trim()
|
||||
|
||||
const commitRE = /^(revert: )?(feat|fix|docs|dx|style|refactor|perf|test|workflow|build|ci|chore|types|wip|release)(\(.+\))?: .{1,50}/
|
||||
const mergeRe = /^(Merge pull request|Merge branch)/
|
||||
|
||||
if (!commitRE.test(msg)) {
|
||||
if (!mergeRe.test(msg)) {
|
||||
console.log('git commit unpass')
|
||||
console.error('git commit error, needs title(scope): desc')
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log('git commit pass')
|
||||
}
|
||||
20
src/App.vue
20
src/App.vue
|
|
@ -1,8 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { storeToRefs } from 'pinia'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import useRouteCache from '@/stores/modules/routeCache'
|
||||
import useAutoThemeSwitcher from '@/hooks/useAutoThemeSwitcher'
|
||||
|
||||
useHead({
|
||||
title: 'Vue3 Vant Mobile',
|
||||
|
|
@ -25,23 +22,18 @@ useHead({
|
|||
],
|
||||
})
|
||||
|
||||
const appStore = useAppStore()
|
||||
const { mode } = storeToRefs(appStore)
|
||||
|
||||
const { initializeThemeSwitcher } = useAutoThemeSwitcher(appStore)
|
||||
|
||||
const keepAliveRouteNames = computed(() => {
|
||||
return useRouteCache().routeCaches as string[]
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
initializeThemeSwitcher()
|
||||
const mode = computed(() => {
|
||||
return isDark.value ? 'dark' : 'light'
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VanConfigProvider :theme="mode">
|
||||
<NavBar />
|
||||
<van-config-provider :theme="mode">
|
||||
<nav-bar />
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<section class="app-wrapper">
|
||||
<keep-alive :include="keepAliveRouteNames">
|
||||
|
|
@ -49,8 +41,8 @@ onMounted(() => {
|
|||
</keep-alive>
|
||||
</section>
|
||||
</router-view>
|
||||
<TabBar />
|
||||
</VanConfigProvider>
|
||||
<tab-bar />
|
||||
</van-config-provider>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
const contrastColor = 'rgba(255, 255, 255, 0.65)'
|
||||
const backgroundColor = 'transparent'
|
||||
const axisCommon = function () {
|
||||
function axisCommon() {
|
||||
return {
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
import type { AppStore } from '@/stores/modules/app'
|
||||
|
||||
export default function useAutoThemeSwitcher(appStore: AppStore) {
|
||||
const handleAttributeChange = () => {
|
||||
const rootElement = document.documentElement
|
||||
const mode = rootElement.classList.contains('dark') ? 'dark' : 'light'
|
||||
appStore.switchMode(mode)
|
||||
}
|
||||
|
||||
const observerOptions = {
|
||||
attributes: true,
|
||||
attributeFilter: ['class'],
|
||||
}
|
||||
|
||||
const observer = new MutationObserver(handleAttributeChange)
|
||||
|
||||
const targetElement = document.querySelector('html')
|
||||
|
||||
const initializeThemeSwitcher = () => {
|
||||
observer.observe(targetElement, observerOptions)
|
||||
}
|
||||
|
||||
return { initializeThemeSwitcher }
|
||||
}
|
||||
|
|
@ -1,26 +1,18 @@
|
|||
<script setup lang="ts">
|
||||
import type { PickerColumn } from 'vant'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import { languageColumns, locale } from '@/utils/i18n'
|
||||
|
||||
const appStore = useAppStore()
|
||||
const checked = ref<boolean>(isDark.value)
|
||||
|
||||
watch(
|
||||
() => isDark.value,
|
||||
(newMode) => {
|
||||
checked.value = newMode
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
function toggle() {
|
||||
toggleDark()
|
||||
appStore.switchMode(isDark.value ? 'dark' : 'light')
|
||||
}
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const menuItems = computed(() => ([
|
||||
{ title: t('menus.mockGuide'), route: 'mock' },
|
||||
{ title: t('menus.echartsDemo'), route: 'charts' },
|
||||
{ title: t('menus.unocssExample'), route: 'unocss' },
|
||||
{ title: t('menus.persistPiniaState'), route: 'counter' },
|
||||
{ title: t('menus.keepAlive'), route: 'keepalive' },
|
||||
{ title: t('menus.404Demo'), route: 'unknown' },
|
||||
]))
|
||||
|
||||
const showLanguagePicker = ref(false)
|
||||
const languageValues = ref<Array<string>>([locale.value])
|
||||
const language = computed(() => languageColumns.find(l => l.value === locale.value).text)
|
||||
|
|
@ -30,37 +22,44 @@ function onLanguageConfirm(event: { selectedOptions: PickerColumn }) {
|
|||
showLanguagePicker.value = false
|
||||
}
|
||||
|
||||
const menuItems = computed(() => ([
|
||||
{ title: t('menus.mockGuide'), route: 'mock' },
|
||||
{ title: t('menus.echartsDemo'), route: 'charts' },
|
||||
{ title: t('menus.unocssExample'), route: 'unocss' },
|
||||
{ title: t('menus.persistPiniaState'), route: 'counter' },
|
||||
{ title: t('menus.keepAlive'), route: 'keepalive' },
|
||||
{ title: t('menus.404Demo'), route: 'unknown' },
|
||||
]))
|
||||
const checked = ref<boolean>(isDark.value)
|
||||
|
||||
watchEffect(() => {
|
||||
checked.value = isDark.value
|
||||
})
|
||||
|
||||
function toggle(val: boolean) {
|
||||
checked.value = val
|
||||
toggleDark()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VanCellGroup :title="t('menus.basicSettings')" :border="false" :inset="true">
|
||||
<VanCell center :title="t('menus.darkMode')">
|
||||
<van-cell-group :title="t('menus.basicSettings')" :border="false" :inset="true">
|
||||
<van-cell center :title="t('menus.darkMode')">
|
||||
<template #right-icon>
|
||||
<VanSwitch v-model="checked" size="20px" aria-label="on/off Dark Mode" @click="toggle()" />
|
||||
<van-switch
|
||||
v-model="checked"
|
||||
size="20px"
|
||||
aria-label="on/off Dark Mode"
|
||||
@change="toggle"
|
||||
/>
|
||||
</template>
|
||||
</VanCell>
|
||||
</van-cell>
|
||||
|
||||
<VanCell
|
||||
<van-cell
|
||||
is-link
|
||||
:title="t('menus.language')"
|
||||
:value="language"
|
||||
@click="showLanguagePicker = true"
|
||||
/>
|
||||
</VanCellGroup>
|
||||
</van-cell-group>
|
||||
|
||||
<VanCellGroup :title="t('menus.exampleComponents')" :border="false" :inset="true">
|
||||
<van-cell-group :title="t('menus.exampleComponents')" :border="false" :inset="true">
|
||||
<template v-for="item in menuItems" :key="item.route">
|
||||
<VanCell :title="item.title" :to="item.route" is-link />
|
||||
<van-cell :title="item.title" :to="item.route" is-link />
|
||||
</template>
|
||||
</VanCellGroup>
|
||||
</van-cell-group>
|
||||
|
||||
<van-popup v-model:show="showLanguagePicker" position="bottom">
|
||||
<van-picker
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
import { createPinia } from 'pinia'
|
||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
||||
|
||||
import useAppStore from './modules/app'
|
||||
import useUserStore from './modules/user'
|
||||
|
||||
const pinia = createPinia()
|
||||
pinia.use(piniaPluginPersistedstate)
|
||||
|
||||
export { useAppStore, useUserStore }
|
||||
export { useUserStore }
|
||||
export default pinia
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import type { ConfigProviderTheme } from 'vant'
|
||||
|
||||
export interface AppStore {
|
||||
switchMode: (val: ConfigProviderTheme) => void
|
||||
}
|
||||
|
||||
const prefersDark
|
||||
= window.matchMedia
|
||||
&& window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
|
||||
const useAppStore = defineStore('app', () => {
|
||||
const theme = prefersDark ? 'dark' : 'light'
|
||||
const mode = ref<ConfigProviderTheme>(theme)
|
||||
|
||||
const switchMode = (val: ConfigProviderTheme) => {
|
||||
mode.value = val
|
||||
}
|
||||
|
||||
return {
|
||||
mode,
|
||||
switchMode,
|
||||
}
|
||||
}, {
|
||||
persist: true,
|
||||
})
|
||||
|
||||
export default useAppStore
|
||||
|
|
@ -1,32 +1,26 @@
|
|||
import {
|
||||
defineConfig,
|
||||
presetAttributify,
|
||||
presetIcons,
|
||||
presetMini,
|
||||
presetUno,
|
||||
} from 'unocss'
|
||||
|
||||
import presetRemToPx from '@unocss/preset-rem-to-px'
|
||||
|
||||
// 刚使用unocss的朋友,可以借助这个工具: https://to-unocss.netlify.app
|
||||
|
||||
export default defineConfig({
|
||||
presets: [
|
||||
presetUno,
|
||||
presetAttributify,
|
||||
presetIcons(),
|
||||
// 为什么要用到这个插件?
|
||||
// 模板使用 viewport 作为移动端适配方案,unocss 默认单位为 rem
|
||||
// 所以需要转成 px,然后由 postcss 把 px 转成 vw/vh,完成适配
|
||||
presetRemToPx({
|
||||
// 这里为什么要设置基础字体大小?看下面这篇文章
|
||||
// https://juejin.cn/post/7262975395620618298
|
||||
baseFontSize: 4,
|
||||
}),
|
||||
presetMini(),
|
||||
],
|
||||
shortcuts: [
|
||||
// shortcuts to multiple utilities
|
||||
['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'],
|
||||
],
|
||||
})
|
||||
import {
|
||||
defineConfig,
|
||||
presetAttributify,
|
||||
presetIcons,
|
||||
presetMini,
|
||||
} from 'unocss'
|
||||
|
||||
import presetWind3 from '@unocss/preset-wind3'
|
||||
// https://unocss.dev/presets/rem-to-px
|
||||
import presetRemToPx from '@unocss/preset-rem-to-px'
|
||||
|
||||
export default defineConfig({
|
||||
presets: [
|
||||
presetWind3(),
|
||||
presetAttributify,
|
||||
presetIcons(),
|
||||
presetRemToPx({
|
||||
baseFontSize: 4,
|
||||
}),
|
||||
presetMini(),
|
||||
],
|
||||
shortcuts: [
|
||||
// shortcuts to multiple utilities
|
||||
['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'],
|
||||
],
|
||||
})
|
||||
|
|
|
|||
|
|
@ -45,10 +45,7 @@ export default ({ mode }: ConfigEnv): UserConfig => {
|
|||
appSelector: '#app',
|
||||
viewportWidth: 375,
|
||||
maxDisplayWidth: 600,
|
||||
rootContainingBlockSelectorList: [
|
||||
'van-tabbar',
|
||||
'van-popup',
|
||||
],
|
||||
appContainingBlock: 'auto',
|
||||
border: true,
|
||||
}),
|
||||
],
|
||||
|
|
|
|||
Loading…
Reference in New Issue