snice 3.5.0 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/snice.js +2 -1
- package/bin/templates/CLAUDE.md +24 -2
- package/bin/templates/pwa/README.md +173 -0
- package/bin/templates/pwa/global.d.ts +10 -0
- package/bin/templates/pwa/index.html +17 -0
- package/bin/templates/pwa/package.json +25 -0
- package/bin/templates/pwa/public/icons/.gitkeep +6 -0
- package/bin/templates/pwa/public/manifest.json +24 -0
- package/bin/templates/pwa/public/vite.svg +1 -0
- package/bin/templates/pwa/src/daemons/notifications.ts +148 -0
- package/bin/templates/pwa/src/guards/auth.ts +10 -0
- package/bin/templates/pwa/src/main.ts +42 -0
- package/bin/templates/pwa/src/middleware/auth.ts +15 -0
- package/bin/templates/pwa/src/middleware/error.ts +25 -0
- package/bin/templates/pwa/src/middleware/retry.ts +27 -0
- package/bin/templates/pwa/src/pages/dashboard.ts +142 -0
- package/bin/templates/pwa/src/pages/login.ts +161 -0
- package/bin/templates/pwa/src/pages/notifications.ts +156 -0
- package/bin/templates/pwa/src/pages/profile.ts +163 -0
- package/bin/templates/pwa/src/router.ts +16 -0
- package/bin/templates/pwa/src/services/auth.ts +48 -0
- package/bin/templates/pwa/src/services/jwt.ts +35 -0
- package/bin/templates/pwa/src/services/storage.ts +24 -0
- package/bin/templates/pwa/src/styles/global.css +55 -0
- package/bin/templates/pwa/src/types/auth.ts +21 -0
- package/bin/templates/pwa/src/types/notifications.ts +9 -0
- package/bin/templates/pwa/src/utils/fetch.ts +39 -0
- package/bin/templates/pwa/tsconfig.json +23 -0
- package/bin/templates/pwa/vite.config.ts +94 -0
- package/dist/components/audio-recorder/snice-audio-recorder.d.ts +14 -4
- package/dist/components/audio-recorder/snice-audio-recorder.js +248 -71
- package/dist/components/audio-recorder/snice-audio-recorder.js.map +1 -1
- package/dist/components/audio-recorder/snice-audio-recorder.types.d.ts +2 -0
- package/dist/components/music-player/snice-music-player.d.ts +72 -0
- package/dist/components/music-player/snice-music-player.js +730 -0
- package/dist/components/music-player/snice-music-player.js.map +1 -0
- package/dist/components/music-player/snice-music-player.types.d.ts +43 -0
- package/dist/components/timer/snice-timer.d.ts +27 -0
- package/dist/components/timer/snice-timer.js +197 -0
- package/dist/components/timer/snice-timer.js.map +1 -0
- package/dist/components/timer/snice-timer.types.d.ts +10 -0
- package/dist/fetcher.d.ts +65 -0
- package/dist/index.cjs +92 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.esm.js +92 -4
- package/dist/index.esm.js.map +1 -1
- package/dist/index.iife.js +92 -3
- package/dist/index.iife.js.map +1 -1
- package/dist/symbols.cjs +1 -1
- package/dist/symbols.esm.js +1 -1
- package/dist/transitions.cjs +1 -1
- package/dist/transitions.esm.js +1 -1
- package/dist/types/context.d.ts +7 -1
- package/dist/types/router-options.d.ts +6 -0
- package/docs/ai/api.md +33 -1
- package/docs/ai/components/music-player.md +134 -0
- package/docs/ai/components/terminal.md +147 -0
- package/docs/ai/components/timer.md +43 -0
- package/docs/ai/patterns.md +47 -0
- package/docs/components/music-player.md +314 -0
- package/docs/components/terminal.md +451 -0
- package/docs/components/timer.md +143 -0
- package/docs/fetcher.md +447 -0
- package/docs/routing.md +2 -0
- package/package.json +2 -1
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
# snice-terminal
|
|
2
|
+
|
|
3
|
+
A shell terminal emulator component with command execution, history navigation, ANSI color support, and keyboard shortcuts.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Command execution** - Execute commands with @request/@respond pattern
|
|
8
|
+
- **Command history** - Navigate with arrow keys (↑/↓)
|
|
9
|
+
- **ANSI colors** - Support for ANSI escape sequences
|
|
10
|
+
- **Keyboard shortcuts** - Ctrl+C, Ctrl+L, Tab (planned)
|
|
11
|
+
- **Readonly mode** - Display-only terminal output
|
|
12
|
+
- **Line management** - Auto-scroll and line limit
|
|
13
|
+
- **Timestamps** - Optional timestamp display
|
|
14
|
+
- **Customizable styling** - CSS custom properties for theming
|
|
15
|
+
|
|
16
|
+
## Basic Usage
|
|
17
|
+
|
|
18
|
+
```html
|
|
19
|
+
<snice-terminal id="terminal" prompt="$ " cwd="~"></snice-terminal>
|
|
20
|
+
|
|
21
|
+
<script type="module">
|
|
22
|
+
import 'snice';
|
|
23
|
+
|
|
24
|
+
const terminal = document.getElementById('terminal');
|
|
25
|
+
|
|
26
|
+
// Write to terminal
|
|
27
|
+
terminal.writeln('Welcome to the terminal!', 'info');
|
|
28
|
+
terminal.writeln('Type "help" for commands', 'output');
|
|
29
|
+
</script>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Properties
|
|
33
|
+
|
|
34
|
+
| Property | Attribute | Type | Default | Description |
|
|
35
|
+
| ----------------- | ------------------ | --------- | ---------- | ------------------------------------- |
|
|
36
|
+
| `prompt` | `prompt` | `string` | `"$ "` | Terminal prompt string |
|
|
37
|
+
| `cwd` | `cwd` | `string` | `"~"` | Current working directory |
|
|
38
|
+
| `readonly` | `readonly` | `boolean` | `false` | Disable input (display only) |
|
|
39
|
+
| `maxLines` | `max-lines` | `number` | `1000` | Maximum lines to keep in history |
|
|
40
|
+
| `showTimestamps` | `show-timestamps` | `boolean` | `false` | Show timestamps on each line |
|
|
41
|
+
|
|
42
|
+
## Methods
|
|
43
|
+
|
|
44
|
+
### `write(content: string, type?: TerminalLineType): void`
|
|
45
|
+
|
|
46
|
+
Write content to terminal without adding a newline.
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
terminal.write('Loading', 'output');
|
|
50
|
+
terminal.write('...', 'output');
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### `writeln(content: string, type?: TerminalLineType): void`
|
|
54
|
+
|
|
55
|
+
Write a line to the terminal with a newline.
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
terminal.writeln('Command completed successfully', 'success');
|
|
59
|
+
terminal.writeln('Warning: Low disk space', 'warning');
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### `writeLines(lines: Array<{ content: string; type?: TerminalLineType }>): void`
|
|
63
|
+
|
|
64
|
+
Write multiple lines at once.
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
terminal.writeLines([
|
|
68
|
+
{ content: 'File listing:', type: 'info' },
|
|
69
|
+
{ content: 'file1.txt', type: 'output' },
|
|
70
|
+
{ content: 'file2.txt', type: 'output' },
|
|
71
|
+
{ content: 'file3.txt', type: 'output' },
|
|
72
|
+
]);
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### `writeError(content: string): void`
|
|
76
|
+
|
|
77
|
+
Write an error message to the terminal.
|
|
78
|
+
|
|
79
|
+
```javascript
|
|
80
|
+
terminal.writeError('Error: File not found');
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### `clear(): void`
|
|
84
|
+
|
|
85
|
+
Clear all terminal output.
|
|
86
|
+
|
|
87
|
+
```javascript
|
|
88
|
+
terminal.clear();
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### `focus(): void`
|
|
92
|
+
|
|
93
|
+
Focus the terminal input.
|
|
94
|
+
|
|
95
|
+
```javascript
|
|
96
|
+
terminal.focus();
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### `getHistory(): string[]`
|
|
100
|
+
|
|
101
|
+
Get the command history.
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
const history = terminal.getHistory();
|
|
105
|
+
console.log('Command history:', history);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### `clearHistory(): void`
|
|
109
|
+
|
|
110
|
+
Clear the command history.
|
|
111
|
+
|
|
112
|
+
```javascript
|
|
113
|
+
terminal.clearHistory();
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Events
|
|
117
|
+
|
|
118
|
+
### `@snice/terminal-command`
|
|
119
|
+
|
|
120
|
+
Emitted when a command is entered.
|
|
121
|
+
|
|
122
|
+
```javascript
|
|
123
|
+
terminal.addEventListener('@snice/terminal-command', (e) => {
|
|
124
|
+
console.log('Command:', e.detail.command);
|
|
125
|
+
console.log('Args:', e.detail.args);
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Detail:**
|
|
130
|
+
- `command: string` - The command name
|
|
131
|
+
- `args: string[]` - Command arguments
|
|
132
|
+
|
|
133
|
+
### `@snice/terminal-clear`
|
|
134
|
+
|
|
135
|
+
Emitted when the terminal is cleared.
|
|
136
|
+
|
|
137
|
+
```javascript
|
|
138
|
+
terminal.addEventListener('@snice/terminal-clear', () => {
|
|
139
|
+
console.log('Terminal was cleared');
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### `@snice/terminal-ready`
|
|
144
|
+
|
|
145
|
+
Emitted when the terminal is ready.
|
|
146
|
+
|
|
147
|
+
```javascript
|
|
148
|
+
terminal.addEventListener('@snice/terminal-ready', () => {
|
|
149
|
+
console.log('Terminal is ready');
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Command Execution Pattern
|
|
154
|
+
|
|
155
|
+
The terminal uses Snice's `@request`/`@respond` pattern for command execution:
|
|
156
|
+
|
|
157
|
+
```javascript
|
|
158
|
+
import { element, respond } from 'snice';
|
|
159
|
+
|
|
160
|
+
@element('terminal-controller')
|
|
161
|
+
class TerminalController extends HTMLElement {
|
|
162
|
+
@respond('terminal-command')
|
|
163
|
+
async handleCommand(payload) {
|
|
164
|
+
const { command, args, cwd, history } = payload;
|
|
165
|
+
|
|
166
|
+
// Handle different commands
|
|
167
|
+
switch (command) {
|
|
168
|
+
case 'echo':
|
|
169
|
+
return { output: args.join(' '), exitCode: 0 };
|
|
170
|
+
|
|
171
|
+
case 'pwd':
|
|
172
|
+
return { output: cwd, exitCode: 0 };
|
|
173
|
+
|
|
174
|
+
case 'clear':
|
|
175
|
+
// Special marker to trigger clear
|
|
176
|
+
return { output: '\x1B[CLEAR]' };
|
|
177
|
+
|
|
178
|
+
case 'history':
|
|
179
|
+
return { output: history.join('\n'), exitCode: 0 };
|
|
180
|
+
|
|
181
|
+
default:
|
|
182
|
+
return {
|
|
183
|
+
error: `Command not found: ${command}`,
|
|
184
|
+
exitCode: 127,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Line Types
|
|
192
|
+
|
|
193
|
+
The terminal supports different line types for styling:
|
|
194
|
+
|
|
195
|
+
- `input` - User input echoed back
|
|
196
|
+
- `output` - Standard command output
|
|
197
|
+
- `error` - Error messages (red)
|
|
198
|
+
- `info` - Information messages (blue)
|
|
199
|
+
- `success` - Success messages (green)
|
|
200
|
+
- `warning` - Warning messages (yellow)
|
|
201
|
+
|
|
202
|
+
```javascript
|
|
203
|
+
terminal.writeln('This is output', 'output');
|
|
204
|
+
terminal.writeln('This is an error', 'error');
|
|
205
|
+
terminal.writeln('This is info', 'info');
|
|
206
|
+
terminal.writeln('This is success', 'success');
|
|
207
|
+
terminal.writeln('This is a warning', 'warning');
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Keyboard Shortcuts
|
|
211
|
+
|
|
212
|
+
| Key | Action |
|
|
213
|
+
| ----------- | -------------------------- |
|
|
214
|
+
| `Enter` | Execute command |
|
|
215
|
+
| `↑` | Previous command (history) |
|
|
216
|
+
| `↓` | Next command (history) |
|
|
217
|
+
| `Ctrl+C` | Cancel current input |
|
|
218
|
+
| `Ctrl+L` | Clear terminal |
|
|
219
|
+
| `Tab` | Auto-complete (TODO) |
|
|
220
|
+
|
|
221
|
+
## ANSI Color Support
|
|
222
|
+
|
|
223
|
+
The terminal supports ANSI escape sequences for colored output:
|
|
224
|
+
|
|
225
|
+
```javascript
|
|
226
|
+
// Standard colors (30-37)
|
|
227
|
+
terminal.writeln('\x1b[31mRed text\x1b[0m', 'output');
|
|
228
|
+
terminal.writeln('\x1b[32mGreen text\x1b[0m', 'output');
|
|
229
|
+
terminal.writeln('\x1b[33mYellow text\x1b[0m', 'output');
|
|
230
|
+
terminal.writeln('\x1b[34mBlue text\x1b[0m', 'output');
|
|
231
|
+
terminal.writeln('\x1b[35mMagenta text\x1b[0m', 'output');
|
|
232
|
+
terminal.writeln('\x1b[36mCyan text\x1b[0m', 'output');
|
|
233
|
+
terminal.writeln('\x1b[37mWhite text\x1b[0m', 'output');
|
|
234
|
+
|
|
235
|
+
// Bright colors (90-97)
|
|
236
|
+
terminal.writeln('\x1b[91mBright Red\x1b[0m', 'output');
|
|
237
|
+
terminal.writeln('\x1b[92mBright Green\x1b[0m', 'output');
|
|
238
|
+
terminal.writeln('\x1b[93mBright Yellow\x1b[0m', 'output');
|
|
239
|
+
terminal.writeln('\x1b[94mBright Blue\x1b[0m', 'output');
|
|
240
|
+
|
|
241
|
+
// Reset
|
|
242
|
+
terminal.writeln('\x1b[0mReset to default\x1b[0m', 'output');
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
**ANSI Color Map:**
|
|
246
|
+
- `30` / `90` - Black / Bright Black
|
|
247
|
+
- `31` / `91` - Red / Bright Red
|
|
248
|
+
- `32` / `92` - Green / Bright Green
|
|
249
|
+
- `33` / `93` - Yellow / Bright Yellow
|
|
250
|
+
- `34` / `94` - Blue / Bright Blue
|
|
251
|
+
- `35` / `95` - Magenta / Bright Magenta
|
|
252
|
+
- `36` / `96` - Cyan / Bright Cyan
|
|
253
|
+
- `37` / `97` - White / Bright White
|
|
254
|
+
- `0` - Reset
|
|
255
|
+
|
|
256
|
+
## Styling
|
|
257
|
+
|
|
258
|
+
The component can be styled using CSS custom properties:
|
|
259
|
+
|
|
260
|
+
```css
|
|
261
|
+
snice-terminal {
|
|
262
|
+
/* Container */
|
|
263
|
+
--snice-terminal-background: #1e1e1e;
|
|
264
|
+
--snice-terminal-foreground: #d4d4d4;
|
|
265
|
+
--snice-terminal-border: #3c3c3c;
|
|
266
|
+
|
|
267
|
+
/* Scrollbar */
|
|
268
|
+
--snice-terminal-scrollbar: #424242;
|
|
269
|
+
--snice-terminal-scrollbar-thumb: #686868;
|
|
270
|
+
|
|
271
|
+
/* Line types */
|
|
272
|
+
--snice-terminal-input-color: #d4d4d4;
|
|
273
|
+
--snice-terminal-output-color: #cccccc;
|
|
274
|
+
--snice-terminal-error-color: #ff5555;
|
|
275
|
+
--snice-terminal-info-color: #569cd6;
|
|
276
|
+
--snice-terminal-success-color: #50fa7b;
|
|
277
|
+
--snice-terminal-warning-color: #f1fa8c;
|
|
278
|
+
|
|
279
|
+
/* Prompt */
|
|
280
|
+
--snice-terminal-prompt-color: #569cd6;
|
|
281
|
+
|
|
282
|
+
/* Selection */
|
|
283
|
+
--snice-terminal-selection: rgba(255, 255, 255, 0.2);
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## Examples
|
|
288
|
+
|
|
289
|
+
### Basic Terminal
|
|
290
|
+
|
|
291
|
+
```html
|
|
292
|
+
<snice-terminal id="terminal"></snice-terminal>
|
|
293
|
+
|
|
294
|
+
<script type="module">
|
|
295
|
+
import 'snice';
|
|
296
|
+
|
|
297
|
+
const terminal = document.getElementById('terminal');
|
|
298
|
+
|
|
299
|
+
terminal.writeln('Welcome to the terminal!', 'info');
|
|
300
|
+
terminal.writeln('Type commands to get started', 'output');
|
|
301
|
+
</script>
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### With Command Handler
|
|
305
|
+
|
|
306
|
+
```html
|
|
307
|
+
<terminal-controller></terminal-controller>
|
|
308
|
+
<snice-terminal id="terminal" prompt="myapp $ "></snice-terminal>
|
|
309
|
+
|
|
310
|
+
<script type="module">
|
|
311
|
+
import { element, respond } from 'snice';
|
|
312
|
+
|
|
313
|
+
@element('terminal-controller')
|
|
314
|
+
class TerminalController extends HTMLElement {
|
|
315
|
+
@respond('terminal-command')
|
|
316
|
+
async handleCommand(payload) {
|
|
317
|
+
const { command, args } = payload;
|
|
318
|
+
|
|
319
|
+
switch (command) {
|
|
320
|
+
case 'hello':
|
|
321
|
+
return { output: `Hello, ${args[0] || 'World'}!`, exitCode: 0 };
|
|
322
|
+
|
|
323
|
+
case 'date':
|
|
324
|
+
return { output: new Date().toString(), exitCode: 0 };
|
|
325
|
+
|
|
326
|
+
case 'help':
|
|
327
|
+
return {
|
|
328
|
+
output: 'Available commands:\n hello [name]\n date\n help\n clear',
|
|
329
|
+
exitCode: 0,
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
case 'clear':
|
|
333
|
+
return { output: '\x1B[CLEAR]' };
|
|
334
|
+
|
|
335
|
+
default:
|
|
336
|
+
return {
|
|
337
|
+
error: `Unknown command: ${command}`,
|
|
338
|
+
exitCode: 1,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const terminal = document.getElementById('terminal');
|
|
345
|
+
terminal.writeln('Type "help" for available commands', 'info');
|
|
346
|
+
</script>
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Readonly Terminal
|
|
350
|
+
|
|
351
|
+
```html
|
|
352
|
+
<snice-terminal id="log-viewer" readonly show-timestamps></snice-terminal>
|
|
353
|
+
|
|
354
|
+
<script type="module">
|
|
355
|
+
import 'snice';
|
|
356
|
+
|
|
357
|
+
const logViewer = document.getElementById('log-viewer');
|
|
358
|
+
|
|
359
|
+
// Simulate log streaming
|
|
360
|
+
setInterval(() => {
|
|
361
|
+
const logTypes = ['info', 'warning', 'error', 'success'];
|
|
362
|
+
const type = logTypes[Math.floor(Math.random() * logTypes.length)];
|
|
363
|
+
const message = `Log entry at ${new Date().toISOString()}`;
|
|
364
|
+
logViewer.writeln(message, type);
|
|
365
|
+
}, 2000);
|
|
366
|
+
</script>
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### With ANSI Colors
|
|
370
|
+
|
|
371
|
+
```html
|
|
372
|
+
<snice-terminal id="terminal"></snice-terminal>
|
|
373
|
+
|
|
374
|
+
<script type="module">
|
|
375
|
+
import 'snice';
|
|
376
|
+
|
|
377
|
+
const terminal = document.getElementById('terminal');
|
|
378
|
+
|
|
379
|
+
terminal.writeln('\x1b[1m\x1b[32mSuccess!\x1b[0m Operation completed', 'output');
|
|
380
|
+
terminal.writeln('\x1b[31mError:\x1b[0m Something went wrong', 'output');
|
|
381
|
+
terminal.writeln('\x1b[33mWarning:\x1b[0m Disk space low', 'output');
|
|
382
|
+
terminal.writeln('\x1b[36mInfo:\x1b[0m Processing...', 'output');
|
|
383
|
+
</script>
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### Async Command Execution
|
|
387
|
+
|
|
388
|
+
```html
|
|
389
|
+
<terminal-controller></terminal-controller>
|
|
390
|
+
<snice-terminal id="terminal"></snice-terminal>
|
|
391
|
+
|
|
392
|
+
<script type="module">
|
|
393
|
+
import { element, respond } from 'snice';
|
|
394
|
+
|
|
395
|
+
@element('terminal-controller')
|
|
396
|
+
class TerminalController extends HTMLElement {
|
|
397
|
+
@respond('terminal-command')
|
|
398
|
+
async handleCommand(payload) {
|
|
399
|
+
const { command, args } = payload;
|
|
400
|
+
|
|
401
|
+
if (command === 'fetch') {
|
|
402
|
+
const url = args[0];
|
|
403
|
+
if (!url) {
|
|
404
|
+
return { error: 'Usage: fetch <url>', exitCode: 1 };
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
try {
|
|
408
|
+
const response = await fetch(url);
|
|
409
|
+
const data = await response.json();
|
|
410
|
+
return { output: JSON.stringify(data, null, 2), exitCode: 0 };
|
|
411
|
+
} catch (error) {
|
|
412
|
+
return { error: `Fetch failed: ${error.message}`, exitCode: 1 };
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if (command === 'sleep') {
|
|
417
|
+
const seconds = parseInt(args[0]) || 1;
|
|
418
|
+
await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
|
|
419
|
+
return { output: `Slept for ${seconds} seconds`, exitCode: 0 };
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
return { error: `Unknown command: ${command}`, exitCode: 127 };
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
</script>
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
## Browser Support
|
|
429
|
+
|
|
430
|
+
Works in all modern browsers that support:
|
|
431
|
+
- Custom Elements v1
|
|
432
|
+
- Shadow DOM
|
|
433
|
+
- ES2020+
|
|
434
|
+
|
|
435
|
+
## TypeScript
|
|
436
|
+
|
|
437
|
+
Full TypeScript support with exported types:
|
|
438
|
+
|
|
439
|
+
```typescript
|
|
440
|
+
import type {
|
|
441
|
+
SniceTerminalElement,
|
|
442
|
+
TerminalLine,
|
|
443
|
+
TerminalLineType,
|
|
444
|
+
TerminalCommandRequest,
|
|
445
|
+
TerminalCommandResponse,
|
|
446
|
+
} from 'snice/terminal';
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
## Security Note
|
|
450
|
+
|
|
451
|
+
The terminal uses `unsafeHTML` for rendering ANSI-colored output. Only use trusted content or sanitize user input before displaying.
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Timer Component
|
|
2
|
+
|
|
3
|
+
The `<snice-timer>` component provides a stopwatch and countdown timer.
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<!-- Stopwatch -->
|
|
9
|
+
<snice-timer mode="stopwatch"></snice-timer>
|
|
10
|
+
|
|
11
|
+
<!-- Countdown Timer -->
|
|
12
|
+
<snice-timer mode="timer" initial-time="60"></snice-timer>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Properties
|
|
16
|
+
|
|
17
|
+
| Property | Type | Default | Description |
|
|
18
|
+
|----------|------|---------|-------------|
|
|
19
|
+
| `mode` | `'stopwatch' \| 'timer'` | `'stopwatch'` | Timer mode |
|
|
20
|
+
| `initial-time` | `number` | `0` | Starting time in seconds (for timer mode) |
|
|
21
|
+
| `running` | `boolean` | `false` | Timer running state (read-only) |
|
|
22
|
+
|
|
23
|
+
## Methods
|
|
24
|
+
|
|
25
|
+
| Method | Returns | Description |
|
|
26
|
+
|--------|---------|-------------|
|
|
27
|
+
| `start()` | `void` | Start the timer |
|
|
28
|
+
| `stop()` | `void` | Stop/pause the timer |
|
|
29
|
+
| `reset()` | `void` | Reset to initial state |
|
|
30
|
+
| `getTime()` | `number` | Get current time in seconds |
|
|
31
|
+
|
|
32
|
+
## Events
|
|
33
|
+
|
|
34
|
+
| Event | Detail | Description |
|
|
35
|
+
|-------|--------|-------------|
|
|
36
|
+
| `@snice/timer-start` | `{ timer, time }` | Timer started |
|
|
37
|
+
| `@snice/timer-stop` | `{ timer, time }` | Timer stopped |
|
|
38
|
+
| `@snice/timer-reset` | `{ timer, time }` | Timer reset |
|
|
39
|
+
| `@snice/timer-complete` | `{ timer }` | Countdown completed (timer mode only) |
|
|
40
|
+
|
|
41
|
+
## Examples
|
|
42
|
+
|
|
43
|
+
### Stopwatch
|
|
44
|
+
|
|
45
|
+
```html
|
|
46
|
+
<snice-timer id="stopwatch" mode="stopwatch"></snice-timer>
|
|
47
|
+
|
|
48
|
+
<script>
|
|
49
|
+
const stopwatch = document.getElementById('stopwatch');
|
|
50
|
+
stopwatch.start();
|
|
51
|
+
|
|
52
|
+
// Later...
|
|
53
|
+
stopwatch.stop();
|
|
54
|
+
console.log('Elapsed:', stopwatch.getTime(), 'seconds');
|
|
55
|
+
</script>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Countdown Timer
|
|
59
|
+
|
|
60
|
+
```html
|
|
61
|
+
<snice-timer id="timer" mode="timer" initial-time="300"></snice-timer>
|
|
62
|
+
|
|
63
|
+
<script>
|
|
64
|
+
const timer = document.getElementById('timer');
|
|
65
|
+
|
|
66
|
+
timer.addEventListener('@snice/timer-complete', () => {
|
|
67
|
+
console.log('Time is up!');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
timer.start();
|
|
71
|
+
</script>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Programmatic Control
|
|
75
|
+
|
|
76
|
+
```html
|
|
77
|
+
<snice-timer id="my-timer"></snice-timer>
|
|
78
|
+
|
|
79
|
+
<button onclick="document.getElementById('my-timer').start()">Start</button>
|
|
80
|
+
<button onclick="document.getElementById('my-timer').stop()">Stop</button>
|
|
81
|
+
<button onclick="document.getElementById('my-timer').reset()">Reset</button>
|
|
82
|
+
|
|
83
|
+
<script>
|
|
84
|
+
const timer = document.getElementById('my-timer');
|
|
85
|
+
|
|
86
|
+
timer.addEventListener('@snice/timer-start', (e) => {
|
|
87
|
+
console.log('Timer started at', e.detail.time);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
timer.addEventListener('@snice/timer-stop', (e) => {
|
|
91
|
+
console.log('Timer stopped at', e.detail.time);
|
|
92
|
+
});
|
|
93
|
+
</script>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Workout Timer
|
|
97
|
+
|
|
98
|
+
```html
|
|
99
|
+
<snice-timer id="workout" mode="timer" initial-time="45"></snice-timer>
|
|
100
|
+
|
|
101
|
+
<script>
|
|
102
|
+
const workout = document.getElementById('workout');
|
|
103
|
+
|
|
104
|
+
workout.addEventListener('@snice/timer-complete', () => {
|
|
105
|
+
alert('Rest time!');
|
|
106
|
+
// Start rest period
|
|
107
|
+
workout.initialTime = 15;
|
|
108
|
+
workout.reset();
|
|
109
|
+
workout.start();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
workout.start();
|
|
113
|
+
</script>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Styling
|
|
117
|
+
|
|
118
|
+
The timer uses CSS custom properties from the theme system:
|
|
119
|
+
|
|
120
|
+
```css
|
|
121
|
+
snice-timer {
|
|
122
|
+
--snice-color-background-element: rgb(252 251 249);
|
|
123
|
+
--snice-color-border: rgb(226 226 226);
|
|
124
|
+
--snice-color-text: rgb(23 23 23);
|
|
125
|
+
--snice-color-success: rgb(22 163 74);
|
|
126
|
+
--snice-color-warning: rgb(202 138 4);
|
|
127
|
+
--snice-color-neutral: rgb(82 82 82);
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Accessibility
|
|
132
|
+
|
|
133
|
+
- Large, readable time display
|
|
134
|
+
- Clear button labels and icons
|
|
135
|
+
- Keyboard accessible controls
|
|
136
|
+
- High contrast buttons
|
|
137
|
+
|
|
138
|
+
## Best Practices
|
|
139
|
+
|
|
140
|
+
1. **Choose the right mode**: Use stopwatch for tracking elapsed time, timer for countdowns
|
|
141
|
+
2. **Handle timer-complete**: Listen for completion events in timer mode
|
|
142
|
+
3. **Provide context**: Add labels or descriptions near the timer
|
|
143
|
+
4. **Reset appropriately**: Call `reset()` to return to initial state
|