Spaces:
Sleeping
Sleeping
| <html lang="zh-CN"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>程序员打字练习 | Code Typing Practice</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;700&display=swap" rel="stylesheet"> | |
| <style> | |
| body { | |
| font-family: 'Fira Code', monospace; | |
| } | |
| .cursor { | |
| border-right: 2px solid #3b82f6; | |
| animation: blink 1s step-end infinite; | |
| } | |
| @keyframes blink { | |
| 50% { border-color: transparent; } | |
| } | |
| .no-ligatures { | |
| font-variant-ligatures: none; | |
| } | |
| /* Custom scrollbar */ | |
| ::-webkit-scrollbar { | |
| width: 8px; | |
| height: 8px; | |
| } | |
| ::-webkit-scrollbar-track { | |
| background: #1e293b; | |
| } | |
| ::-webkit-scrollbar-thumb { | |
| background: #475569; | |
| border-radius: 4px; | |
| } | |
| ::-webkit-scrollbar-thumb:hover { | |
| background: #64748b; | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-slate-900 text-slate-200 min-h-screen flex flex-col items-center justify-center p-4 selection:bg-blue-500/30"> | |
| <!-- Header --> | |
| <header class="w-full max-w-5xl flex flex-col md:flex-row justify-between items-center mb-6 gap-4"> | |
| <div class="flex items-baseline gap-2"> | |
| <h1 class="text-2xl font-bold text-blue-400 tracking-tight">程序员打字练习</h1> | |
| <span class="text-slate-500 text-xs font-mono">v1.2</span> | |
| </div> | |
| <div class="flex flex-wrap items-center gap-4 text-sm"> | |
| <!-- Language Selector --> | |
| <div class="flex items-center gap-2 bg-slate-800 px-3 py-1.5 rounded border border-slate-700"> | |
| <label for="lang-select" class="text-slate-400 text-xs uppercase">Language</label> | |
| <select id="lang-select" class="bg-transparent text-yellow-400 font-bold focus:outline-none cursor-pointer"> | |
| <option value="All">All</option> | |
| <!-- Populated by JS --> | |
| </select> | |
| </div> | |
| <!-- Sound Toggle --> | |
| <button id="sound-toggle" class="flex items-center gap-2 px-3 py-1.5 rounded border border-slate-700 bg-slate-800 hover:bg-slate-700 transition-colors" title="开关音效"> | |
| <span id="sound-icon">🔊</span> | |
| </button> | |
| <!-- Custom Code Button --> | |
| <button id="custom-code-btn" class="px-3 py-1.5 rounded border border-slate-700 bg-slate-800 hover:bg-slate-700 transition-colors text-slate-300"> | |
| 自定义代码 | |
| </button> | |
| </div> | |
| </header> | |
| <!-- Main Typing Area --> | |
| <main class="w-full max-w-5xl relative bg-slate-800/80 backdrop-blur-sm rounded-xl shadow-2xl overflow-hidden border border-slate-700/50 ring-1 ring-white/5"> | |
| <!-- Stats Bar --> | |
| <div class="bg-slate-900/50 p-4 flex flex-wrap justify-around border-b border-slate-700/50 gap-4"> | |
| <div class="text-center min-w-[80px]"> | |
| <div class="text-[10px] text-slate-500 uppercase tracking-widest font-bold">WPM</div> | |
| <div id="wpm" class="text-3xl font-bold text-emerald-400 tabular-nums">0</div> | |
| </div> | |
| <div class="text-center min-w-[80px]"> | |
| <div class="text-[10px] text-slate-500 uppercase tracking-widest font-bold">Accuracy</div> | |
| <div id="accuracy" class="text-3xl font-bold text-blue-400 tabular-nums">100%</div> | |
| </div> | |
| <div class="text-center min-w-[80px]"> | |
| <div class="text-[10px] text-slate-500 uppercase tracking-widest font-bold">Progress</div> | |
| <div id="progress" class="text-3xl font-bold text-purple-400 tabular-nums">0%</div> | |
| </div> | |
| <!-- Best WPM (Local Storage) --> | |
| <div class="text-center min-w-[80px] border-l border-slate-700 pl-4 hidden md:block"> | |
| <div class="text-[10px] text-slate-500 uppercase tracking-widest font-bold">Today's Best</div> | |
| <div id="best-wpm" class="text-3xl font-bold text-yellow-500/80 tabular-nums">-</div> | |
| </div> | |
| </div> | |
| <!-- Code Container --> | |
| <div class="relative group"> | |
| <!-- Hidden Input --> | |
| <input type="text" id="hidden-input" class="absolute opacity-0 top-0 left-0 h-full w-full cursor-default z-0" autocomplete="off" spellcheck="false"> | |
| <!-- Code Display --> | |
| <div id="code-container" class="h-[400px] overflow-y-auto p-8 relative z-0 scroll-smooth"> | |
| <div id="code-display" class="whitespace-pre no-ligatures select-none text-lg leading-relaxed text-slate-500" onclick="document.getElementById('hidden-input').focus()"> | |
| <div class="flex items-center justify-center h-full animate-pulse">Loading snippets...</div> | |
| </div> | |
| </div> | |
| <!-- Focus Hint --> | |
| <div id="focus-hint" class="absolute top-4 right-6 text-xs text-slate-500 bg-slate-900/80 px-2 py-1 rounded opacity-0 transition-opacity duration-300 pointer-events-none"> | |
| Click to focus | |
| </div> | |
| <!-- Result Overlay --> | |
| <div id="result-overlay" class="absolute inset-0 bg-slate-900/95 flex flex-col items-center justify-center hidden z-20 backdrop-blur-md transition-all duration-300"> | |
| <div class="text-center transform transition-all duration-500 scale-100"> | |
| <h2 class="text-5xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-blue-400 to-emerald-400 mb-8">Completed!</h2> | |
| <div class="grid grid-cols-2 gap-12 mb-10"> | |
| <div class="text-center"> | |
| <div class="text-sm text-slate-400 uppercase tracking-widest mb-2">WPM</div> | |
| <div id="final-wpm" class="text-6xl font-bold text-emerald-400 drop-shadow-lg">0</div> | |
| </div> | |
| <div class="text-center"> | |
| <div class="text-sm text-slate-400 uppercase tracking-widest mb-2">Accuracy</div> | |
| <div id="final-accuracy" class="text-6xl font-bold text-blue-400 drop-shadow-lg">0%</div> | |
| </div> | |
| </div> | |
| <div class="flex gap-4 justify-center"> | |
| <button id="restart-btn" class="px-8 py-3 bg-blue-600 hover:bg-blue-500 text-white rounded-lg font-bold transition-all transform hover:scale-105 shadow-lg shadow-blue-900/50"> | |
| Again (Enter) | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| <!-- Footer --> | |
| <footer class="mt-8 text-slate-500 text-xs text-center"> | |
| <p class="mb-2"> | |
| <span class="inline-block bg-slate-800 px-2 py-1 rounded border border-slate-700 mx-1">Tab</span> 重置 | |
| <span class="mx-2">|</span> | |
| <span class="inline-block bg-slate-800 px-2 py-1 rounded border border-slate-700 mx-1">Space</span> 缩进 | |
| </p> | |
| <p class="opacity-50">推荐使用 Chrome / Edge 浏览器获得最佳体验</p> | |
| </footer> | |
| <!-- Custom Code Modal --> | |
| <div id="custom-modal" class="fixed inset-0 bg-black/80 flex items-center justify-center hidden z-50 backdrop-blur-sm"> | |
| <div class="bg-slate-800 p-6 rounded-xl shadow-2xl w-full max-w-2xl border border-slate-700"> | |
| <h3 class="text-xl font-bold text-white mb-4">粘贴自定义代码</h3> | |
| <textarea id="custom-input" class="w-full h-64 bg-slate-900 text-slate-300 p-4 rounded-lg font-mono text-sm border border-slate-700 focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none resize-none" placeholder="在此处粘贴代码..."></textarea> | |
| <div class="flex justify-end gap-4 mt-4"> | |
| <button id="custom-cancel" class="px-4 py-2 text-slate-400 hover:text-white transition-colors">取消</button> | |
| <button id="custom-confirm" class="px-6 py-2 bg-blue-600 hover:bg-blue-500 text-white rounded-lg font-bold transition-colors">开始练习</button> | |
| </div> | |
| </div> | |
| </div> | |
| <script src="/static/script.js"></script> | |
| </body> | |
| </html> | |