From fa57938a9d49a23730b92ef9591347b6ff91f55a Mon Sep 17 00:00:00 2001 From: "Conner.G" <1143059327@qq.com> Date: Sun, 21 Dec 2025 20:31:42 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=94=A8=E6=88=B7=E8=B5=84?= =?UTF-8?q?=E6=96=99=E7=82=B9=E5=87=BB=E9=80=BB=E8=BE=91=EF=BC=8C=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E9=A1=B5=E9=9D=A2UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- course-web/package-lock.json | 11 + course-web/src/App.jsx | 28 +- course-web/src/components/UserMenu.jsx | 283 ++++++++++++++++++ course-web/src/components/ui/GlassCard.jsx | 2 +- course-web/src/components/views/PathView.jsx | 26 +- .../src/components/views/ScriptView.jsx | 44 +-- .../src/components/views/TimelineView.jsx | 16 +- course-web/src/index.css | 54 +++- course-web/src/pages/DashboardPage.jsx | 67 +++-- course-web/src/pages/LandingPage.jsx | 4 +- course-web/src/pages/OnboardingPage.jsx | 2 +- course-web/vite.config.js | 3 +- 12 files changed, 451 insertions(+), 89 deletions(-) create mode 100644 course-web/src/components/UserMenu.jsx diff --git a/course-web/package-lock.json b/course-web/package-lock.json index fdfbf47..a2f8003 100644 --- a/course-web/package-lock.json +++ b/course-web/package-lock.json @@ -64,6 +64,7 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -1399,6 +1400,7 @@ "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -1440,6 +1442,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1599,6 +1602,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -1912,6 +1916,7 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -3052,6 +3057,7 @@ "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -3078,6 +3084,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -3125,6 +3132,7 @@ "resolved": "https://registry.npmmirror.com/react/-/react-19.2.3.tgz", "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -3134,6 +3142,7 @@ "resolved": "https://registry.npmmirror.com/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -3399,6 +3408,7 @@ "resolved": "https://registry.npmmirror.com/rolldown-vite/-/rolldown-vite-7.2.5.tgz", "integrity": "sha512-u09tdk/huMiN8xwoiBbig197jKdCamQTtOruSalOzbqGje3jdHiV0njQlAW0YvzoahkirFePNQ4RYlfnRQpXZA==", "license": "MIT", + "peer": true, "dependencies": { "@oxc-project/runtime": "0.97.0", "fdir": "^6.5.0", @@ -3521,6 +3531,7 @@ "integrity": "sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==", "dev": true, "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/course-web/src/App.jsx b/course-web/src/App.jsx index 535540e..64ad5ea 100644 --- a/course-web/src/App.jsx +++ b/course-web/src/App.jsx @@ -10,9 +10,31 @@ function App() { // Logic is now in CurrentPage, App just provides layout return (
- {/* Global Background */} -
-
+ {/* Global Background with Gradient and Glow Effects - Similar to image */} +
+ {/* Base Gradient Background - From blue (left) to dark brown (right) with blue gradient */} +
+ {/* Blue gradient layer for left side */} +
+ {/* Additional gradient layer for smoother transition */} +
+ {/* Vertical gradient for depth */} +
+ + {/* Glow Effects - Enhanced blue on left */} + {/* Left side - Enhanced Blue glow */} +
+
+
+ + {/* Right side - Reddish-orange glow (bottom right prominent like in image) */} +
+
+ + {/* Central subtle glow */} +
+
+
{/* Page Content */} diff --git a/course-web/src/components/UserMenu.jsx b/course-web/src/components/UserMenu.jsx new file mode 100644 index 0000000..cb63a19 --- /dev/null +++ b/course-web/src/components/UserMenu.jsx @@ -0,0 +1,283 @@ +import React, { useState, useRef, useEffect } from 'react'; +import { useStoreData } from '../hooks/useStoreData'; +import { Store } from '../utils/store'; +import { User, Settings, LogOut, X, Edit2 } from 'lucide-react'; +import { GlassCard } from './ui/GlassCard'; +import { Button } from './ui/Button'; +import clsx from 'clsx'; + +/** + * 用户资料菜单组件 + * 显示用户信息、编辑资料和退出登录选项 + */ +export function UserMenu({ isOpen, onClose, onLogout }) { + const data = useStoreData(); + const [showEditModal, setShowEditModal] = useState(false); + const menuRef = useRef(null); + + // 每次打开菜单时,重置编辑模态框状态(模仿 PncyssD 的逻辑) + // 确保每次打开菜单都显示主菜单界面,而不是编辑界面 + useEffect(() => { + if (isOpen) { + // 菜单打开时,确保编辑模态框是关闭的 + setShowEditModal(false); + } + }, [isOpen]); + + // 点击外部关闭菜单 + useEffect(() => { + if (!isOpen) return; + + const handleClickOutside = (event) => { + if (menuRef.current && !menuRef.current.contains(event.target)) { + onClose(); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + return () => document.removeEventListener('mousedown', handleClickOutside); + }, [isOpen, onClose]); + + // 如果菜单未打开,不渲染任何内容(除非正在显示编辑模态框) + if (!isOpen && !showEditModal) return null; + + // 如果正在显示编辑模态框,只渲染编辑模态框 + if (showEditModal) { + return ( + { + setShowEditModal(false); + // 编辑模态框关闭后,如果菜单是打开的,会显示主菜单 + }} + userProfile={data.userProfile} + /> + ); + } + + // 显示主菜单(isOpen 为 true 且 showEditModal 为 false) + + // 显示主菜单 + return ( + <> + {/* 菜单遮罩层 */} +
+ + {/* 用户菜单 */} +
+
+ {/* 用户信息头部 */} +
+
+ {data.userProfile.nickname?.[0] || 'U'} +
+
+
+ {data.userProfile.nickname || '旅人'} +
+
+ + {data.userProfile.mbti || '未知'} · {data.userProfile.zodiac || '未知'} +
+
+
+ + {/* 统计数据 */} +
+
+
+ {data.lifeTimeline?.length || 0} +
+
+ 生命足迹 +
+
+
+
+ {data.generatedScripts?.length || 0} +
+
+ 剧本生成 +
+
+
+ + {/* 操作按钮 */} +
+ + +
+
+
+ + ); +} + +/** + * 编辑资料模态框组件 + */ +function EditProfileModal({ onClose, userProfile }) { + const [formData, setFormData] = useState({ + nickname: userProfile.nickname || '', + mbti: userProfile.mbti || '', + zodiac: userProfile.zodiac || '', + hobbies: userProfile.hobbies?.join(', ') || '', + gender: userProfile.gender || 'secret' + }); + const [isSaving, setIsSaving] = useState(false); + + const handleSave = () => { + setIsSaving(true); + + // 更新用户资料 + Store.updateProfile({ + nickname: formData.nickname, + mbti: formData.mbti, + zodiac: formData.zodiac, + hobbies: formData.hobbies.split(',').map(s => s.trim()).filter(s => s), + gender: formData.gender + }); + + setTimeout(() => { + setIsSaving(false); + onClose(); + }, 300); + }; + + return ( +
+ + {/* 关闭按钮 */} + + + {/* 标题 */} +
+
+ +
+
+

编辑资料

+

调整你的人生航向基础信息

+
+
+ + {/* 表单 */} +
+
+ + setFormData({ ...formData, nickname: e.target.value })} + placeholder="你想被如何称呼?" + className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-xl text-white placeholder-white/30 focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary/50 transition-all" + /> +
+ +
+
+ + setFormData({ ...formData, mbti: e.target.value })} + placeholder="性格色彩" + className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-xl text-white placeholder-white/30 focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary/50 transition-all" + /> +
+
+ + setFormData({ ...formData, zodiac: e.target.value })} + placeholder="星辰指引" + className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-xl text-white placeholder-white/30 focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary/50 transition-all" + /> +
+
+ +
+ + setFormData({ ...formData, hobbies: e.target.value })} + placeholder="让灵魂起舞的事物(用逗号分隔)" + className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-xl text-white placeholder-white/30 focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary/50 transition-all" + /> +
+ +
+ + +
+
+ + {/* 操作按钮 */} +
+ + +
+
+
+ ); +} + diff --git a/course-web/src/components/ui/GlassCard.jsx b/course-web/src/components/ui/GlassCard.jsx index e347eef..d304b13 100644 --- a/course-web/src/components/ui/GlassCard.jsx +++ b/course-web/src/components/ui/GlassCard.jsx @@ -9,7 +9,7 @@ export function GlassCard({ children, className, ...props }) { return (
-

- +

+ 实现路径 @@ -132,14 +132,14 @@ export function PathView({ onSwitchToScript }) {

将幻想落地为行动,AI为你定制专属计划。

-
- -

你需要先有一个剧本,才能生成通往它的路径。

+
+ +

你需要先有一个剧本,才能生成通往它的路径。

@@ -149,7 +149,7 @@ export function PathView({ onSwitchToScript }) { return (
-

+

@@ -245,11 +245,11 @@ export function PathView({ onSwitchToScript }) { onClick={() => setExpandedStep(expandedStep === idx ? null : idx)} >
-
+
{idx + 1}
-

{step.phase}

+

{step.phase}

{step.time} @@ -277,7 +277,7 @@ export function PathView({ onSwitchToScript }) {
handleStepEdit(idx, 'content', e.currentTarget.textContent)} - className={`p-3 rounded-lg text-sm text-gray-300 leading-relaxed border transition-colors ${ + className={`p-3 rounded-lg text-sm text-beige/90 leading-relaxed border transition-colors ${ isEditing ? 'bg-white/10 border-primary/50 ring-2 ring-primary/20' : 'bg-white/5 border-white/5' @@ -325,7 +325,7 @@ export function PathView({ onSwitchToScript }) {
{/* Habits */}
-
+
养成习惯
{step.habit} diff --git a/course-web/src/components/views/ScriptView.jsx b/course-web/src/components/views/ScriptView.jsx index 64a17de..1f45db5 100644 --- a/course-web/src/components/views/ScriptView.jsx +++ b/course-web/src/components/views/ScriptView.jsx @@ -81,9 +81,9 @@ export function ScriptView({ onSwitchToPath }) { return (
-

+

- 剧本生成器 + 爽文剧本

基于你的真实画像,编织平行时空的无限可能。

@@ -108,7 +108,7 @@ export function ScriptView({ onSwitchToPath }) { {data.userProfile.nickname ? data.userProfile.nickname[0] : 'U'}
-
{data.userProfile.nickname || '未命名'}
+
{data.userProfile.nickname || '未命名'}
{data.userProfile.mbti} {data.userProfile.zodiac || '星辰'} @@ -116,12 +116,12 @@ export function ScriptView({ onSwitchToPath }) {
-
- 天赋 +
+ 天赋 {(data.userProfile.hobbies || []).join(' / ') || '暂无'}
-
- 愿景 +
+ 愿景 {data.userProfile.futureVision || '暂无'}
@@ -130,7 +130,7 @@ export function ScriptView({ onSwitchToPath }) { {/* Input Form */} -