File size: 8,611 Bytes
1bd2bb8
 
 
 
 
df1ba4a
1bd2bb8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9fb8186
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1bd2bb8
 
9fb8186
1bd2bb8
 
9fb8186
 
df1ba4a
 
9fb8186
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1bd2bb8
 
 
 
9fb8186
1bd2bb8
 
9fb8186
 
 
 
1bd2bb8
9fb8186
 
 
1bd2bb8
9fb8186
 
 
 
 
 
 
 
1bd2bb8
 
 
 
9fb8186
 
 
1bd2bb8
 
9fb8186
 
 
 
1bd2bb8
 
9fb8186
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1bd2bb8
9fb8186
 
 
 
 
1bd2bb8
 
 
 
 
 
 
9fb8186
 
 
 
 
 
 
1bd2bb8
 
9fb8186
 
 
 
 
 
 
 
 
 
 
 
1bd2bb8
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
<!DOCTYPE html>
<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>