feat: initial implementation of Focus RSVP speed reader
- Pure frontend SPA (Vite + React 19 + TypeScript + Tailwind CSS v4) - Spritz ORP engine with absolute center crosshair gaze fixation - Multilingual hybrid segmentation via Intl.Segmenter with punctuation attachment - Adaptive breathing rhythm delay algorithm for natural comprehension - IndexedDB local bookshelf, progress persistence, and client-side EPUB/TXT/MD parsing - Curated sci-fi, philosophy, and classic speech samples - Dark/OLED/Sepia/Slate/Nord themes and rich keyboard controls Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
65
src/components/ShortcutsModal.tsx
Normal file
65
src/components/ShortcutsModal.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import { HelpCircle, X } from 'lucide-react';
|
||||
import React from 'react';
|
||||
|
||||
interface ShortcutsModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const SHORTCUTS = [
|
||||
{ key: '空格键 (Space)', action: '播放 / 暂停' },
|
||||
{ key: '← / →', action: '快退 / 快进 10 个词' },
|
||||
{ key: 'Shift + ← / →', action: '跳转到 上一句 / 下一句' },
|
||||
{ key: '↑ / ↓', action: '微调阅读语速 ±25 WPM' },
|
||||
{ key: 'Shift + ↑ / ↓', action: '加速调节语速 ±50 WPM' },
|
||||
{ key: '[ / ] 或 PageUp/Down', action: '跳转到 上一章 / 下一章' },
|
||||
{ key: 'R', action: '从头重新开始阅读' },
|
||||
{ key: 'F', action: '切换全屏专注模式' },
|
||||
{ key: 'Esc', action: '关闭当前浮层 / 弹窗' },
|
||||
];
|
||||
|
||||
export const ShortcutsModal: React.FC<ShortcutsModalProps> = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
}) => {
|
||||
if (!isOpen) return null;
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/60 backdrop-blur-sm animate-fade-in select-none">
|
||||
<div className="relative w-full max-w-md bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-800 rounded-2xl shadow-2xl flex flex-col max-h-[85vh] overflow-hidden">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between px-6 py-4 border-b border-neutral-200 dark:border-neutral-800">
|
||||
<div className="flex items-center space-x-2">
|
||||
<HelpCircle className="w-5 h-5 text-rose-500" />
|
||||
<h2 className="text-lg font-bold text-neutral-900 dark:text-neutral-100">
|
||||
键盘极速快捷键
|
||||
</h2>
|
||||
</div>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="p-1 rounded-lg text-neutral-400 hover:text-neutral-900 dark:hover:text-white hover:bg-neutral-100 dark:hover:bg-neutral-800 transition-colors"
|
||||
>
|
||||
<X className="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Shortcuts list */}
|
||||
<div className="p-6 space-y-2.5 flex-1 overflow-y-auto">
|
||||
{SHORTCUTS.map((s, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
className="flex items-center justify-between py-1.5 border-b border-neutral-100 dark:border-neutral-800/60 last:border-0"
|
||||
>
|
||||
<kbd className="px-2.5 py-1 text-xs font-mono font-semibold bg-neutral-100 dark:bg-neutral-800 text-neutral-800 dark:text-neutral-200 rounded-md border border-neutral-200 dark:border-neutral-700 shadow-sm">
|
||||
{s.key}
|
||||
</kbd>
|
||||
<span className="text-sm text-neutral-600 dark:text-neutral-300">
|
||||
{s.action}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user