feat: 重新设计现代化图标系统

新增 Icons.tsx 统一图标组件(25 个图标):
- AppIcon: 渐变蓝色圆角矩形 + M↓ 符号
- 工具栏: FolderOpen, Save, SplitView, EditMode, PreviewMode, Moon, Sun
- 标签栏: Close, Plus
- 侧边栏: Folder, File, ChevronRight, FolderPlus
- 搜索栏: ChevronUp, ChevronDown, X
- 拖拽: UploadCloud
- 导航: ArrowUp, ArrowDown
- 欢迎: WelcomeFile, WelcomeNew

设计风格:
- 线性图标(stroke-based),统一 1.75px 线宽
- 圆角风格,现代科技感
- 蓝色主色调渐变应用图标
- 部分图标添加微妙的填充细节(opacity 0.3-0.4)

更新组件:
- Toolbar: 使用 FolderOpen/Save/SplitView/EditMode/PreviewMode/Moon/Sun
- TabBar: 使用 Close/Plus
- Sidebar: 使用 FolderPlus/File/Folder/ChevronRight
- SearchBar: 使用 ChevronUp/ChevronDown/X
- WelcomeScreen: 使用 AppIcon/WelcomeFile/WelcomeNew
- DropOverlay: 使用 UploadCloud
This commit is contained in:
thzxx
2026-05-27 21:44:26 +08:00
parent 70dff0cf01
commit db94ecfad0
7 changed files with 283 additions and 108 deletions
+3 -14
View File
@@ -1,6 +1,7 @@
import React, { useCallback, useState, useEffect, useRef } from 'react'
import { useTabStore } from '../../stores/tabStore'
import { getFileName } from '../../lib/fileUtils'
import { Close, Plus } from '../Icons'
interface ContextMenuState {
visible: boolean
@@ -22,7 +23,6 @@ export function TabBar() {
const [menu, setMenu] = useState<ContextMenuState>({ visible: false, x: 0, y: 0, tabId: '' })
const menuRef = useRef<HTMLDivElement>(null)
// 关闭标签(带未保存确认)
const handleClose = useCallback((e: React.MouseEvent, tabId: string) => {
e.stopPropagation()
const tab = tabs.find(t => t.id === tabId)
@@ -44,7 +44,6 @@ export function TabBar() {
setMenu({ visible: true, x: Math.max(0, x), y: Math.max(0, y), tabId })
}, [])
// 点击空白处关闭菜单
useEffect(() => {
if (!menu.visible) return
const handleClick = () => setMenu(prev => ({ ...prev, visible: false }))
@@ -52,7 +51,6 @@ export function TabBar() {
return () => document.removeEventListener('click', handleClick)
}, [menu.visible])
// 菜单操作
const handleMenuClose = useCallback(() => {
const tab = tabs.find(t => t.id === menu.tabId)
if (tab?.isModified) {
@@ -64,7 +62,6 @@ export function TabBar() {
}, [tabs, menu.tabId, closeTab])
const handleMenuCloseOthers = useCallback(() => {
// 检查其他标签是否有未保存
const otherModified = tabs.filter(t => t.id !== menu.tabId && t.isModified)
if (otherModified.length > 0) {
const names = otherModified.map(t => t.filePath ? getFileName(t.filePath) : '未命名').join('、')
@@ -96,7 +93,6 @@ export function TabBar() {
setMenu(prev => ({ ...prev, visible: false }))
}, [tabs, menu.tabId, closeTabsToRight])
// 判断右侧是否还有标签
const hasRightTabs = menu.visible && (() => {
const index = tabs.findIndex(t => t.id === menu.tabId)
return index < tabs.length - 1
@@ -121,10 +117,7 @@ export function TabBar() {
className="tab-close"
onClick={(e) => handleClose(e, tab.id)}
>
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<line x1="18" y1="6" x2="6" y2="18" />
<line x1="6" y1="6" x2="18" y2="18" />
</svg>
<Close size={10} />
</button>
</div>
))}
@@ -134,10 +127,7 @@ export function TabBar() {
onClick={() => createTab(null, '')}
title="新建标签页 (Ctrl+T)"
>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<line x1="12" y1="5" x2="12" y2="19" />
<line x1="5" y1="12" x2="19" y2="12" />
</svg>
<Plus size={14} />
</button>
{/* 右键菜单 */}
@@ -151,7 +141,6 @@ export function TabBar() {
<div className="tab-context-item" onClick={handleMenuClose}>
</div>
{/* M-03: 单标签时隐藏"关闭其他标签" */}
{tabs.length > 1 && (
<div className="tab-context-item" onClick={handleMenuCloseOthers}>