@dorsk/tsumikit 0.2.7 → 0.2.8
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.
|
@@ -3,24 +3,64 @@
|
|
|
3
3
|
// background/border/radius/padding from theme tokens. `tap` adds the
|
|
4
4
|
// interactive hover/active affordance for tappable list items (e.g. session
|
|
5
5
|
// rows); `as` lets it be a button/anchor when the whole surface is clickable.
|
|
6
|
+
// `padding` dials the inner spacing (none/sm/md/lg) for denser cards.
|
|
7
|
+
//
|
|
8
|
+
// `stacked` fakes a pile of cards by drawing two layers peeking out below
|
|
9
|
+
// (and optionally to the right) via pseudo-elements. `stackTone` tints those
|
|
10
|
+
// back layers with a semantic hue (e.g. `info` for a blue stack); `neutral`
|
|
11
|
+
// keeps them on the plain border colour. `stackY`/`stackX` set the per-layer
|
|
12
|
+
// vertical / horizontal offset in px (vertical spacing stays even across the
|
|
13
|
+
// 3 borders); horizontal defaults to a tiny 2px peek.
|
|
6
14
|
import type { Snippet } from 'svelte';
|
|
7
15
|
|
|
16
|
+
type Tone = 'neutral' | 'ok' | 'warn' | 'danger' | 'info';
|
|
17
|
+
|
|
8
18
|
let {
|
|
9
19
|
tap = false,
|
|
10
20
|
as = 'div',
|
|
21
|
+
padding = 'md',
|
|
22
|
+
stacked = false,
|
|
23
|
+
stackTone = 'neutral',
|
|
24
|
+
stackY = 8,
|
|
25
|
+
stackX = 2,
|
|
11
26
|
class: klass = '',
|
|
27
|
+
style = '',
|
|
12
28
|
children,
|
|
13
29
|
...rest
|
|
14
30
|
}: {
|
|
15
31
|
tap?: boolean;
|
|
16
32
|
as?: 'div' | 'button' | 'a' | 'li' | 'section' | 'form';
|
|
33
|
+
padding?: 'none' | 'sm' | 'md' | 'lg';
|
|
34
|
+
stacked?: boolean;
|
|
35
|
+
stackTone?: Tone;
|
|
36
|
+
stackY?: number;
|
|
37
|
+
stackX?: number;
|
|
17
38
|
class?: string;
|
|
39
|
+
style?: string;
|
|
18
40
|
children?: Snippet;
|
|
19
41
|
[key: string]: unknown;
|
|
20
42
|
} = $props();
|
|
43
|
+
|
|
44
|
+
let stackStyle = $derived(
|
|
45
|
+
stacked ? `--stack-y:${stackY}px;--stack-x:${stackX}px;` : ''
|
|
46
|
+
);
|
|
21
47
|
</script>
|
|
22
48
|
|
|
23
|
-
<svelte:element
|
|
49
|
+
<svelte:element
|
|
50
|
+
this={as}
|
|
51
|
+
class="card {klass}"
|
|
52
|
+
class:pad-none={padding === 'none'}
|
|
53
|
+
class:pad-sm={padding === 'sm'}
|
|
54
|
+
class:pad-lg={padding === 'lg'}
|
|
55
|
+
class:card-tap={tap}
|
|
56
|
+
class:card-stacked={stacked}
|
|
57
|
+
class:stack-ok={stacked && stackTone === 'ok'}
|
|
58
|
+
class:stack-warn={stacked && stackTone === 'warn'}
|
|
59
|
+
class:stack-danger={stacked && stackTone === 'danger'}
|
|
60
|
+
class:stack-info={stacked && stackTone === 'info'}
|
|
61
|
+
style={`${stackStyle}${style}`}
|
|
62
|
+
{...rest}
|
|
63
|
+
>
|
|
24
64
|
{@render children?.()}
|
|
25
65
|
</svelte:element>
|
|
26
66
|
|
|
@@ -31,6 +71,15 @@
|
|
|
31
71
|
border-radius: var(--r-lg);
|
|
32
72
|
padding: var(--sp-4);
|
|
33
73
|
}
|
|
74
|
+
.pad-none {
|
|
75
|
+
padding: 0;
|
|
76
|
+
}
|
|
77
|
+
.pad-sm {
|
|
78
|
+
padding: var(--sp-2);
|
|
79
|
+
}
|
|
80
|
+
.pad-lg {
|
|
81
|
+
padding: var(--sp-6);
|
|
82
|
+
}
|
|
34
83
|
.card-tap {
|
|
35
84
|
cursor: pointer;
|
|
36
85
|
transition:
|
|
@@ -43,4 +92,59 @@
|
|
|
43
92
|
.card-tap:hover {
|
|
44
93
|
border-color: var(--border-strong);
|
|
45
94
|
}
|
|
95
|
+
|
|
96
|
+
/* Stacked effect — two back layers peeking out bottom-right. The front
|
|
97
|
+
surface keeps its own background so the layers only show at the edges. */
|
|
98
|
+
.card-stacked {
|
|
99
|
+
position: relative;
|
|
100
|
+
/* Defaults; overridden inline by the stackY/stackX props. */
|
|
101
|
+
--stack-y: 8px;
|
|
102
|
+
--stack-x: 2px;
|
|
103
|
+
--stack-bg: var(--bg-elevated-2);
|
|
104
|
+
--stack-border: var(--border);
|
|
105
|
+
/* Reserve room for the two peeking layers so they aren't clipped. */
|
|
106
|
+
margin-right: calc(var(--stack-x) * 2);
|
|
107
|
+
margin-bottom: calc(var(--stack-y) * 2);
|
|
108
|
+
}
|
|
109
|
+
.card-stacked::before,
|
|
110
|
+
.card-stacked::after {
|
|
111
|
+
content: '';
|
|
112
|
+
position: absolute;
|
|
113
|
+
inset: 0;
|
|
114
|
+
border-radius: inherit;
|
|
115
|
+
/* Opaque fill so each layer fully hides the one behind it — only the
|
|
116
|
+
bottom-right peek (and its single border line) stays visible. */
|
|
117
|
+
background: var(--stack-bg);
|
|
118
|
+
border: 1px solid var(--stack-border);
|
|
119
|
+
}
|
|
120
|
+
/* Nearest back layer — sits just under the front surface. */
|
|
121
|
+
.card-stacked::before {
|
|
122
|
+
z-index: -1;
|
|
123
|
+
transform: translate(var(--stack-x), var(--stack-y));
|
|
124
|
+
}
|
|
125
|
+
/* Furthest back layer — behind the nearest one. */
|
|
126
|
+
.card-stacked::after {
|
|
127
|
+
z-index: -2;
|
|
128
|
+
transform: translate(
|
|
129
|
+
calc(var(--stack-x) * 2),
|
|
130
|
+
calc(var(--stack-y) * 2)
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.stack-ok {
|
|
135
|
+
--stack-border: color-mix(in srgb, var(--ok) 45%, transparent);
|
|
136
|
+
--stack-bg: color-mix(in srgb, var(--ok) 12%, var(--bg-elevated));
|
|
137
|
+
}
|
|
138
|
+
.stack-warn {
|
|
139
|
+
--stack-border: color-mix(in srgb, var(--warn) 45%, transparent);
|
|
140
|
+
--stack-bg: color-mix(in srgb, var(--warn) 12%, var(--bg-elevated));
|
|
141
|
+
}
|
|
142
|
+
.stack-danger {
|
|
143
|
+
--stack-border: color-mix(in srgb, var(--danger) 45%, transparent);
|
|
144
|
+
--stack-bg: color-mix(in srgb, var(--danger) 12%, var(--bg-elevated));
|
|
145
|
+
}
|
|
146
|
+
.stack-info {
|
|
147
|
+
--stack-border: color-mix(in srgb, var(--info) 45%, transparent);
|
|
148
|
+
--stack-bg: color-mix(in srgb, var(--info) 12%, var(--bg-elevated));
|
|
149
|
+
}
|
|
46
150
|
</style>
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
|
+
type Tone = 'neutral' | 'ok' | 'warn' | 'danger' | 'info';
|
|
2
3
|
type $$ComponentProps = {
|
|
3
4
|
tap?: boolean;
|
|
4
5
|
as?: 'div' | 'button' | 'a' | 'li' | 'section' | 'form';
|
|
6
|
+
padding?: 'none' | 'sm' | 'md' | 'lg';
|
|
7
|
+
stacked?: boolean;
|
|
8
|
+
stackTone?: Tone;
|
|
9
|
+
stackY?: number;
|
|
10
|
+
stackX?: number;
|
|
5
11
|
class?: string;
|
|
12
|
+
style?: string;
|
|
6
13
|
children?: Snippet;
|
|
7
14
|
[key: string]: unknown;
|
|
8
15
|
};
|
|
@@ -293,14 +293,18 @@
|
|
|
293
293
|
touch-action: none;
|
|
294
294
|
z-index: 1;
|
|
295
295
|
}
|
|
296
|
+
/* Persistent grip hint (mirrors the Modal): a small pill centered on the
|
|
297
|
+
handle, brightening to the accent on hover / while dragging. */
|
|
296
298
|
.shell-sidebar-resize::after {
|
|
297
299
|
content: '';
|
|
298
300
|
position: absolute;
|
|
299
|
-
top:
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
width:
|
|
303
|
-
|
|
301
|
+
top: 50%;
|
|
302
|
+
right: 1px;
|
|
303
|
+
transform: translateY(-50%);
|
|
304
|
+
width: 3px;
|
|
305
|
+
height: 28px;
|
|
306
|
+
border-radius: 999px;
|
|
307
|
+
background: var(--border-strong);
|
|
304
308
|
transition: background 0.12s var(--ease);
|
|
305
309
|
}
|
|
306
310
|
.shell-sidebar-resize:hover::after,
|
package/package.json
CHANGED