Skip to content

Commit a05e242

Browse files
committed
add hot key recorder hook
1 parent 8d0fabd commit a05e242

13 files changed

Lines changed: 1285 additions & 1 deletion

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// @ts-check
2+
3+
import rootConfig from '../../../eslint.config.js'
4+
5+
/** @type {import('eslint').Linter.Config[]} */
6+
export default [
7+
{
8+
ignores: ['eslint.config.js'],
9+
},
10+
...rootConfig,
11+
]
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
<meta name="theme-color" content="#000000" />
7+
<title>Shortcut Settings - TanStack Keys React Example</title>
8+
</head>
9+
<body>
10+
<noscript>You need to enable JavaScript to run this app.</noscript>
11+
<div id="root"></div>
12+
<script type="module" src="/src/index.tsx"></script>
13+
</body>
14+
</html>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "@tanstack/keys-example-react-shortcut-settings",
3+
"private": true,
4+
"type": "module",
5+
"scripts": {
6+
"dev": "vite --port=3069",
7+
"build": "vite build",
8+
"preview": "vite preview",
9+
"lint": "eslint .",
10+
"lint:fix": "eslint . --fix",
11+
"test:types": "tsc"
12+
},
13+
"dependencies": {
14+
"@tanstack/react-keys": "^0.0.0",
15+
"react": "^19.2.4",
16+
"react-dom": "^19.2.4"
17+
},
18+
"devDependencies": {
19+
"@types/react": "^19.2.10",
20+
"@types/react-dom": "^19.2.3",
21+
"@vitejs/plugin-react": "^5.1.3",
22+
"typescript": "5.9.3",
23+
"vite": "^7.3.1"
24+
}
25+
}
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
* {
2+
box-sizing: border-box;
3+
}
4+
body {
5+
margin: 0;
6+
font-family:
7+
system-ui,
8+
-apple-system,
9+
sans-serif;
10+
background: #f5f5f5;
11+
color: #333;
12+
}
13+
.app {
14+
max-width: 900px;
15+
margin: 0 auto;
16+
padding: 20px;
17+
}
18+
header {
19+
text-align: center;
20+
margin-bottom: 40px;
21+
}
22+
header h1 {
23+
margin: 0 0 10px;
24+
color: #0066cc;
25+
}
26+
header p {
27+
color: #666;
28+
margin: 0;
29+
max-width: 600px;
30+
margin: 0 auto;
31+
}
32+
.demo-section {
33+
background: white;
34+
border-radius: 12px;
35+
padding: 24px;
36+
margin-bottom: 24px;
37+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
38+
}
39+
.demo-section h2 {
40+
margin: 0 0 16px;
41+
font-size: 20px;
42+
}
43+
.demo-section p {
44+
margin: 0 0 16px;
45+
}
46+
kbd {
47+
background: linear-gradient(180deg, #f8f8f8 0%, #e8e8e8 100%);
48+
border: 1px solid #ccc;
49+
border-bottom-width: 2px;
50+
border-radius: 4px;
51+
padding: 2px 8px;
52+
font-family: monospace;
53+
font-size: 13px;
54+
}
55+
button {
56+
background: #0066cc;
57+
color: white;
58+
border: none;
59+
padding: 8px 16px;
60+
border-radius: 6px;
61+
cursor: pointer;
62+
font-size: 14px;
63+
transition: background 0.2s;
64+
}
65+
button:hover {
66+
background: #0052a3;
67+
}
68+
button:active {
69+
background: #004080;
70+
}
71+
.cancel-button {
72+
background: #dc3545;
73+
}
74+
.cancel-button:hover {
75+
background: #c82333;
76+
}
77+
.edit-button {
78+
background: #28a745;
79+
}
80+
.edit-button:hover {
81+
background: #218838;
82+
}
83+
.code-block {
84+
background: #1e1e1e;
85+
color: #d4d4d4;
86+
padding: 16px;
87+
border-radius: 8px;
88+
overflow-x: auto;
89+
font-size: 13px;
90+
line-height: 1.5;
91+
margin-top: 16px;
92+
}
93+
.info-box {
94+
background: #e3f2fd;
95+
border-radius: 8px;
96+
padding: 12px 16px;
97+
margin: 20px 0;
98+
}
99+
.recording-notice {
100+
background: #fff3cd;
101+
border: 2px solid #ffc107;
102+
animation: pulse 2s ease-in-out infinite;
103+
}
104+
@keyframes pulse {
105+
0%,
106+
100% {
107+
opacity: 1;
108+
}
109+
50% {
110+
opacity: 0.8;
111+
}
112+
}
113+
114+
/* Shortcuts List */
115+
.shortcuts-list {
116+
display: flex;
117+
flex-direction: column;
118+
gap: 12px;
119+
}
120+
.shortcut-item {
121+
display: flex;
122+
align-items: center;
123+
justify-content: space-between;
124+
padding: 16px;
125+
background: #f8f9fa;
126+
border: 2px solid transparent;
127+
border-radius: 8px;
128+
transition: all 0.2s;
129+
}
130+
.shortcut-item:hover {
131+
background: #f0f0f0;
132+
}
133+
.shortcut-item.recording {
134+
background: #fff3cd;
135+
border-color: #ffc107;
136+
box-shadow: 0 0 0 3px rgba(255, 193, 7, 0.2);
137+
animation: recordingPulse 1.5s ease-in-out infinite;
138+
}
139+
@keyframes recordingPulse {
140+
0%,
141+
100% {
142+
box-shadow: 0 0 0 3px rgba(255, 193, 7, 0.2);
143+
}
144+
50% {
145+
box-shadow: 0 0 0 6px rgba(255, 193, 7, 0.1);
146+
}
147+
}
148+
.shortcut-item-content {
149+
display: flex;
150+
align-items: center;
151+
gap: 24px;
152+
flex: 1;
153+
}
154+
.shortcut-action {
155+
font-weight: 500;
156+
min-width: 80px;
157+
font-size: 15px;
158+
}
159+
.shortcut-hotkey {
160+
display: flex;
161+
align-items: center;
162+
min-height: 32px;
163+
}
164+
.shortcut-hotkey kbd {
165+
font-size: 14px;
166+
}
167+
.no-shortcut {
168+
color: #999;
169+
font-style: italic;
170+
font-size: 14px;
171+
}
172+
.shortcut-actions {
173+
display: flex;
174+
gap: 8px;
175+
}
176+
177+
/* Recording Indicator */
178+
.recording-indicator {
179+
display: flex;
180+
align-items: center;
181+
gap: 8px;
182+
}
183+
.recording-text {
184+
color: #856404;
185+
font-style: italic;
186+
font-size: 14px;
187+
}
188+
.held-keys {
189+
display: flex;
190+
align-items: center;
191+
gap: 4px;
192+
}
193+
.held-keys .plus {
194+
color: #856404;
195+
font-size: 16px;
196+
margin: 0 4px;
197+
}
198+
.held-keys kbd {
199+
background: #ffc107;
200+
border-color: #ff9800;
201+
color: #856404;
202+
font-weight: 600;
203+
}
204+
205+
/* Demo Stats */
206+
.demo-stats {
207+
display: grid;
208+
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
209+
gap: 16px;
210+
margin-top: 20px;
211+
}
212+
.stat-item {
213+
display: flex;
214+
flex-direction: column;
215+
align-items: center;
216+
padding: 16px;
217+
background: #f8f9fa;
218+
border-radius: 8px;
219+
gap: 8px;
220+
}
221+
.stat-label {
222+
font-size: 13px;
223+
color: #666;
224+
text-transform: uppercase;
225+
letter-spacing: 0.5px;
226+
}
227+
.stat-value {
228+
font-size: 32px;
229+
font-weight: bold;
230+
color: #0066cc;
231+
}
232+
.stat-item kbd {
233+
margin-top: 4px;
234+
}
235+
236+
/* Responsive */
237+
@media (max-width: 600px) {
238+
.shortcut-item {
239+
flex-direction: column;
240+
align-items: flex-start;
241+
gap: 12px;
242+
}
243+
.shortcut-item-content {
244+
width: 100%;
245+
flex-direction: column;
246+
align-items: flex-start;
247+
gap: 8px;
248+
}
249+
.shortcut-actions {
250+
width: 100%;
251+
justify-content: flex-end;
252+
}
253+
.demo-stats {
254+
grid-template-columns: repeat(2, 1fr);
255+
}
256+
}

0 commit comments

Comments
 (0)