From d120622de18b5a0cb39b5705ec34ebdf077d4196 Mon Sep 17 00:00:00 2001 From: wintsa Date: Sun, 22 Feb 2026 23:42:49 +0800 Subject: [PATCH] first commit --- .gitignore | 24 ++ .vscode/extensions.json | 3 + README.md | 5 + bun.lock | 329 +++++++++++++++++++ components.json | 21 ++ index.html | 13 + package.json | 35 ++ public/vite.svg | 1 + src/App.vue | 11 + src/assets/vue.svg | 1 + src/components/ui/button/Button.vue | 29 ++ src/components/ui/button/index.ts | 38 +++ src/components/ui/card/Card.vue | 22 ++ src/components/ui/card/CardAction.vue | 17 + src/components/ui/card/CardContent.vue | 17 + src/components/ui/card/CardDescription.vue | 17 + src/components/ui/card/CardFooter.vue | 17 + src/components/ui/card/CardHeader.vue | 17 + src/components/ui/card/CardTitle.vue | 17 + src/components/ui/card/index.ts | 7 + src/components/ui/scroll-area/ScrollArea.vue | 33 ++ src/components/ui/scroll-area/ScrollBar.vue | 32 ++ src/components/ui/scroll-area/index.ts | 2 + src/components/views/Ht.vue | 70 ++++ src/components/views/Xm.vue | 4 + src/components/views/xmInfo.vue | 32 ++ src/layout/tab.vue | 62 ++++ src/layout/typeLine.vue | 50 +++ src/lib/utils.ts | 7 + src/main.ts | 8 + src/pinia/tab.ts | 36 ++ src/style.css | 122 +++++++ tsconfig.app.json | 21 ++ tsconfig.json | 18 + tsconfig.node.json | 26 ++ vite.config.ts | 13 + 36 files changed, 1177 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/extensions.json create mode 100644 README.md create mode 100644 bun.lock create mode 100644 components.json create mode 100644 index.html create mode 100644 package.json create mode 100644 public/vite.svg create mode 100644 src/App.vue create mode 100644 src/assets/vue.svg create mode 100644 src/components/ui/button/Button.vue create mode 100644 src/components/ui/button/index.ts create mode 100644 src/components/ui/card/Card.vue create mode 100644 src/components/ui/card/CardAction.vue create mode 100644 src/components/ui/card/CardContent.vue create mode 100644 src/components/ui/card/CardDescription.vue create mode 100644 src/components/ui/card/CardFooter.vue create mode 100644 src/components/ui/card/CardHeader.vue create mode 100644 src/components/ui/card/CardTitle.vue create mode 100644 src/components/ui/card/index.ts create mode 100644 src/components/ui/scroll-area/ScrollArea.vue create mode 100644 src/components/ui/scroll-area/ScrollBar.vue create mode 100644 src/components/ui/scroll-area/index.ts create mode 100644 src/components/views/Ht.vue create mode 100644 src/components/views/Xm.vue create mode 100644 src/components/views/xmInfo.vue create mode 100644 src/layout/tab.vue create mode 100644 src/layout/typeLine.vue create mode 100644 src/lib/utils.ts create mode 100644 src/main.ts create mode 100644 src/pinia/tab.ts create mode 100644 src/style.css create mode 100644 tsconfig.app.json create mode 100644 tsconfig.json create mode 100644 tsconfig.node.json create mode 100644 vite.config.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..a7cea0b --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["Vue.volar"] +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..33895ab --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# Vue 3 + TypeScript + Vite + +This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 ` + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..39be7ac --- /dev/null +++ b/package.json @@ -0,0 +1,35 @@ +{ + "name": "my-vue-app", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "bunx --bun vite", + "build": "bunx vue-tsc -b && bunx --bun vite build", + "preview": "bunx --bun vite preview", + "type-check": "bunx vue-tsc --noEmit" + }, + "dependencies": { + "@tailwindcss/vite": "^4.1.18", + "@vueuse/core": "^14.2.1", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lucide-vue-next": "^0.563.0", + "pinia": "^3.0.4", + "pinia-plugin-persistedstate": "^4.7.1", + "reka-ui": "^2.8.0", + "tailwind-merge": "^3.4.0", + "tailwindcss": "^4.1.18", + "vue": "^3.5.25" + }, + "devDependencies": { + "@types/node": "^24.10.1", + "@vitejs/plugin-vue": "^6.0.2", + "@vue/tsconfig": "^0.8.1", + "tw-animate-css": "^1.4.0", + "typescript": "~5.9.3", + "vite": "^8.0.0-beta.13", + "vue-tsc": "^3.1.5", + "@types/bun": "latest" + } +} diff --git a/public/vite.svg b/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..b4a3562 --- /dev/null +++ b/src/App.vue @@ -0,0 +1,11 @@ + + + + + diff --git a/src/assets/vue.svg b/src/assets/vue.svg new file mode 100644 index 0000000..770e9d3 --- /dev/null +++ b/src/assets/vue.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/ui/button/Button.vue b/src/components/ui/button/Button.vue new file mode 100644 index 0000000..374320b --- /dev/null +++ b/src/components/ui/button/Button.vue @@ -0,0 +1,29 @@ + + + diff --git a/src/components/ui/button/index.ts b/src/components/ui/button/index.ts new file mode 100644 index 0000000..26e2c55 --- /dev/null +++ b/src/components/ui/button/index.ts @@ -0,0 +1,38 @@ +import type { VariantProps } from "class-variance-authority" +import { cva } from "class-variance-authority" + +export { default as Button } from "./Button.vue" + +export const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", + { + variants: { + variant: { + default: + "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: + "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: + "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + "default": "h-9 px-4 py-2 has-[>svg]:px-3", + "sm": "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5", + "lg": "h-10 rounded-md px-6 has-[>svg]:px-4", + "icon": "size-9", + "icon-sm": "size-8", + "icon-lg": "size-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + }, +) +export type ButtonVariants = VariantProps diff --git a/src/components/ui/card/Card.vue b/src/components/ui/card/Card.vue new file mode 100644 index 0000000..f5a0707 --- /dev/null +++ b/src/components/ui/card/Card.vue @@ -0,0 +1,22 @@ + + + diff --git a/src/components/ui/card/CardAction.vue b/src/components/ui/card/CardAction.vue new file mode 100644 index 0000000..c91638b --- /dev/null +++ b/src/components/ui/card/CardAction.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/components/ui/card/CardContent.vue b/src/components/ui/card/CardContent.vue new file mode 100644 index 0000000..dfbc552 --- /dev/null +++ b/src/components/ui/card/CardContent.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/components/ui/card/CardDescription.vue b/src/components/ui/card/CardDescription.vue new file mode 100644 index 0000000..71c1b8d --- /dev/null +++ b/src/components/ui/card/CardDescription.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/components/ui/card/CardFooter.vue b/src/components/ui/card/CardFooter.vue new file mode 100644 index 0000000..9e3739e --- /dev/null +++ b/src/components/ui/card/CardFooter.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/components/ui/card/CardHeader.vue b/src/components/ui/card/CardHeader.vue new file mode 100644 index 0000000..4fe4da4 --- /dev/null +++ b/src/components/ui/card/CardHeader.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/components/ui/card/CardTitle.vue b/src/components/ui/card/CardTitle.vue new file mode 100644 index 0000000..5f479e7 --- /dev/null +++ b/src/components/ui/card/CardTitle.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/components/ui/card/index.ts b/src/components/ui/card/index.ts new file mode 100644 index 0000000..1627758 --- /dev/null +++ b/src/components/ui/card/index.ts @@ -0,0 +1,7 @@ +export { default as Card } from "./Card.vue" +export { default as CardAction } from "./CardAction.vue" +export { default as CardContent } from "./CardContent.vue" +export { default as CardDescription } from "./CardDescription.vue" +export { default as CardFooter } from "./CardFooter.vue" +export { default as CardHeader } from "./CardHeader.vue" +export { default as CardTitle } from "./CardTitle.vue" diff --git a/src/components/ui/scroll-area/ScrollArea.vue b/src/components/ui/scroll-area/ScrollArea.vue new file mode 100644 index 0000000..6112caa --- /dev/null +++ b/src/components/ui/scroll-area/ScrollArea.vue @@ -0,0 +1,33 @@ + + + diff --git a/src/components/ui/scroll-area/ScrollBar.vue b/src/components/ui/scroll-area/ScrollBar.vue new file mode 100644 index 0000000..a0b6f9b --- /dev/null +++ b/src/components/ui/scroll-area/ScrollBar.vue @@ -0,0 +1,32 @@ + + + diff --git a/src/components/ui/scroll-area/index.ts b/src/components/ui/scroll-area/index.ts new file mode 100644 index 0000000..c416759 --- /dev/null +++ b/src/components/ui/scroll-area/index.ts @@ -0,0 +1,2 @@ +export { default as ScrollArea } from "./ScrollArea.vue" +export { default as ScrollBar } from "./ScrollBar.vue" diff --git a/src/components/views/Ht.vue b/src/components/views/Ht.vue new file mode 100644 index 0000000..30d0ba1 --- /dev/null +++ b/src/components/views/Ht.vue @@ -0,0 +1,70 @@ + + + \ No newline at end of file diff --git a/src/components/views/Xm.vue b/src/components/views/Xm.vue new file mode 100644 index 0000000..05ed4b8 --- /dev/null +++ b/src/components/views/Xm.vue @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/src/components/views/xmInfo.vue b/src/components/views/xmInfo.vue new file mode 100644 index 0000000..405d644 --- /dev/null +++ b/src/components/views/xmInfo.vue @@ -0,0 +1,32 @@ + \ No newline at end of file diff --git a/src/layout/tab.vue b/src/layout/tab.vue new file mode 100644 index 0000000..98a4a8b --- /dev/null +++ b/src/layout/tab.vue @@ -0,0 +1,62 @@ + + + + + \ No newline at end of file diff --git a/src/layout/typeLine.vue b/src/layout/typeLine.vue new file mode 100644 index 0000000..4c6a757 --- /dev/null +++ b/src/layout/typeLine.vue @@ -0,0 +1,50 @@ + + + \ No newline at end of file diff --git a/src/lib/utils.ts b/src/lib/utils.ts new file mode 100644 index 0000000..c66a9d9 --- /dev/null +++ b/src/lib/utils.ts @@ -0,0 +1,7 @@ +import type { ClassValue } from "clsx" +import { clsx } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..acccb13 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,8 @@ +import { createApp } from 'vue' +import './style.css' +import App from './App.vue' +import { createPinia } from 'pinia' +import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' // 引入 +const pinia = createPinia() +pinia.use(piniaPluginPersistedstate) +createApp(App).use(pinia).mount('#app') diff --git a/src/pinia/tab.ts b/src/pinia/tab.ts new file mode 100644 index 0000000..550fc37 --- /dev/null +++ b/src/pinia/tab.ts @@ -0,0 +1,36 @@ +// src/stores/tab.ts +import { defineStore } from 'pinia' +import { ref } from 'vue' + +export const useTabStore = defineStore('tabs', () => { + const tabs = ref([ + { id: 'XmView', title: '项目卡片', componentName: 'XmView' } + ]) + const activeTabId = ref('XmView') + + const openTab = (config: { id: string; title: string; componentName: string; props?: any }) => { + const exists = tabs.value.find(t => t.id === config.id) + if (!exists) { + tabs.value.push(config) + } + activeTabId.value = config.id + } + + const removeTab = (id: string) => { + if (id === 'XmView') return // 首页不可删除 + const index = tabs.value.findIndex(t => t.id === id) + if (activeTabId.value === id) { + activeTabId.value = (tabs.value[index - 1]?.id || tabs.value[index + 1]?.id ) as string + } + tabs.value.splice(index, 1) + } + + return { tabs, activeTabId, openTab, removeTab } +}, { + // --- 关键配置:开启持久化 --- + persist: { + key: 'tabs', // 存储在 localStorage 里的 key + storage: localStorage, // 也可以改用 sessionStorage + pick: ['tabs', 'activeTabId'], // 指定哪些变量需要持久化 + } +}) \ No newline at end of file diff --git a/src/style.css b/src/style.css new file mode 100644 index 0000000..f6c86eb --- /dev/null +++ b/src/style.css @@ -0,0 +1,122 @@ +@import "tailwindcss"; +@import "tw-animate-css"; +#app{ + height: 100vh; +} +@custom-variant dark (&:is(.dark *)); + +@theme inline { + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); +} + +:root { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 0000000..93fde25 --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,21 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], +"baseUrl": ".", + "paths": { + "@/*": [ + "./src/*" + ] + }, + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..3bc830d --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,18 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.node.json" + } + ], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + }, + "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"] + } +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..8a67f62 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..01de06d --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,13 @@ +import path from 'node:path' +import { defineConfig } from 'vite' +import tailwindcss from '@tailwindcss/vite' +import vue from '@vitejs/plugin-vue' + +export default defineConfig({ + plugins: [vue(), tailwindcss()], + resolve: { + alias: { + '@': path.resolve(__dirname, './src'), + }, + }, +})