diff --git a/Dockerfile b/Dockerfile
index b26bde7..ed4e615 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,15 +1,16 @@
-FROM node:latest AS builder
+FROM node:lts-alpine AS builder
RUN mkdir -p /workspace
WORKDIR /workspace
+RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
+RUN apk update && apk add git
RUN npm config set registry https://registry.npmmirror.com
RUN git clone https://github.com/setube/ogame-vue-ts.git
RUN mv ./ogame-vue-ts/* . ; rm -rf ./ogame-vue-ts/
RUN npm install -g pnpm ; pnpm install;
-RUN pnpm build
+RUN pnpm run build
-# --- 第二阶段:Nginx ---
FROM nginx:alpine
COPY nginx.conf /etc/nginx/conf.d/default.conf
diff --git a/package.json b/package.json
index 6b0a664..a7a48a2 100644
--- a/package.json
+++ b/package.json
@@ -23,18 +23,16 @@
"@tailwindcss/vite": "^4.1.17",
"@tanstack/vue-table": "^8.21.3",
"@vueuse/core": "^14.1.0",
- "class-variance-authority": "^0.7.1",
- "clsx": "^2.1.1",
"crypto-js": "^4.2.0",
"file-saver": "^2.0.5",
"finalhandler": "^2.1.1",
"lucide-vue-next": "^0.556.0",
"marked": "^17.0.1",
+ "motion-v": "^1.7.4",
"pinia": "^3.0.4",
"pinia-plugin-persistedstate": "^4.7.1",
"reka-ui": "^2.6.1",
"serve-static": "^2.2.0",
- "tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.17",
"vue": "^3.5.24",
"vue-router": "4",
@@ -46,10 +44,13 @@
"@types/node": "^24.10.2",
"@vitejs/plugin-vue": "^6.0.1",
"@vue/tsconfig": "^0.8.1",
+ "class-variance-authority": "^0.7.1",
+ "clsx": "^2.1.1",
"cross-env": "^7.0.3",
"electron": "^39.2.7",
"electron-builder": "^26.0.12",
"electron-vite": "^5.0.0",
+ "tailwind-merge": "^3.4.0",
"tw-animate-css": "^1.4.0",
"typescript": "~5.9.3",
"vite": "npm:rolldown-vite@7.2.5",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index df85f50..e633e4d 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -20,12 +20,6 @@ importers:
'@vueuse/core':
specifier: ^14.1.0
version: 14.1.0(vue@3.5.25(typescript@5.9.3))
- class-variance-authority:
- specifier: ^0.7.1
- version: 0.7.1
- clsx:
- specifier: ^2.1.1
- version: 2.1.1
crypto-js:
specifier: ^4.2.0
version: 4.2.0
@@ -41,6 +35,9 @@ importers:
marked:
specifier: ^17.0.1
version: 17.0.1
+ motion-v:
+ specifier: ^1.7.4
+ version: 1.7.4(@vueuse/core@14.1.0(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))
pinia:
specifier: ^3.0.4
version: 3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))
@@ -53,9 +50,6 @@ importers:
serve-static:
specifier: ^2.2.0
version: 2.2.0
- tailwind-merge:
- specifier: ^3.4.0
- version: 3.4.0
tailwindcss:
specifier: ^4.1.17
version: 4.1.17
@@ -84,6 +78,12 @@ importers:
'@vue/tsconfig':
specifier: ^0.8.1
version: 0.8.1(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))
+ class-variance-authority:
+ specifier: ^0.7.1
+ version: 0.7.1
+ clsx:
+ specifier: ^2.1.1
+ version: 2.1.1
cross-env:
specifier: ^7.0.3
version: 7.0.3
@@ -96,6 +96,9 @@ importers:
electron-vite:
specifier: ^5.0.0
version: 5.0.0(rolldown-vite@7.2.5(@types/node@24.10.2)(esbuild@0.25.12)(jiti@2.6.1)(terser@5.44.1))
+ tailwind-merge:
+ specifier: ^3.4.0
+ version: 3.4.0
tw-animate-css:
specifier: ^1.4.0
version: 1.4.0
@@ -2103,6 +2106,20 @@ packages:
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
engines: {node: '>= 6'}
+ framer-motion@12.23.12:
+ resolution: {integrity: sha512-6e78rdVtnBvlEVgu6eFEAgG9v3wLnYEboM8I5O5EXvfKC8gxGQB8wXJdhkMy10iVcn05jl6CNw7/HTsTCfwcWg==}
+ peerDependencies:
+ '@emotion/is-prop-valid': '*'
+ react: ^18.0.0 || ^19.0.0
+ react-dom: ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@emotion/is-prop-valid':
+ optional: true
+ react:
+ optional: true
+ react-dom:
+ optional: true
+
fresh@2.0.0:
resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
engines: {node: '>= 0.8'}
@@ -2244,6 +2261,9 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
+ hey-listen@1.0.8:
+ resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==}
+
hookable@5.5.3:
resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
@@ -2772,6 +2792,18 @@ packages:
engines: {node: '>=10'}
hasBin: true
+ motion-dom@12.23.12:
+ resolution: {integrity: sha512-RcR4fvMCTESQBD/uKQe49D5RUeDOokkGRmz4ceaJKDBgHYtZtntC/s2vLvY38gqGaytinij/yi3hMcWVcEF5Kw==}
+
+ motion-utils@12.23.6:
+ resolution: {integrity: sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==}
+
+ motion-v@1.7.4:
+ resolution: {integrity: sha512-YNDUAsany04wfI7YtHxQK3kxzNvh+OdFUk9GpA3+hMt7j6P+5WrVAAgr8kmPPoVza9EsJiAVhqoN3YYFN0Twrw==}
+ peerDependencies:
+ '@vueuse/core': '>=10.0.0'
+ vue: '>=3.0.0'
+
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
@@ -6027,6 +6059,12 @@ snapshots:
hasown: 2.0.2
mime-types: 2.1.35
+ framer-motion@12.23.12:
+ dependencies:
+ motion-dom: 12.23.12
+ motion-utils: 12.23.6
+ tslib: 2.8.1
+
fresh@2.0.0: {}
fs-extra@10.1.0:
@@ -6208,6 +6246,8 @@ snapshots:
dependencies:
function-bind: 1.1.2
+ hey-listen@1.0.8: {}
+
hookable@5.5.3: {}
hosted-git-info@4.1.0:
@@ -6694,6 +6734,24 @@ snapshots:
mkdirp@1.0.4: {}
+ motion-dom@12.23.12:
+ dependencies:
+ motion-utils: 12.23.6
+
+ motion-utils@12.23.6: {}
+
+ motion-v@1.7.4(@vueuse/core@14.1.0(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)):
+ dependencies:
+ '@vueuse/core': 14.1.0(vue@3.5.25(typescript@5.9.3))
+ framer-motion: 12.23.12
+ hey-listen: 1.0.8
+ motion-dom: 12.23.12
+ vue: 3.5.25(typescript@5.9.3)
+ transitivePeerDependencies:
+ - '@emotion/is-prop-valid'
+ - react
+ - react-dom
+
ms@2.1.3: {}
muggle-string@0.4.1: {}
diff --git a/src/App.vue b/src/App.vue
index f2182b4..c093067 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -327,9 +327,30 @@
-
-
-
+
+
+
@@ -453,6 +474,8 @@
import { toast } from 'vue-sonner'
import { migrateGameData } from '@/utils/migration'
import { checkLatestVersion } from '@/utils/versionCheck'
+ import {StarsBackground} from "@/components/ui/bg-stars";
+ import {ParticlesBg} from "@/components/ui/particles-bg";
// 执行数据迁移(在 store 初始化之前)
migrateGameData()
diff --git a/src/assets/main.css b/src/assets/main.css
new file mode 100644
index 0000000..3deaa42
--- /dev/null
+++ b/src/assets/main.css
@@ -0,0 +1,92 @@
+@custom-variant dark (&:is(.dark *));
+
+:root {
+ --card: oklch(1 0 0);
+ --card-foreground: oklch(0.141 0.005 285.823);
+ --popover: oklch(1 0 0);
+ --popover-foreground: oklch(0.141 0.005 285.823);
+ --primary: oklch(0.21 0.006 285.885);
+ --primary-foreground: oklch(0.985 0 0);
+ --secondary: oklch(0.967 0.001 286.375);
+ --secondary-foreground: oklch(0.21 0.006 285.885);
+ --muted: oklch(0.967 0.001 286.375);
+ --muted-foreground: oklch(0.552 0.016 285.938);
+ --accent: oklch(0.967 0.001 286.375);
+ --accent-foreground: oklch(0.21 0.006 285.885);
+ --destructive: oklch(0.577 0.245 27.325);
+ --destructive-foreground: oklch(0.577 0.245 27.325);
+ --border: oklch(0.92 0.004 286.32);
+ --input: oklch(0.92 0.004 286.32);
+ --ring: oklch(0.705 0.015 286.067);
+ --radius: 0.625rem;
+ --background: oklch(1 0 0);
+ --foreground: oklch(0.141 0.005 285.823);
+}
+
+.dark {
+ --background: oklch(0.141 0.005 285.823);
+ --foreground: oklch(0.985 0 0);
+ --card: oklch(0.141 0.005 285.823);
+ --card-foreground: oklch(0.985 0 0);
+ --popover: oklch(0.141 0.005 285.823);
+ --popover-foreground: oklch(0.985 0 0);
+ --primary: oklch(0.985 0 0);
+ --primary-foreground: oklch(0.21 0.006 285.885);
+ --secondary: oklch(0.274 0.006 286.033);
+ --secondary-foreground: oklch(0.985 0 0);
+ --muted: oklch(0.274 0.006 286.033);
+ --muted-foreground: oklch(0.705 0.015 286.067);
+ --accent: oklch(0.274 0.006 286.033);
+ --accent-foreground: oklch(0.985 0 0);
+ --destructive: oklch(0.396 0.141 25.723);
+ --destructive-foreground: oklch(0.637 0.237 25.331);
+ --border: oklch(0.274 0.006 286.033);
+ --input: oklch(0.274 0.006 286.033);
+ --ring: oklch(0.442 0.017 285.786);
+}
+
+@theme inline {
+ --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-destructive-foreground: var(--destructive-foreground);
+ --color-border: var(--border);
+ --color-input: var(--input);
+ --color-ring: var(--ring);
+
+ --radius-sm: calc(var(--radius) - 4px);
+ --radius-md: calc(var(--radius) - 2px);
+ --radius-lg: var(--radius);
+ --radius-xl: calc(var(--radius) + 4px);
+}
+
+@layer base {
+ * {
+ @apply border-border outline-ring/50;
+ }
+ body {
+ @apply bg-background text-foreground;
+ }
+}
+
+html {
+ color-scheme: light dark;
+}
+html.dark {
+ color-scheme: dark;
+}
+html.light {
+ color-scheme: light;
+}
diff --git a/src/components/ui/bg-stars/StarsBackground.vue b/src/components/ui/bg-stars/StarsBackground.vue
new file mode 100644
index 0000000..ccec34b
--- /dev/null
+++ b/src/components/ui/bg-stars/StarsBackground.vue
@@ -0,0 +1,176 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/ui/bg-stars/index.ts b/src/components/ui/bg-stars/index.ts
new file mode 100644
index 0000000..205c143
--- /dev/null
+++ b/src/components/ui/bg-stars/index.ts
@@ -0,0 +1 @@
+export { default as StarsBackground } from "./StarsBackground.vue";
diff --git a/src/components/ui/particles-bg/ParticlesBg.vue b/src/components/ui/particles-bg/ParticlesBg.vue
new file mode 100644
index 0000000..13607db
--- /dev/null
+++ b/src/components/ui/particles-bg/ParticlesBg.vue
@@ -0,0 +1,250 @@
+
+
+
+
+
+
+
diff --git a/src/components/ui/particles-bg/index.ts b/src/components/ui/particles-bg/index.ts
new file mode 100644
index 0000000..e544838
--- /dev/null
+++ b/src/components/ui/particles-bg/index.ts
@@ -0,0 +1 @@
+export { default as ParticlesBg } from "./ParticlesBg.vue";
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index 2aec90c..c66a9d9 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -1,7 +1,7 @@
-import type { ClassValue } from 'clsx'
-import { clsx } from 'clsx'
-import { twMerge } from 'tailwind-merge'
+import type { ClassValue } from "clsx"
+import { clsx } from "clsx"
+import { twMerge } from "tailwind-merge"
-export const cn = (...inputs: ClassValue[]) => {
+export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
diff --git a/src/style.css b/src/style.css
index b518455..d1b0bc8 100644
--- a/src/style.css
+++ b/src/style.css
@@ -1,5 +1,6 @@
@import "tailwindcss";
@import "tw-animate-css";
+@import "@/assets/main.css";
@custom-variant dark (&:is(.dark *));