添加用户资料点击逻辑,更新页面UI

This commit is contained in:
Conner.G
2025-12-21 20:31:42 +08:00
parent 6b9b74c9e4
commit fa57938a9d
12 changed files with 451 additions and 89 deletions
+11
View File
@@ -64,6 +64,7 @@
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.27.1", "@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5", "@babel/generator": "^7.28.5",
@@ -1399,6 +1400,7 @@
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"csstype": "^3.2.2" "csstype": "^3.2.2"
} }
@@ -1440,6 +1442,7 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
@@ -1599,6 +1602,7 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"baseline-browser-mapping": "^2.9.0", "baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759", "caniuse-lite": "^1.0.30001759",
@@ -1912,6 +1916,7 @@
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1", "@eslint-community/regexpp": "^4.12.1",
@@ -3052,6 +3057,7 @@
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz", "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
@@ -3078,6 +3084,7 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"nanoid": "^3.3.11", "nanoid": "^3.3.11",
"picocolors": "^1.1.1", "picocolors": "^1.1.1",
@@ -3125,6 +3132,7 @@
"resolved": "https://registry.npmmirror.com/react/-/react-19.2.3.tgz", "resolved": "https://registry.npmmirror.com/react/-/react-19.2.3.tgz",
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@@ -3134,6 +3142,7 @@
"resolved": "https://registry.npmmirror.com/react-dom/-/react-dom-19.2.3.tgz", "resolved": "https://registry.npmmirror.com/react-dom/-/react-dom-19.2.3.tgz",
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"scheduler": "^0.27.0" "scheduler": "^0.27.0"
}, },
@@ -3399,6 +3408,7 @@
"resolved": "https://registry.npmmirror.com/rolldown-vite/-/rolldown-vite-7.2.5.tgz", "resolved": "https://registry.npmmirror.com/rolldown-vite/-/rolldown-vite-7.2.5.tgz",
"integrity": "sha512-u09tdk/huMiN8xwoiBbig197jKdCamQTtOruSalOzbqGje3jdHiV0njQlAW0YvzoahkirFePNQ4RYlfnRQpXZA==", "integrity": "sha512-u09tdk/huMiN8xwoiBbig197jKdCamQTtOruSalOzbqGje3jdHiV0njQlAW0YvzoahkirFePNQ4RYlfnRQpXZA==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@oxc-project/runtime": "0.97.0", "@oxc-project/runtime": "0.97.0",
"fdir": "^6.5.0", "fdir": "^6.5.0",
@@ -3521,6 +3531,7 @@
"integrity": "sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==", "integrity": "sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"funding": { "funding": {
"url": "https://github.com/sponsors/colinhacks" "url": "https://github.com/sponsors/colinhacks"
} }
+25 -3
View File
@@ -10,9 +10,31 @@ function App() {
// Logic is now in CurrentPage, App just provides layout // Logic is now in CurrentPage, App just provides layout
return ( return (
<div className="relative min-h-screen font-sans text-gray-100 overflow-hidden"> <div className="relative min-h-screen font-sans text-gray-100 overflow-hidden">
{/* Global Background */} {/* Global Background with Gradient and Glow Effects - Similar to image */}
<div className="fixed inset-0 -z-20 bg-gradient-to-br from-deep-sea via-[#1a3c46] to-[#155e55] opacity-100 transition-colors duration-1000"></div> <div className="fixed inset-0 -z-30">
<div className="fixed inset-0 -z-10 bg-noise opacity-20 brightness-100 contrast-150 pointer-events-none"></div> {/* Base Gradient Background - From blue (left) to dark brown (right) with blue gradient */}
<div className="absolute inset-0 bg-gradient-to-r from-[#1a1c2c] via-[#1a1c2c] via-[#1f1f2e] to-[#2d1b1b]"></div>
{/* Blue gradient layer for left side */}
<div className="absolute inset-0 bg-gradient-to-r from-[#1e3a5f]/40 via-[#1a1c2c]/30 to-transparent"></div>
{/* Additional gradient layer for smoother transition */}
<div className="absolute inset-0 bg-gradient-to-r from-[#1a1c2c]/75 via-[#1f1f2e]/55 to-[#2d1b1b]/75"></div>
{/* Vertical gradient for depth */}
<div className="absolute inset-0 bg-gradient-to-b from-[#1a1c2c]/65 via-transparent to-[#2d1b1b]/55"></div>
{/* Glow Effects - Enhanced blue on left */}
{/* Left side - Enhanced Blue glow */}
<div className="absolute top-[-8%] left-[-8%] w-[60%] h-[60%] bg-blue-700/25 blur-[140px] rounded-full animate-float"></div>
<div className="absolute bottom-[5%] left-[5%] w-[45%] h-[45%] bg-blue-800/20 blur-[110px] rounded-full animate-pulse-slow"></div>
<div className="absolute top-[20%] left-[15%] w-[35%] h-[35%] bg-cyan-800/15 blur-[100px] rounded-full animate-float"></div>
{/* Right side - Reddish-orange glow (bottom right prominent like in image) */}
<div className="absolute bottom-[-8%] right-[-8%] w-[55%] h-[55%] bg-orange-800/22 blur-[140px] rounded-full animate-float-delayed"></div>
<div className="absolute top-[15%] right-[10%] w-[40%] h-[40%] bg-amber-800/16 blur-[120px] rounded-full animate-pulse-slow"></div>
{/* Central subtle glow */}
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[50%] h-[50%] bg-orange-900/12 blur-[160px] rounded-full"></div>
</div>
<div className="fixed inset-0 -z-10 bg-noise opacity-10 brightness-120 contrast-130 pointer-events-none"></div>
{/* Page Content */} {/* Page Content */}
<CurrentPage /> <CurrentPage />
+283
View File
@@ -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 (
<EditProfileModal
onClose={() => {
setShowEditModal(false);
// 编辑模态框关闭后,如果菜单是打开的,会显示主菜单
}}
userProfile={data.userProfile}
/>
);
}
// 显示主菜单(isOpen 为 true 且 showEditModal 为 false
// 显示主菜单
return (
<>
{/* 菜单遮罩层 */}
<div
className="fixed inset-0 z-40"
onClick={onClose}
/>
{/* 用户菜单 */}
<div
ref={menuRef}
className="fixed top-24 md:top-4 left-4 md:left-[300px] z-50 w-[calc(100%-2rem)] md:w-80 animate-fade-in"
>
<div className="bg-[#1a1c2c]/95 border border-white/20 shadow-2xl rounded-2xl p-6 space-y-6 backdrop-blur-sm">
{/* 用户信息头部 */}
<div className="flex items-center gap-4 pb-4 border-b border-white/10">
<div className="w-16 h-16 rounded-2xl bg-gradient-to-br from-primary/30 to-blue-600/30 flex items-center justify-center text-2xl font-bold text-white border border-white/20 shadow-lg">
{data.userProfile.nickname?.[0] || 'U'}
</div>
<div className="flex-1 overflow-hidden">
<div className="font-bold text-gray-100 text-lg truncate">
{data.userProfile.nickname || '旅人'}
</div>
<div className="text-xs text-primary flex items-center gap-1.5 mt-1">
<span className="w-1.5 h-1.5 rounded-full bg-primary shadow-[0_0_5px_rgba(205,133,63,0.5)] animate-pulse"></span>
{data.userProfile.mbti || '未知'} · {data.userProfile.zodiac || '未知'}
</div>
</div>
</div>
{/* 统计数据 */}
<div className="grid grid-cols-2 gap-3">
<div className="p-4 bg-white/5 rounded-xl border border-white/5 text-center">
<div className="text-2xl font-bold text-primary">
{data.lifeTimeline?.length || 0}
</div>
<div className="text-[10px] text-white/40 uppercase tracking-widest mt-1">
生命足迹
</div>
</div>
<div className="p-4 bg-white/5 rounded-xl border border-white/5 text-center">
<div className="text-2xl font-bold text-blue-400">
{data.generatedScripts?.length || 0}
</div>
<div className="text-[10px] text-white/40 uppercase tracking-widest mt-1">
剧本生成
</div>
</div>
</div>
{/* 操作按钮 */}
<div className="space-y-2 pt-2 border-t border-white/5">
<Button
variant="secondary"
size="md"
className="w-full justify-start"
onClick={() => {
setShowEditModal(true);
// 不关闭主菜单,让编辑模态框显示在主菜单之上
// 这样关闭编辑模态框后,主菜单仍然可见
}}
>
<Settings className="w-4 h-4 mr-2" />
编辑资料
</Button>
<Button
variant="ghost"
size="md"
className="w-full justify-start text-red-400 hover:text-red-300 hover:bg-red-500/10"
onClick={() => {
if (window.confirm('确定要退出登录并清除所有数据吗?此操作不可逆。')) {
Store.reset();
if (onLogout) onLogout();
}
}}
>
<LogOut className="w-4 h-4 mr-2" />
退出登录
</Button>
</div>
</div>
</div>
</>
);
}
/**
* 编辑资料模态框组件
*/
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 (
<div className="fixed inset-0 z-[100] flex items-center justify-center p-4 bg-black/60 backdrop-blur-xl">
<GlassCard className="w-full max-w-lg p-8 relative max-h-[90vh] overflow-y-auto">
{/* 关闭按钮 */}
<button
onClick={onClose}
className="absolute top-6 right-6 text-white/40 hover:text-white transition-colors z-10"
>
<X className="w-5 h-5" />
</button>
{/* 标题 */}
<div className="flex items-center gap-4 mb-8">
<div className="w-12 h-12 rounded-xl bg-primary/20 flex items-center justify-center">
<Edit2 className="text-primary w-6 h-6" />
</div>
<div>
<h3 className="text-2xl font-bold text-gray-100">编辑资料</h3>
<p className="text-xs text-gray-400 mt-1">调整你的人生航向基础信息</p>
</div>
</div>
{/* 表单 */}
<div className="space-y-6">
<div>
<label className="text-sm font-medium text-gray-300 mb-2 block">昵称</label>
<input
type="text"
value={formData.nickname}
onChange={(e) => 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"
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="text-sm font-medium text-gray-300 mb-2 block">MBTI</label>
<input
type="text"
value={formData.mbti}
onChange={(e) => 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"
/>
</div>
<div>
<label className="text-sm font-medium text-gray-300 mb-2 block">星座</label>
<input
type="text"
value={formData.zodiac}
onChange={(e) => 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"
/>
</div>
</div>
<div>
<label className="text-sm font-medium text-gray-300 mb-2 block">兴趣爱好</label>
<input
type="text"
value={formData.hobbies}
onChange={(e) => 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"
/>
</div>
<div>
<label className="text-sm font-medium text-gray-300 mb-2 block">性别</label>
<select
value={formData.gender}
onChange={(e) => setFormData({ ...formData, gender: e.target.value })}
className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-xl text-white focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary/50 transition-all"
>
<option value="secret">保密</option>
<option value="male"></option>
<option value="female"></option>
</select>
</div>
</div>
{/* 操作按钮 */}
<div className="flex gap-4 mt-8 pt-6 border-t border-white/5">
<Button
variant="primary"
size="md"
className="flex-1"
onClick={handleSave}
isLoading={isSaving}
>
保存修改
</Button>
<Button
variant="ghost"
size="md"
onClick={onClose}
>
取消
</Button>
</div>
</GlassCard>
</div>
);
}
+1 -1
View File
@@ -9,7 +9,7 @@ export function GlassCard({ children, className, ...props }) {
return ( return (
<div <div
className={clsx( className={clsx(
"bg-white/5 backdrop-blur-xl border border-white/10 shadow-2xl rounded-2xl transition-all duration-300", "bg-white/10 backdrop-blur-xl border border-white/15 shadow-2xl rounded-2xl transition-all duration-300",
className className
)} )}
{...props} {...props}
+13 -13
View File
@@ -123,8 +123,8 @@ export function PathView({ onSwitchToScript }) {
return ( return (
<div className="max-w-4xl mx-auto md:p-12 pb-24"> <div className="max-w-4xl mx-auto md:p-12 pb-24">
<header className="mb-8"> <header className="mb-8">
<h2 className="text-3xl font-bold text-white mb-2 flex items-center gap-2"> <h2 className="text-3xl font-bold text-gold-gradient mb-2 flex items-center gap-2">
<span className="bg-green-100/10 p-2 rounded-lg text-aurora-green"> <span className="bg-primary/10 p-2 rounded-lg text-primary">
<Map className="w-6 h-6 icon-glow" /> <Map className="w-6 h-6 icon-glow" />
</span> </span>
实现路径 实现路径
@@ -132,14 +132,14 @@ export function PathView({ onSwitchToScript }) {
<p className="text-gray-400">将幻想落地为行动AI为你定制专属计划</p> <p className="text-gray-400">将幻想落地为行动AI为你定制专属计划</p>
</header> </header>
<div className="p-16 text-center text-gray-400 glass-card rounded-2xl border-dashed border-2 border-white/10"> <div className="p-16 text-center rounded-2xl border border-white/10 bg-[#1a1c2c]/40 backdrop-blur-sm">
<Ghost className="w-16 h-16 mx-auto mb-4 opacity-30" /> <Ghost className="w-16 h-16 mx-auto mb-4 opacity-20 text-gray-500" />
<p className="mb-4">你需要先有一个剧本才能生成通往它的路径</p> <p className="mb-4 text-gray-400">你需要先有一个剧本才能生成通往它的路径</p>
<button <button
className="text-primary font-bold hover:underline flex items-center justify-center gap-1 mx-auto" className="text-primary font-bold hover:text-accent transition-colors flex items-center justify-center gap-1 mx-auto group"
onClick={onSwitchToScript} onClick={onSwitchToScript}
> >
去生成剧本 <ArrowRight className="w-4 h-4" /> 去生成剧本 <ArrowRight className="w-4 h-4 group-hover:translate-x-1 transition-transform" />
</button> </button>
</div> </div>
</div> </div>
@@ -149,7 +149,7 @@ export function PathView({ onSwitchToScript }) {
return ( return (
<div className="max-w-4xl mx-auto md:p-12 pb-24"> <div className="max-w-4xl mx-auto md:p-12 pb-24">
<header className="mb-8"> <header className="mb-8">
<h2 className="text-3xl font-bold text-white mb-2 flex items-center gap-2"> <h2 className="text-3xl font-bold text-gold-gradient mb-2 flex items-center gap-2">
<span className="bg-green-100/10 p-2 rounded-lg text-aurora-green"> <span className="bg-green-100/10 p-2 rounded-lg text-aurora-green">
<Map className="w-6 h-6 icon-glow" /> <Map className="w-6 h-6 icon-glow" />
</span> </span>
@@ -245,11 +245,11 @@ export function PathView({ onSwitchToScript }) {
onClick={() => setExpandedStep(expandedStep === idx ? null : idx)} onClick={() => setExpandedStep(expandedStep === idx ? null : idx)}
> >
<div className="flex items-center gap-5"> <div className="flex items-center gap-5">
<div className="w-10 h-10 rounded-full bg-gradient-to-br from-primary to-green-400 text-white flex items-center justify-center font-bold text-lg shadow-lg shadow-primary/30 shrink-0"> <div className="w-10 h-10 rounded-full bg-gradient-to-br from-primary to-accent text-white flex items-center justify-center font-bold text-lg shadow-lg shadow-primary/30 shrink-0">
{idx + 1} {idx + 1}
</div> </div>
<div> <div>
<h4 className="font-bold text-lg text-white">{step.phase}</h4> <h4 className="font-bold text-lg text-beige">{step.phase}</h4>
<span className="text-xs text-primary font-medium bg-primary/10 px-2 py-0.5 rounded-full border border-primary/20"> <span className="text-xs text-primary font-medium bg-primary/10 px-2 py-0.5 rounded-full border border-primary/20">
{step.time} {step.time}
</span> </span>
@@ -277,7 +277,7 @@ export function PathView({ onSwitchToScript }) {
<div <div
contentEditable={isEditing} contentEditable={isEditing}
onBlur={(e) => handleStepEdit(idx, 'content', e.currentTarget.textContent)} onBlur={(e) => 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 isEditing
? 'bg-white/10 border-primary/50 ring-2 ring-primary/20' ? 'bg-white/10 border-primary/50 ring-2 ring-primary/20'
: 'bg-white/5 border-white/5' : 'bg-white/5 border-white/5'
@@ -325,7 +325,7 @@ export function PathView({ onSwitchToScript }) {
</div> </div>
{/* Habits */} {/* Habits */}
<div> <div>
<h5 className="text-xs font-bold text-green-400 uppercase tracking-wider mb-2 flex items-center gap-1"> <h5 className="text-xs font-bold text-primary uppercase tracking-wider mb-2 flex items-center gap-1">
<Repeat className="w-3 h-3" /> 养成习惯 <Repeat className="w-3 h-3" /> 养成习惯
</h5> </h5>
<div <div
@@ -334,7 +334,7 @@ export function PathView({ onSwitchToScript }) {
className={`p-3 rounded-lg text-xs text-gray-400 leading-relaxed transition-colors ${ className={`p-3 rounded-lg text-xs text-gray-400 leading-relaxed transition-colors ${
isEditing isEditing
? 'bg-white/10 border border-primary/50 ring-2 ring-primary/20' ? 'bg-white/10 border border-primary/50 ring-2 ring-primary/20'
: 'bg-green-500/10 border border-green-500/20' : 'bg-primary/10 border border-primary/20'
}`} }`}
> >
{step.habit} {step.habit}
+22 -22
View File
@@ -81,9 +81,9 @@ export function ScriptView({ onSwitchToPath }) {
return ( return (
<div className="max-w-7xl mx-auto md:p-8 h-full flex flex-col pb-20 md:pb-0"> <div className="max-w-7xl mx-auto md:p-8 h-full flex flex-col pb-20 md:pb-0">
<header className="mb-8 px-4 md:px-0 pt-4 md:pt-0"> <header className="mb-8 px-4 md:px-0 pt-4 md:pt-0">
<h2 className="text-3xl font-bold text-white mb-2 flex items-center gap-3"> <h2 className="text-3xl font-bold text-gold-gradient mb-2 flex items-center gap-3">
<span className="bg-primary/10 p-2 rounded-xl text-primary ring-1 ring-primary/20"><Film className="w-6 h-6 icon-glow" /></span> <span className="bg-primary/10 p-2 rounded-xl text-primary ring-1 ring-primary/20"><Film className="w-6 h-6 icon-glow" /></span>
<span className="bg-clip-text text-transparent bg-gradient-to-r from-white to-gray-400">剧本生成器</span> <span className="bg-clip-text text-transparent bg-gradient-to-r from-white to-gray-400">爽文剧本</span>
</h2> </h2>
<p className="text-gray-400 ml-1">基于你的真实画像编织平行时空的无限可能</p> <p className="text-gray-400 ml-1">基于你的真实画像编织平行时空的无限可能</p>
</header> </header>
@@ -108,7 +108,7 @@ export function ScriptView({ onSwitchToPath }) {
{data.userProfile.nickname ? data.userProfile.nickname[0] : 'U'} {data.userProfile.nickname ? data.userProfile.nickname[0] : 'U'}
</div> </div>
<div> <div>
<div className="font-bold text-lg text-white">{data.userProfile.nickname || '未命名'}</div> <div className="font-bold text-lg text-beige">{data.userProfile.nickname || '未命名'}</div>
<div className="text-xs text-primary flex items-center gap-2 mt-1"> <div className="text-xs text-primary flex items-center gap-2 mt-1">
<span className="px-2 py-0.5 bg-primary/10 rounded-full border border-primary/20">{data.userProfile.mbti}</span> <span className="px-2 py-0.5 bg-primary/10 rounded-full border border-primary/20">{data.userProfile.mbti}</span>
<span className="text-gray-400">{data.userProfile.zodiac || '星辰'}</span> <span className="text-gray-400">{data.userProfile.zodiac || '星辰'}</span>
@@ -116,12 +116,12 @@ export function ScriptView({ onSwitchToPath }) {
</div> </div>
</div> </div>
<div className="space-y-3"> <div className="space-y-3">
<div className="text-xs text-gray-300 bg-black/20 p-3 rounded-xl border border-white/5"> <div className="text-xs text-beige/90 bg-black/20 p-3 rounded-xl border border-white/5">
<span className="text-primary font-bold block mb-1">天赋</span> <span className="text-gold-gradient font-bold block mb-1">天赋</span>
{(data.userProfile.hobbies || []).join(' / ') || '暂无'} {(data.userProfile.hobbies || []).join(' / ') || '暂无'}
</div> </div>
<div className="text-xs text-gray-300 bg-black/20 p-3 rounded-xl border border-white/5"> <div className="text-xs text-beige/90 bg-black/20 p-3 rounded-xl border border-white/5">
<span className="text-primary font-bold block mb-1">愿景</span> <span className="text-gold-gradient font-bold block mb-1">愿景</span>
<span className="line-clamp-2">{data.userProfile.futureVision || '暂无'}</span> <span className="line-clamp-2">{data.userProfile.futureVision || '暂无'}</span>
</div> </div>
</div> </div>
@@ -130,7 +130,7 @@ export function ScriptView({ onSwitchToPath }) {
{/* Input Form */} {/* Input Form */}
<Card className="p-5"> <Card className="p-5">
<label className="block text-sm font-bold text-gray-300 mb-2 flex items-center gap-2"> <label className="block text-sm font-bold text-beige/90 mb-2 flex items-center gap-2">
<span className="w-5 h-5 rounded-full bg-white/10 flex items-center justify-center text-xs">1</span> <span className="w-5 h-5 rounded-full bg-white/10 flex items-center justify-center text-xs">1</span>
你的渴望主题 你的渴望主题
</label> </label>
@@ -170,7 +170,7 @@ export function ScriptView({ onSwitchToPath }) {
variant="primary" variant="primary"
onClick={handleGenerate} onClick={handleGenerate}
disabled={loading} disabled={loading}
className="w-full py-3 shadow-[0_0_20px_rgba(16,185,129,0.2)] flex justify-center items-center gap-2 group" className="w-full py-3 shadow-[0_0_20px_rgba(205,133,63,0.2)] flex justify-center items-center gap-2 group"
> >
{loading ? <><Loader className="animate-spin w-4 h-4" /> 编织命运中...</> : <><Sparkles className="w-4 h-4 group-hover:rotate-12 transition-transform" /> 生成平行人生</>} {loading ? <><Loader className="animate-spin w-4 h-4" /> 编织命运中...</> : <><Sparkles className="w-4 h-4 group-hover:rotate-12 transition-transform" /> 生成平行人生</>}
</Button> </Button>
@@ -197,11 +197,11 @@ export function ScriptView({ onSwitchToPath }) {
className={clsx( className={clsx(
"group relative p-3 rounded-xl cursor-pointer transition-all border", "group relative p-3 rounded-xl cursor-pointer transition-all border",
selectedScriptId === s.id selectedScriptId === s.id
? "bg-primary/10 border-primary/30 shadow-[inset_0_0_10px_rgba(16,185,129,0.05)]" ? "bg-primary/10 border-primary/30 shadow-[inset_0_0_10px_rgba(205,133,63,0.05)]"
: "bg-transparent border-transparent hover:bg-white/5 hover:border-white/10" : "bg-transparent border-transparent hover:bg-white/5 hover:border-white/10"
)} )}
> >
<div className={clsx("font-bold text-sm truncate mb-1 pr-6 transition-colors", selectedScriptId === s.id ? "text-primary" : "text-gray-300 group-hover:text-white")}> <div className={clsx("font-bold text-sm truncate mb-1 pr-6 transition-colors", selectedScriptId === s.id ? "text-primary" : "text-beige/90 group-hover:text-beige")}>
{s.title} {s.title}
</div> </div>
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
@@ -233,8 +233,8 @@ export function ScriptView({ onSwitchToPath }) {
<div className="w-24 h-24 rounded-full bg-white/5 flex items-center justify-center mb-6 animate-pulse-slow ring-1 ring-white/10"> <div className="w-24 h-24 rounded-full bg-white/5 flex items-center justify-center mb-6 animate-pulse-slow ring-1 ring-white/10">
<Film className="w-10 h-10 opacity-40" /> <Film className="w-10 h-10 opacity-40" />
</div> </div>
<p className="text-xl mb-2 font-medium text-gray-300">舞台已就绪</p> <p className="text-xl mb-2 font-medium text-beige/90">舞台已就绪</p>
<p className="text-sm opacity-60">请在左侧输入设定生成你的平行人生</p> <p className="text-sm opacity-60">请在左侧设定需求开启你的爽文人生</p>
</div> </div>
) : ( ) : (
<Card className="h-full overflow-hidden flex flex-col relative group bg-black/20 backdrop-blur-xl border-white/10"> <Card className="h-full overflow-hidden flex flex-col relative group bg-black/20 backdrop-blur-xl border-white/10">
@@ -251,11 +251,11 @@ export function ScriptView({ onSwitchToPath }) {
<div className="flex-1 overflow-y-auto custom-scrollbar p-6 md:p-12"> <div className="flex-1 overflow-y-auto custom-scrollbar p-6 md:p-12">
<div className="text-center mb-12 border-b border-white/10 pb-8"> <div className="text-center mb-12 border-b border-white/10 pb-8">
<span className="inline-flex items-center gap-1 px-3 py-1 bg-gradient-to-r from-primary/20 to-accent/20 text-primary text-xs font-bold rounded-full mb-6 tracking-widest uppercase border border-primary/20 shadow-[0_0_10px_rgba(16,185,129,0.1)]"> <span className="inline-flex items-center gap-1 px-3 py-1 bg-gradient-to-r from-primary/20 via-accent/20 to-aurora-green/20 text-gold-gradient text-xs font-bold rounded-full mb-6 tracking-widest uppercase border border-primary/20 shadow-[0_0_10px_rgba(205,133,63,0.1)]">
<Stars className="w-3 h-3" /> <Stars className="w-3 h-3" />
{selectedScript.style === 'career' ? '职场逆袭' : selectedScript.style === 'love' ? '情感圆满' : '玄幻觉醒'} {selectedScript.style === 'career' ? '职场逆袭' : selectedScript.style === 'love' ? '情感圆满' : '玄幻觉醒'}
</span> </span>
<h2 className="text-3xl md:text-5xl font-bold text-white leading-tight mb-4 tracking-tight drop-shadow-lg">{selectedScript.title}</h2> <h2 className="text-3xl md:text-5xl font-bold text-gold-gradient leading-tight mb-4 tracking-tight drop-shadow-lg">{selectedScript.title}</h2>
<div className="text-sm text-gray-500 flex items-center justify-center gap-2"> <div className="text-sm text-gray-500 flex items-center justify-center gap-2">
<span>生成于 {new Date(selectedScript.createdAt).toLocaleDateString()}</span> <span>生成于 {new Date(selectedScript.createdAt).toLocaleDateString()}</span>
<span>·</span> <span>·</span>
@@ -275,7 +275,7 @@ export function ScriptView({ onSwitchToPath }) {
<div className="w-10 h-10 rounded-full bg-white/10 text-primary font-bold flex items-center justify-center border border-white/10 shadow-[0_0_10px_rgba(0,0,0,0.2)] z-10 shrink-0 text-lg font-serif">1</div> <div className="w-10 h-10 rounded-full bg-white/10 text-primary font-bold flex items-center justify-center border border-white/10 shadow-[0_0_10px_rgba(0,0,0,0.2)] z-10 shrink-0 text-lg font-serif">1</div>
<h4 className="font-bold text-gray-100 text-xl group-hover/chapter:text-primary transition-colors">序幕低谷回响</h4> <h4 className="font-bold text-gray-100 text-xl group-hover/chapter:text-primary transition-colors">序幕低谷回响</h4>
</div> </div>
<div className="md:pl-14 text-gray-300 leading-loose text-justify text-lg font-light tracking-wide"> <div className="md:pl-14 text-beige/90 leading-loose text-justify text-lg font-light tracking-wide">
{selectedScript.plot.intro} {selectedScript.plot.intro}
</div> </div>
</div> </div>
@@ -283,11 +283,11 @@ export function ScriptView({ onSwitchToPath }) {
{/* Chapter 2 */} {/* Chapter 2 */}
<div className="mb-12 relative group/chapter"> <div className="mb-12 relative group/chapter">
<div className="flex items-center gap-4 mb-4"> <div className="flex items-center gap-4 mb-4">
<div className="w-10 h-10 rounded-full bg-primary/20 text-primary font-bold flex items-center justify-center border border-primary/20 shadow-[0_0_15px_rgba(16,185,129,0.1)] z-10 shrink-0 text-lg font-serif">2</div> <div className="w-10 h-10 rounded-full bg-primary/20 text-primary font-bold flex items-center justify-center border border-primary/20 shadow-[0_0_15px_rgba(205,133,63,0.1)] z-10 shrink-0 text-lg font-serif">2</div>
<h4 className="font-bold text-white text-xl group-hover/chapter:text-primary transition-colors">转折契机出现</h4> <h4 className="font-bold text-beige text-xl group-hover/chapter:text-primary transition-colors">转折契机出现</h4>
</div> </div>
<div className="md:pl-14"> <div className="md:pl-14">
<div className="text-gray-200 leading-loose text-justify p-6 bg-gradient-to-b from-white/5 to-transparent rounded-2xl border border-white/5 text-lg font-light tracking-wide shadow-inner"> <div className="text-beige/95 leading-loose text-justify p-6 bg-gradient-to-b from-white/5 to-transparent rounded-2xl border border-white/5 text-lg font-light tracking-wide shadow-inner">
{selectedScript.plot.turning} {selectedScript.plot.turning}
</div> </div>
</div> </div>
@@ -297,9 +297,9 @@ export function ScriptView({ onSwitchToPath }) {
<div className="mb-12 relative group/chapter"> <div className="mb-12 relative group/chapter">
<div className="flex items-center gap-4 mb-4"> <div className="flex items-center gap-4 mb-4">
<div className="w-10 h-10 rounded-full bg-accent/20 text-accent font-bold flex items-center justify-center border border-accent/20 shadow-[0_0_15px_rgba(255,165,0,0.1)] z-10 shrink-0 text-lg font-serif">3</div> <div className="w-10 h-10 rounded-full bg-accent/20 text-accent font-bold flex items-center justify-center border border-accent/20 shadow-[0_0_15px_rgba(255,165,0,0.1)] z-10 shrink-0 text-lg font-serif">3</div>
<h4 className="font-bold text-white text-xl group-hover/chapter:text-accent transition-colors">高潮命运抉择</h4> <h4 className="font-bold text-beige text-xl group-hover/chapter:text-accent transition-colors">高潮命运抉择</h4>
</div> </div>
<div className="md:pl-14 text-gray-300 leading-loose text-justify text-lg font-light tracking-wide"> <div className="md:pl-14 text-beige/90 leading-loose text-justify text-lg font-light tracking-wide">
{selectedScript.plot.climax} {selectedScript.plot.climax}
</div> </div>
</div> </div>
@@ -310,7 +310,7 @@ export function ScriptView({ onSwitchToPath }) {
<div className="w-10 h-10 rounded-full bg-white/10 text-gray-400 font-bold flex items-center justify-center border border-white/10 z-10 shrink-0 text-lg font-serif">4</div> <div className="w-10 h-10 rounded-full bg-white/10 text-gray-400 font-bold flex items-center justify-center border border-white/10 z-10 shrink-0 text-lg font-serif">4</div>
<h4 className="font-bold text-gray-100 text-xl group-hover/chapter:text-gray-300 transition-colors">结局新的开始</h4> <h4 className="font-bold text-gray-100 text-xl group-hover/chapter:text-gray-300 transition-colors">结局新的开始</h4>
</div> </div>
<div className="md:pl-14 text-gray-300 leading-loose text-justify text-lg font-light tracking-wide"> <div className="md:pl-14 text-beige/90 leading-loose text-justify text-lg font-light tracking-wide">
{selectedScript.plot.ending} {selectedScript.plot.ending}
</div> </div>
</div> </div>
@@ -44,11 +44,11 @@ export function TimelineView() {
return ( return (
<div className="max-w-4xl mx-auto md:p-12 pb-24"> <div className="max-w-4xl mx-auto md:p-12 pb-24">
<header className="mb-8 md:mb-12"> <header className="mb-8 md:mb-12">
<h2 className="text-3xl font-bold text-white mb-2 flex items-center gap-2"> <h2 className="text-3xl font-bold text-gold-gradient mb-2 flex items-center gap-2">
<span className="bg-primary/20 p-2 rounded-lg text-primary"><BookHeart className="w-6 h-6 icon-glow" /></span> <span className="bg-primary/20 p-2 rounded-lg text-primary"><BookHeart className="w-6 h-6 icon-glow" /></span>
时空日记 人生轨迹
</h2> </h2>
<p className="text-gray-400 text-sm md:text-base">记录每一个当下让AI为你照见未来</p> <p className="text-gray-400 text-sm md:text-base">塑造你的每一刻都被星辰见证</p>
</header> </header>
<Card className="p-5 md:p-8 mb-12 relative overflow-hidden group hover:shadow-xl border-l-4 border-primary"> <Card className="p-5 md:p-8 mb-12 relative overflow-hidden group hover:shadow-xl border-l-4 border-primary">
@@ -83,7 +83,7 @@ export function TimelineView() {
{events.length === 0 ? ( {events.length === 0 ? (
<div className="text-center text-gray-400 py-20 bg-white/5 rounded-3xl border border-dashed border-white/10 relative z-10"> <div className="text-center text-gray-400 py-20 bg-white/5 rounded-3xl border border-dashed border-white/10 relative z-10">
<PenTool className="w-12 h-12 mx-auto mb-4 opacity-30 text-primary" /> <PenTool className="w-12 h-12 mx-auto mb-4 opacity-30 text-primary" />
<p>暂无记录写下你的第一篇日记吧</p> <p>执笔写下哪些经历让你成为了现在的自己</p>
</div> </div>
) : ( ) : (
events.map((item, index) => ( events.map((item, index) => (
@@ -99,16 +99,16 @@ export function TimelineView() {
</div> </div>
{/* Center Dot */} {/* Center Dot */}
<div className="absolute left-6 md:left-1/2 -translate-x-1/2 w-4 h-4 rounded-full border-4 border-deep-sea bg-primary z-20 shadow-[0_0_15px_rgba(42,157,143,0.5)] group-hover:scale-125 transition-transform order-2"></div> <div className="absolute left-6 md:left-1/2 -translate-x-1/2 w-4 h-4 rounded-full border-4 border-deep-sea bg-primary z-20 shadow-[0_0_15px_rgba(205,133,63,0.5)] group-hover:scale-125 transition-transform order-2"></div>
{/* Content Card */} {/* Content Card */}
<div className={`md:w-5/12 pl-12 md:pl-0 order-3 ${index % 2 === 1 ? 'md:order-1 md:text-right md:pr-10' : 'md:pl-10'}`}> <div className={`md:w-5/12 pl-12 md:pl-0 order-3 ${index % 2 === 1 ? 'md:order-1 md:text-right md:pr-10' : 'md:pl-10'}`}>
<Card className="p-5 hover:-translate-y-1 transition-transform relative overflow-hidden"> <Card className="p-5 hover:-translate-y-1 transition-transform relative overflow-hidden">
<div className="absolute top-0 right-0 p-3 opacity-10"> <div className="absolute top-0 right-0 p-3 opacity-10">
<Quote className="w-8 h-8 text-white" /> <Quote className="w-8 h-8 text-beige" />
</div> </div>
<h3 className="font-bold text-lg text-white mb-2">{item.title}</h3> <h3 className="font-bold text-lg text-beige mb-2">{item.title}</h3>
<p className="text-gray-300 text-sm leading-relaxed mb-4">{item.content}</p> <p className="text-beige/90 text-sm leading-relaxed mb-4">{item.content}</p>
{item.aiReply && ( {item.aiReply && (
<div className="bg-primary/10 rounded-xl p-3 text-sm text-primary/90 flex gap-3 border border-primary/10"> <div className="bg-primary/10 rounded-xl p-3 text-sm text-primary/90 flex gap-3 border border-primary/10">
+38 -16
View File
@@ -1,11 +1,16 @@
@import "tailwindcss"; @import "tailwindcss";
@theme { @theme {
--color-primary: #2A9D8F; --color-primary: #CD853F;
--color-secondary: #264653; --color-secondary: #0a0c10;
--color-accent: #E9C46A; --color-accent: #DAA520;
--color-aurora-green: #4CC9F0; --color-aurora-green: #FFD700;
--color-deep-sea: #0f1c2e; --color-deep-sea: #1a1c2c;
--color-text-beige: #E8D5B7;
--color-text-warm: #E8D5B7;
--color-gold-dark: #CD853F;
--color-gold-medium: #DAA520;
--color-gold-light: #FFD700;
--font-sans: "Noto Sans SC", sans-serif; --font-sans: "Noto Sans SC", sans-serif;
@@ -30,9 +35,12 @@
100% { transform: translateY(0); opacity: 1; } 100% { transform: translateY(0); opacity: 1; }
} }
@keyframes float { @keyframes float {
0%, 100% { transform: translateY(0); } 0%, 100% { transform: translate(0, 0) scale(1); }
50% { transform: translateY(-10px); } 50% { transform: translate(5%, 5%) scale(1.1); }
} }
.animate-float { animation: float 15s infinite ease-in-out; }
.animate-float-delayed { animation: float 20s infinite ease-in-out reverse; }
@keyframes breathe { @keyframes breathe {
0%, 100% { opacity: 0.8; transform: scale(1); } 0%, 100% { opacity: 0.8; transform: scale(1); }
50% { opacity: 1; transform: scale(1.02); } 50% { opacity: 1; transform: scale(1.02); }
@@ -42,9 +50,9 @@
to { transform: rotate(360deg); } to { transform: rotate(360deg); }
} }
@keyframes pulse-ring { @keyframes pulse-ring {
0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(42, 157, 143, 0.7); } 0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(255, 171, 145, 0.7); }
70% { transform: scale(1); box-shadow: 0 0 0 10px rgba(42, 157, 143, 0); } 70% { transform: scale(1); box-shadow: 0 0 0 10px rgba(255, 171, 145, 0); }
100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(42, 157, 143, 0); } 100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(255, 171, 145, 0); }
} }
@keyframes audio-wave { @keyframes audio-wave {
0%, 100% { height: 5px; } 0%, 100% { height: 5px; }
@@ -55,7 +63,7 @@
body { body {
-webkit-tap-highlight-color: transparent; -webkit-tap-highlight-color: transparent;
font-family: 'Noto Sans SC', sans-serif; font-family: 'Noto Sans SC', sans-serif;
@apply bg-deep-sea text-gray-800 overflow-x-hidden selection:bg-primary selection:text-white; @apply bg-deep-sea text-gray-100 overflow-x-hidden selection:bg-primary/30 selection:text-white;
} }
/* Background Noise Utility */ /* Background Noise Utility */
@@ -76,14 +84,14 @@ body {
border-radius: 4px; border-radius: 4px;
} }
::-webkit-scrollbar-thumb:hover { ::-webkit-scrollbar-thumb:hover {
background: rgba(42, 157, 143, 0.6); background: rgba(255, 171, 145, 0.6);
} }
.custom-scrollbar::-webkit-scrollbar-thumb { .custom-scrollbar::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.1); background: rgba(0, 0, 0, 0.1);
} }
.custom-scrollbar::-webkit-scrollbar-thumb:hover { .custom-scrollbar::-webkit-scrollbar-thumb:hover {
background: rgba(42, 157, 143, 0.4); background: rgba(255, 171, 145, 0.4);
} }
/* Transitions */ /* Transitions */
@@ -128,8 +136,8 @@ body {
} }
.input-field:focus { .input-field:focus {
border-color: #2A9D8F; border-color: #CD853F;
box-shadow: 0 0 0 4px rgba(42, 157, 143, 0.15); box-shadow: 0 0 0 4px rgba(205, 133, 63, 0.15);
background: white; background: white;
} }
@@ -140,7 +148,7 @@ body {
} }
.input-field-dark:focus { .input-field-dark:focus {
background: rgba(255, 255, 255, 0.1); background: rgba(255, 255, 255, 0.1);
border-color: #2A9D8F; border-color: #CD853F;
} }
select.input-field { select.input-field {
@@ -172,6 +180,20 @@ select.input-field-dark option {
.audio-waves span:nth-child(3) { animation-delay: 0.2s; } .audio-waves span:nth-child(3) { animation-delay: 0.2s; }
.audio-waves span:nth-child(4) { animation-delay: 0.3s; } .audio-waves span:nth-child(4) { animation-delay: 0.3s; }
/* Text Beige Color Utility - 浅米色文字 */
.text-beige {
color: #E8D5B7;
}
/* Advanced Gold Gradient Text - 高级金色渐变文字(更白亮、更明显、降低饱和度) */
.text-gold-gradient {
background: linear-gradient(135deg, #E8D5B7 0%, #F4D03F 30%, #FFD700 60%, #FFF8DC 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
filter: brightness(1.1) saturate(0.9);
}
/* Utilities */ /* Utilities */
.scrollbar-hide::-webkit-scrollbar { .scrollbar-hide::-webkit-scrollbar {
display: none; display: none;
+45 -22
View File
@@ -5,6 +5,7 @@ import { AudioEngine } from '../utils/audioEngine';
import { TimelineView } from '../components/views/TimelineView'; import { TimelineView } from '../components/views/TimelineView';
import { ScriptView } from '../components/views/ScriptView'; import { ScriptView } from '../components/views/ScriptView';
import { PathView } from '../components/views/PathView'; import { PathView } from '../components/views/PathView';
import { UserMenu } from '../components/UserMenu';
import { import {
Compass, Compass,
BookOpen, BookOpen,
@@ -24,6 +25,7 @@ export function DashboardPage() {
const [activeTab, setActiveTab] = useState('timeline'); const [activeTab, setActiveTab] = useState('timeline');
const [isMusicPlaying, setIsMusicPlaying] = useState(false); const [isMusicPlaying, setIsMusicPlaying] = useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const [isUserMenuOpen, setIsUserMenuOpen] = useState(false);
// Initialize Audio Engine state based on store // Initialize Audio Engine state based on store
useEffect(() => { useEffect(() => {
@@ -55,32 +57,40 @@ export function DashboardPage() {
className={clsx( className={clsx(
"w-full text-left px-4 py-3 rounded-xl flex items-center gap-3 transition-all duration-300 relative overflow-hidden group", "w-full text-left px-4 py-3 rounded-xl flex items-center gap-3 transition-all duration-300 relative overflow-hidden group",
activeTab === tab activeTab === tab
? "bg-primary/20 text-primary font-bold shadow-[0_0_15px_rgba(16,185,129,0.1)] border border-primary/20" ? "bg-primary/20 text-primary font-bold shadow-[0_0_15px_rgba(205,133,63,0.1)] border border-primary/20"
: "text-gray-400 hover:text-white hover:bg-white/5 border border-transparent" : "text-gray-400 hover:text-primary hover:bg-white/5 border border-transparent"
)} )}
> >
<Icon className={clsx("w-5 h-5 transition-transform", activeTab === tab ? "text-primary" : "text-gray-400 group-hover:text-white", activeTab !== tab && "group-hover:scale-110")} /> <Icon className={clsx("w-5 h-5 transition-transform", activeTab === tab ? "text-primary" : "text-gray-400 group-hover:text-primary", activeTab !== tab && "group-hover:scale-110")} />
<span className="hidden md:inline">{label}</span> <span className="hidden md:inline">{label}</span>
<span className="md:hidden">{mobileLabel || label}</span> <span className="md:hidden">{mobileLabel || label}</span>
{activeTab === tab && ( {activeTab === tab && (
<div className="absolute right-0 top-0 bottom-0 w-1 bg-primary shadow-[0_0_10px_#10b981]"></div> <div className="absolute right-0 top-0 bottom-0 w-1 bg-primary shadow-[0_0_10px_rgba(205,133,63,0.8)]"></div>
)} )}
</button> </button>
); );
return ( return (
<div className="min-h-screen flex flex-col md:flex-row transition-all duration-500 font-sans text-gray-100 bg-deep-sea overflow-hidden"> <div className="min-h-screen flex flex-col md:flex-row transition-all duration-500 font-sans text-gray-100 bg-deep-sea overflow-hidden">
{/* Ambient Background */} {/* Ambient Background - Additional Layer for Dashboard with Blue Gradient */}
<div className="fixed inset-0 pointer-events-none z-0"> <div className="fixed inset-0 pointer-events-none z-0">
<div className="absolute top-0 left-0 w-full h-full bg-[radial-gradient(circle_at_50%_50%,rgba(16,185,129,0.05),transparent_50%)]"></div> {/* Blue gradient overlay on left */}
<div className="absolute top-[-20%] left-[-10%] w-[50%] h-[50%] bg-primary/5 rounded-full blur-[120px] animate-pulse-slow"></div> <div className="absolute top-0 left-0 w-full h-full bg-[radial-gradient(circle_at_20%_50%,rgba(30,58,95,0.15),transparent_60%)]"></div>
{/* Subtle radial gradient overlay */}
<div className="absolute top-0 left-0 w-full h-full bg-[radial-gradient(circle_at_30%_50%,rgba(205,133,63,0.08),transparent_70%)]"></div>
<div className="absolute top-0 right-0 w-full h-full bg-[radial-gradient(circle_at_70%_50%,rgba(255,140,0,0.06),transparent_65%)]"></div>
{/* Blue glow effects on left */}
<div className="absolute top-[20%] left-[15%] w-[40%] h-[40%] bg-blue-700/10 rounded-full blur-[120px] animate-pulse-slow"></div>
<div className="absolute bottom-[20%] left-[10%] w-[35%] h-[35%] bg-cyan-800/8 rounded-full blur-[100px] animate-float"></div>
{/* Subtle glow effects on right */}
<div className="absolute top-[25%] right-[25%] w-[35%] h-[35%] bg-orange-800/8 rounded-full blur-[120px] animate-pulse-slow"></div>
</div> </div>
{/* Mobile Header */} {/* Mobile Header */}
<div className="md:hidden bg-black/20 backdrop-blur-xl border-b border-white/10 p-4 flex justify-between items-center z-50 relative"> <div className="md:hidden bg-black/15 backdrop-blur-xl border-b border-white/10 p-4 flex justify-between items-center z-50 relative">
<div className="flex items-center gap-2 font-bold text-lg"> <div className="flex items-center gap-2 font-bold text-lg">
<Compass className="text-primary w-6 h-6 animate-spin-slow" /> <Compass className="text-primary w-6 h-6 animate-spin-slow" />
<span className="bg-clip-text text-transparent bg-gradient-to-r from-primary to-accent">人生轨迹</span> <span className="text-gold-gradient">人生OS</span>
</div> </div>
<button onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}> <button onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}>
{isMobileMenuOpen ? <X className="text-white" /> : <Menu className="text-white" />} {isMobileMenuOpen ? <X className="text-white" /> : <Menu className="text-white" />}
@@ -89,47 +99,50 @@ export function DashboardPage() {
{/* Sidebar (Desktop) / Drawer (Mobile) */} {/* Sidebar (Desktop) / Drawer (Mobile) */}
<nav className={clsx( <nav className={clsx(
"bg-black/20 backdrop-blur-xl border-r border-white/10 w-full md:w-72 flex-shrink-0 flex flex-col justify-between z-40 fixed md:relative h-[calc(100vh-64px)] md:h-screen top-16 md:top-0 left-0 transition-transform duration-300", "bg-black/15 backdrop-blur-xl border-r border-white/10 w-full md:w-72 flex-shrink-0 flex flex-col justify-between z-40 fixed md:relative h-[calc(100vh-64px)] md:h-screen top-16 md:top-0 left-0 transition-transform duration-300",
isMobileMenuOpen ? "translate-x-0" : "-translate-x-full md:translate-x-0" isMobileMenuOpen ? "translate-x-0" : "-translate-x-full md:translate-x-0"
)}> )}>
{/* Background Decoration */} {/* Background Decoration */}
<div className="absolute top-0 left-0 w-full h-full bg-gradient-to-b from-transparent to-primary/5 pointer-events-none"></div> <div className="absolute top-0 left-0 w-full h-full bg-gradient-to-b from-transparent to-primary/5 pointer-events-none"></div>
<div className="p-6 overflow-y-auto relative z-10"> <div className="p-6 overflow-y-auto relative z-10">
<h1 className="hidden md:flex text-2xl font-bold tracking-wider mb-8 items-center gap-3 text-transparent bg-clip-text bg-gradient-to-r from-primary to-white"> <h1 className="hidden md:flex text-2xl font-bold tracking-wider mb-8 items-center gap-3 text-gold-gradient">
<Compass className="text-primary stroke-2 animate-spin-slow" /> 人生轨迹 <Compass className="text-primary stroke-2 animate-spin-slow" /> 人生OS
</h1> </h1>
{/* User Card */} {/* User Card */}
<div className="flex items-center gap-4 mb-8 p-4 bg-white/5 rounded-2xl backdrop-blur-sm border border-white/10 hover:bg-white/10 transition-colors cursor-default group"> <button
onClick={() => setIsUserMenuOpen(!isUserMenuOpen)}
className="flex items-center gap-4 mb-8 p-4 bg-white/5 rounded-2xl backdrop-blur-sm border border-white/10 hover:bg-white/10 transition-colors cursor-pointer group w-full text-left"
>
<div className="w-12 h-12 rounded-full bg-gradient-to-br from-primary to-blue-600 flex items-center justify-center text-white font-bold text-xl shadow-inner relative overflow-hidden group-hover:scale-105 transition-transform shrink-0 border border-white/20"> <div className="w-12 h-12 rounded-full bg-gradient-to-br from-primary to-blue-600 flex items-center justify-center text-white font-bold text-xl shadow-inner relative overflow-hidden group-hover:scale-105 transition-transform shrink-0 border border-white/20">
{data.userProfile.nickname?.[0] || 'U'} {data.userProfile.nickname?.[0] || 'U'}
<div className="absolute inset-0 bg-white/20 opacity-0 group-hover:opacity-100 transition-opacity"></div> <div className="absolute inset-0 bg-white/20 opacity-0 group-hover:opacity-100 transition-opacity"></div>
</div> </div>
<div className="overflow-hidden"> <div className="overflow-hidden flex-1">
<div className="font-bold text-white truncate">{data.userProfile.nickname || '旅人'}</div> <div className="font-bold text-gray-100 truncate">{data.userProfile.nickname || '旅人'}</div>
<div className="text-xs text-primary flex items-center gap-1.5 mt-0.5"> <div className="text-xs text-primary flex items-center gap-1.5 mt-0.5">
<span className="w-1.5 h-1.5 rounded-full bg-primary shadow-[0_0_5px_rgba(16,185,129,0.5)] animate-pulse"></span> <span className="w-1.5 h-1.5 rounded-full bg-primary shadow-[0_0_5px_rgba(205,133,63,0.5)] animate-pulse"></span>
{data.userProfile.mbti} · {data.userProfile.zodiac || '未知'} {data.userProfile.mbti || '未知'} · {data.userProfile.zodiac || '未知'}
</div> </div>
</div> </div>
</div> </button>
{/* Navigation */} {/* Navigation */}
<div className="space-y-2"> <div className="space-y-2">
<NavButton tab="timeline" icon={BookOpen} label="时空日记" mobileLabel="日记" /> <NavButton tab="timeline" icon={BookOpen} label="人生轨迹" mobileLabel="轨迹" />
<NavButton tab="script" icon={Film} label="剧本生成器" mobileLabel="剧本" /> <NavButton tab="script" icon={Film} label="爽文剧本" mobileLabel="剧本" />
<NavButton tab="path" icon={Map} label="实现路径" mobileLabel="路径" /> <NavButton tab="path" icon={Map} label="实现路径" mobileLabel="路径" />
</div> </div>
</div> </div>
<div className="p-6 text-xs text-gray-500 border-t border-white/5 space-y-4 bg-black/40 backdrop-blur-md md:bg-transparent relative z-10"> <div className="p-6 text-xs text-gray-500 border-t border-white/5 space-y-4 bg-black/20 backdrop-blur-md md:bg-transparent relative z-10">
{/* Music Player */} {/* Music Player */}
<button <button
onClick={handleMusicToggle} onClick={handleMusicToggle}
className={clsx( className={clsx(
"flex items-center justify-between w-full px-4 py-3 rounded-xl bg-white/5 hover:bg-white/10 transition-all border group", "flex items-center justify-between w-full px-4 py-3 rounded-xl bg-white/5 hover:bg-white/10 transition-all border group",
isMusicPlaying ? "border-primary/30 shadow-[0_0_10px_rgba(16,185,129,0.1)]" : "border-white/5" isMusicPlaying ? "border-primary/30 shadow-[0_0_10px_rgba(205,133,63,0.1)]" : "border-white/5"
)} )}
> >
<div className="flex items-center gap-3 text-gray-300"> <div className="flex items-center gap-3 text-gray-300">
@@ -163,6 +176,16 @@ export function DashboardPage() {
{activeTab === 'script' && <ScriptView onSwitchToPath={() => setActiveTab('path')} />} {activeTab === 'script' && <ScriptView onSwitchToPath={() => setActiveTab('path')} />}
{activeTab === 'path' && <PathView onSwitchToScript={() => setActiveTab('script')} />} {activeTab === 'path' && <PathView onSwitchToScript={() => setActiveTab('script')} />}
</main> </main>
{/* User Menu */}
<UserMenu
isOpen={isUserMenuOpen}
onClose={() => setIsUserMenuOpen(false)}
onLogout={() => {
// 退出登录后,App.jsx 会检测到 onboardingComplete 变为 false,自动跳转到登录页
window.location.reload();
}}
/>
</div> </div>
); );
} }
+2 -2
View File
@@ -93,7 +93,7 @@ export function LandingPage({ onStart }) {
</div> </div>
<h1 className="text-4xl md:text-6xl font-bold text-white tracking-tight landing-title"> <h1 className="text-4xl md:text-6xl font-bold text-white tracking-tight landing-title">
人生轨迹 人生OS
<span className="block text-xl md:text-2xl font-light mt-4 text-primary/80">Life Trajectory</span> <span className="block text-xl md:text-2xl font-light mt-4 text-primary/80">Life Trajectory</span>
</h1> </h1>
@@ -113,7 +113,7 @@ export function LandingPage({ onStart }) {
variant="primary" variant="primary"
size="lg" size="lg"
onClick={() => setShowLoginModal(true)} onClick={() => setShowLoginModal(true)}
className="w-full shadow-[0_0_20px_rgba(16,185,129,0.3)] hover:shadow-[0_0_30px_rgba(16,185,129,0.5)] transition-all" className="w-full shadow-[0_0_20px_rgba(205,133,63,0.3)] hover:shadow-[0_0_30px_rgba(205,133,63,0.5)] transition-all"
> >
登录账号 登录账号
</Button> </Button>
+1 -1
View File
@@ -171,7 +171,7 @@ export function OnboardingPage({ onFinish }) {
{[0,1,2,3,4].map(i => ( {[0,1,2,3,4].map(i => (
<div key={i} className={clsx( <div key={i} className={clsx(
"h-1 rounded-full transition-all duration-500", "h-1 rounded-full transition-all duration-500",
i <= step ? 'w-8 bg-primary shadow-[0_0_10px_rgba(42,157,143,0.5)]' : 'w-2 bg-white/10' i <= step ? 'w-8 bg-primary shadow-[0_0_10px_rgba(205,133,63,0.5)]' : 'w-2 bg-white/10'
)}></div> )}></div>
))} ))}
</div> </div>
+2 -1
View File
@@ -9,7 +9,8 @@ export default defineConfig({
server: { server: {
proxy: { proxy: {
'/api': { '/api': {
target: 'http://localhost:19089', // target: 'http://localhost:19089',
target: 'http://101.200.208.45:19089',
changeOrigin: true, changeOrigin: true,
} }
} }