@signal9/era-ui 4.14.1 → 4.15.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/dist/apps/notes/notes.svelte +139 -71
- package/dist/apps/notes/notes.svelte.d.ts +31 -0
- package/dist/era-ui.css +1 -1
- package/dist/generated-docs/llms-full.txt +1 -0
- package/dist/generated-docs/manifest.json +1 -1
- package/dist/generated-docs/pane.md +1 -0
- package/dist/os/pane-manager.svelte.d.ts +12 -0
- package/dist/os/pane-manager.svelte.js +4 -0
- package/dist/os/pane.svelte +16 -9
- package/dist/styles/themes.css +38 -33
- package/dist/ui/pane/pane-handle.svelte +36 -1
- package/dist/ui/pane/pane-handle.svelte.d.ts +7 -0
- package/dist/ui/pane/pane.svelte +12 -2
- package/dist/ui/pane/pane.svelte.d.ts +2 -0
- package/package.json +1 -1
|
@@ -1028,6 +1028,7 @@ after the pane's own. Pass Compartments for reactive plugin sets. |
|
|
|
1028
1028
|
| `onDragEnd?` | `(data: DragEventData) => void` | — | — |
|
|
1029
1029
|
| `onClose?` | `() => void` | — | When set, a close button renders at the right of the handle bar. |
|
|
1030
1030
|
| `header?` | `Snippet` | — | Extra handle-bar content, rendered after the title. |
|
|
1031
|
+
| `center?` | `Snippet` | — | Content centred on the bar itself — Pane.Handle's three-track grid. |
|
|
1031
1032
|
| `children?` | `Snippet` | — | — |
|
|
1032
1033
|
|
|
1033
1034
|
<!-- end: pane -->
|
|
@@ -29,4 +29,5 @@ after the pane's own. Pass Compartments for reactive plugin sets. |
|
|
|
29
29
|
| `onDragEnd?` | `(data: DragEventData) => void` | — | — |
|
|
30
30
|
| `onClose?` | `() => void` | — | When set, a close button renders at the right of the handle bar. |
|
|
31
31
|
| `header?` | `Snippet` | — | Extra handle-bar content, rendered after the title. |
|
|
32
|
+
| `center?` | `Snippet` | — | Content centred on the bar itself — Pane.Handle's three-track grid. |
|
|
32
33
|
| `children?` | `Snippet` | — | — |
|
|
@@ -150,6 +150,14 @@ export interface AppDefinition {
|
|
|
150
150
|
* live AppPane too, so a host can swap it as the pane's content
|
|
151
151
|
* changes. */
|
|
152
152
|
actions?: Snippet;
|
|
153
|
+
/** Replaces the default icon+title cluster on the LEFT of the title bar.
|
|
154
|
+
* Assignable live, like `actions`. */
|
|
155
|
+
lead?: Snippet;
|
|
156
|
+
/** Content centred on the title bar itself (a document title, a breadcrumb) —
|
|
157
|
+
* rendered in Pane.Handle's three-track grid, so it stays pinned to the true
|
|
158
|
+
* centre of the bar however the sides grow. Assignable live. Interactive
|
|
159
|
+
* content in it must carry data-pane-control (the bar is the drag zone). */
|
|
160
|
+
center?: Snippet;
|
|
153
161
|
}
|
|
154
162
|
/** A live pane instance in the registry. */
|
|
155
163
|
export interface AppPane {
|
|
@@ -173,6 +181,10 @@ export interface AppPane {
|
|
|
173
181
|
minimizable: boolean;
|
|
174
182
|
bodyClass?: string;
|
|
175
183
|
actions?: Snippet;
|
|
184
|
+
/** See AppDefinition — both assignable on the live pane, which is how an
|
|
185
|
+
* app claims its own chrome: `pane.center = mySnippet` from the body. */
|
|
186
|
+
lead?: Snippet;
|
|
187
|
+
center?: Snippet;
|
|
176
188
|
/** App-specific state, carried verbatim through a snapshot. */
|
|
177
189
|
props?: JsonValue;
|
|
178
190
|
}
|
|
@@ -183,6 +183,8 @@ export class PaneManager {
|
|
|
183
183
|
minimizable: app.minimizable ?? true,
|
|
184
184
|
bodyClass: app.bodyClass,
|
|
185
185
|
actions: app.actions,
|
|
186
|
+
lead: app.lead,
|
|
187
|
+
center: app.center,
|
|
186
188
|
props: app.props
|
|
187
189
|
};
|
|
188
190
|
this.panes.push(win);
|
|
@@ -364,6 +366,8 @@ export class PaneManager {
|
|
|
364
366
|
minimizable: app.minimizable ?? true,
|
|
365
367
|
bodyClass: app.bodyClass,
|
|
366
368
|
actions: app.actions,
|
|
369
|
+
lead: app.lead,
|
|
370
|
+
center: app.center,
|
|
367
371
|
props: s.props ?? app.props
|
|
368
372
|
});
|
|
369
373
|
}
|
package/dist/os/pane.svelte
CHANGED
|
@@ -92,14 +92,21 @@
|
|
|
92
92
|
from the edge against 5px above and below it — read as crowded because it
|
|
93
93
|
was. --era-inset-md is (h-md − text)/2, so the label now starts the same
|
|
94
94
|
distance in from the edge as it sits from the top. -->
|
|
95
|
-
<Pane.Handle class="gap-(--era-gap) pl-(--era-inset-md)">
|
|
96
|
-
{#if pane.
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
<Pane.Handle class="gap-(--era-gap) pl-(--era-inset-md)" center={pane.center}>
|
|
96
|
+
{#if pane.lead}
|
|
97
|
+
<!-- The app replaced the whole icon+title cluster. Its content lives in
|
|
98
|
+
the drag zone like the default one; anything interactive in it
|
|
99
|
+
carries data-pane-control itself. -->
|
|
100
|
+
{@render pane.lead()}
|
|
101
|
+
{:else}
|
|
102
|
+
{#if pane.icon}
|
|
103
|
+
{@const Icon = pane.icon}
|
|
104
|
+
<Icon class="size-(--era-h-xs) shrink-0 text-muted" />
|
|
105
|
+
{/if}
|
|
106
|
+
<span class={cn('truncate text-body', focused ? 'text-bright' : 'text-muted')}
|
|
107
|
+
>{pane.title}</span
|
|
108
|
+
>
|
|
99
109
|
{/if}
|
|
100
|
-
<span class={cn('truncate text-body', focused ? 'text-bright' : 'text-muted')}
|
|
101
|
-
>{pane.title}</span
|
|
102
|
-
>
|
|
103
110
|
<!-- Close / minimize / maximize. Deliberately NOT data-pane-control (same as
|
|
104
111
|
the raw Pane.Close): a left press-and-HOLD drags the pane — neodrag only
|
|
105
112
|
drags the primary button and suppresses the trailing click after a real
|
|
@@ -109,7 +116,7 @@
|
|
|
109
116
|
rhythm as the rest of the handle. Like the close button they carry no
|
|
110
117
|
data-pane-control, so a press-and-hold anywhere on the bar still drags
|
|
111
118
|
the pane and only a clean click activates them. -->
|
|
112
|
-
|
|
119
|
+
{#snippet trail()}
|
|
113
120
|
{@render pane.actions?.()}
|
|
114
121
|
<!-- The macOS traffic lights, one button: red = close at rest, and the
|
|
115
122
|
held preview recolours to the action it will commit — yellow for
|
|
@@ -158,7 +165,7 @@
|
|
|
158
165
|
<X />
|
|
159
166
|
{/if}
|
|
160
167
|
</Button>
|
|
161
|
-
|
|
168
|
+
{/snippet}
|
|
162
169
|
</Pane.Handle>
|
|
163
170
|
|
|
164
171
|
<Pane.Content class={pane.bodyClass}>
|
package/dist/styles/themes.css
CHANGED
|
@@ -454,12 +454,16 @@
|
|
|
454
454
|
}
|
|
455
455
|
|
|
456
456
|
/* -------------------------------------------------- */
|
|
457
|
-
/* Signalnine — dark (Tomorrow,
|
|
457
|
+
/* Signalnine — dark (Tomorrow bones, amber ink) */
|
|
458
458
|
/* */
|
|
459
|
-
/* The classic imageboard dark theme. The
|
|
460
|
-
/*
|
|
461
|
-
/*
|
|
462
|
-
/*
|
|
459
|
+
/* The classic imageboard dark theme. The scale keeps */
|
|
460
|
+
/* Tomorrow Night's lightnesses — comment and */
|
|
461
|
+
/* foreground still land at steps 8 and 11 — but the */
|
|
462
|
+
/* BLUE IS GONE: the ramp's cast and the accent are */
|
|
463
|
+
/* both a cool amber (hue 84, the yellow side of */
|
|
464
|
+
/* amber), so chrome, links and emphasis share one */
|
|
465
|
+
/* temperature instead of a blue ramp under yellow */
|
|
466
|
+
/* accents. */
|
|
463
467
|
/* */
|
|
464
468
|
/* The DARK END is deliberately deeper than Tomorrow's. */
|
|
465
469
|
/* Its #1d1f21 page read light next to era's other dark */
|
|
@@ -474,11 +478,11 @@
|
|
|
474
478
|
/* the link blue had been placed IN the ramp, which */
|
|
475
479
|
/* forced the steps under it to swerve to reach it. */
|
|
476
480
|
/* Tomorrow does not work that way and neither does */
|
|
477
|
-
/* this now — the ramp is one
|
|
478
|
-
/*
|
|
479
|
-
/*
|
|
480
|
-
/*
|
|
481
|
-
/* carried by the text.
|
|
481
|
+
/* this now — the ramp is one gray from end to end */
|
|
482
|
+
/* (cast faintly amber, never placed IN the ramp), and */
|
|
483
|
+
/* the amber, red and green are ACCENT tokens sitting */
|
|
484
|
+
/* on top of it. That is what an imageboard actually */
|
|
485
|
+
/* looks like: gray chrome, colour carried by the text. */
|
|
482
486
|
/* -------------------------------------------------- */
|
|
483
487
|
:root[data-theme='signalnine'],
|
|
484
488
|
[data-theme='signalnine'].dark {
|
|
@@ -488,18 +492,18 @@
|
|
|
488
492
|
* own #1d1f21 — that read too light beside the other dark themes. Everything
|
|
489
493
|
* from step 2 up re-spaces evenly from the new floor to the comment anchor,
|
|
490
494
|
* so lowering the page did not leave a cliff between it and the panels. */
|
|
491
|
-
--color-1: oklch(0.168 0.
|
|
492
|
-
--color-2: oklch(0.225 0.
|
|
493
|
-
--color-3: oklch(0.29 0.
|
|
494
|
-
--color-4: oklch(0.355 0.
|
|
495
|
-
--color-5: oklch(0.435 0.
|
|
496
|
-
--color-6: oklch(0.515 0.
|
|
497
|
-
--color-7: oklch(0.596 0.
|
|
498
|
-
--color-8: oklch(0.677 0.006
|
|
499
|
-
--color-9: oklch(0.73 0.005
|
|
500
|
-
--color-10: oklch(0.78 0.005
|
|
501
|
-
--color-11: oklch(0.83 0.
|
|
502
|
-
--color-12: oklch(0.9 0.
|
|
495
|
+
--color-1: oklch(0.168 0.004 84); /* graphite floor, amber-cast */
|
|
496
|
+
--color-2: oklch(0.225 0.005 84);
|
|
497
|
+
--color-3: oklch(0.29 0.007 84);
|
|
498
|
+
--color-4: oklch(0.355 0.008 84);
|
|
499
|
+
--color-5: oklch(0.435 0.008 84);
|
|
500
|
+
--color-6: oklch(0.515 0.008 84);
|
|
501
|
+
--color-7: oklch(0.596 0.007 84);
|
|
502
|
+
--color-8: oklch(0.677 0.006 84); /* comment grey, warmed */
|
|
503
|
+
--color-9: oklch(0.73 0.005 84);
|
|
504
|
+
--color-10: oklch(0.78 0.005 84);
|
|
505
|
+
--color-11: oklch(0.83 0.005 84); /* foreground, warmed */
|
|
506
|
+
--color-12: oklch(0.9 0.005 84);
|
|
503
507
|
|
|
504
508
|
/* Border sits a step LOWER than the usual 5. Tomorrow's own rules are
|
|
505
509
|
* quiet — its border colour is the current-line grey — and at step 5 the
|
|
@@ -507,25 +511,26 @@
|
|
|
507
511
|
* page, inside the 1.7–3.2 the other dark themes hold. */
|
|
508
512
|
--color-border: var(--color-4);
|
|
509
513
|
--color-surface: var(--color-2);
|
|
510
|
-
--color-hover: oklch(0.255 0.
|
|
514
|
+
--color-hover: oklch(0.255 0.006 84);
|
|
511
515
|
--color-fg: var(--color-11);
|
|
512
516
|
--color-bright: color-mix(in oklch, var(--color-12) 88%, var(--color-primary));
|
|
513
517
|
/* Tomorrow's comment grey, which is what it uses for de-emphasised text. */
|
|
514
518
|
--color-muted: var(--color-8);
|
|
515
|
-
/* The link
|
|
516
|
-
--color-link:
|
|
517
|
-
|
|
518
|
-
/*
|
|
519
|
-
*
|
|
520
|
-
|
|
521
|
-
--color-primary
|
|
519
|
+
/* The link follows the accent — one ink for "this is interactive". */
|
|
520
|
+
--color-link: var(--color-primary);
|
|
521
|
+
|
|
522
|
+
/* A COOL amber: hue 84 — the yellow side of amber, not orange — with the
|
|
523
|
+
* pastel restraint of the Tomorrow accents it replaces, so it still takes
|
|
524
|
+
* DARK text (the page colour) rather than white. */
|
|
525
|
+
--color-primary: oklch(0.76 0.115 84); /* cool amber */
|
|
526
|
+
--color-primary-fg: oklch(0.168 0.004 84);
|
|
522
527
|
--color-primary-hover: color-mix(in oklch, var(--color-primary) 85%, oklch(0 0 none));
|
|
523
528
|
--color-destructive: oklch(0.6308 0.1298 21.4); /* #cc6666 red */
|
|
524
|
-
--color-destructive-fg: oklch(0.168 0.
|
|
529
|
+
--color-destructive-fg: oklch(0.168 0.004 84);
|
|
525
530
|
--color-success: oklch(0.7733 0.1095 113.4); /* #b5bd68 green */
|
|
526
|
-
--color-success-fg: oklch(0.168 0.
|
|
531
|
+
--color-success-fg: oklch(0.168 0.004 84);
|
|
527
532
|
--color-warning: oklch(0.8462 0.1115 82.9); /* #f0c674 yellow */
|
|
528
|
-
--color-warning-fg: oklch(0.168 0.
|
|
533
|
+
--color-warning-fg: oklch(0.168 0.004 84);
|
|
529
534
|
}
|
|
530
535
|
|
|
531
536
|
/* Signalnine — light (yahoo.co.jp, measured) */
|
|
@@ -7,11 +7,20 @@
|
|
|
7
7
|
let {
|
|
8
8
|
ref = $bindable(null),
|
|
9
9
|
children,
|
|
10
|
+
center,
|
|
11
|
+
trail,
|
|
10
12
|
class: className,
|
|
11
13
|
...restProps
|
|
12
14
|
}: HTMLAttributes<HTMLDivElement> & {
|
|
13
15
|
ref?: HTMLDivElement | null;
|
|
14
16
|
children?: Snippet;
|
|
17
|
+
/** Content centred on the BAR itself (a document title, a breadcrumb).
|
|
18
|
+
* Presence switches the handle to its three-track grid — see below. */
|
|
19
|
+
center?: Snippet;
|
|
20
|
+
/** Trailing cluster. With `center` it is the grid's third track; without,
|
|
21
|
+
* it renders as the familiar ml-auto cluster. The close/window controls
|
|
22
|
+
* belong here, always LAST — extra trailing content goes before them. */
|
|
23
|
+
trail?: Snippet;
|
|
15
24
|
} = $props();
|
|
16
25
|
</script>
|
|
17
26
|
|
|
@@ -49,9 +58,35 @@
|
|
|
49
58
|
// bar itself. It still follows the bottom radius, so the divider curves up
|
|
50
59
|
// at the ends exactly as before.
|
|
51
60
|
'shrink-0 rounded-t-none rounded-b-(--era-rd-md) [box-shadow:0_1px_0_var(--color-divider-faded)] select-none',
|
|
61
|
+
// THE CENTRE LAW — [minmax(0,1fr) minmax(0,auto) minmax(0,1fr)].
|
|
62
|
+
//
|
|
63
|
+
// A centred title must be centred on the BAR, not on whatever space the
|
|
64
|
+
// sides happened to leave (a flex-1 spacer centres on the leftovers, so the
|
|
65
|
+
// title drifts every time the lead or trail grows — the reference terminal
|
|
66
|
+
// app has exactly that drift). Equal fr tracks pin the middle to the true
|
|
67
|
+
// centre no matter how unequal the sides are; when a side outgrows its
|
|
68
|
+
// share it TRUNCATES (minmax 0) instead of shoving the title, and only when
|
|
69
|
+
// both sides are exhausted does the centre itself start to yield. Nothing
|
|
70
|
+
// ever overlaps and nothing ever jumps.
|
|
71
|
+
//
|
|
72
|
+
// Grid only when centred content exists: the flex flow is the right model
|
|
73
|
+
// for every other handle, and children/trail render in it untouched.
|
|
74
|
+
center && 'grid grid-cols-[minmax(0,1fr)_minmax(0,auto)_minmax(0,1fr)]',
|
|
52
75
|
className
|
|
53
76
|
)}
|
|
54
77
|
{...restProps}
|
|
55
78
|
>
|
|
56
|
-
{
|
|
79
|
+
{#if center}
|
|
80
|
+
<div class="flex min-w-0 items-center gap-(--era-gap)">{@render children?.()}</div>
|
|
81
|
+
<!-- Anything interactive dropped in here (an editable title, a picker)
|
|
82
|
+
carries data-pane-control itself: the bar is the drag zone, and only
|
|
83
|
+
the control can know that a press on it means caret, not drag. -->
|
|
84
|
+
<div class="flex min-w-0 items-center justify-center gap-(--era-gap)">{@render center()}</div>
|
|
85
|
+
<div class="flex min-w-0 items-center justify-end gap-(--era-gap)">{@render trail?.()}</div>
|
|
86
|
+
{:else}
|
|
87
|
+
{@render children?.()}
|
|
88
|
+
{#if trail}
|
|
89
|
+
<div class="ml-auto flex shrink-0 items-center gap-(--era-gap)">{@render trail()}</div>
|
|
90
|
+
{/if}
|
|
91
|
+
{/if}
|
|
57
92
|
</Bar>
|
|
@@ -3,6 +3,13 @@ import type { HTMLAttributes } from 'svelte/elements';
|
|
|
3
3
|
type $$ComponentProps = HTMLAttributes<HTMLDivElement> & {
|
|
4
4
|
ref?: HTMLDivElement | null;
|
|
5
5
|
children?: Snippet;
|
|
6
|
+
/** Content centred on the BAR itself (a document title, a breadcrumb).
|
|
7
|
+
* Presence switches the handle to its three-track grid — see below. */
|
|
8
|
+
center?: Snippet;
|
|
9
|
+
/** Trailing cluster. With `center` it is the grid's third track; without,
|
|
10
|
+
* it renders as the familiar ml-auto cluster. The close/window controls
|
|
11
|
+
* belong here, always LAST — extra trailing content goes before them. */
|
|
12
|
+
trail?: Snippet;
|
|
6
13
|
};
|
|
7
14
|
declare const PaneHandle: import("svelte").Component<$$ComponentProps, {}, "ref">;
|
|
8
15
|
type PaneHandle = ReturnType<typeof PaneHandle>;
|
package/dist/ui/pane/pane.svelte
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
onDragEnd,
|
|
24
24
|
onClose,
|
|
25
25
|
header,
|
|
26
|
+
center,
|
|
26
27
|
children,
|
|
27
28
|
class: className,
|
|
28
29
|
...restProps
|
|
@@ -51,6 +52,8 @@
|
|
|
51
52
|
onClose?: () => void;
|
|
52
53
|
/** Extra handle-bar content, rendered after the title. */
|
|
53
54
|
header?: Snippet;
|
|
55
|
+
/** Content centred on the bar itself — Pane.Handle's three-track grid. */
|
|
56
|
+
center?: Snippet;
|
|
54
57
|
children?: Snippet;
|
|
55
58
|
} = $props();
|
|
56
59
|
</script>
|
|
@@ -58,6 +61,11 @@
|
|
|
58
61
|
<!-- The ergonomic single-component pane: a titled handle + body, composed from
|
|
59
62
|
the same Pane.Root / Handle / Content / Close parts you can assemble by hand
|
|
60
63
|
for richer layouts (e.g. tabs in the handle — see Pane.Tabs). -->
|
|
64
|
+
<!-- Declared OUTSIDE <Root> — a snippet that is a direct child of a component
|
|
65
|
+
becomes one of its props, and Root has no `closeTrail`. -->
|
|
66
|
+
{#snippet closeTrail()}
|
|
67
|
+
<Close onclick={onClose} />
|
|
68
|
+
{/snippet}
|
|
61
69
|
<Root
|
|
62
70
|
bind:ref
|
|
63
71
|
bind:position
|
|
@@ -71,11 +79,13 @@
|
|
|
71
79
|
class={className}
|
|
72
80
|
{...restProps}
|
|
73
81
|
>
|
|
74
|
-
|
|
82
|
+
<!-- The close cluster rides the `trail` slot, so it lands in the grid's third
|
|
83
|
+
track when `center` is present and in the ml-auto cluster when it isn't —
|
|
84
|
+
one close button, correct in both geometries. -->
|
|
85
|
+
<Handle {center} trail={onClose ? closeTrail : undefined}>
|
|
75
86
|
{#if icon}{@const Icon = icon}<Icon class="size-(--era-h-xs) shrink-0 text-muted" />{/if}
|
|
76
87
|
{#if title}<span class="text-body text-bright">{title}</span>{/if}
|
|
77
88
|
{@render header?.()}
|
|
78
|
-
{#if onClose}<Close onclick={onClose} class="ml-auto" />{/if}
|
|
79
89
|
</Handle>
|
|
80
90
|
{#if children}
|
|
81
91
|
<Content>
|
|
@@ -33,6 +33,8 @@ type $$ComponentProps = HTMLAttributes<HTMLDivElement> & {
|
|
|
33
33
|
onClose?: () => void;
|
|
34
34
|
/** Extra handle-bar content, rendered after the title. */
|
|
35
35
|
header?: Snippet;
|
|
36
|
+
/** Content centred on the bar itself — Pane.Handle's three-track grid. */
|
|
37
|
+
center?: Snippet;
|
|
36
38
|
children?: Snippet;
|
|
37
39
|
};
|
|
38
40
|
declare const Pane: Component<$$ComponentProps, {}, "position" | "size" | "ref">;
|