feat(web): 采用 Notion 设计系统 — 暖色调 + 白色侧边栏 + Inter 字体

引入 Notion 风格的 DESIGN.md 设计系统文件,并全面重构前端 UI:

- 主色从 Indigo (#4F46E5) 迁移到 Notion Blue (#0075de)
- 页面背景从冷灰 (#F1F5F9) 迁移到暖白 (#f6f5f4)
- 侧边栏从深色 (#0F172A) 迁移到白色,活跃项用蓝色指示
- 文字从 Slate 冷色迁移到暖灰系列 (Warm Gray 500/300)
- 圆角从 8px 缩小到 4px(按钮/输入),8px(卡片)
- 阴影改为多层超轻 Notion 风格(最大 opacity 0.05)
- 字体优先使用 Inter,保留中文回退
- 暗色模式适配暖黑色调 (#191918)
- 更新 27 个前端文件的硬编码颜色值
This commit is contained in:
iven
2026-04-20 13:08:22 +08:00
parent 40b37cc776
commit 8f3d2d58e7
27 changed files with 825 additions and 406 deletions

View File

@@ -5,9 +5,9 @@ import type { ColumnsType } from 'antd/es/table';
import { listTemplates, createTemplate, type MessageTemplateInfo } from '../../api/messageTemplates';
const channelMap: Record<string, { label: string; color: string }> = {
in_app: { label: '站内', color: '#4F46E5' },
email: { label: '邮件', color: '#059669' },
sms: { label: '短信', color: '#D97706' },
in_app: { label: '站内', color: '#0075de' },
email: { label: '邮件', color: '#1aae39' },
sms: { label: '短信', color: '#dd5b00' },
wechat: { label: '微信', color: '#7C3AED' },
};
@@ -64,9 +64,9 @@ export default function MessageTemplates() {
key: 'code',
render: (v: string) => (
<Tag style={{
background: isDark ? '#1E293B' : '#F1F5F9',
background: isDark ? '#1e1e1d' : '#f6f5f4',
border: 'none',
color: isDark ? '#94A3B8' : '#64748B',
color: isDark ? '#a39e98' : '#615d59',
fontFamily: 'monospace',
fontSize: 12,
}}>
@@ -80,7 +80,7 @@ export default function MessageTemplates() {
key: 'channel',
width: 90,
render: (c: string) => {
const info = channelMap[c] || { label: c, color: '#64748B' };
const info = channelMap[c] || { label: c, color: '#615d59' };
return (
<Tag style={{
background: info.color + '15',
@@ -111,7 +111,7 @@ export default function MessageTemplates() {
key: 'created_at',
width: 180,
render: (v: string) => (
<span style={{ color: isDark ? '#64748B' : '#94A3B8', fontSize: 13 }}>{v}</span>
<span style={{ color: isDark ? '#615d59' : '#a39e98', fontSize: 13 }}>{v}</span>
),
},
];
@@ -124,7 +124,7 @@ export default function MessageTemplates() {
alignItems: 'center',
marginBottom: 16,
}}>
<span style={{ fontSize: 13, color: isDark ? '#64748B' : '#94A3B8' }}>
<span style={{ fontSize: 13, color: isDark ? '#615d59' : '#a39e98' }}>
{total}
</span>
<Button type="primary" icon={<PlusOutlined />} onClick={() => setModalOpen(true)}>
@@ -135,7 +135,7 @@ export default function MessageTemplates() {
<div style={{
background: isDark ? '#111827' : '#FFFFFF',
borderRadius: 12,
border: `1px solid ${isDark ? '#1E293B' : '#F1F5F9'}`,
border: `1px solid ${isDark ? '#1e1e1d' : '#f6f5f4'}`,
overflow: 'hidden',
}}>
<Table

View File

@@ -11,9 +11,9 @@ interface Props {
}
const priorityStyles: Record<string, { bg: string; color: string; text: string }> = {
urgent: { bg: '#FEF2F2', color: '#DC2626', text: '紧急' },
important: { bg: '#FFFBEB', color: '#D97706', text: '重要' },
normal: { bg: '#EEF2FF', color: '#4F46E5', text: '普通' },
urgent: { bg: '#FEF2F2', color: '#e5534b', text: '紧急' },
important: { bg: '#FFFBEB', color: '#dd5b00', text: '重要' },
normal: { bg: '#f2f9ff', color: '#0075de', text: '普通' },
};
export default function NotificationList({ queryFilter }: Props) {
@@ -83,7 +83,7 @@ export default function NotificationList({ queryFilter }: Props) {
content: (
<div>
<Paragraph>{record.body}</Paragraph>
<div style={{ marginTop: 8, color: isDark ? '#475569' : '#94A3B8', fontSize: 12 }}>
<div style={{ marginTop: 8, color: isDark ? '#615d59' : '#a39e98', fontSize: 12 }}>
{record.created_at}
</div>
</div>
@@ -104,7 +104,7 @@ export default function NotificationList({ queryFilter }: Props) {
style={{
fontWeight: record.is_read ? 400 : 600,
cursor: 'pointer',
color: record.is_read ? (isDark ? '#94A3B8' : '#64748B') : 'inherit',
color: record.is_read ? (isDark ? '#a39e98' : '#615d59') : 'inherit',
}}
onClick={() => showDetail(record)}
>
@@ -114,7 +114,7 @@ export default function NotificationList({ queryFilter }: Props) {
width: 6,
height: 6,
borderRadius: '50%',
background: '#4F46E5',
background: '#0075de',
marginRight: 8,
}} />
)}
@@ -128,7 +128,7 @@ export default function NotificationList({ queryFilter }: Props) {
key: 'priority',
width: 90,
render: (p: string) => {
const info = priorityStyles[p] || { bg: '#F1F5F9', color: '#64748B', text: p };
const info = priorityStyles[p] || { bg: '#f6f5f4', color: '#615d59', text: p };
return (
<Tag style={{
background: info.bg,
@@ -146,7 +146,7 @@ export default function NotificationList({ queryFilter }: Props) {
dataIndex: 'sender_type',
key: 'sender_type',
width: 80,
render: (s: string) => <span style={{ color: isDark ? '#64748B' : '#94A3B8' }}>{s === 'system' ? '系统' : '用户'}</span>,
render: (s: string) => <span style={{ color: isDark ? '#615d59' : '#a39e98' }}>{s === 'system' ? '系统' : '用户'}</span>,
},
{
title: '状态',
@@ -155,9 +155,9 @@ export default function NotificationList({ queryFilter }: Props) {
width: 80,
render: (r: boolean) => (
<Tag style={{
background: r ? (isDark ? '#1E293B' : '#F1F5F9') : '#EEF2FF',
background: r ? (isDark ? '#1e1e1d' : '#f6f5f4') : '#f2f9ff',
border: 'none',
color: r ? (isDark ? '#64748B' : '#94A3B8') : '#4F46E5',
color: r ? (isDark ? '#615d59' : '#a39e98') : '#0075de',
fontWeight: 500,
}}>
{r ? '已读' : '未读'}
@@ -170,7 +170,7 @@ export default function NotificationList({ queryFilter }: Props) {
key: 'created_at',
width: 180,
render: (v: string) => (
<span style={{ color: isDark ? '#64748B' : '#94A3B8', fontSize: 13 }}>{v}</span>
<span style={{ color: isDark ? '#615d59' : '#a39e98', fontSize: 13 }}>{v}</span>
),
},
{
@@ -185,7 +185,7 @@ export default function NotificationList({ queryFilter }: Props) {
size="small"
icon={<CheckOutlined />}
onClick={() => handleMarkRead(record.id)}
style={{ color: '#4F46E5' }}
style={{ color: '#0075de' }}
/>
)}
<Button
@@ -193,7 +193,7 @@ export default function NotificationList({ queryFilter }: Props) {
size="small"
icon={<EyeOutlined />}
onClick={() => showDetail(record)}
style={{ color: isDark ? '#64748B' : '#94A3B8' }}
style={{ color: isDark ? '#615d59' : '#a39e98' }}
/>
<Button
type="text"
@@ -215,7 +215,7 @@ export default function NotificationList({ queryFilter }: Props) {
alignItems: 'center',
marginBottom: 16,
}}>
<span style={{ fontSize: 13, color: isDark ? '#64748B' : '#94A3B8' }}>
<span style={{ fontSize: 13, color: isDark ? '#615d59' : '#a39e98' }}>
{total}
</span>
<Button icon={<CheckOutlined />} onClick={handleMarkAllRead}>
@@ -226,7 +226,7 @@ export default function NotificationList({ queryFilter }: Props) {
<div style={{
background: isDark ? '#111827' : '#FFFFFF',
borderRadius: 12,
border: `1px solid ${isDark ? '#1E293B' : '#F1F5F9'}`,
border: `1px solid ${isDark ? '#1e1e1d' : '#f6f5f4'}`,
overflow: 'hidden',
}}>
<Table

View File

@@ -48,12 +48,12 @@ export default function NotificationPreferences() {
<div style={{
background: isDark ? '#111827' : '#FFFFFF',
borderRadius: 12,
border: `1px solid ${isDark ? '#1E293B' : '#F1F5F9'}`,
border: `1px solid ${isDark ? '#1e1e1d' : '#f6f5f4'}`,
padding: 24,
maxWidth: 600,
}}>
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 20 }}>
<BellOutlined style={{ fontSize: 16, color: '#4F46E5' }} />
<BellOutlined style={{ fontSize: 16, color: '#0075de' }} />
<span style={{ fontSize: 15, fontWeight: 600 }}></span>
</div>