diff --git a/apps/web/src/App.css b/apps/web/src/App.css index d82b09dc3..24233c189 100644 --- a/apps/web/src/App.css +++ b/apps/web/src/App.css @@ -1,14 +1,140 @@ -.App { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; +/* V21 App Root Styles */ + +.xx-app-root { + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + background: linear-gradient(135deg, #f8fafc 0%, #eef2ff 100%); + padding: 24px; +} + +.xx-app-container { + max-width: 480px; + width: 100%; text-align: center; } -.card { - padding: 2em; +/* Hero Section */ +.xx-hero-section { + margin-bottom: 40px; } -.read-the-docs { - color: #888; +.xx-logo { + font-size: 72px; + margin-bottom: 24px; + animation: float 3s ease-in-out infinite; +} + +@keyframes float { + 0%, 100% { transform: translateY(0); } + 50% { transform: translateY(-10px); } +} + +.xx-hero-section h1 { + font-size: 36px; + font-weight: 850; + color: #0f172a; + margin: 0 0 12px; + letter-spacing: -0.5px; +} + +.xx-hero-section p { + font-size: 18px; + color: #64748b; + margin: 0; +} + +.xx-status-badge { + display: inline-flex; + align-items: center; + gap: 8px; + margin-top: 20px; + padding: 8px 16px; + background: #eef2ff; + color: #4f46e5; + border-radius: 20px; + font-size: 14px; + font-weight: 600; +} + +.xx-status-dot { + width: 8px; + height: 8px; + background: #4f46e5; + border-radius: 50%; + animation: pulse 2s ease-in-out infinite; +} + +@keyframes pulse { + 0%, 100% { opacity: 1; transform: scale(1); } + 50% { opacity: 0.5; transform: scale(1.2); } +} + +/* Card */ +.xx-card { + background: rgba(255,255,255,0.94); + border: 1px solid rgba(226,232,240,0.95); + border-radius: 22px; + box-shadow: 0 24px 70px rgba(15,23,42,0.09); + padding: 28px; + transition: all 0.25s; +} + +.xx-card:hover { + box-shadow: 0 26px 64px rgba(15,23,42,0.14); + transform: translateY(-2px); +} + +.xx-card h3 { + font-size: 18px; + font-weight: 700; + color: #0f172a; + margin: 0 0 20px; + text-align: left; +} + +/* Quick Links */ +.xx-link-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 16px; +} + +.xx-link-item { + display: flex; + flex-direction: column; + align-items: center; + gap: 12px; + padding: 24px 16px; + background: #f8fafc; + border: 1px solid #e2e8f0; + border-radius: 16px; + text-decoration: none; + color: #0f172a; + font-weight: 600; + transition: all 0.2s; +} + +.xx-link-item:hover { + background: #eef2ff; + border-color: #4f46e5; + color: #4f46e5; + transform: translateY(-2px); + box-shadow: 0 8px 24px rgba(79,70,229,0.15); +} + +.xx-link-icon { + font-size: 32px; +} + +/* Responsive */ +@media (max-width: 480px) { + .xx-hero-section h1 { + font-size: 28px; + } + + .xx-link-grid { + grid-template-columns: 1fr; + } } diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx index f6939bbc9..8338d6664 100644 --- a/apps/web/src/App.tsx +++ b/apps/web/src/App.tsx @@ -1,23 +1,40 @@ -import { useState } from 'react' -import './App.css' +/** + * App Root Component - V21 UI + * 注意:此组件已被路由系统接管,仅作为默认展示 + */ +import { Link } from 'react-router-dom'; +import './App.css'; function App() { - const [count, setCount] = useState(0) - return ( -
-

小虾 SaaS

-

自动化视频剪辑平台

-
- +
+
+
+
🎬
+

小虾 SaaS

+

自动化视频剪辑平台

+
+ + 前端开发中 +
+
+ +
+

快速链接

+
+ + 📁 + 工作空间 + + + 📋 + 我的项目 + +
+
-

- Phase 6: 前端开发中... -

- ) + ); } -export default App +export default App; diff --git a/apps/web/src/components/business/InviteMemberModal.tsx b/apps/web/src/components/business/InviteMemberModal.tsx index 0b8d98a47..4c276413e 100644 --- a/apps/web/src/components/business/InviteMemberModal.tsx +++ b/apps/web/src/components/business/InviteMemberModal.tsx @@ -1,9 +1,10 @@ /** - * 邀请成员弹窗 + * 邀请成员弹窗 - V21 UI */ import React from 'react'; import { Modal, Form, Input, Select, message } from 'antd'; import { useInviteMember } from '@/hooks/useWorkspace'; +import './business.css'; interface InviteMemberModalProps { workspaceId: string; @@ -45,6 +46,8 @@ const InviteMemberModal: React.FC = ({ confirmLoading={inviteMutation.isPending} okText="发送邀请" cancelText="取消" + className="xx-modal" + width={480} >
= ({ diff --git a/apps/web/src/components/business/MemberList.tsx b/apps/web/src/components/business/MemberList.tsx index e78ae0276..959b6b335 100644 --- a/apps/web/src/components/business/MemberList.tsx +++ b/apps/web/src/components/business/MemberList.tsx @@ -1,5 +1,5 @@ /** - * 成员列表组件 + * 成员列表组件 - V21 UI */ import React from 'react'; import { Table, Button, Tag, Space, Popconfirm, message, Select } from 'antd'; @@ -7,6 +7,7 @@ import { DeleteOutlined } from '@ant-design/icons'; import { useWorkspaceMembers } from '@/hooks/useWorkspace'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { removeMember, updateMemberRole } from '@/api/workspace'; +import './business.css'; interface MemberListProps { workspaceId: string; @@ -34,14 +35,14 @@ const MemberList: React.FC = ({ workspaceId }) => { }); const getRoleTag = (role: string) => { - const roleConfig: Record = { - owner: { color: 'gold', text: '拥有者' }, - admin: { color: 'blue', text: '管理员' }, - member: { color: 'green', text: '成员' }, - viewer: { color: 'default', text: '访客' }, + const roleConfig: Record = { + owner: { color: 'gold', text: '拥有者', className: 'xx-tag-warning' }, + admin: { color: 'blue', text: '管理员', className: 'xx-tag-indigo' }, + member: { color: 'green', text: '成员', className: 'xx-tag-success' }, + viewer: { color: 'default', text: '访客', className: '' }, }; const config = roleConfig[role] || roleConfig.member; - return {config.text}; + return {config.text}; }; const columns = [ @@ -49,11 +50,13 @@ const MemberList: React.FC = ({ workspaceId }) => { title: '用户名', dataIndex: 'username', key: 'username', + render: (text: string) => {text}, }, { title: '邮箱', dataIndex: 'email', key: 'email', + render: (text: string) => {text}, }, { title: '角色', @@ -66,7 +69,7 @@ const MemberList: React.FC = ({ workspaceId }) => { return (