@dorsk/tsumikit 0.71.0 → 0.73.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/README.md +54 -5
- package/dist/autoresize.js +13 -0
- package/dist/clipboard.js +12 -0
- package/dist/components/atoms/Artwork.svelte +4 -2
- package/dist/components/atoms/Avatar.svelte +4 -3
- package/dist/components/atoms/Badge.svelte +13 -0
- package/dist/components/atoms/Button.svelte +25 -9
- package/dist/components/atoms/Card.svelte +2 -0
- package/dist/components/atoms/Dot.svelte +1 -1
- package/dist/components/atoms/Icon.svelte +7 -0
- package/dist/components/atoms/Icon.svelte.d.ts +7 -0
- package/dist/components/atoms/Kbd.svelte +28 -16
- package/dist/components/atoms/Link.svelte +6 -4
- package/dist/components/atoms/Scrim.svelte +18 -1
- package/dist/components/atoms/Slider.svelte +11 -1
- package/dist/components/atoms/Swatch.svelte +12 -0
- package/dist/components/atoms/TimeDisplay.svelte +98 -0
- package/dist/components/atoms/TimeDisplay.svelte.d.ts +24 -0
- package/dist/components/layouts/AppShell.svelte +72 -40
- package/dist/components/layouts/Container.svelte +25 -3
- package/dist/components/layouts/MasterDetail.svelte +59 -33
- package/dist/components/layouts/MasterDetail.svelte.d.ts +1 -1
- package/dist/components/layouts/NavItem.svelte +8 -4
- package/dist/components/layouts/NavSection.svelte +8 -2
- package/dist/components/layouts/ResizablePanel.svelte +19 -4
- package/dist/components/layouts/TabBar.svelte +217 -0
- package/dist/components/layouts/TabBar.svelte.d.ts +27 -0
- package/dist/components/layouts/Toolbar.svelte +5 -0
- package/dist/components/layouts/toolbar-roving.d.ts +16 -0
- package/dist/components/layouts/toolbar-roving.js +47 -1
- package/dist/components/molecules/Accordion.svelte +2 -1
- package/dist/components/molecules/AttachmentList.svelte +1 -0
- package/dist/components/molecules/Breadcrumb.svelte +7 -6
- package/dist/components/molecules/Breadcrumb.svelte.d.ts +2 -1
- package/dist/components/molecules/CapBar.svelte +3 -1
- package/dist/components/molecules/Composer.svelte +27 -5
- package/dist/components/molecules/Drawer.svelte +10 -1
- package/dist/components/molecules/Dropzone.svelte +2 -1
- package/dist/components/molecules/FilterInput.svelte +17 -1
- package/dist/components/molecules/FilterInput.svelte.d.ts +2 -0
- package/dist/components/molecules/Metric.svelte +28 -3
- package/dist/components/molecules/Modal.svelte +20 -4
- package/dist/components/molecules/Popover.svelte +7 -3
- package/dist/components/molecules/PullToRefresh.svelte +205 -0
- package/dist/components/molecules/PullToRefresh.svelte.d.ts +18 -0
- package/dist/components/molecules/SectionHeader.svelte +29 -14
- package/dist/components/molecules/SeekSlider.svelte +370 -0
- package/dist/components/molecules/SeekSlider.svelte.d.ts +37 -0
- package/dist/components/molecules/SegmentedControl.svelte +10 -6
- package/dist/components/molecules/SelectButton.svelte +33 -22
- package/dist/components/molecules/SwipeRow.svelte +349 -0
- package/dist/components/molecules/SwipeRow.svelte.d.ts +37 -0
- package/dist/components/molecules/Tabs.svelte +11 -5
- package/dist/components/molecules/Timestamp.svelte +1 -1
- package/dist/components/molecules/Toaster.svelte +70 -13
- package/dist/components/molecules/Tooltip.svelte +19 -10
- package/dist/components/molecules/VolumeSlider.svelte +367 -0
- package/dist/components/molecules/VolumeSlider.svelte.d.ts +30 -0
- package/dist/components/molecules/combobox-keyboard.js +2 -1
- package/dist/components/organisms/ConversationFeed.svelte +22 -8
- package/dist/components/organisms/ConversationFeed.svelte.d.ts +2 -0
- package/dist/components/organisms/DataTable.svelte +22 -5
- package/dist/components/organisms/DataTable.svelte.d.ts +4 -2
- package/dist/components/organisms/FilterSearchBar.svelte +4 -0
- package/dist/components/organisms/FilterSearchBar.svelte.d.ts +2 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/markdown.js +15 -7
- package/dist/media-time.d.ts +6 -0
- package/dist/media-time.js +25 -0
- package/dist/query/edit.js +1 -16
- package/dist/query/parser.js +68 -28
- package/dist/query/query.js +9 -5
- package/dist/query/quotes.d.ts +24 -0
- package/dist/query/quotes.js +78 -0
- package/dist/query/single.js +1 -3
- package/dist/query/suggest.js +25 -32
- package/dist/stores/fontscale.svelte.js +3 -2
- package/dist/stores/storage.d.ts +2 -0
- package/dist/stores/storage.js +16 -0
- package/dist/stores/theme.svelte.js +4 -7
- package/dist/styles/reset.css +30 -0
- package/dist/styles/syntax.css +0 -29
- package/package.json +1 -1
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
// `resizeKey`).
|
|
10
10
|
import type { Snippet } from 'svelte';
|
|
11
11
|
import { browser } from '../../env';
|
|
12
|
+
import { readStorage, writeStorage } from '../../stores/storage';
|
|
12
13
|
import Icon, { type IconName } from '../atoms/Icon.svelte';
|
|
13
14
|
import Spinner from '../atoms/Spinner.svelte';
|
|
14
15
|
import IconButton from './IconButton.svelte';
|
|
@@ -76,7 +77,7 @@
|
|
|
76
77
|
|
|
77
78
|
function loadWidth(): number | null {
|
|
78
79
|
if (!browser || !resizeKey) return null;
|
|
79
|
-
const n = Number(
|
|
80
|
+
const n = Number(readStorage(resizeKey));
|
|
80
81
|
return Number.isFinite(n) && n >= MIN_W ? Math.min(n, MAX_W) : null;
|
|
81
82
|
}
|
|
82
83
|
let width = $state<number | null>(loadWidth());
|
|
@@ -103,9 +104,17 @@
|
|
|
103
104
|
}
|
|
104
105
|
|
|
105
106
|
// Click outside: <dialog fills the viewport; clicks on its padding-free self
|
|
106
|
-
// (not the inner .sheet) are backdrop clicks.
|
|
107
|
+
// (not the inner .sheet) are backdrop clicks. A drag that starts in the sheet
|
|
108
|
+
// and ends on the backdrop also fires click on the dialog, so the press must
|
|
109
|
+
// have landed on the backdrop too.
|
|
110
|
+
let pressOnBackdrop = false;
|
|
111
|
+
function onDialogPointerDown(e: PointerEvent) {
|
|
112
|
+
pressOnBackdrop = e.target === dialogEl;
|
|
113
|
+
}
|
|
107
114
|
function onDialogClick(e: MouseEvent) {
|
|
108
|
-
|
|
115
|
+
const outside = pressOnBackdrop && e.target === dialogEl;
|
|
116
|
+
pressOnBackdrop = false;
|
|
117
|
+
if (outside) requestClose();
|
|
109
118
|
}
|
|
110
119
|
|
|
111
120
|
// --- resize ---
|
|
@@ -146,7 +155,7 @@
|
|
|
146
155
|
} catch {
|
|
147
156
|
/* already released */
|
|
148
157
|
}
|
|
149
|
-
if (browser && resizeKey && width != null)
|
|
158
|
+
if (browser && resizeKey && width != null) writeStorage(resizeKey, String(width));
|
|
150
159
|
}
|
|
151
160
|
</script>
|
|
152
161
|
|
|
@@ -166,6 +175,7 @@
|
|
|
166
175
|
onclose={() => {
|
|
167
176
|
if (controlled) open = false;
|
|
168
177
|
}}
|
|
178
|
+
onpointerdown={onDialogPointerDown}
|
|
169
179
|
onclick={onDialogClick}
|
|
170
180
|
>
|
|
171
181
|
<div
|
|
@@ -283,6 +293,12 @@
|
|
|
283
293
|
opacity: 0.4;
|
|
284
294
|
}
|
|
285
295
|
}
|
|
296
|
+
@media (prefers-reduced-motion: reduce) {
|
|
297
|
+
.modal::backdrop,
|
|
298
|
+
.sheet {
|
|
299
|
+
animation: none;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
286
302
|
.modal.resizing .sheet {
|
|
287
303
|
user-select: none;
|
|
288
304
|
/* Make per-frame width changes cheap to paint: hint the animated property,
|
|
@@ -186,7 +186,11 @@
|
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
const hover = createHoverIntent({ open: show, close });
|
|
189
|
-
$effect(() => () =>
|
|
189
|
+
$effect(() => () => {
|
|
190
|
+
hover.cancel();
|
|
191
|
+
removeEventListener('scroll', reposition, true);
|
|
192
|
+
removeEventListener('resize', reposition);
|
|
193
|
+
});
|
|
190
194
|
|
|
191
195
|
function onPointerEnter(e: PointerEvent) {
|
|
192
196
|
if (disabled || !opensOnHover(openOn, e.pointerType)) return;
|
|
@@ -194,8 +198,8 @@
|
|
|
194
198
|
else hover.enter(hoverDelay);
|
|
195
199
|
}
|
|
196
200
|
|
|
197
|
-
function onPointerLeave() {
|
|
198
|
-
if (openOn
|
|
201
|
+
function onPointerLeave(e: PointerEvent) {
|
|
202
|
+
if (!opensOnHover(openOn, e.pointerType)) return;
|
|
199
203
|
hover.leave(HOVER_CLOSE_GRACE);
|
|
200
204
|
}
|
|
201
205
|
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// Pull-down-to-refresh scroll container. The pull only starts from
|
|
3
|
+
// `scrollTop === 0` with a touch or pen pointer, the distance is damped so
|
|
4
|
+
// the indicator asymptotically approaches twice the threshold, and a release
|
|
5
|
+
// past the threshold awaits `onrefresh` while a Spinner holds the slot.
|
|
6
|
+
// Mouse and keyboard users refresh through the page's own control.
|
|
7
|
+
import type { Snippet } from 'svelte';
|
|
8
|
+
import Icon from '../atoms/Icon.svelte';
|
|
9
|
+
import Spinner from '../atoms/Spinner.svelte';
|
|
10
|
+
|
|
11
|
+
let {
|
|
12
|
+
children,
|
|
13
|
+
onrefresh,
|
|
14
|
+
threshold = 72,
|
|
15
|
+
label = 'Refreshing…',
|
|
16
|
+
pullLabel = 'Pull to refresh',
|
|
17
|
+
releaseLabel = 'Release to refresh',
|
|
18
|
+
disabled = false,
|
|
19
|
+
class: klass = '',
|
|
20
|
+
...rest
|
|
21
|
+
}: {
|
|
22
|
+
children?: Snippet;
|
|
23
|
+
/** Awaited after a release past the threshold; the spinner shows until it settles. */
|
|
24
|
+
onrefresh?: () => Promise<void> | void;
|
|
25
|
+
/** Damped pull distance (px) that arms the refresh. */
|
|
26
|
+
threshold?: number;
|
|
27
|
+
/** Announced through the live region while `onrefresh` is pending. */
|
|
28
|
+
label?: string;
|
|
29
|
+
pullLabel?: string;
|
|
30
|
+
releaseLabel?: string;
|
|
31
|
+
disabled?: boolean;
|
|
32
|
+
class?: string;
|
|
33
|
+
[key: string]: unknown;
|
|
34
|
+
} = $props();
|
|
35
|
+
|
|
36
|
+
const SLOP = 6;
|
|
37
|
+
|
|
38
|
+
let scroller: HTMLElement | undefined;
|
|
39
|
+
let offset = $state(0);
|
|
40
|
+
let pending = $state(false);
|
|
41
|
+
let pulling = $state(false);
|
|
42
|
+
let press: { id: number; y: number } | null = null;
|
|
43
|
+
|
|
44
|
+
const ready = $derived(pulling && offset >= threshold);
|
|
45
|
+
const phase = $derived(pending ? 'refreshing' : ready ? 'ready' : pulling ? 'pulling' : 'idle');
|
|
46
|
+
const progress = $derived(Math.min(1, offset / Math.max(1, threshold)));
|
|
47
|
+
|
|
48
|
+
function damp(dy: number) {
|
|
49
|
+
const max = threshold * 2;
|
|
50
|
+
return max * (1 - Math.exp(-dy / max));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function onpointerdown(e: PointerEvent) {
|
|
54
|
+
if (disabled || pending || press) return;
|
|
55
|
+
if (e.pointerType !== 'touch' && e.pointerType !== 'pen') return;
|
|
56
|
+
if (!scroller || scroller.scrollTop > 0) return;
|
|
57
|
+
press = { id: e.pointerId, y: e.clientY };
|
|
58
|
+
addEventListener('pointermove', onpointermove);
|
|
59
|
+
addEventListener('pointerup', onpointerup);
|
|
60
|
+
addEventListener('pointercancel', onpointercancel);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function onpointermove(e: PointerEvent) {
|
|
64
|
+
if (!press || e.pointerId !== press.id) return;
|
|
65
|
+
const dy = e.clientY - press.y;
|
|
66
|
+
if (!pulling) {
|
|
67
|
+
if (dy < -SLOP || (scroller && scroller.scrollTop > 0)) return release();
|
|
68
|
+
if (dy < SLOP) return;
|
|
69
|
+
pulling = true;
|
|
70
|
+
}
|
|
71
|
+
offset = dy > 0 ? damp(dy) : 0;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function onpointerup(e: PointerEvent) {
|
|
75
|
+
if (!press || e.pointerId !== press.id) return;
|
|
76
|
+
const fire = ready;
|
|
77
|
+
release();
|
|
78
|
+
if (fire) void refresh();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function onpointercancel(e: PointerEvent) {
|
|
82
|
+
if (!press || e.pointerId !== press.id) return;
|
|
83
|
+
release();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function release() {
|
|
87
|
+
press = null;
|
|
88
|
+
pulling = false;
|
|
89
|
+
if (!pending) offset = 0;
|
|
90
|
+
removeEventListener('pointermove', onpointermove);
|
|
91
|
+
removeEventListener('pointerup', onpointerup);
|
|
92
|
+
removeEventListener('pointercancel', onpointercancel);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function refresh() {
|
|
96
|
+
if (pending) return;
|
|
97
|
+
pending = true;
|
|
98
|
+
offset = threshold;
|
|
99
|
+
try {
|
|
100
|
+
await onrefresh?.();
|
|
101
|
+
} finally {
|
|
102
|
+
pending = false;
|
|
103
|
+
offset = 0;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function scrollRoot(el: HTMLElement) {
|
|
108
|
+
scroller = el;
|
|
109
|
+
const block = (e: TouchEvent) => {
|
|
110
|
+
if (pulling) e.preventDefault();
|
|
111
|
+
};
|
|
112
|
+
el.addEventListener('touchmove', block, { passive: false });
|
|
113
|
+
return () => {
|
|
114
|
+
el.removeEventListener('touchmove', block);
|
|
115
|
+
release();
|
|
116
|
+
scroller = undefined;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
</script>
|
|
120
|
+
|
|
121
|
+
<div
|
|
122
|
+
data-tsu="PullToRefresh"
|
|
123
|
+
data-state={phase}
|
|
124
|
+
class="ptr {klass}"
|
|
125
|
+
class:pulling
|
|
126
|
+
class:pending
|
|
127
|
+
style:--ptr-offset="{offset}px"
|
|
128
|
+
style:--ptr-progress={progress}
|
|
129
|
+
aria-busy={pending || undefined}
|
|
130
|
+
{onpointerdown}
|
|
131
|
+
{@attach scrollRoot}
|
|
132
|
+
{...rest}
|
|
133
|
+
>
|
|
134
|
+
<div class="ptr-indicator" aria-hidden="true">
|
|
135
|
+
{#if pending}
|
|
136
|
+
<Spinner label={undefined} />
|
|
137
|
+
{:else}
|
|
138
|
+
<Icon name="arrow-down" class="ptr-arrow" />
|
|
139
|
+
{/if}
|
|
140
|
+
</div>
|
|
141
|
+
<div class="ptr-status sr-only" role="status" aria-live="polite">
|
|
142
|
+
{#if pending}{label}{:else if ready}{releaseLabel}{:else if pulling}{pullLabel}{/if}
|
|
143
|
+
</div>
|
|
144
|
+
<div class="ptr-content">
|
|
145
|
+
{@render children?.()}
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
<style>
|
|
150
|
+
.ptr {
|
|
151
|
+
position: relative;
|
|
152
|
+
overflow-y: auto;
|
|
153
|
+
overscroll-behavior-y: contain;
|
|
154
|
+
-webkit-overflow-scrolling: touch;
|
|
155
|
+
touch-action: pan-y;
|
|
156
|
+
}
|
|
157
|
+
.ptr-content {
|
|
158
|
+
translate: 0 var(--ptr-offset, 0px);
|
|
159
|
+
transition: translate 200ms var(--ease);
|
|
160
|
+
}
|
|
161
|
+
.pulling .ptr-content {
|
|
162
|
+
transition: none;
|
|
163
|
+
}
|
|
164
|
+
.ptr-indicator {
|
|
165
|
+
position: absolute;
|
|
166
|
+
inset: 0 0 auto;
|
|
167
|
+
display: flex;
|
|
168
|
+
align-items: center;
|
|
169
|
+
justify-content: center;
|
|
170
|
+
height: var(--ptr-offset, 0px);
|
|
171
|
+
overflow: hidden;
|
|
172
|
+
color: var(--text-muted);
|
|
173
|
+
opacity: var(--ptr-progress, 0);
|
|
174
|
+
transition: height 200ms var(--ease);
|
|
175
|
+
pointer-events: none;
|
|
176
|
+
}
|
|
177
|
+
.pulling .ptr-indicator {
|
|
178
|
+
transition: none;
|
|
179
|
+
}
|
|
180
|
+
.ptr-indicator :global(.ptr-arrow) {
|
|
181
|
+
rotate: calc(180deg * var(--ptr-progress, 0));
|
|
182
|
+
transition: rotate 150ms var(--ease);
|
|
183
|
+
}
|
|
184
|
+
.pending .ptr-indicator {
|
|
185
|
+
color: var(--accent);
|
|
186
|
+
}
|
|
187
|
+
.sr-only {
|
|
188
|
+
position: absolute;
|
|
189
|
+
width: 1px;
|
|
190
|
+
height: 1px;
|
|
191
|
+
overflow: hidden;
|
|
192
|
+
clip: rect(0 0 0 0);
|
|
193
|
+
white-space: nowrap;
|
|
194
|
+
}
|
|
195
|
+
@media (prefers-reduced-motion: reduce) {
|
|
196
|
+
.ptr-content,
|
|
197
|
+
.ptr-indicator,
|
|
198
|
+
.ptr-indicator :global(.ptr-arrow) {
|
|
199
|
+
transition: none;
|
|
200
|
+
}
|
|
201
|
+
.ptr-indicator :global(.ptr-arrow) {
|
|
202
|
+
rotate: none;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
</style>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
children?: Snippet;
|
|
4
|
+
/** Awaited after a release past the threshold; the spinner shows until it settles. */
|
|
5
|
+
onrefresh?: () => Promise<void> | void;
|
|
6
|
+
/** Damped pull distance (px) that arms the refresh. */
|
|
7
|
+
threshold?: number;
|
|
8
|
+
/** Announced through the live region while `onrefresh` is pending. */
|
|
9
|
+
label?: string;
|
|
10
|
+
pullLabel?: string;
|
|
11
|
+
releaseLabel?: string;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
class?: string;
|
|
14
|
+
[key: string]: unknown;
|
|
15
|
+
};
|
|
16
|
+
declare const PullToRefresh: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
17
|
+
type PullToRefresh = ReturnType<typeof PullToRefresh>;
|
|
18
|
+
export default PullToRefresh;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// swatch and right-aligned actions on one wrapping row. `divider` underlines
|
|
5
5
|
// it, `sticky` pins it under the app header and publishes its height as
|
|
6
6
|
// `--section-header-h` on the parent so sibling sticky content can offset
|
|
7
|
-
// itself. `collapsible`
|
|
7
|
+
// itself. `collapsible` puts a disclosure button inside the heading that
|
|
8
8
|
// toggles the `children` block rendered beneath. `variant="group"` is the
|
|
9
9
|
// non-wrapping list-group row: `lead` · title · count · flexible rule · actions.
|
|
10
10
|
import type { Snippet } from 'svelte';
|
|
@@ -90,16 +90,7 @@
|
|
|
90
90
|
>
|
|
91
91
|
<div class="sh-row">
|
|
92
92
|
{#if collapsible}
|
|
93
|
-
<
|
|
94
|
-
type="button"
|
|
95
|
-
class="sh-toggle"
|
|
96
|
-
aria-expanded={open}
|
|
97
|
-
aria-controls={panelId}
|
|
98
|
-
onclick={() => (open = !open)}
|
|
99
|
-
>
|
|
100
|
-
<Icon name="chevron-right" class="sh-chevron" />
|
|
101
|
-
{@render head()}
|
|
102
|
-
</button>
|
|
93
|
+
<span class="sh-head">{@render head()}</span>
|
|
103
94
|
{:else}
|
|
104
95
|
{@render head()}
|
|
105
96
|
{/if}
|
|
@@ -125,10 +116,28 @@
|
|
|
125
116
|
{#if hue !== undefined}
|
|
126
117
|
<span class="sh-swatch" style:--sh-hue={hue} aria-hidden="true"></span>
|
|
127
118
|
{/if}
|
|
128
|
-
{#if
|
|
129
|
-
<
|
|
119
|
+
{#if collapsible}
|
|
120
|
+
<Heading {level} {size} class="sh-title">
|
|
121
|
+
<button
|
|
122
|
+
type="button"
|
|
123
|
+
class="sh-toggle"
|
|
124
|
+
aria-expanded={open}
|
|
125
|
+
aria-controls={open ? panelId : undefined}
|
|
126
|
+
onclick={() => (open = !open)}
|
|
127
|
+
>
|
|
128
|
+
<Icon name="chevron-right" class="sh-chevron" />
|
|
129
|
+
{#if icon}
|
|
130
|
+
<span class="sh-icon" aria-hidden="true"><Icon name={icon} /></span>
|
|
131
|
+
{/if}
|
|
132
|
+
{text}
|
|
133
|
+
</button>
|
|
134
|
+
</Heading>
|
|
135
|
+
{:else}
|
|
136
|
+
{#if icon}
|
|
137
|
+
<span class="sh-icon" aria-hidden="true"><Icon name={icon} /></span>
|
|
138
|
+
{/if}
|
|
139
|
+
<Heading {level} {size} class="sh-title">{text}</Heading>
|
|
130
140
|
{/if}
|
|
131
|
-
<Heading {level} {size} class="sh-title">{text}</Heading>
|
|
132
141
|
{#if count !== undefined}
|
|
133
142
|
<Text tone="faint" weight="normal" numeric class="sh-count">{count}</Text>
|
|
134
143
|
{/if}
|
|
@@ -233,6 +242,12 @@
|
|
|
233
242
|
gap: var(--sp-2);
|
|
234
243
|
margin-inline-start: auto;
|
|
235
244
|
}
|
|
245
|
+
.sh-head {
|
|
246
|
+
display: inline-flex;
|
|
247
|
+
align-items: center;
|
|
248
|
+
gap: var(--sp-2);
|
|
249
|
+
min-width: 0;
|
|
250
|
+
}
|
|
236
251
|
.sh-toggle {
|
|
237
252
|
display: inline-flex;
|
|
238
253
|
align-items: center;
|