@joewinke/jatui 0.23.0 → 0.24.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/CLAUDE.md +32 -2
- package/dist/components/AudioRecorder.svelte +84 -304
- package/dist/components/AudioRecorder.svelte.d.ts +1 -7
- package/dist/components/BulkActionBar.svelte +40 -0
- package/dist/components/BulkActionBar.svelte.d.ts +9 -0
- package/dist/components/ConfirmDialog.svelte +39 -35
- package/dist/components/CopyButton.svelte +5 -2
- package/dist/components/FloatingActionBar.svelte +55 -1
- package/dist/components/FloatingActionBar.svelte.d.ts +8 -1
- package/dist/components/InputDialog.svelte +49 -38
- package/dist/components/KeyboardShortcutsOverlay.svelte +54 -0
- package/dist/components/KeyboardShortcutsOverlay.svelte.d.ts +30 -0
- package/dist/components/bulkActionBarKeys.d.ts +40 -0
- package/dist/components/bulkActionBarKeys.js +38 -0
- package/dist/components/linked-columns/LinkedColumns.svelte +10 -22
- package/dist/components/linked-columns/LinkedColumns.svelte.d.ts +1 -9
- package/dist/components/linked-columns/types.d.ts +9 -0
- package/dist/components/linked-columns/types.js +1 -0
- package/dist/components/replay/ChapterTimeline.svelte +43 -25
- package/dist/components/replay/ChapterTimeline.svelte.d.ts +26 -1
- package/dist/components/toast/ToastItem.svelte +47 -2
- package/dist/index.d.ts +7 -4
- package/dist/index.js +5 -1
- package/dist/stores/toast.d.ts +8 -0
- package/dist/stores/toast.js +2 -0
- package/dist/utils/audioRecorder.d.ts +28 -0
- package/dist/utils/audioRecorder.js +58 -0
- package/dist/utils/audioRecorderCore.d.ts +132 -0
- package/dist/utils/audioRecorderCore.js +447 -0
- package/dist/utils/clipboard.d.ts +25 -0
- package/dist/utils/clipboard.js +59 -0
- package/dist/utils/dateFormatters.d.ts +11 -2
- package/dist/utils/dateFormatters.js +22 -2
- package/package.json +1 -1
|
@@ -23,7 +23,23 @@
|
|
|
23
23
|
*
|
|
24
24
|
* Precedence: `sections` > `registry` > `shortcuts`. The overlay owns `?` —
|
|
25
25
|
* don't register it in the registry too.
|
|
26
|
+
*
|
|
27
|
+
* App-specific sections (marks, list motions, cockpit panels…) that the
|
|
28
|
+
* overlay itself doesn't know about come in via `extraSections` — they
|
|
29
|
+
* render after the primary content, before the meta rows, in EVERY mode:
|
|
30
|
+
*
|
|
31
|
+
* <KeyboardShortcutsOverlay {registry} extraSections={[
|
|
32
|
+
* { title: 'Marks & jumps (Vim)', shortcuts: [{ key: "m{a-z}", description: 'Drop a mark' }] },
|
|
33
|
+
* ]} />
|
|
34
|
+
*
|
|
35
|
+
* For content the section renderer can't express, an `extra` snippet is
|
|
36
|
+
* rendered last (just above the meta rows):
|
|
37
|
+
*
|
|
38
|
+
* <KeyboardShortcutsOverlay {registry}>
|
|
39
|
+
* {#snippet extra()}<div>…custom footer…</div>{/snippet}
|
|
40
|
+
* </KeyboardShortcutsOverlay>
|
|
26
41
|
*/
|
|
42
|
+
import type { Snippet } from 'svelte';
|
|
27
43
|
import type { ShortcutRegistry } from '../utils/keyboardShortcutRegistry';
|
|
28
44
|
export interface KeyboardShortcut {
|
|
29
45
|
key: string;
|
|
@@ -52,6 +68,20 @@ type $$ComponentProps = {
|
|
|
52
68
|
* the stack first). Ignored when `sections` is given.
|
|
53
69
|
*/
|
|
54
70
|
registry?: ShortcutRegistry;
|
|
71
|
+
/**
|
|
72
|
+
* Extra app-provided sections (e.g. marks, list motions, cockpit
|
|
73
|
+
* panels) appended after the primary content and before the meta
|
|
74
|
+
* rows, regardless of whether the primary content came from
|
|
75
|
+
* `sections`, `registry` or the flat `shortcuts` list. Same shape
|
|
76
|
+
* as `sections`, with per-key `color` tinting supported.
|
|
77
|
+
*/
|
|
78
|
+
extraSections?: ShortcutSection[];
|
|
79
|
+
/**
|
|
80
|
+
* Fully custom footer content, rendered after `extraSections` and
|
|
81
|
+
* just above the built-in meta rows. Use when the section renderer
|
|
82
|
+
* (title + key/description rows) can't express the markup.
|
|
83
|
+
*/
|
|
84
|
+
extra?: Snippet;
|
|
55
85
|
title?: string;
|
|
56
86
|
open?: boolean;
|
|
57
87
|
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure hotkey resolution for `BulkActionBar` (jatui-is2ow.6) — ported from
|
|
3
|
+
* the IDE's fork (`ide/src/lib/components/BulkActionBar.svelte`, audit
|
|
4
|
+
* jat-1alfp row 15).
|
|
5
|
+
*
|
|
6
|
+
* The IDE fork keeps key handling in the host page; here it lives in the
|
|
7
|
+
* component, but the DECIDING logic is this pure function so it can be
|
|
8
|
+
* unit-tested without a DOM. The component's keydown handler calls
|
|
9
|
+
* `matchBulkHotkey(event, actions)` and invokes the returned action's
|
|
10
|
+
* `onSelect`.
|
|
11
|
+
*
|
|
12
|
+
* Rules (mirroring the shortcut registry's sharp edges):
|
|
13
|
+
* - single printable keys only (`event.key.length === 1`) — an action
|
|
14
|
+
* declaring a multi-char `key` is never matched;
|
|
15
|
+
* - matched case-insensitively (`'C'` on the action fires on `'c'`);
|
|
16
|
+
* - ignored while the focus is in a text entry target (`isTypingTarget`);
|
|
17
|
+
* - ignored for modifier combos (Ctrl/⌘/Alt) and already-handled events.
|
|
18
|
+
*/
|
|
19
|
+
/** The subset of `BulkAction` the resolver needs. */
|
|
20
|
+
export interface BulkHotkeyAction {
|
|
21
|
+
/** Single-key binding (e.g. 'c'). Multi-char values never match. */
|
|
22
|
+
key?: string;
|
|
23
|
+
/** Click handler — fired by the component when the hotkey matches. */
|
|
24
|
+
onSelect: () => void;
|
|
25
|
+
}
|
|
26
|
+
/** Minimal structural subset of `KeyboardEvent` — real events satisfy it. */
|
|
27
|
+
export interface BulkHotkeyEvent {
|
|
28
|
+
key: string;
|
|
29
|
+
target: EventTarget | null;
|
|
30
|
+
defaultPrevented?: boolean;
|
|
31
|
+
ctrlKey?: boolean;
|
|
32
|
+
metaKey?: boolean;
|
|
33
|
+
altKey?: boolean;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Resolve a keydown to the bulk action whose single-key binding matches,
|
|
37
|
+
* or return null when the event must not fire a hotkey (typing target,
|
|
38
|
+
* modifier combo, defaultPrevented, non-printable key, no match).
|
|
39
|
+
*/
|
|
40
|
+
export declare function matchBulkHotkey(event: BulkHotkeyEvent, actions: readonly BulkHotkeyAction[]): BulkHotkeyAction | null;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure hotkey resolution for `BulkActionBar` (jatui-is2ow.6) — ported from
|
|
3
|
+
* the IDE's fork (`ide/src/lib/components/BulkActionBar.svelte`, audit
|
|
4
|
+
* jat-1alfp row 15).
|
|
5
|
+
*
|
|
6
|
+
* The IDE fork keeps key handling in the host page; here it lives in the
|
|
7
|
+
* component, but the DECIDING logic is this pure function so it can be
|
|
8
|
+
* unit-tested without a DOM. The component's keydown handler calls
|
|
9
|
+
* `matchBulkHotkey(event, actions)` and invokes the returned action's
|
|
10
|
+
* `onSelect`.
|
|
11
|
+
*
|
|
12
|
+
* Rules (mirroring the shortcut registry's sharp edges):
|
|
13
|
+
* - single printable keys only (`event.key.length === 1`) — an action
|
|
14
|
+
* declaring a multi-char `key` is never matched;
|
|
15
|
+
* - matched case-insensitively (`'C'` on the action fires on `'c'`);
|
|
16
|
+
* - ignored while the focus is in a text entry target (`isTypingTarget`);
|
|
17
|
+
* - ignored for modifier combos (Ctrl/⌘/Alt) and already-handled events.
|
|
18
|
+
*/
|
|
19
|
+
import { isTypingTarget } from '../utils/keyboardShortcutRegistry';
|
|
20
|
+
/**
|
|
21
|
+
* Resolve a keydown to the bulk action whose single-key binding matches,
|
|
22
|
+
* or return null when the event must not fire a hotkey (typing target,
|
|
23
|
+
* modifier combo, defaultPrevented, non-printable key, no match).
|
|
24
|
+
*/
|
|
25
|
+
export function matchBulkHotkey(event, actions) {
|
|
26
|
+
if (event.defaultPrevented)
|
|
27
|
+
return null;
|
|
28
|
+
if (event.ctrlKey || event.metaKey || event.altKey)
|
|
29
|
+
return null;
|
|
30
|
+
if (isTypingTarget(event.target))
|
|
31
|
+
return null;
|
|
32
|
+
// Single printable keys only — 'Escape', 'ArrowDown', 'Enter' etc. are
|
|
33
|
+
// navigation keys owned by listNav and must never trigger a bulk action.
|
|
34
|
+
if (!event.key || event.key.length !== 1)
|
|
35
|
+
return null;
|
|
36
|
+
const wanted = event.key.toLowerCase();
|
|
37
|
+
return (actions.find((a) => a.key && a.key.length === 1 && a.key.toLowerCase() === wanted) ?? null);
|
|
38
|
+
}
|
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
<script module lang="ts">
|
|
2
|
-
// Declared in the module script so `import type { ColumnLink } from
|
|
3
|
-
// './LinkedColumns.svelte'` resolves (instance-script exports are not module members).
|
|
4
|
-
/** Describes which left items a single right (anchor) item covers. */
|
|
5
|
-
export interface ColumnLink {
|
|
6
|
-
/** The right item's id this link belongs to. */
|
|
7
|
-
rightId: string | number;
|
|
8
|
-
/** First left item id in the covered range (inclusive). */
|
|
9
|
-
leftStartId: string | number;
|
|
10
|
-
/** Last left item id in the covered range (inclusive). */
|
|
11
|
-
leftEndId: string | number;
|
|
12
|
-
}
|
|
13
|
-
</script>
|
|
14
|
-
|
|
15
1
|
<script lang="ts" generics="L extends { id: string | number }, R extends { id: string | number }">
|
|
16
2
|
/**
|
|
17
3
|
* LinkedColumns — generic two-column ink-up ribbon primitive.
|
|
@@ -64,8 +50,7 @@
|
|
|
64
50
|
*/
|
|
65
51
|
|
|
66
52
|
import type { Snippet } from 'svelte';
|
|
67
|
-
|
|
68
|
-
// ColumnLink is declared in the module <script> above so it's importable as a module member.
|
|
53
|
+
import type { ColumnLink } from './types.js';
|
|
69
54
|
|
|
70
55
|
let {
|
|
71
56
|
leftItems,
|
|
@@ -410,12 +395,15 @@
|
|
|
410
395
|
</div>
|
|
411
396
|
|
|
412
397
|
<style>
|
|
398
|
+
/* Theme tokens (jatui-is2ow.3): fallbacks chain token → token (never a
|
|
399
|
+
hard-coded oklch). --n-16 is a jat-IDE neutral; its inline fallback keeps
|
|
400
|
+
standalone consumers (no app.css) rendering the same value. */
|
|
413
401
|
.lc-wrap {
|
|
414
402
|
position: relative;
|
|
415
403
|
display: flex;
|
|
416
404
|
height: 100%;
|
|
417
405
|
min-height: 0;
|
|
418
|
-
background: var(--color-base-100,
|
|
406
|
+
background: var(--color-base-100, var(--color-base-300));
|
|
419
407
|
border-radius: 0.75rem;
|
|
420
408
|
overflow: hidden;
|
|
421
409
|
}
|
|
@@ -431,7 +419,7 @@
|
|
|
431
419
|
transition: stroke-opacity 0.25s ease, stroke-width 0.25s ease;
|
|
432
420
|
}
|
|
433
421
|
.lc-ribbon-active {
|
|
434
|
-
filter: drop-shadow(0 0 6px var(--color-success
|
|
422
|
+
filter: drop-shadow(0 0 6px var(--color-success));
|
|
435
423
|
}
|
|
436
424
|
|
|
437
425
|
/* Columns */
|
|
@@ -473,10 +461,10 @@
|
|
|
473
461
|
font-weight: 700;
|
|
474
462
|
letter-spacing: 0.08em;
|
|
475
463
|
text-transform: uppercase;
|
|
476
|
-
color: var(--color-base-content
|
|
464
|
+
color: var(--color-base-content);
|
|
477
465
|
opacity: 0.55;
|
|
478
466
|
background: linear-gradient(
|
|
479
|
-
var(--color-base-100, oklch(0.16 0.01 250)) 70%,
|
|
467
|
+
var(--color-base-100, var(--n-16, oklch(0.16 0.01 250))) 70%,
|
|
480
468
|
transparent
|
|
481
469
|
);
|
|
482
470
|
}
|
|
@@ -489,8 +477,8 @@
|
|
|
489
477
|
transition: background-color 0.2s ease, box-shadow 0.2s ease;
|
|
490
478
|
}
|
|
491
479
|
.lc-left-item-active {
|
|
492
|
-
background: color-mix(in oklch, var(--color-success
|
|
493
|
-
box-shadow: inset 2px 0 0 var(--color-success
|
|
480
|
+
background: color-mix(in oklch, var(--color-success) 8%, transparent);
|
|
481
|
+
box-shadow: inset 2px 0 0 var(--color-success);
|
|
494
482
|
}
|
|
495
483
|
|
|
496
484
|
/* Right item wrapper — consumers style via snippet; provides CSS vars */
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
/** Describes which left items a single right (anchor) item covers. */
|
|
2
|
-
export interface ColumnLink {
|
|
3
|
-
/** The right item's id this link belongs to. */
|
|
4
|
-
rightId: string | number;
|
|
5
|
-
/** First left item id in the covered range (inclusive). */
|
|
6
|
-
leftStartId: string | number;
|
|
7
|
-
/** Last left item id in the covered range (inclusive). */
|
|
8
|
-
leftEndId: string | number;
|
|
9
|
-
}
|
|
10
1
|
/**
|
|
11
2
|
* LinkedColumns — generic two-column ink-up ribbon primitive.
|
|
12
3
|
*
|
|
@@ -57,6 +48,7 @@ export interface ColumnLink {
|
|
|
57
48
|
* ```
|
|
58
49
|
*/
|
|
59
50
|
import type { Snippet } from 'svelte';
|
|
51
|
+
import type { ColumnLink } from './types.js';
|
|
60
52
|
declare function $$render<L extends {
|
|
61
53
|
id: string | number;
|
|
62
54
|
}, R extends {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Describes which left items a single right (anchor) item covers. */
|
|
2
|
+
export interface ColumnLink {
|
|
3
|
+
/** The right item's id this link belongs to. */
|
|
4
|
+
rightId: string | number;
|
|
5
|
+
/** First left item id in the covered range (inclusive). */
|
|
6
|
+
leftStartId: string | number;
|
|
7
|
+
/** Last left item id in the covered range (inclusive). */
|
|
8
|
+
leftEndId: string | number;
|
|
9
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -11,7 +11,12 @@
|
|
|
11
11
|
* on the full IDE codebase (jat-jj79f.16 G1).
|
|
12
12
|
*
|
|
13
13
|
* The IDE-specific `SESSION_STATE_VISUALS` import has been replaced with
|
|
14
|
-
* an inline `SIGNAL_COLORS` map that covers the same canonical signal types
|
|
14
|
+
* an inline `SIGNAL_COLORS` map that covers the same canonical signal types,
|
|
15
|
+
* plus an optional `stateVisual(state)` resolver prop (jatui-is2ow.4): a
|
|
16
|
+
* caller — e.g. the jat IDE with its own SESSION_STATE_VISUALS — can supply
|
|
17
|
+
* its own colour resolver and the built-in palette is only used as the
|
|
18
|
+
* default / fallback. `ChapterBlock.itemRange` matches the IDE's WorkBlock
|
|
19
|
+
* shape so IDE callers can pass blocks straight through without remapping.
|
|
15
20
|
*/
|
|
16
21
|
|
|
17
22
|
export interface ChapterBlock {
|
|
@@ -22,17 +27,20 @@
|
|
|
22
27
|
filesTouched: { path: string; how: string }[];
|
|
23
28
|
checkpoint: { timestamp: string | null };
|
|
24
29
|
summary: string | null;
|
|
30
|
+
/** Index span of the transcript items this block owns (IDE WorkBlock shape). */
|
|
31
|
+
itemRange?: { start: number; end: number };
|
|
25
32
|
}
|
|
26
33
|
|
|
27
|
-
/**
|
|
28
|
-
interface
|
|
34
|
+
/** Colour descriptors the timeline needs per canonical signal state. */
|
|
35
|
+
export interface ChapterStateVisual {
|
|
29
36
|
accent: string;
|
|
30
37
|
bgTint: string;
|
|
31
38
|
glow: string;
|
|
32
39
|
shortLabel: string;
|
|
33
40
|
}
|
|
34
41
|
|
|
35
|
-
|
|
42
|
+
/** Default palette for each canonical signal state — kept for standalone consumers without a resolver. */
|
|
43
|
+
const SIGNAL_COLORS: Record<string, ChapterStateVisual> = {
|
|
36
44
|
starting: { accent: 'oklch(0.70 0.16 250)', bgTint: 'oklch(0.70 0.16 250 / 0.10)', glow: 'oklch(0.70 0.16 250 / 0.45)', shortLabel: '🚀 Starting' },
|
|
37
45
|
working: { accent: 'oklch(0.75 0.16 85)', bgTint: 'oklch(0.75 0.16 85 / 0.08)', glow: 'oklch(0.75 0.16 85 / 0.45)', shortLabel: '🔧 Working' },
|
|
38
46
|
'needs-input': { accent: 'oklch(0.68 0.19 25)', bgTint: 'oklch(0.68 0.19 25 / 0.08)', glow: 'oklch(0.68 0.19 25 / 0.4)', shortLabel: '❓ Needs Input' },
|
|
@@ -49,10 +57,19 @@
|
|
|
49
57
|
blocks = [],
|
|
50
58
|
activeBlockId = null,
|
|
51
59
|
onSeek = (_blockId: string) => {},
|
|
60
|
+
stateVisual,
|
|
52
61
|
}: {
|
|
53
62
|
blocks: ChapterBlock[];
|
|
54
63
|
activeBlockId: string | null;
|
|
55
64
|
onSeek?: (blockId: string) => void;
|
|
65
|
+
/**
|
|
66
|
+
* Optional colour resolver: canonical state name → visual. Receives the
|
|
67
|
+
* NORMALIZED state (e.g. `'needs-input'`, not the raw `'needs_input'`),
|
|
68
|
+
* so a caller can pass `(state) => SESSION_STATE_VISUALS[state]` directly.
|
|
69
|
+
* Return `undefined` for unknown states — the built-in palette (then
|
|
70
|
+
* idle) is used as the fallback, matching the IDE's `?? idle` behaviour.
|
|
71
|
+
*/
|
|
72
|
+
stateVisual?: (state: string) => ChapterStateVisual | undefined;
|
|
56
73
|
} = $props();
|
|
57
74
|
|
|
58
75
|
function rawTypeToState(raw: string): string {
|
|
@@ -65,8 +82,9 @@
|
|
|
65
82
|
}
|
|
66
83
|
}
|
|
67
84
|
|
|
68
|
-
function visual(signalType: string):
|
|
69
|
-
|
|
85
|
+
function visual(signalType: string): ChapterStateVisual {
|
|
86
|
+
const state = rawTypeToState(signalType);
|
|
87
|
+
return stateVisual?.(state) ?? SIGNAL_COLORS[state] ?? DEFAULT_COLOR;
|
|
70
88
|
}
|
|
71
89
|
|
|
72
90
|
function glyph(signalType: string): string {
|
|
@@ -183,7 +201,7 @@
|
|
|
183
201
|
|
|
184
202
|
.empty {
|
|
185
203
|
font-size: 0.75rem;
|
|
186
|
-
color: oklch(
|
|
204
|
+
color: oklch(from var(--color-base-content) l c h / 60%);
|
|
187
205
|
padding: 0.5rem;
|
|
188
206
|
text-align: center;
|
|
189
207
|
}
|
|
@@ -193,8 +211,8 @@
|
|
|
193
211
|
height: 2.25rem;
|
|
194
212
|
border-radius: 0.5rem;
|
|
195
213
|
overflow: hidden;
|
|
196
|
-
background:
|
|
197
|
-
border: 1px solid
|
|
214
|
+
background: var(--color-base-300);
|
|
215
|
+
border: 1px solid var(--color-base-100);
|
|
198
216
|
gap: 1px;
|
|
199
217
|
}
|
|
200
218
|
|
|
@@ -203,9 +221,9 @@
|
|
|
203
221
|
align-items: center;
|
|
204
222
|
gap: 0.3rem;
|
|
205
223
|
padding: 0 0.5rem;
|
|
206
|
-
background: var(--chapter-tint,
|
|
224
|
+
background: var(--chapter-tint, var(--color-base-200));
|
|
207
225
|
border: none;
|
|
208
|
-
border-right: 1px solid
|
|
226
|
+
border-right: 1px solid var(--color-base-100);
|
|
209
227
|
cursor: pointer;
|
|
210
228
|
transition: background 0.12s ease, box-shadow 0.12s ease;
|
|
211
229
|
overflow: hidden;
|
|
@@ -218,12 +236,12 @@
|
|
|
218
236
|
}
|
|
219
237
|
|
|
220
238
|
.chapter:hover {
|
|
221
|
-
background: color-mix(in oklch, var(--chapter-accent) 18%,
|
|
239
|
+
background: color-mix(in oklch, var(--chapter-accent) 18%, var(--color-base-300));
|
|
222
240
|
box-shadow: inset 0 0 0 1px color-mix(in oklch, var(--chapter-accent) 40%, transparent);
|
|
223
241
|
}
|
|
224
242
|
|
|
225
243
|
.chapter.active {
|
|
226
|
-
background: color-mix(in oklch, var(--chapter-accent) 22%,
|
|
244
|
+
background: color-mix(in oklch, var(--chapter-accent) 22%, var(--color-base-300));
|
|
227
245
|
box-shadow:
|
|
228
246
|
inset 0 0 0 2px color-mix(in oklch, var(--chapter-accent) 70%, transparent),
|
|
229
247
|
0 0 12px color-mix(in oklch, var(--chapter-glow) 30%, transparent);
|
|
@@ -247,20 +265,20 @@
|
|
|
247
265
|
|
|
248
266
|
.ch-label {
|
|
249
267
|
font-size: 0.7rem;
|
|
250
|
-
color: oklch(
|
|
268
|
+
color: oklch(from var(--color-base-content) l c h / 90%);
|
|
251
269
|
overflow: hidden;
|
|
252
270
|
text-overflow: ellipsis;
|
|
253
271
|
min-width: 0;
|
|
254
272
|
}
|
|
255
273
|
|
|
256
274
|
.chapter.active .ch-label {
|
|
257
|
-
color: oklch(0.92 0.06
|
|
275
|
+
color: oklch(from var(--color-primary) 0.92 0.06 h);
|
|
258
276
|
font-weight: 600;
|
|
259
277
|
}
|
|
260
278
|
|
|
261
279
|
.ch-meta {
|
|
262
280
|
font-size: 0.6rem;
|
|
263
|
-
color: oklch(
|
|
281
|
+
color: oklch(from var(--color-base-content) l c h / 55%);
|
|
264
282
|
margin-left: auto;
|
|
265
283
|
flex-shrink: 0;
|
|
266
284
|
font-family: monospace;
|
|
@@ -273,10 +291,10 @@
|
|
|
273
291
|
gap: 0.6rem;
|
|
274
292
|
padding: 0.25rem 0.5rem;
|
|
275
293
|
font-size: 0.72rem;
|
|
276
|
-
color: oklch(
|
|
277
|
-
background:
|
|
294
|
+
color: oklch(from var(--color-base-content) l c h / 80%);
|
|
295
|
+
background: var(--color-base-300);
|
|
278
296
|
border-radius: 0.375rem;
|
|
279
|
-
border: 1px solid
|
|
297
|
+
border: 1px solid var(--color-base-100);
|
|
280
298
|
min-height: 1.75rem;
|
|
281
299
|
flex-wrap: wrap;
|
|
282
300
|
gap-y: 0.15rem;
|
|
@@ -285,7 +303,7 @@
|
|
|
285
303
|
.ch-detail-idx {
|
|
286
304
|
font-size: 0.65rem;
|
|
287
305
|
font-family: monospace;
|
|
288
|
-
color: oklch(
|
|
306
|
+
color: oklch(from var(--color-base-content) l c h / 55%);
|
|
289
307
|
flex-shrink: 0;
|
|
290
308
|
}
|
|
291
309
|
|
|
@@ -297,7 +315,7 @@
|
|
|
297
315
|
}
|
|
298
316
|
|
|
299
317
|
.ch-detail-summary.muted {
|
|
300
|
-
color: oklch(
|
|
318
|
+
color: oklch(from var(--color-base-content) l c h / 60%);
|
|
301
319
|
font-style: italic;
|
|
302
320
|
}
|
|
303
321
|
|
|
@@ -310,17 +328,17 @@
|
|
|
310
328
|
.ch-file {
|
|
311
329
|
font-size: 0.64rem;
|
|
312
330
|
font-family: monospace;
|
|
313
|
-
background:
|
|
314
|
-
border: 1px solid
|
|
331
|
+
background: var(--color-base-200);
|
|
332
|
+
border: 1px solid var(--color-base-100);
|
|
315
333
|
border-radius: 0.2rem;
|
|
316
334
|
padding: 0.1rem 0.35rem;
|
|
317
|
-
color:
|
|
335
|
+
color: var(--color-info);
|
|
318
336
|
}
|
|
319
337
|
|
|
320
338
|
.ch-detail-ts {
|
|
321
339
|
font-size: 0.62rem;
|
|
322
340
|
font-family: monospace;
|
|
323
|
-
color: oklch(
|
|
341
|
+
color: oklch(from var(--color-base-content) l c h / 50%);
|
|
324
342
|
flex-shrink: 0;
|
|
325
343
|
}
|
|
326
344
|
</style>
|
|
@@ -10,7 +10,12 @@
|
|
|
10
10
|
* on the full IDE codebase (jat-jj79f.16 G1).
|
|
11
11
|
*
|
|
12
12
|
* The IDE-specific `SESSION_STATE_VISUALS` import has been replaced with
|
|
13
|
-
* an inline `SIGNAL_COLORS` map that covers the same canonical signal types
|
|
13
|
+
* an inline `SIGNAL_COLORS` map that covers the same canonical signal types,
|
|
14
|
+
* plus an optional `stateVisual(state)` resolver prop (jatui-is2ow.4): a
|
|
15
|
+
* caller — e.g. the jat IDE with its own SESSION_STATE_VISUALS — can supply
|
|
16
|
+
* its own colour resolver and the built-in palette is only used as the
|
|
17
|
+
* default / fallback. `ChapterBlock.itemRange` matches the IDE's WorkBlock
|
|
18
|
+
* shape so IDE callers can pass blocks straight through without remapping.
|
|
14
19
|
*/
|
|
15
20
|
export interface ChapterBlock {
|
|
16
21
|
id: string;
|
|
@@ -28,11 +33,31 @@ export interface ChapterBlock {
|
|
|
28
33
|
timestamp: string | null;
|
|
29
34
|
};
|
|
30
35
|
summary: string | null;
|
|
36
|
+
/** Index span of the transcript items this block owns (IDE WorkBlock shape). */
|
|
37
|
+
itemRange?: {
|
|
38
|
+
start: number;
|
|
39
|
+
end: number;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** Colour descriptors the timeline needs per canonical signal state. */
|
|
43
|
+
export interface ChapterStateVisual {
|
|
44
|
+
accent: string;
|
|
45
|
+
bgTint: string;
|
|
46
|
+
glow: string;
|
|
47
|
+
shortLabel: string;
|
|
31
48
|
}
|
|
32
49
|
type $$ComponentProps = {
|
|
33
50
|
blocks: ChapterBlock[];
|
|
34
51
|
activeBlockId: string | null;
|
|
35
52
|
onSeek?: (blockId: string) => void;
|
|
53
|
+
/**
|
|
54
|
+
* Optional colour resolver: canonical state name → visual. Receives the
|
|
55
|
+
* NORMALIZED state (e.g. `'needs-input'`, not the raw `'needs_input'`),
|
|
56
|
+
* so a caller can pass `(state) => SESSION_STATE_VISUALS[state]` directly.
|
|
57
|
+
* Return `undefined` for unknown states — the built-in palette (then
|
|
58
|
+
* idle) is used as the fallback, matching the IDE's `?? idle` behaviour.
|
|
59
|
+
*/
|
|
60
|
+
stateVisual?: (state: string) => ChapterStateVisual | undefined;
|
|
36
61
|
};
|
|
37
62
|
declare const ChapterTimeline: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
38
63
|
type ChapterTimeline = ReturnType<typeof ChapterTimeline>;
|
|
@@ -151,7 +151,11 @@
|
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
//
|
|
154
|
+
// Collapsible details (toast.details)
|
|
155
|
+
let detailsOpen = $state(false);
|
|
156
|
+
const detailsId = $derived(`toast-details-${toast.id}`);
|
|
157
|
+
|
|
158
|
+
// DaisyUI alert class per type
|
|
155
159
|
const alertClass: Record<string, string> = {
|
|
156
160
|
info: 'alert-info',
|
|
157
161
|
success: 'alert-success',
|
|
@@ -223,7 +227,40 @@
|
|
|
223
227
|
></span>
|
|
224
228
|
{/if}
|
|
225
229
|
|
|
226
|
-
<
|
|
230
|
+
<div class="flex-1 min-w-0">
|
|
231
|
+
<span class="text-sm">{toast.message}</span>
|
|
232
|
+
|
|
233
|
+
{#if toast.details}
|
|
234
|
+
<button
|
|
235
|
+
type="button"
|
|
236
|
+
class="toast-details-toggle btn btn-ghost btn-xs mt-0.5 h-auto min-h-0 gap-1 px-0 font-semibold opacity-70"
|
|
237
|
+
aria-expanded={detailsOpen}
|
|
238
|
+
aria-controls={detailsId}
|
|
239
|
+
onclick={() => (detailsOpen = !detailsOpen)}
|
|
240
|
+
>
|
|
241
|
+
<svg
|
|
242
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
243
|
+
class="size-3"
|
|
244
|
+
class:rotate-90={detailsOpen}
|
|
245
|
+
viewBox="0 0 24 24"
|
|
246
|
+
fill="none"
|
|
247
|
+
stroke="currentColor"
|
|
248
|
+
stroke-width="2.5"
|
|
249
|
+
stroke-linecap="round"
|
|
250
|
+
stroke-linejoin="round"
|
|
251
|
+
>
|
|
252
|
+
<path d="m9 18 6-6-6-6" />
|
|
253
|
+
</svg>
|
|
254
|
+
Details
|
|
255
|
+
</button>
|
|
256
|
+
{#if detailsOpen}
|
|
257
|
+
<pre
|
|
258
|
+
id={detailsId}
|
|
259
|
+
class="toast-details mt-1 max-h-40 overflow-auto rounded border border-current/20 bg-base-content/5 p-2 font-mono text-xs whitespace-pre-wrap break-words"
|
|
260
|
+
>{toast.details}</pre>
|
|
261
|
+
{/if}
|
|
262
|
+
{/if}
|
|
263
|
+
</div>
|
|
227
264
|
|
|
228
265
|
{#if toast.onUndo}
|
|
229
266
|
<button
|
|
@@ -274,7 +311,15 @@
|
|
|
274
311
|
to { transform: scaleX(0); }
|
|
275
312
|
}
|
|
276
313
|
|
|
314
|
+
.toast-details-toggle svg {
|
|
315
|
+
transition: transform var(--motion-fast) var(--motion-glide);
|
|
316
|
+
}
|
|
317
|
+
|
|
277
318
|
@media (prefers-reduced-motion: reduce) {
|
|
319
|
+
.toast-details-toggle svg {
|
|
320
|
+
transition: none;
|
|
321
|
+
}
|
|
322
|
+
|
|
278
323
|
.toast-progress {
|
|
279
324
|
animation: none;
|
|
280
325
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,9 +6,9 @@ export { collapse } from './actions/collapse';
|
|
|
6
6
|
export type { CollapseOptions } from './actions/collapse';
|
|
7
7
|
export { default as Collapse } from './components/Collapse.svelte';
|
|
8
8
|
export { default as LinkedColumns } from './components/linked-columns/LinkedColumns.svelte';
|
|
9
|
-
export type { ColumnLink } from './components/linked-columns/
|
|
9
|
+
export type { ColumnLink } from './components/linked-columns/types.js';
|
|
10
10
|
export { default as ChapterTimeline } from './components/replay/ChapterTimeline.svelte';
|
|
11
|
-
export type { ChapterBlock } from './components/replay/ChapterTimeline.svelte';
|
|
11
|
+
export type { ChapterBlock, ChapterStateVisual } from './components/replay/ChapterTimeline.svelte';
|
|
12
12
|
export { default as TranscriptPlayer } from './components/TranscriptPlayer.svelte';
|
|
13
13
|
export type { TranscriptSegment, TranscriptBookmark, TranscriptChapter, TranscriptSpeakerTalkTime, } from './components/TranscriptPlayer.svelte';
|
|
14
14
|
export { default as VideoPlayer } from './components/VideoPlayer.svelte';
|
|
@@ -83,7 +83,9 @@ export { default as ResizablePanel } from './components/ResizablePanel.svelte';
|
|
|
83
83
|
export { default as VoicePlayer } from './components/VoicePlayer.svelte';
|
|
84
84
|
export { default as SpeechForm } from './components/SpeechForm.svelte';
|
|
85
85
|
export { default as AudioRecorder } from './components/AudioRecorder.svelte';
|
|
86
|
-
export type { AudioRecordingResult } from './
|
|
86
|
+
export type { AudioRecordingResult } from './utils/audioRecorderCore';
|
|
87
|
+
export { createAudioRecorder } from './utils/audioRecorder';
|
|
88
|
+
export type { AudioRecorder, AudioRecorderCore, AudioRecorderError, AudioRecorderErrorKind, AudioRecorderFrame, AudioRecorderMode, AudioRecorderOptions, AudioRecorderPhase, AudioRecorderSnapshot } from './utils/audioRecorderCore';
|
|
87
89
|
export { default as ThemeSelector } from './components/ThemeSelector.svelte';
|
|
88
90
|
export { default as Sparkline } from './components/Sparkline.svelte';
|
|
89
91
|
export { default as BurndownChart } from './components/BurndownChart.svelte';
|
|
@@ -128,7 +130,7 @@ export type { Milestone, MilestoneStatus } from './types/milestone';
|
|
|
128
130
|
export type { LocationType, BookingStatus, OverrideType, Host, EventType, WeeklyAvailability, DateOverride, Booking, BookingAttendee, TimeSlot, BookingFormData, AvailabilityCounts } from './types/booking';
|
|
129
131
|
export { DAYS_OF_WEEK, DAYS_SHORT, LOCATION_LABELS, LOCATION_ICONS } from './types/booking';
|
|
130
132
|
export type { ImageVariantSpec, ImageProcessingSpec, VariantResult, VariantState, } from './types/smartImageEditor';
|
|
131
|
-
export { normalizeTimestamp, parseTimestamp, formatRelativeTime, formatFullDate, formatShortDate, formatLastActivity, formatDate, getTimeSinceMs, getTimeSinceMinutes, isWithinMinutes, formatDateTime, taskAge, pacingColor, type PacingLevel, type PacingResult, } from './utils/dateFormatters';
|
|
133
|
+
export { normalizeTimestamp, parseTimestamp, formatRelativeTime, formatFullDate, formatShortDate, formatLastActivity, formatDate, getTimeSinceMs, getTimeSinceMinutes, isWithinMinutes, formatDateTime, taskAge, pacingColor, formatPacingDuration, type PacingLevel, type PacingResult, type PacingOptions, } from './utils/dateFormatters';
|
|
132
134
|
export { statusColor, priorityColor, typeIcon, statusLabel, } from './utils/taskUtils';
|
|
133
135
|
export { stripPhoneNumber, formatPhoneNumber, isCompletePhoneNumber, isValidPhoneNumber, updatePhoneInput } from './utils/phoneFormat';
|
|
134
136
|
export { toE164, formatPhoneForDisplay, isValidPhone, listCountries, DEFAULT_COUNTRY, PRIORITY_COUNTRIES, type CountryOption, } from './utils/phone';
|
|
@@ -198,6 +200,7 @@ export type { GlideOrigin, GlideParams } from './transitions/glide';
|
|
|
198
200
|
export { themeWipe } from './utils/themeWipe';
|
|
199
201
|
export { viewTransition } from './utils/viewTransition';
|
|
200
202
|
export { play as playSound, registerSound, isSoundEnabled, setSoundEnabled } from './utils/sound';
|
|
203
|
+
export { copyText, readClipboardText } from './utils/clipboard';
|
|
201
204
|
export { splitText } from './utils/splitText';
|
|
202
205
|
export type { SplitBy, SplitTextOptions, SplitTextResult } from './utils/splitText';
|
|
203
206
|
export { default as ToastHost } from './components/toast/ToastHost.svelte';
|
package/dist/index.js
CHANGED
|
@@ -102,6 +102,8 @@ export { default as ResizablePanel } from './components/ResizablePanel.svelte';
|
|
|
102
102
|
export { default as VoicePlayer } from './components/VoicePlayer.svelte';
|
|
103
103
|
export { default as SpeechForm } from './components/SpeechForm.svelte';
|
|
104
104
|
export { default as AudioRecorder } from './components/AudioRecorder.svelte';
|
|
105
|
+
// Headless audio capture — the factory behind AudioRecorder (jatui-is2ow.8)
|
|
106
|
+
export { createAudioRecorder } from './utils/audioRecorder';
|
|
105
107
|
// Components — from Headcount
|
|
106
108
|
export { default as ThemeSelector } from './components/ThemeSelector.svelte';
|
|
107
109
|
export { default as Sparkline } from './components/Sparkline.svelte';
|
|
@@ -137,7 +139,7 @@ export { default as AvailabilityModal } from './components/AvailabilityModal.sve
|
|
|
137
139
|
export { default as BookingForm } from './components/BookingForm.svelte';
|
|
138
140
|
export { DAYS_OF_WEEK, DAYS_SHORT, LOCATION_LABELS, LOCATION_ICONS } from './types/booking';
|
|
139
141
|
// Utilities — date formatting
|
|
140
|
-
export { normalizeTimestamp, parseTimestamp, formatRelativeTime, formatFullDate, formatShortDate, formatLastActivity, formatDate, getTimeSinceMs, getTimeSinceMinutes, isWithinMinutes, formatDateTime, taskAge, pacingColor, } from './utils/dateFormatters';
|
|
142
|
+
export { normalizeTimestamp, parseTimestamp, formatRelativeTime, formatFullDate, formatShortDate, formatLastActivity, formatDate, getTimeSinceMs, getTimeSinceMinutes, isWithinMinutes, formatDateTime, taskAge, pacingColor, formatPacingDuration, } from './utils/dateFormatters';
|
|
141
143
|
// Utilities — task display helpers
|
|
142
144
|
export { statusColor, priorityColor, typeIcon, statusLabel, } from './utils/taskUtils';
|
|
143
145
|
// Utilities — phone formatting (legacy US-only)
|
|
@@ -224,6 +226,8 @@ export { themeWipe } from './utils/themeWipe';
|
|
|
224
226
|
export { viewTransition } from './utils/viewTransition';
|
|
225
227
|
// Sound kit (functional feedback, opt-in)
|
|
226
228
|
export { play as playSound, registerSound, isSoundEnabled, setSoundEnabled } from './utils/sound';
|
|
229
|
+
// Clipboard (secure-context aware: execCommand fallback for plain-HTTP origins)
|
|
230
|
+
export { copyText, readClipboardText } from './utils/clipboard';
|
|
227
231
|
// Text utilities
|
|
228
232
|
export { splitText } from './utils/splitText';
|
|
229
233
|
// Toast system
|
package/dist/stores/toast.d.ts
CHANGED
|
@@ -2,6 +2,12 @@ export type ToastType = 'info' | 'success' | 'warning' | 'error';
|
|
|
2
2
|
export type ToastOptions = {
|
|
3
3
|
type?: ToastType;
|
|
4
4
|
message: string;
|
|
5
|
+
/** Extended detail text (e.g. a stack trace or error chain) — rendered by
|
|
6
|
+
* ToastHost behind a collapsible "Details" toggle. Multiline-safe. */
|
|
7
|
+
details?: string;
|
|
8
|
+
/** Arbitrary structured context carried on the Toast for programmatic
|
|
9
|
+
* access (getToasts()); not rendered by ToastHost. */
|
|
10
|
+
meta?: Record<string, unknown>;
|
|
5
11
|
action?: {
|
|
6
12
|
label: string;
|
|
7
13
|
onClick: () => void;
|
|
@@ -13,6 +19,8 @@ export type Toast = {
|
|
|
13
19
|
id: number;
|
|
14
20
|
type: ToastType;
|
|
15
21
|
message: string;
|
|
22
|
+
details?: string;
|
|
23
|
+
meta?: Record<string, unknown>;
|
|
16
24
|
action?: {
|
|
17
25
|
label: string;
|
|
18
26
|
onClick: () => void;
|
package/dist/stores/toast.js
CHANGED