studynote/src/components/editor/WelcomeView.tsx
MikiVL 999d5e1b82 feat: add Windows shortcuts to WelcomeView shortcut table
Show macOS and Windows shortcuts side-by-side in a three-column table.
Windows uses Ctrl instead of ⌘, Ctrl+Y for redo (vs ⌘⇧Z on Mac).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 19:29:56 +08:00

237 lines
8.1 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
FileText, Folder, Slash, MousePointer, Save,
Search, Moon, Plus, Hash, Star, Image, Code2,
BookOpen, Maximize2,
} from 'lucide-react'
import { useAppStore } from '../../stores/appStore'
const FEATURES = [
{
icon: <FileText size={18} />,
title: '富文本编辑',
desc: '标题、列表、引用、代码块、表格、任务清单,应有尽有',
},
{
icon: <Code2 size={18} />,
title: '语法高亮',
desc: '代码块自动识别语言并高亮,支持 JS、TS、Python、Go 等数十种语言',
},
{
icon: <Image size={18} />,
title: '图片插入',
desc: '斜杠命令输入 URL或直接拖拽 / 粘贴截图到编辑器',
},
{
icon: <Slash size={18} />,
title: '斜杠命令',
desc: '输入 / 唤出命令菜单,用键盘快速插入任意内容块',
},
{
icon: <MousePointer size={18} />,
title: '浮动工具栏',
desc: '选中文字后浮现格式工具栏,点击即可加粗、高亮、转标题',
},
{
icon: <Save size={18} />,
title: '自动保存',
desc: '停止输入 1 秒后自动写入本地 IndexedDB无需手动保存',
},
{
icon: <BookOpen size={18} />,
title: '字数 & 阅读时长',
desc: '底部实时显示字数,并估算当前笔记的阅读时长',
},
{
icon: <Maximize2 size={18} />,
title: '专注模式',
desc: '点击标题栏图标收起侧边栏,全屏沉浸写作,按 Esc 退出',
},
{
icon: <Folder size={18} />,
title: '文件夹管理',
desc: '创建多级文件夹,右键可重命名或删除,笔记可分类归档',
},
{
icon: <Star size={18} />,
title: '收藏',
desc: '点击标题旁星标或笔记列表 hover 按钮,快速收藏重要笔记',
},
{
icon: <Search size={18} />,
title: '全文搜索',
desc: '侧边栏搜索框实时过滤笔记标题和标签',
},
{
icon: <Hash size={18} />,
title: '标签系统',
desc: '为笔记添加多个标签,跨文件夹快速定位相关内容',
},
{
icon: <Moon size={18} />,
title: '深色模式',
desc: '点击左上角图标一键切换亮色 / 暗色主题',
},
]
const SHORTCUTS = [
{ desc: '粗体', mac: ['⌘', 'B'], win: ['Ctrl', 'B'] },
{ desc: '斜体', mac: ['⌘', 'I'], win: ['Ctrl', 'I'] },
{ desc: '下划线', mac: ['⌘', 'U'], win: ['Ctrl', 'U'] },
{ desc: '行内代码', mac: ['⌘', 'E'], win: ['Ctrl', 'E'] },
{ desc: '撤销', mac: ['⌘', 'Z'], win: ['Ctrl', 'Z'] },
{ desc: '重做', mac: ['⌘', '⇧', 'Z'], win: ['Ctrl', 'Y'] },
{ desc: '命令菜单', mac: ['/'], win: ['/'] },
{ desc: '退出专注模式', mac: ['Esc'], win: ['Esc'] },
]
export function WelcomeView() {
const { createNote } = useAppStore()
return (
<div
className="flex-1 overflow-y-auto h-full"
style={{ background: 'var(--bg)' }}
>
<div className="max-w-2xl mx-auto px-12 pt-16 pb-20">
{/* Hero */}
<div className="mb-12">
<div
className="inline-flex items-center justify-center w-14 h-14 rounded-2xl mb-6 text-2xl"
style={{ background: 'var(--accent-subtle)', color: 'var(--accent)' }}
>
</div>
<h1
className="text-4xl font-bold mb-3"
style={{ color: 'var(--text)', letterSpacing: '-0.03em', lineHeight: 1.15 }}
>
使
</h1>
<p className="text-base" style={{ color: 'var(--text-muted)', lineHeight: 1.7 }}>
Vite + React + TipTap
<br />
</p>
<button
onClick={() => createNote(null)}
className="inline-flex items-center gap-2 mt-6 px-4 py-2 rounded-lg text-sm font-medium transition-colors"
style={{
background: 'var(--accent)',
color: '#fff',
}}
onMouseEnter={e => (e.currentTarget.style.background = 'var(--accent-hover)')}
onMouseLeave={e => (e.currentTarget.style.background = 'var(--accent)')}
>
<Plus size={15} />
</button>
</div>
{/* Divider */}
<div style={{ borderTop: '1px solid var(--border)', marginBottom: '2.5rem' }} />
{/* Features */}
<h2
className="text-xs font-semibold uppercase tracking-widest mb-5"
style={{ color: 'var(--text-faint)' }}
>
</h2>
<div className="grid grid-cols-2 gap-3 mb-12">
{FEATURES.map(f => (
<div
key={f.title}
className="rounded-xl p-4"
style={{ background: 'var(--bg-subtle)', border: '1px solid var(--border)' }}
>
<div
className="inline-flex items-center justify-center w-8 h-8 rounded-lg mb-3"
style={{ background: 'var(--accent-subtle)', color: 'var(--accent)' }}
>
{f.icon}
</div>
<div className="text-sm font-semibold mb-1" style={{ color: 'var(--text)' }}>{f.title}</div>
<div className="text-xs leading-relaxed" style={{ color: 'var(--text-muted)' }}>{f.desc}</div>
</div>
))}
</div>
{/* Shortcuts */}
<h2
className="text-xs font-semibold uppercase tracking-widest mb-4"
style={{ color: 'var(--text-faint)' }}
>
</h2>
<div className="rounded-xl overflow-hidden" style={{ border: '1px solid var(--border)' }}>
{/* Header */}
<div
className="grid px-5 py-2 text-xs font-semibold uppercase tracking-wider"
style={{
gridTemplateColumns: '1fr auto auto',
gap: '2rem',
background: 'var(--bg-muted)',
color: 'var(--text-faint)',
borderBottom: '1px solid var(--border)',
}}
>
<span></span>
<span>macOS</span>
<span>Windows</span>
</div>
{SHORTCUTS.map((s, i) => (
<div
key={s.desc}
className="grid items-center px-5 py-3"
style={{
gridTemplateColumns: '1fr auto auto',
gap: '2rem',
borderTop: i > 0 ? '1px solid var(--border)' : 'none',
background: 'var(--bg-subtle)',
}}
>
<span className="text-sm" style={{ color: 'var(--text-muted)' }}>{s.desc}</span>
<div className="flex items-center gap-1 justify-end">
{s.mac.map(k => (
<kbd
key={k}
className="inline-flex items-center justify-center px-2 py-0.5 rounded text-xs font-mono"
style={{
background: 'var(--bg)',
border: '1px solid var(--border)',
color: 'var(--text)',
minWidth: 28,
boxShadow: '0 1px 0 var(--border)',
}}
>
{k}
</kbd>
))}
</div>
<div className="flex items-center gap-1 justify-end">
{s.win.map(k => (
<kbd
key={k}
className="inline-flex items-center justify-center px-2 py-0.5 rounded text-xs font-mono"
style={{
background: 'var(--bg)',
border: '1px solid var(--border)',
color: 'var(--text)',
minWidth: 28,
boxShadow: '0 1px 0 var(--border)',
}}
>
{k}
</kbd>
))}
</div>
</div>
))}
</div>
</div>
</div>
)
}