Compare commits
8 Commits
9c82e12144
...
193cbe74ba
| Author | SHA1 | Date | |
|---|---|---|---|
| 193cbe74ba | |||
| 5be781a388 | |||
| f97d8d56e9 | |||
| e0d8cd6cb5 | |||
| e9b38b48e9 | |||
| e6fbcff21a | |||
| 8311456a9e | |||
| 1f59e81c52 |
27
bun.lock
@@ -10,6 +10,7 @@
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"daisyui": "^5.0.50",
|
||||
"echarts": "^6.0.0",
|
||||
"element-plus": "^2.13.2",
|
||||
"lucide-vue-next": "^0.563.0",
|
||||
"motion-v": "^1.6.1",
|
||||
@@ -19,6 +20,8 @@
|
||||
"reka-ui": "^2.8.0",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"vue": "^3.5.17",
|
||||
"vue-echarts": "^8.0.1",
|
||||
"vue-i18n": "11",
|
||||
"vue-router": "^4.5.1",
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -209,6 +212,12 @@
|
||||
|
||||
"@internationalized/number": ["@internationalized/number@3.6.5", "", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g=="],
|
||||
|
||||
"@intlify/core-base": ["@intlify/core-base@11.2.8", "", { "dependencies": { "@intlify/message-compiler": "11.2.8", "@intlify/shared": "11.2.8" } }, "sha512-nBq6Y1tVkjIUsLsdOjDSJj4AsjvD0UG3zsg9Fyc+OivwlA/oMHSKooUy9tpKj0HqZ+NWFifweHavdljlBLTwdA=="],
|
||||
|
||||
"@intlify/message-compiler": ["@intlify/message-compiler@11.2.8", "", { "dependencies": { "@intlify/shared": "11.2.8", "source-map-js": "^1.0.2" } }, "sha512-A5n33doOjmHsBtCN421386cG1tWp5rpOjOYPNsnpjIJbQ4POF0QY2ezhZR9kr0boKwaHjbOifvyQvHj2UTrDFQ=="],
|
||||
|
||||
"@intlify/shared": ["@intlify/shared@11.2.8", "", {}, "sha512-l6e4NZyUgv8VyXXH4DbuucFOBmxLF56C/mqh2tvApbzl2Hrhi1aTDcuv5TKdxzfHYmpO3UB0Cz04fgDT9vszfw=="],
|
||||
|
||||
"@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="],
|
||||
|
||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
|
||||
@@ -561,6 +570,8 @@
|
||||
|
||||
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
||||
|
||||
"echarts": ["echarts@6.0.0", "", { "dependencies": { "tslib": "2.3.0", "zrender": "6.0.0" } }, "sha512-Tte/grDQRiETQP4xz3iZWSvoHrkCQtwqd6hs+mifXcjrCuo2iKWbajFObuLJVBlDIJlOzgQPd1hsaKt/3+OMkQ=="],
|
||||
|
||||
"electron-to-chromium": ["electron-to-chromium@1.5.217", "", {}, "sha512-Pludfu5iBxp9XzNl0qq2G87hdD17ZV7h5T4n6rQXDi3nCyloBV3jreE9+8GC6g4X/5yxqVgXEURpcLtM0WS4jA=="],
|
||||
|
||||
"element-plus": ["element-plus@2.13.2", "", { "dependencies": { "@ctrl/tinycolor": "^3.4.1", "@element-plus/icons-vue": "^2.3.2", "@floating-ui/dom": "^1.0.1", "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", "@types/lodash": "^4.17.20", "@types/lodash-es": "^4.17.12", "@vueuse/core": "^10.11.0", "async-validator": "^4.2.5", "dayjs": "^1.11.19", "lodash": "^4.17.23", "lodash-es": "^4.17.23", "lodash-unified": "^1.0.3", "memoize-one": "^6.0.0", "normalize-wheel-es": "^1.2.0" }, "peerDependencies": { "vue": "^3.3.0" } }, "sha512-Zjzm1NnFXGhV4LYZ6Ze9skPlYi2B4KAmN18FL63A3PZcjhDfroHwhtM6RE8BonlOPHXUnPQynH0BgaoEfvhrGw=="],
|
||||
@@ -1081,7 +1092,7 @@
|
||||
|
||||
"ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="],
|
||||
|
||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
"tslib": ["tslib@2.3.0", "", {}, "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="],
|
||||
|
||||
"tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="],
|
||||
|
||||
@@ -1147,8 +1158,12 @@
|
||||
|
||||
"vue-demi": ["vue-demi@0.14.10", "", { "peerDependencies": { "@vue/composition-api": "^1.0.0-rc.1", "vue": "^3.0.0-0 || ^2.6.0" }, "optionalPeers": ["@vue/composition-api"], "bin": { "vue-demi-fix": "bin/vue-demi-fix.js", "vue-demi-switch": "bin/vue-demi-switch.js" } }, "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg=="],
|
||||
|
||||
"vue-echarts": ["vue-echarts@8.0.1", "", { "peerDependencies": { "echarts": "^6.0.0", "vue": "^3.3.0" } }, "sha512-23rJTFLu1OUEGRWjJGmdGt8fP+8+ja1gVgzMYPIPaHWpXegcO1viIAaeu2H4QHESlVeHzUAHIxKXGrwjsyXAaA=="],
|
||||
|
||||
"vue-eslint-parser": ["vue-eslint-parser@10.2.0", "", { "dependencies": { "debug": "^4.4.0", "eslint-scope": "^8.2.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.6.0", "semver": "^7.6.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0" } }, "sha512-CydUvFOQKD928UzZhTp4pr2vWz1L+H99t7Pkln2QSPdvmURT0MoC4wUccfCnuEaihNsu9aYYyk+bep8rlfkUXw=="],
|
||||
|
||||
"vue-i18n": ["vue-i18n@11.2.8", "", { "dependencies": { "@intlify/core-base": "11.2.8", "@intlify/shared": "11.2.8", "@vue/devtools-api": "^6.5.0" }, "peerDependencies": { "vue": "^3.0.0" } }, "sha512-vJ123v/PXCZntd6Qj5Jumy7UBmIuE92VrtdX+AXr+1WzdBHojiBxnAxdfctUFL+/JIN+VQH4BhsfTtiGsvVObg=="],
|
||||
|
||||
"vue-router": ["vue-router@4.5.1", "", { "dependencies": { "@vue/devtools-api": "^6.6.4" }, "peerDependencies": { "vue": "^3.2.0" } }, "sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw=="],
|
||||
|
||||
"vue-tsc": ["vue-tsc@2.2.12", "", { "dependencies": { "@volar/typescript": "2.4.15", "@vue/language-core": "2.2.12" }, "peerDependencies": { "typescript": ">=5.0.0" }, "bin": { "vue-tsc": "./bin/vue-tsc.js" } }, "sha512-P7OP77b2h/Pmk+lZdJ0YWs+5tJ6J2+uOQPo7tlBnY44QqQSPYvS0qVT4wqDJgwrZaLe47etJLLQRFia71GYITw=="],
|
||||
@@ -1173,10 +1188,14 @@
|
||||
|
||||
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
|
||||
|
||||
"zrender": ["zrender@6.0.0", "", { "dependencies": { "tslib": "2.3.0" } }, "sha512-41dFXEEXuJpNecuUQq6JlbybmnHaqqpGlbH1yxnA5V9MMP4SbohSVZsJIwz+zdjQXSSlR1Vc34EgH1zxyTDvhg=="],
|
||||
|
||||
"zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
|
||||
|
||||
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
|
||||
|
||||
"@swc/helpers/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.5.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.5.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ=="],
|
||||
@@ -1203,12 +1222,16 @@
|
||||
|
||||
"@vue/language-core/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
||||
|
||||
"aria-hidden/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"element-plus/@vueuse/core": ["@vueuse/core@10.11.1", "", { "dependencies": { "@types/web-bluetooth": "^0.0.20", "@vueuse/metadata": "10.11.1", "@vueuse/shared": "10.11.1", "vue-demi": ">=0.14.8" } }, "sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww=="],
|
||||
|
||||
"eslint-plugin-vue/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
||||
|
||||
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||
|
||||
"framer-motion/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
|
||||
|
||||
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
@@ -1237,6 +1260,8 @@
|
||||
|
||||
"vue-eslint-parser/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
||||
|
||||
"vue-i18n/@vue/devtools-api": ["@vue/devtools-api@6.6.4", "", {}, "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="],
|
||||
|
||||
"vue-router/@vue/devtools-api": ["@vue/devtools-api@6.6.4", "", {}, "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
|
||||
|
||||
10
components.d.ts
vendored
@@ -12,6 +12,7 @@ export {}
|
||||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
AnimatePresence: typeof import('motion-v')['AnimatePresence']
|
||||
Button: typeof import('./src/components/ui/button/Button.vue')['default']
|
||||
Calendar: typeof import('./src/components/ui/calendar/Calendar.vue')['default']
|
||||
CalendarCell: typeof import('./src/components/ui/calendar/CalendarCell.vue')['default']
|
||||
@@ -28,7 +29,11 @@ declare module 'vue' {
|
||||
ChangeLanguageDropdownButton: typeof import('./src/components/button/ChangeLanguageDropdownButton.vue')['default']
|
||||
ChangeThemeDropdownButton: typeof import('./src/components/button/ChangeThemeDropdownButton.vue')['default']
|
||||
DatePicker: typeof import('./src/components/date-picker/DatePicker.vue')['default']
|
||||
DatePickerDisplayCard: typeof import('./src/components/card/DatePickerDisplayCard.vue')['default']
|
||||
DevelopProgressCard: typeof import('./src/components/card/DevelopProgressCard.vue')['default']
|
||||
DevelopProgressDiagram: typeof import('./src/components/diagram/DevelopProgressDiagram.vue')['default']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
FooterBar: typeof import('./src/components/layout/FooterBar.vue')['default']
|
||||
NativeSelect: typeof import('./src/components/ui/native-select/NativeSelect.vue')['default']
|
||||
NativeSelectOptGroup: typeof import('./src/components/ui/native-select/NativeSelectOptGroup.vue')['default']
|
||||
NativeSelectOption: typeof import('./src/components/ui/native-select/NativeSelectOption.vue')['default']
|
||||
@@ -44,6 +49,7 @@ declare module 'vue' {
|
||||
|
||||
// For TSX support
|
||||
declare global {
|
||||
const AnimatePresence: typeof import('motion-v')['AnimatePresence']
|
||||
const Button: typeof import('./src/components/ui/button/Button.vue')['default']
|
||||
const Calendar: typeof import('./src/components/ui/calendar/Calendar.vue')['default']
|
||||
const CalendarCell: typeof import('./src/components/ui/calendar/CalendarCell.vue')['default']
|
||||
@@ -60,7 +66,11 @@ declare global {
|
||||
const ChangeLanguageDropdownButton: typeof import('./src/components/button/ChangeLanguageDropdownButton.vue')['default']
|
||||
const ChangeThemeDropdownButton: typeof import('./src/components/button/ChangeThemeDropdownButton.vue')['default']
|
||||
const DatePicker: typeof import('./src/components/date-picker/DatePicker.vue')['default']
|
||||
const DatePickerDisplayCard: typeof import('./src/components/card/DatePickerDisplayCard.vue')['default']
|
||||
const DevelopProgressCard: typeof import('./src/components/card/DevelopProgressCard.vue')['default']
|
||||
const DevelopProgressDiagram: typeof import('./src/components/diagram/DevelopProgressDiagram.vue')['default']
|
||||
const ElButton: typeof import('element-plus/es')['ElButton']
|
||||
const FooterBar: typeof import('./src/components/layout/FooterBar.vue')['default']
|
||||
const NativeSelect: typeof import('./src/components/ui/native-select/NativeSelect.vue')['default']
|
||||
const NativeSelectOptGroup: typeof import('./src/components/ui/native-select/NativeSelectOptGroup.vue')['default']
|
||||
const NativeSelectOption: typeof import('./src/components/ui/native-select/NativeSelectOption.vue')['default']
|
||||
|
||||
@@ -25,6 +25,10 @@ export default defineConfig({
|
||||
items: [
|
||||
{ text: "自动路由", link: "/cli-feature/auto-router" },
|
||||
{ text: "组件库", link: "/cli-feature/component-lib" },
|
||||
{ text: "国际化", link: "/cli-feature/international" },
|
||||
{ text: "图表", link: "/cli-feature/chart" },
|
||||
{ text: "辅助工具", link: "/cli-feature/radash" },
|
||||
{ text: "动画", link: "/cli-feature/motion" },
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -104,6 +104,12 @@ const router = createRouter({
|
||||
4. 中文命名:兼容性差,且不利于团队协作和项目维护。
|
||||
:::
|
||||
|
||||
## 路由跳转
|
||||
|
||||
Hucky 封装了 `utils/navigator.ts` 模块,提供了 `navigateTo` 函数,用于在 Vue 组件中进行路由跳转。
|
||||
|
||||
如果您以 `/` 开头,将会跳转到前端路由,如果您以 `http` 开头,将会跳转到外部链接。通过设定 `replace` 参数为 `true`,可以在跳转外部链接时,替换当前页面而不是打开新标签页。
|
||||
|
||||
## 特殊规则
|
||||
|
||||
:::danger 危险
|
||||
|
||||
42
docs/cli-feature/chart.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# 图表
|
||||
|
||||
## 使用
|
||||
|
||||
Hucky 选用 Echarts + Vue Echarts 组件库来为项目绘制图表。首先您需要熟悉如何使用 Echarts 的 option 来绘制一个图表,您可以前往 [Echarts 官方示例站点](https://echarts.apache.org/examples/zh/index.html) 先选择一个参考图表,然后复制其 option 代码。
|
||||
|
||||
然后您需要前往 [Vue Echarts 站点](https://vue-echarts.dev/#codegen) 并使用其提供的引入代码生成器来生成 import 代码。将您的 option 对象粘贴并获取对应的 import 代码。注意这里粘贴的是具体的 option 对象,而不是以 option = 开头的赋值语句。
|
||||
|
||||
接下来在您需要用到图表的组件中引入 vue echarts 提供的 VChart 组件。并动态绑定 option 到 VChart 组件的 props 中。可参考如下代码。
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import VChart from "vue-echarts";
|
||||
import { type EChartsOption } from "echarts";
|
||||
|
||||
// 自动生成的 import 代码
|
||||
import { use } from "echarts/core";
|
||||
import { PieChart } from "echarts/charts";
|
||||
import { TooltipComponent, LegendComponent } from "echarts/components";
|
||||
import { CanvasRenderer } from "echarts/renderers";
|
||||
|
||||
use([TooltipComponent, LegendComponent, PieChart, CanvasRenderer]);
|
||||
|
||||
const option = ref<EChartsOption>({
|
||||
// 此处为您复制的 Echarts 官方示例站点的 option 代码
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- 必须设置图表容器的高度和宽度 -->
|
||||
<div class="h-96 w-96">
|
||||
<VChart :option="option" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
```
|
||||
|
||||
:::tip 提示
|
||||
您可以前往 [Vue Echarts 文档](https://github.com/ecomfe/vue-echarts/blob/HEAD/README.zh-Hans.md) 查看更多使用方法。
|
||||
:::
|
||||
39
docs/cli-feature/international.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# 国际化
|
||||
|
||||
## 使用 i18n
|
||||
|
||||
如果您需要适配国际化,Hucky 提供了 i18n 基础配置,首先您可以先查阅 [i18n 文档](https://vue-i18n.intlify.dev/guide/advanced/composition.html) 其中的 composition api 部分以获取基础知识。
|
||||
|
||||
其中您主要需要使用到的是 `useI18n` 函数,它返回一个对象,其中包含了 `t` 方法,用于翻译字符串。
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div>
|
||||
<p>{{ t("nav.home") }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
</script>
|
||||
```
|
||||
|
||||
关于 t 方法后方的参数,它来自于 `i18n/index.ts` 中的实现 `messagesInterface` 接口的对象。也就是说如果您需要添加新的翻译字符串,您需要首先在 `messagesInterface` 接口中添加新的属性,然后在类似 `zh_CNMessages` 和 `en_USMessages` 等具体语言文件中添加对应的翻译字符串。
|
||||
|
||||
## 切换语言
|
||||
|
||||
切换语言同样需要用到 `useI18n` 函数,其中包含了 `locale` 属性,您可以通过修改这个属性来切换语言。
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { locale } = useI18n();
|
||||
|
||||
locale.value = "EN"; // 切换到英文,由 i18n/index.ts 中的 locale 配置决定
|
||||
</script>
|
||||
```
|
||||
|
||||
Hucky 本身提供了 `ChangeLanguageDropdownButton` 组件以及相对应的一些封装方法,通过使用这个组件您可以让用户自行更改需要的语言。您也可以深入 `hooks/globalLanguageHook` 中的方法来拓展更多功能。
|
||||
33
docs/cli-feature/motion.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# 动画
|
||||
|
||||
## 使用
|
||||
|
||||
:::warning 警告
|
||||
motion-v 的自动引入系统经过测试无法使用,您仍需要手动引入
|
||||
:::
|
||||
|
||||
Hucky 安装了 [motion-v](https://motion.net.cn/docs/vue) 库,您可以在组件中使用它来添加动画效果。
|
||||
|
||||
简单来看,您只需要引入 motion-v 的 `motion` 组件,并使用它来包裹需要添加动画效果的元素,然后编写 :animate 指令即可。
|
||||
|
||||
```html
|
||||
<motion.div :animate="{ rotate: 360 }" />
|
||||
```
|
||||
|
||||
您也可以通过设置 :initial 指令来设置元素的初始状态。
|
||||
|
||||
```html
|
||||
<motion.div :animate="{ rotate: 360 }" :initial="{ rotate: 0 }" />
|
||||
```
|
||||
|
||||
通过 `AnimatePresence` 组件,您可以在元素进入或退出时添加动画效果。
|
||||
|
||||
```html
|
||||
<AnimatePresence>
|
||||
<motion.div v-if="show" :exit="{ opacity: 0 }" />
|
||||
</AnimatePresence>
|
||||
```
|
||||
|
||||
:::tip 提示
|
||||
exit 会自动为元素的进入也添加动画效果。
|
||||
:::
|
||||
34
docs/cli-feature/radash.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# 辅助工具
|
||||
|
||||
## 使用
|
||||
|
||||
Hucky 安装了 [Radash](https://radash.uihtm.com/) 库,用于辅助处理数组、对象、字符串等数据。
|
||||
|
||||
您可以自行查询文档来了解更多用法。
|
||||
|
||||
## 节流
|
||||
|
||||
在查阅 Radash 文档时发现其 `throttle` 函数的使用存在错误,在这里补充纠正,在文档中的用法如下:
|
||||
|
||||
```ts
|
||||
import { throttle } from 'radash'
|
||||
|
||||
const throttledScroll = throttle(() => {
|
||||
console.log('Scroll event handled')
|
||||
}, 100)
|
||||
|
||||
window.addEventListener('scroll', throttledScroll)
|
||||
// 滚动时,函数最多每100ms执行一次
|
||||
```
|
||||
|
||||
事实上 `throttle` 函数的第一个参数才是节流时间,第二个参数是函数。正确写法应该如下:
|
||||
|
||||
```ts
|
||||
import { throttle } from 'radash'
|
||||
|
||||
const throttledScroll = throttle(100, () => {
|
||||
console.log('Scroll event handled')
|
||||
})
|
||||
|
||||
window.addEventListener('scroll', throttledScroll)
|
||||
```
|
||||
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 673 KiB |
@@ -21,6 +21,7 @@
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"daisyui": "^5.0.50",
|
||||
"echarts": "^6.0.0",
|
||||
"element-plus": "^2.13.2",
|
||||
"lucide-vue-next": "^0.563.0",
|
||||
"motion-v": "^1.6.1",
|
||||
@@ -30,6 +31,8 @@
|
||||
"reka-ui": "^2.8.0",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"vue": "^3.5.17",
|
||||
"vue-echarts": "^8.0.1",
|
||||
"vue-i18n": "11",
|
||||
"vue-router": "^4.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
BIN
public/logo.png
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 673 KiB |
BIN
public/qq-rc.jpg
Normal file
|
After Width: | Height: | Size: 74 KiB |
10
src/App.vue
@@ -1,4 +1,12 @@
|
||||
<script lang="ts" setup></script>
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useLanguageStore } from "./stores/LanguageStore";
|
||||
|
||||
onMounted(() => {
|
||||
// 加载 i18n 初始语言
|
||||
useI18n().locale.value = useLanguageStore().language;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
|
||||
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 673 KiB |
@@ -1,8 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import { useGlobalLanguageHook } from "@/hooks/globalLanguageHook";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { changeGlobalLanguage, curGlobalLanguage, optionalLanguages } =
|
||||
useGlobalLanguageHook();
|
||||
|
||||
const { locale, t } = useI18n();
|
||||
|
||||
const onClickChangeLocal = (newLanguage: string) => {
|
||||
changeGlobalLanguage(newLanguage, locale);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -41,7 +48,7 @@ const { changeGlobalLanguage, curGlobalLanguage, optionalLanguages } =
|
||||
class="dropdown-content bg-base-200 text-base-content rounded-box top-px mt-14 w-56 overflow-y-auto border-[length:var(--border)] border-white/5 shadow-2xl outline-[length:var(--border)] outline-black/5"
|
||||
>
|
||||
<ul class="menu menu-sm w-full">
|
||||
<li class="menu-title text-xs">语言</li>
|
||||
<li class="menu-title text-xs">{{ t("nav.locale") }}</li>
|
||||
<li
|
||||
v-for="optionalLanguage in optionalLanguages"
|
||||
:key="optionalLanguage.label"
|
||||
@@ -50,7 +57,7 @@ const { changeGlobalLanguage, curGlobalLanguage, optionalLanguages } =
|
||||
:class="[
|
||||
curGlobalLanguage === optionalLanguage.label ? 'menu-active' : '',
|
||||
]"
|
||||
@click="changeGlobalLanguage(optionalLanguage.label)"
|
||||
@click="onClickChangeLocal(optionalLanguage.label)"
|
||||
>
|
||||
<span class="pe-4 font-mono font-bold opacity-40">
|
||||
{{ optionalLanguage.label }}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { useGlobalThemeHook } from "@/hooks/globalThemeHook";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const { changeGlobalTheme, curGlobalTheme, optionalThemes } =
|
||||
useGlobalThemeHook();
|
||||
@@ -31,7 +34,7 @@ const { changeGlobalTheme, curGlobalTheme, optionalThemes } =
|
||||
tabindex="-1"
|
||||
class="dropdown-content bg-base-300 rounded-box z-1 w-52 p-2 shadow-2xl max-h-84 overflow-auto mt-6"
|
||||
>
|
||||
<li class="menu-title text-xs my-1">主题</li>
|
||||
<li class="menu-title text-xs my-1">{{ t("nav.theme") }}</li>
|
||||
<li
|
||||
v-for="optionalTheme in optionalThemes"
|
||||
:key="optionalTheme"
|
||||
|
||||
17
src/components/card/DatePickerDisplayCard.vue
Normal file
@@ -0,0 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
import DatePicker from "../date-picker/DatePicker.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="card bg-base-100 w-96 shadow-sm">
|
||||
<div class="p-4 min-h-82">
|
||||
<DatePicker />
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">日期选择器</h2>
|
||||
<p>日期选择器组件演示</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
27
src/components/card/DevelopProgressCard.vue
Normal file
@@ -0,0 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import DevelopProgressDiagram from "../diagram/DevelopProgressDiagram.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
completed: number;
|
||||
pending: number;
|
||||
title: string;
|
||||
intro: string;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="card bg-base-100 w-96 shadow-sm">
|
||||
<DevelopProgressDiagram
|
||||
:completed="props.completed"
|
||||
:pending="props.pending"
|
||||
/>
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">{{ props.title }}</h2>
|
||||
<p>
|
||||
{{ props.intro }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
62
src/components/diagram/DevelopProgressDiagram.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<script setup lang="ts">
|
||||
import { use } from "echarts/core";
|
||||
import { PieChart } from "echarts/charts";
|
||||
import { TooltipComponent, LegendComponent } from "echarts/components";
|
||||
import { CanvasRenderer } from "echarts/renderers";
|
||||
import VChart from "vue-echarts";
|
||||
import { type EChartsOption } from "echarts";
|
||||
|
||||
use([TooltipComponent, LegendComponent, PieChart, CanvasRenderer]);
|
||||
|
||||
const props = defineProps<{
|
||||
completed: number;
|
||||
pending: number;
|
||||
}>();
|
||||
|
||||
const option = ref<EChartsOption>({
|
||||
color: ["#52c41a", "#ff4d4f"],
|
||||
legend: {
|
||||
top: "5%",
|
||||
left: "center",
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "开发进度",
|
||||
type: "pie",
|
||||
radius: ["40%", "70%"],
|
||||
itemStyle: {
|
||||
borderRadius: 10,
|
||||
borderColor: "#fff",
|
||||
borderWidth: 2,
|
||||
},
|
||||
label: {
|
||||
show: false,
|
||||
position: "center",
|
||||
},
|
||||
labelLine: {
|
||||
show: false,
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: true,
|
||||
fontSize: 32,
|
||||
fontWeight: "bold",
|
||||
formatter: "{d}%",
|
||||
},
|
||||
},
|
||||
data: [
|
||||
{ value: props.completed, name: "已完成" },
|
||||
{ value: props.pending, name: "待开发" },
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-96 w-96">
|
||||
<VChart :option="option" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
55
src/components/layout/FooterBar.vue
Normal file
@@ -0,0 +1,55 @@
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<footer class="footer sm:footer-horizontal bg-base-300 items-center p-4">
|
||||
<aside class="grid-flow-col items-center">
|
||||
<img src="@/assets/hucky.png" alt="hucky" class="h-18" />
|
||||
<p>Copyright © {{ new Date().getFullYear() }} - All right reserved</p>
|
||||
</aside>
|
||||
<nav class="grid-flow-col gap-4 md:place-self-center md:justify-self-end">
|
||||
<a>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
class="fill-current"
|
||||
>
|
||||
<path
|
||||
d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"
|
||||
/>
|
||||
</svg>
|
||||
</a>
|
||||
<a>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
class="fill-current"
|
||||
>
|
||||
<path
|
||||
d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z"
|
||||
/>
|
||||
</svg>
|
||||
</a>
|
||||
<a>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
class="fill-current"
|
||||
>
|
||||
<path
|
||||
d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z"
|
||||
/>
|
||||
</svg>
|
||||
</a>
|
||||
</nav>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,48 +1,90 @@
|
||||
<script setup lang="ts">
|
||||
import ChangeLanguageDropdownButton from "@/components/button/ChangeLanguageDropdownButton.vue";
|
||||
import ChangeThemeDropdownButton from "@/components/button/ChangeThemeDropdownButton.vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { throttle } from "radash";
|
||||
import { AnimatePresence, motion } from "motion-v";
|
||||
import { navigateTo } from "@/utils/navigator";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const showNavBar = ref(true);
|
||||
const curScrollY = ref(0);
|
||||
|
||||
const handleThrottleScroll = throttle(100, () => {
|
||||
const scrollY = window.scrollY;
|
||||
if (scrollY > curScrollY.value) {
|
||||
showNavBar.value = false;
|
||||
} else {
|
||||
showNavBar.value = true;
|
||||
}
|
||||
curScrollY.value = scrollY;
|
||||
});
|
||||
|
||||
window.addEventListener("scroll", handleThrottleScroll);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="navbar bg-base-200 shadow-sm">
|
||||
<div class="navbar-start">
|
||||
<div class="dropdown">
|
||||
<div tabindex="0" role="button" class="btn btn-ghost lg:hidden">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 6h16M4 12h8m-8 6h16"
|
||||
/>
|
||||
</svg>
|
||||
<div class="w-full">
|
||||
<AnimatePresence>
|
||||
<motion.div
|
||||
v-show="showNavBar"
|
||||
class="navbar glass shadow-sm h-16"
|
||||
:exit="{
|
||||
y: -100,
|
||||
transition: {
|
||||
duration: 0.3,
|
||||
},
|
||||
}"
|
||||
>
|
||||
<div class="navbar-start">
|
||||
<div class="dropdown">
|
||||
<div tabindex="0" role="button" class="btn btn-ghost lg:hidden">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 6h16M4 12h8m-8 6h16"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<ul
|
||||
tabindex="-1"
|
||||
class="menu dropdown-content bg-base-100 rounded-box z-1 mt-5 w-52 p-2 shadow"
|
||||
>
|
||||
<li>
|
||||
<a @click="navigateTo('/')">{{ t("nav.home") }}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a @click="navigateTo('/about')">{{ t("nav.about") }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<a class="btn btn-ghost text-xl">Hucky</a>
|
||||
</div>
|
||||
<ul
|
||||
tabindex="-1"
|
||||
class="menu dropdown-content bg-base-100 rounded-box z-1 mt-5 w-52 p-2 shadow"
|
||||
>
|
||||
<li><a>首页</a></li>
|
||||
<li><a>关于</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<a class="btn btn-ghost text-xl">daisyUI</a>
|
||||
</div>
|
||||
<div class="navbar-center hidden lg:flex">
|
||||
<ul class="menu menu-horizontal px-1">
|
||||
<li><a>首页</a></li>
|
||||
<li><a>关于</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="navbar-end">
|
||||
<ChangeThemeDropdownButton />
|
||||
<ChangeLanguageDropdownButton />
|
||||
</div>
|
||||
<div class="navbar-center hidden lg:flex">
|
||||
<ul class="menu menu-horizontal px-1">
|
||||
<li>
|
||||
<a @click="navigateTo('/')">{{ t("nav.home") }}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a @click="navigateTo('/about')">{{ t("nav.about") }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="navbar-end">
|
||||
<ChangeThemeDropdownButton />
|
||||
<ChangeLanguageDropdownButton />
|
||||
</div>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -16,8 +16,12 @@ export const optionalLanguages = Object.entries(languageMap).map(
|
||||
// 一定不要通过改变 curGlobalLanguage 来改变语言,而要通过 changeGlobalLanguage 来改变语言
|
||||
const curGlobalLanguage = computed(() => languageStore.language);
|
||||
|
||||
function changeGlobalLanguage(language: GlobalLanguage) {
|
||||
function changeGlobalLanguage(
|
||||
language: GlobalLanguage,
|
||||
locale: WritableComputedRef<string>,
|
||||
) {
|
||||
languageStore.setLanguage(language);
|
||||
locale.value = language;
|
||||
}
|
||||
|
||||
export const useGlobalLanguageHook = () => ({
|
||||
|
||||
10
src/i18n/en_US.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { messagesInterface } from ".";
|
||||
|
||||
export const en_USMessages: messagesInterface = {
|
||||
nav: {
|
||||
home: "Home",
|
||||
about: "About",
|
||||
theme: "Theme",
|
||||
locale: "Locale",
|
||||
},
|
||||
};
|
||||
24
src/i18n/index.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { createI18n } from "vue-i18n";
|
||||
import { zh_CNMessages } from "./zh_CN";
|
||||
import { en_USMessages } from "./en_US";
|
||||
|
||||
export interface messagesInterface {
|
||||
nav: {
|
||||
home: string;
|
||||
about: string;
|
||||
theme: string;
|
||||
locale: string;
|
||||
};
|
||||
}
|
||||
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: "ZH",
|
||||
fallbackLocale: "EN",
|
||||
messages: {
|
||||
ZH: zh_CNMessages,
|
||||
EN: en_USMessages,
|
||||
},
|
||||
});
|
||||
|
||||
export default i18n;
|
||||
10
src/i18n/zh_CN.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { messagesInterface } from ".";
|
||||
|
||||
export const zh_CNMessages: messagesInterface = {
|
||||
nav: {
|
||||
home: "首页",
|
||||
about: "关于",
|
||||
theme: "主题",
|
||||
locale: "语言",
|
||||
},
|
||||
};
|
||||
@@ -2,10 +2,11 @@ import { createApp } from "vue";
|
||||
import "./style.css";
|
||||
import App from "./App.vue";
|
||||
import router from "./router";
|
||||
import i18n from "./i18n";
|
||||
import { createPinia } from "pinia";
|
||||
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
|
||||
|
||||
const pinia = createPinia();
|
||||
pinia.use(piniaPluginPersistedstate);
|
||||
|
||||
createApp(App).use(router).use(pinia).mount("#app");
|
||||
createApp(App).use(router).use(pinia).use(i18n).mount("#app");
|
||||
|
||||
95
src/pages/about.vue
Normal file
@@ -0,0 +1,95 @@
|
||||
<script setup lang="ts">
|
||||
import NavBar from "@/components/menu/NavBar.vue";
|
||||
import { navigateTo } from "@/utils/navigator";
|
||||
import { motion } from "motion-v";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="bg-base-200">
|
||||
<NavBar class="fixed top-0 left-0 z-10" />
|
||||
<!-- 同高度占位颜色叠加 -->
|
||||
<div class="h-16 bg-base-300" />
|
||||
<div class="p-4 gap-4 flex flex-col">
|
||||
<div class="mockup-browser border-base-300 border w-full">
|
||||
<div class="mockup-browser-toolbar">
|
||||
<motion.div
|
||||
class="input cursor-pointer"
|
||||
:while-hover="{ scale: 1.1 }"
|
||||
@click="navigateTo('https://daisyui.com')"
|
||||
>
|
||||
https://daisyui.com
|
||||
</motion.div>
|
||||
</div>
|
||||
<div class="grid place-content-center border-t border-base-300 h-16">
|
||||
由 DaisyUI 提供组件库支持
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mockup-browser border-base-300 border w-full">
|
||||
<div class="mockup-browser-toolbar">
|
||||
<motion.div
|
||||
class="input cursor-pointer"
|
||||
:while-hover="{ scale: 1.1 }"
|
||||
@click="navigateTo('https://motion.net.cn/')"
|
||||
>
|
||||
https://motion.net.cn/
|
||||
</motion.div>
|
||||
</div>
|
||||
<div class="grid place-content-center border-t border-base-300 h-16">
|
||||
由 Motion 提供动画库支持
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mockup-browser border-base-300 border w-full">
|
||||
<div class="mockup-browser-toolbar">
|
||||
<motion.div
|
||||
class="input cursor-pointer"
|
||||
:while-hover="{ scale: 1.1 }"
|
||||
@click="navigateTo('https://space.bilibili.com/34875940')"
|
||||
>
|
||||
https://space.bilibili.com/34875940
|
||||
</motion.div>
|
||||
</div>
|
||||
<div class="grid place-content-center border-t border-base-300 h-16">
|
||||
B站搜索谷神神神
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mockup-browser border-base-300 border w-full">
|
||||
<div class="mockup-browser-toolbar">
|
||||
<motion.div
|
||||
class="input cursor-pointer"
|
||||
:while-hover="{ scale: 1.1 }"
|
||||
@click="
|
||||
navigateTo(
|
||||
'https://www.douyin.com/user/MS4wLjABAAAAf6Q5VoHL_UfFQE8fmH3mgYCgL0tGxlpoSMLM9ZcKbpY?from_tab_name=main',
|
||||
)
|
||||
"
|
||||
>
|
||||
https://www.douyin.com/search/谷神神神
|
||||
</motion.div>
|
||||
</div>
|
||||
<div class="grid place-content-center border-t border-base-300 h-16">
|
||||
抖音搜索谷神神神
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mockup-browser border-base-300 border w-full">
|
||||
<div class="mockup-browser-toolbar">
|
||||
<motion.div
|
||||
class="input cursor-pointer"
|
||||
:while-hover="{ scale: 1.1 }"
|
||||
@click="navigateTo('https://qm.qq.com/q/wt1ukamVJ6')"
|
||||
>
|
||||
https://qm.qq.com/q/wt1ukamVJ6
|
||||
</motion.div>
|
||||
</div>
|
||||
<div class="p-4 grid place-content-center border-t border-base-300">
|
||||
<img src="/qq-rc.jpg" alt="qq" class="h-96" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,15 +1,87 @@
|
||||
<script lang="ts" setup>
|
||||
import DatePicker from "@/components/date-picker/DatePicker.vue";
|
||||
import DatePickerDisplayCard from "@/components/card/DatePickerDisplayCard.vue";
|
||||
import DevelopProgressCard from "@/components/card/DevelopProgressCard.vue";
|
||||
import FooterBar from "@/components/layout/FooterBar.vue";
|
||||
import NavBar from "@/components/menu/NavBar.vue";
|
||||
import { navigateTo } from "@/utils/navigator";
|
||||
|
||||
const progress = ref([
|
||||
{
|
||||
name: "auto-router",
|
||||
completed: 80,
|
||||
pending: 20,
|
||||
title: "自动路由开发进度",
|
||||
intro: "自动将 pages 目录下的所有 vue 文件转换为路由",
|
||||
},
|
||||
{
|
||||
name: "component-list",
|
||||
completed: 95,
|
||||
pending: 5,
|
||||
title: "组件库开发进度",
|
||||
intro: "自动加载项目所需要的组件库",
|
||||
},
|
||||
{
|
||||
name: "international",
|
||||
completed: 95,
|
||||
pending: 5,
|
||||
title: "国际化开发进度",
|
||||
intro: "有序地组织项目翻译文件",
|
||||
},
|
||||
{
|
||||
name: "chart",
|
||||
completed: 95,
|
||||
pending: 5,
|
||||
title: "图表开发进度",
|
||||
intro: "使用精美的图表呈现内容",
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<NavBar />
|
||||
<div class="mt-4">
|
||||
<div>路由系统加载进度:100%</div>
|
||||
<DatePicker />
|
||||
<div class="bg-base-200">
|
||||
<div class="h-screen flex flex-col">
|
||||
<NavBar class="fixed top-0 left-0 z-10" />
|
||||
<!-- 同高度占位颜色叠加 -->
|
||||
<div class="h-16 bg-base-300" />
|
||||
<div class="hero flex-1">
|
||||
<div class="hero-content text-center">
|
||||
<div class="max-w-md">
|
||||
<h1 class="text-5xl font-bold">欢迎加入</h1>
|
||||
<p class="py-6">
|
||||
超现代化的 Vue3 Based 脚手架<br />
|
||||
赋予您高效的开发体验<br />
|
||||
使用 bun docs 命令启动 Hucky 的文档服务器
|
||||
</p>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
@click="navigateTo('http://localhost:5174')"
|
||||
>
|
||||
查阅文档
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h1 class="text-4xl font-bold mb-12 ml-10">脚手架开发进度</h1>
|
||||
<div class="w-full grid grid-cols-3 gap-4 justify-items-center">
|
||||
<DevelopProgressCard
|
||||
v-for="item in progress"
|
||||
:key="item.title"
|
||||
:completed="item.completed"
|
||||
:pending="item.pending"
|
||||
:title="item.title"
|
||||
:intro="item.intro"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h1 class="text-4xl font-bold mb-12 ml-10">组件演示</h1>
|
||||
<div class="w-full grid grid-cols-3 gap-4 justify-items-center">
|
||||
<DatePickerDisplayCard />
|
||||
</div>
|
||||
</div>
|
||||
<FooterBar />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
13
src/utils/navigator.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import router from "@/router";
|
||||
|
||||
export const navigateTo = (path: string, replace?: boolean = false) => {
|
||||
if (path.startsWith("http")) {
|
||||
if (replace) {
|
||||
window.open(path, "_self");
|
||||
} else {
|
||||
window.open(path, "_blank");
|
||||
}
|
||||
return;
|
||||
}
|
||||
router.push(path);
|
||||
};
|
||||
@@ -5,6 +5,7 @@ import tailwindcss from "@tailwindcss/vite";
|
||||
import vueJsx from "@vitejs/plugin-vue-jsx";
|
||||
import AutoImport from "unplugin-auto-import/vite";
|
||||
import Components from "unplugin-vue-components/vite";
|
||||
import MotionResolver from "motion-v/resolver";
|
||||
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
|
||||
|
||||
// https://vite.dev/config/
|
||||
@@ -19,7 +20,7 @@ export default defineConfig({
|
||||
resolvers: [ElementPlusResolver()],
|
||||
}),
|
||||
Components({
|
||||
resolvers: [ElementPlusResolver()],
|
||||
resolvers: [ElementPlusResolver(), MotionResolver()],
|
||||
dts: true,
|
||||
}),
|
||||
],
|
||||
|
||||