@jelinek/ui 0.3.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 +492 -0
- package/dist/components/Alert.svelte +59 -0
- package/dist/components/Alert.svelte.d.ts +13 -0
- package/dist/components/Button.svelte +178 -0
- package/dist/components/Button.svelte.d.ts +19 -0
- package/dist/components/Card.svelte +68 -0
- package/dist/components/Card.svelte.d.ts +11 -0
- package/dist/components/ChapterNav.svelte +290 -0
- package/dist/components/ChapterNav.svelte.d.ts +18 -0
- package/dist/components/Checkbox.svelte +52 -0
- package/dist/components/Checkbox.svelte.d.ts +11 -0
- package/dist/components/CodeCopy.svelte +294 -0
- package/dist/components/CodeCopy.svelte.d.ts +51 -0
- package/dist/components/Container.svelte +34 -0
- package/dist/components/Container.svelte.d.ts +10 -0
- package/dist/components/ContentLogo.svelte +151 -0
- package/dist/components/ContentLogo.svelte.d.ts +37 -0
- package/dist/components/Demo.svelte +111 -0
- package/dist/components/Demo.svelte.d.ts +12 -0
- package/dist/components/Eyebrow.svelte +70 -0
- package/dist/components/Eyebrow.svelte.d.ts +12 -0
- package/dist/components/Glass.svelte +75 -0
- package/dist/components/Glass.svelte.d.ts +10 -0
- package/dist/components/Grid.svelte +87 -0
- package/dist/components/Grid.svelte.d.ts +11 -0
- package/dist/components/Label.svelte +37 -0
- package/dist/components/Label.svelte.d.ts +11 -0
- package/dist/components/PageHero.svelte +312 -0
- package/dist/components/PageHero.svelte.d.ts +55 -0
- package/dist/components/Pager.svelte +98 -0
- package/dist/components/Pager.svelte.d.ts +13 -0
- package/dist/components/Panel.svelte +89 -0
- package/dist/components/Panel.svelte.d.ts +12 -0
- package/dist/components/ProductCard.svelte +81 -0
- package/dist/components/ProductCard.svelte.d.ts +18 -0
- package/dist/components/Radio.svelte +54 -0
- package/dist/components/Radio.svelte.d.ts +11 -0
- package/dist/components/RadioGroup.svelte +42 -0
- package/dist/components/RadioGroup.svelte.d.ts +12 -0
- package/dist/components/Select.svelte +65 -0
- package/dist/components/Select.svelte.d.ts +20 -0
- package/dist/components/SiteFooter.svelte +121 -0
- package/dist/components/SiteFooter.svelte.d.ts +13 -0
- package/dist/components/SiteHeader.svelte +613 -0
- package/dist/components/SiteHeader.svelte.d.ts +80 -0
- package/dist/components/Slider.svelte +55 -0
- package/dist/components/Slider.svelte.d.ts +14 -0
- package/dist/components/Swatch.svelte +174 -0
- package/dist/components/Swatch.svelte.d.ts +58 -0
- package/dist/components/Tab.svelte +88 -0
- package/dist/components/Tab.svelte.d.ts +11 -0
- package/dist/components/Tabs.svelte +306 -0
- package/dist/components/Tabs.svelte.d.ts +20 -0
- package/dist/components/Tag.svelte +71 -0
- package/dist/components/Tag.svelte.d.ts +16 -0
- package/dist/components/TextField.svelte +100 -0
- package/dist/components/TextField.svelte.d.ts +18 -0
- package/dist/components/ThemeToggle.svelte +122 -0
- package/dist/components/ThemeToggle.svelte.d.ts +11 -0
- package/dist/components/Tile.svelte +115 -0
- package/dist/components/Tile.svelte.d.ts +14 -0
- package/dist/components/TileScroller.svelte +199 -0
- package/dist/components/TileScroller.svelte.d.ts +25 -0
- package/dist/components/container-context.d.ts +1 -0
- package/dist/components/container-context.js +6 -0
- package/dist/components/deer-mark-path.d.ts +16 -0
- package/dist/components/deer-mark-path.js +16 -0
- package/dist/components/nav.d.ts +25 -0
- package/dist/components/nav.js +17 -0
- package/dist/components/radio-context.d.ts +6 -0
- package/dist/components/radio-context.js +1 -0
- package/dist/components/tabs-context.d.ts +5 -0
- package/dist/components/tabs-context.js +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +37 -0
- package/dist/theme/base.css +439 -0
- package/dist/theme/extras.css +2 -0
- package/dist/theme/fonts.css +107 -0
- package/dist/theme/tokens.css +208 -0
- package/dist/utils/chapter-nav-dock.svelte.d.ts +23 -0
- package/dist/utils/chapter-nav-dock.svelte.js +65 -0
- package/dist/utils/cn.d.ts +2 -0
- package/dist/utils/cn.js +27 -0
- package/package.json +79 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/* GENERATED FILE — DO NOT EDIT.
|
|
2
|
+
Source: assets/css/jelinek.css
|
|
3
|
+
Regenerate: pnpm gen:tokens
|
|
4
|
+
Hand-written additions belong in extras.css. */
|
|
5
|
+
|
|
6
|
+
/* 1) Semantic layer — copied verbatim from the guide. These flip with the mode. */
|
|
7
|
+
:root {
|
|
8
|
+
--JELINEK-WHITE: hsl(0, 0%, 100%);
|
|
9
|
+
--JELINEK-BROWN: hsl(29, 44%, 62%);
|
|
10
|
+
--JELINEK-MAGENTA: hsl(324, 100%, 46%);
|
|
11
|
+
--JELINEK-BLACK: hsl(0, 0%, 0%);
|
|
12
|
+
--JELINEK-WHITE-HIGHLIGHT: hsl(0, 0%, 95%);
|
|
13
|
+
--JELINEK-BROWN-HIGHLIGHT: hsl(29, 44%, 80%);
|
|
14
|
+
--JELINEK-MAGENTA-HIGHLIGHT: hsl(324, 100%, 70%);
|
|
15
|
+
--JELINEK-BLACK-HIGHLIGHT: hsl(0, 0%, 38%);
|
|
16
|
+
--ON-JELINEK-BLACK: hsl(0, 0%, 95%);
|
|
17
|
+
--bg-white: hsl(0, 0%, 100%);
|
|
18
|
+
--bg-gray: hsl(0, 0%, 95%);
|
|
19
|
+
--bg-brown: hsl(29, 44%, 95%);
|
|
20
|
+
--bg-magenta: hsl(324, 100%, 95%);
|
|
21
|
+
--bg-black: hsl(0, 0%, 0%);
|
|
22
|
+
--border-subtle: hsl(0, 0%, 91%);
|
|
23
|
+
--text-black: hsl(0, 0%, 5%);
|
|
24
|
+
--text-muted1: hsl(0, 0%, 38%);
|
|
25
|
+
--text-muted2: hsl(0, 0%, 62%);
|
|
26
|
+
--text-white: hsl(0, 0%, 95%);
|
|
27
|
+
--sem-success: hsl(80, 47%, 90%);
|
|
28
|
+
--sem-error: hsl(5, 100%, 90%);
|
|
29
|
+
--sem-warning: hsl(45, 67%, 90%);
|
|
30
|
+
--sem-info: hsl(173, 19%, 90%);
|
|
31
|
+
--sem-success-strong: hsl(142, 76%, 38%);
|
|
32
|
+
--sem-error-strong: hsl(5, 100%, 38%);
|
|
33
|
+
--radius-button: 8px;
|
|
34
|
+
--radius-image: clamp(10px, 0.8vw, 15px);
|
|
35
|
+
--radius-card: clamp(10px, 1vw, 15px);
|
|
36
|
+
--radius-section: clamp(10px, 3vw, 15px);
|
|
37
|
+
--radius-pill: 9999px;
|
|
38
|
+
--shadow-interactive: 0px 4px 4px hsl(0, 0%, 0%, 0.188), 0px 12px 12px hsl(0, 0%, 0%, 0.082);
|
|
39
|
+
--shadow-resting: 0px 2px 2px hsl(0, 0%, 0%, 0.188), 0px 6px 6px hsl(0, 0%, 0%, 0.082);
|
|
40
|
+
--dur-fast: 0.12s;
|
|
41
|
+
--dur-base: 0.15s;
|
|
42
|
+
--dur-slow: 0.2s;
|
|
43
|
+
--ease: ease;
|
|
44
|
+
--box-primary: hsl(0, 0%, 50%);
|
|
45
|
+
--glass-fill: hsl(0, 0%, 100%, 0.5);
|
|
46
|
+
--glass-border: hsl(0, 0%, 100%, 0.75);
|
|
47
|
+
--glass-filter: blur(25px) saturate(140%);
|
|
48
|
+
--focus-color: var(--JELINEK-BROWN);
|
|
49
|
+
--focus-width: 2px;
|
|
50
|
+
--focus-offset: 2px;
|
|
51
|
+
--font-primary: "GT Walsheim Pro", Arial, Helvetica, sans-serif;
|
|
52
|
+
--font-secondary: "GT Walsheim Pro", Arial, Helvetica, sans-serif;
|
|
53
|
+
--font-serif: "Archer", Georgia, "Times New Roman", serif;
|
|
54
|
+
--page-max: 1180px;
|
|
55
|
+
--header-h: 70px;
|
|
56
|
+
--subnav-h: 58px;
|
|
57
|
+
--step0: 1rem;
|
|
58
|
+
--step1: clamp(1.125rem, 1.0682rem + 0.2841vw, 1.25rem);
|
|
59
|
+
--step2: clamp(1.3125rem, 1.2273rem + 0.4261vw, 1.5rem);
|
|
60
|
+
--step3: clamp(1.4375rem, 1.2955rem + 0.7102vw, 1.75rem);
|
|
61
|
+
--step4: clamp(1.625rem, 1.3977rem + 1.1364vw, 2.125rem);
|
|
62
|
+
--step5: clamp(1.8125rem, 1.5rem + 1.5625vw, 2.5rem);
|
|
63
|
+
--step6: clamp(2.0625rem, 1.6364rem + 2.1307vw, 3rem);
|
|
64
|
+
--step-down1: 0.9375rem;
|
|
65
|
+
--step-down2: 0.8125rem;
|
|
66
|
+
--space-1: 8px;
|
|
67
|
+
--space-2: 16px;
|
|
68
|
+
--space-3: 24px;
|
|
69
|
+
--space-4: 32px;
|
|
70
|
+
--space-5: 48px;
|
|
71
|
+
--space-6: 64px;
|
|
72
|
+
--space-section: clamp(24px, 4vw, 48px);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@media (min-width: 640px) {
|
|
76
|
+
:root {
|
|
77
|
+
--header-h: 94px;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
:root[data-theme="dark"],
|
|
82
|
+
.dark {
|
|
83
|
+
--bg-white: hsl(0, 0%, 5%);
|
|
84
|
+
--bg-gray: hsl(0, 0%, 15%);
|
|
85
|
+
--bg-brown: hsl(29, 44%, 10%);
|
|
86
|
+
--bg-magenta: hsl(324, 100%, 10%);
|
|
87
|
+
--bg-black: hsl(0, 0%, 0%);
|
|
88
|
+
--text-black: hsl(0, 0%, 92%);
|
|
89
|
+
--text-muted1: hsl(0, 0%, 62%);
|
|
90
|
+
--text-muted2: hsl(0, 0%, 38%);
|
|
91
|
+
--text-white: hsl(0, 0%, 95%);
|
|
92
|
+
--JELINEK-BROWN: hsl(29, 44%, 40%);
|
|
93
|
+
--JELINEK-MAGENTA: hsl(324, 100%, 30%);
|
|
94
|
+
--JELINEK-BROWN-HIGHLIGHT: hsl(29, 44%, 62%);
|
|
95
|
+
--JELINEK-MAGENTA-HIGHLIGHT: hsl(324, 100%, 46%);
|
|
96
|
+
--JELINEK-WHITE: hsl(0, 0%, 0%);
|
|
97
|
+
--JELINEK-BLACK: hsl(0, 0%, 95%);
|
|
98
|
+
--JELINEK-BLACK-HIGHLIGHT: hsl(0, 0%, 60%);
|
|
99
|
+
--JELINEK-WHITE-HIGHLIGHT: hsl(0, 0%, 5%);
|
|
100
|
+
--ON-JELINEK-BLACK: hsl(0, 0%, 5%);
|
|
101
|
+
--sem-success: hsl(80, 47%, 24%);
|
|
102
|
+
--sem-error: hsl(5, 100%, 24%);
|
|
103
|
+
--sem-warning: hsl(45, 67%, 38%);
|
|
104
|
+
--sem-info: hsl(173, 19%, 24%);
|
|
105
|
+
--sem-error-strong: hsl(5, 100%, 54%);
|
|
106
|
+
--glass-fill: hsl(0, 0%, 0%, 0.6);
|
|
107
|
+
--glass-border: hsl(0, 0%, 100%, 0.25);
|
|
108
|
+
--focus-color: var(--JELINEK-BROWN-HIGHLIGHT);
|
|
109
|
+
--border-subtle: hsl(0, 0%, 20%);
|
|
110
|
+
--border-highlight-white: hsl(0, 0%, 40%);
|
|
111
|
+
--shadow-interactive: 0px 4px 4px hsl(0, 0%, 0%, 0.063), 0px 12px 12px hsl(0, 0%, 0%, 0.188);
|
|
112
|
+
--shadow-resting: 0px 2px 2px hsl(0, 0%, 0%, 0.063), 0px 6px 6px hsl(0, 0%, 0%, 0.188);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* 2) Tailwind mapping. `inline` makes utilities emit var(--GUIDE-NAME), so they
|
|
116
|
+
follow the semantic layer above instead of freezing the light values. */
|
|
117
|
+
@theme inline {
|
|
118
|
+
/* Pinned to a literal px, not Tailwind v4's default 0.25rem, which is
|
|
119
|
+
rem-relative and therefore tracks whatever the root font-size is.
|
|
120
|
+
TYPE scales with the viewport; SPACING does not. Keeping them on one
|
|
121
|
+
lever is the defect this pin exists to prevent, and it was a real one:
|
|
122
|
+
until Task 25 the guide's root was clamp(13px, 8px + 1.4vw, 16px)
|
|
123
|
+
(jelinek.css:251), so a rem-based --spacing silently shrank every p,
|
|
124
|
+
px, m, gap and w utility by up to 19% below ~571px viewport width —
|
|
125
|
+
exactly the range mobile-first design cares most about. Task 25 flattened
|
|
126
|
+
the root to 16px and moved the fluidity onto the individual --stepN
|
|
127
|
+
clamp()s instead, which happens to make 0.25rem and 4px agree today.
|
|
128
|
+
The pin stays anyway: that agreement is a property of the current root
|
|
129
|
+
value, not of the system, and the guide's spacing is authored in fixed
|
|
130
|
+
px regardless (searching jelinek.css for "rem" outside font-size,
|
|
131
|
+
line-height and --step contexts turns up exactly one hit, line 483's
|
|
132
|
+
fixed-px padding deliberately paired with one fluid-rem margin on the
|
|
133
|
+
same line — not evidence that spacing in general is meant to be rem).
|
|
134
|
+
Pinning here keeps every component's bare Tailwind spacing utility
|
|
135
|
+
(documented against literal guide px values throughout
|
|
136
|
+
src/lib/components) correct at every viewport width, and matches the
|
|
137
|
+
equivalence the PASSTHROUGH comment in token-map.js assumes for space-1
|
|
138
|
+
through space-6. */
|
|
139
|
+
--spacing: 4px;
|
|
140
|
+
--color-jelinek-black: var(--JELINEK-BLACK);
|
|
141
|
+
--color-jelinek-black-highlight: var(--JELINEK-BLACK-HIGHLIGHT);
|
|
142
|
+
--color-jelinek-brown: var(--JELINEK-BROWN);
|
|
143
|
+
--color-jelinek-brown-highlight: var(--JELINEK-BROWN-HIGHLIGHT);
|
|
144
|
+
--color-jelinek-magenta: var(--JELINEK-MAGENTA);
|
|
145
|
+
--color-jelinek-magenta-highlight: var(--JELINEK-MAGENTA-HIGHLIGHT);
|
|
146
|
+
--color-jelinek-white: var(--JELINEK-WHITE);
|
|
147
|
+
--color-jelinek-white-highlight: var(--JELINEK-WHITE-HIGHLIGHT);
|
|
148
|
+
--color-on-jelinek-black: var(--ON-JELINEK-BLACK);
|
|
149
|
+
--color-surface-black: var(--bg-black);
|
|
150
|
+
--color-surface-brown: var(--bg-brown);
|
|
151
|
+
--color-surface-gray: var(--bg-gray);
|
|
152
|
+
--color-surface-magenta: var(--bg-magenta);
|
|
153
|
+
--color-surface: var(--bg-white);
|
|
154
|
+
--color-border-highlight: var(--border-highlight-white);
|
|
155
|
+
--color-border-subtle: var(--border-subtle);
|
|
156
|
+
--font-primary: var(--font-primary);
|
|
157
|
+
--font-secondary: var(--font-secondary);
|
|
158
|
+
--font-serif: var(--font-serif);
|
|
159
|
+
--container-page: var(--page-max);
|
|
160
|
+
--radius-button: var(--radius-button);
|
|
161
|
+
--radius-card: var(--radius-card);
|
|
162
|
+
--radius-image: var(--radius-image);
|
|
163
|
+
--radius-pill: var(--radius-pill);
|
|
164
|
+
--radius-section: var(--radius-section);
|
|
165
|
+
--color-sem-error: var(--sem-error);
|
|
166
|
+
--color-sem-error-strong: var(--sem-error-strong);
|
|
167
|
+
--color-sem-info: var(--sem-info);
|
|
168
|
+
--color-sem-success: var(--sem-success);
|
|
169
|
+
--color-sem-success-strong: var(--sem-success-strong);
|
|
170
|
+
--color-sem-warning: var(--sem-warning);
|
|
171
|
+
--shadow-interactive: var(--shadow-interactive);
|
|
172
|
+
--shadow-resting: var(--shadow-resting);
|
|
173
|
+
--text-step-down1: var(--step-down1);
|
|
174
|
+
--text-step-down2: var(--step-down2);
|
|
175
|
+
--text-step0: var(--step0);
|
|
176
|
+
--text-step1: var(--step1);
|
|
177
|
+
--text-step2: var(--step2);
|
|
178
|
+
--text-step3: var(--step3);
|
|
179
|
+
--text-step4: var(--step4);
|
|
180
|
+
--text-step5: var(--step5);
|
|
181
|
+
--text-step6: var(--step6);
|
|
182
|
+
--color-fg: var(--text-black);
|
|
183
|
+
--color-fg-muted1: var(--text-muted1);
|
|
184
|
+
--color-fg-muted2: var(--text-muted2);
|
|
185
|
+
--color-fg-inverse: var(--text-white);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/* 3) Variants. Both selectors are supported so pim/admin's .dark keeps working. */
|
|
189
|
+
@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *, .dark, .dark *));
|
|
190
|
+
|
|
191
|
+
/* 4) Division re-theme — Zdravý spánek swaps the accent brown → magenta.
|
|
192
|
+
[data-theme="mattress"] is an alias kept for the e-shop's existing markup.
|
|
193
|
+
:root-scoped duplicates come FIRST so that, when both data-theme="dark"
|
|
194
|
+
and data-division="mattress" land on the same <html>, this block ties
|
|
195
|
+
the dark block above on specificity (0,2,0 vs 0,2,0) and wins on source
|
|
196
|
+
order instead of losing outright to the dark block's plain (0,1,0)
|
|
197
|
+
compare (0,2,0 beats 0,1,0 regardless of order — that was the bug: the
|
|
198
|
+
bare-selector-only version of this block could never outrank dark on
|
|
199
|
+
:root). The bare selectors stay too, so data-division/data-theme set on
|
|
200
|
+
a non-root element still re-themes just that subtree. */
|
|
201
|
+
:root[data-division="mattress"],
|
|
202
|
+
:root[data-theme="mattress"],
|
|
203
|
+
[data-division="mattress"],
|
|
204
|
+
[data-theme="mattress"] {
|
|
205
|
+
--JELINEK-BROWN: var(--JELINEK-MAGENTA);
|
|
206
|
+
--JELINEK-BROWN-HIGHLIGHT: var(--JELINEK-MAGENTA-HIGHLIGHT);
|
|
207
|
+
--bg-brown: var(--bg-magenta);
|
|
208
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tracks the guide's chapter-nav "docked" scroll state: `true` while the
|
|
3
|
+
* page has not yet scrolled past 50px (the header should read as fused to
|
|
4
|
+
* the chapter nav below it), `false` once it has (the header should detach
|
|
5
|
+
* into its own rounded, shadowed bar). Mirrors
|
|
6
|
+
* `assets/js/jelinek.js:354`'s `window.scrollY > 50` threshold exactly.
|
|
7
|
+
*
|
|
8
|
+
* Must be called during component initialisation, like any other rune.
|
|
9
|
+
* Registers a passive `scroll` listener only while `enabled()` is true, and
|
|
10
|
+
* always removes it via the `$effect` cleanup function on unmount or when
|
|
11
|
+
* `enabled()` turns false — never `onDestroy` alongside runes. The handler
|
|
12
|
+
* only reads `window.scrollY`, never DOM geometry, so it does no layout
|
|
13
|
+
* work on every scroll event.
|
|
14
|
+
*
|
|
15
|
+
* @param enabled - reactive getter for whether a chapter nav is actually
|
|
16
|
+
* present. Mirrors the guide's own `initSubnavDock()`
|
|
17
|
+
* (assets/js/jelinek.js:350), which returns early and never attaches a
|
|
18
|
+
* listener at all when `document.querySelector('.chapter-nav')` finds
|
|
19
|
+
* nothing on the page.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createChapterNavDock(enabled: () => boolean): {
|
|
22
|
+
readonly docked: boolean;
|
|
23
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Task 15 — the guide's joined header/chapter-nav seam. jelinek.css:432-448
|
|
2
|
+
// expresses "is the header still fused to the chapter nav below it" with
|
|
3
|
+
// `:root:has(.chapter-nav):not(.is-subnav-scrolled)`, a selector that
|
|
4
|
+
// reaches OUTSIDE a component's own subtree to find a sibling and reacts to
|
|
5
|
+
// a class assets/js/jelinek.js:354 toggles on <html> from a page-level
|
|
6
|
+
// scroll listener (`window.scrollY > 50`). Neither half of that is
|
|
7
|
+
// expressible from inside a single Svelte component (no :root selectors,
|
|
8
|
+
// no :has() reaching outside this component's own subtree), which is why
|
|
9
|
+
// Task 9 deferred the seam entirely. This module is the reactive-state half
|
|
10
|
+
// of the replacement: a consumer signals "a ChapterNav sits directly below
|
|
11
|
+
// me" locally (as a prop), and this tracks the same 50px scroll threshold
|
|
12
|
+
// as a plain boolean instead of a document-level class.
|
|
13
|
+
//
|
|
14
|
+
// Runes used outside a .svelte file require the .svelte.ts extension for
|
|
15
|
+
// the compiler to process them — hence this file living here rather than
|
|
16
|
+
// inline in SiteHeader.svelte. Factored out (rather than kept as a private
|
|
17
|
+
// effect inside SiteHeader) for two reasons: it is exported from the
|
|
18
|
+
// package as its own primitive for a consumer assembling fully custom
|
|
19
|
+
// chrome who wants the exact same scroll-linked boolean without
|
|
20
|
+
// hand-writing a listener, and it keeps SiteHeader's own script focused on
|
|
21
|
+
// class computation rather than scroll bookkeeping.
|
|
22
|
+
//
|
|
23
|
+
// `enabled` is a getter, not a plain boolean, because this module lives
|
|
24
|
+
// outside the component that owns the prop — passing the current value by
|
|
25
|
+
// itself would freeze it at call time; reading it through a closure inside
|
|
26
|
+
// the effect keeps it live against prop changes, the same way `$derived`
|
|
27
|
+
// depends on whatever reactive values its expression reads.
|
|
28
|
+
/**
|
|
29
|
+
* Tracks the guide's chapter-nav "docked" scroll state: `true` while the
|
|
30
|
+
* page has not yet scrolled past 50px (the header should read as fused to
|
|
31
|
+
* the chapter nav below it), `false` once it has (the header should detach
|
|
32
|
+
* into its own rounded, shadowed bar). Mirrors
|
|
33
|
+
* `assets/js/jelinek.js:354`'s `window.scrollY > 50` threshold exactly.
|
|
34
|
+
*
|
|
35
|
+
* Must be called during component initialisation, like any other rune.
|
|
36
|
+
* Registers a passive `scroll` listener only while `enabled()` is true, and
|
|
37
|
+
* always removes it via the `$effect` cleanup function on unmount or when
|
|
38
|
+
* `enabled()` turns false — never `onDestroy` alongside runes. The handler
|
|
39
|
+
* only reads `window.scrollY`, never DOM geometry, so it does no layout
|
|
40
|
+
* work on every scroll event.
|
|
41
|
+
*
|
|
42
|
+
* @param enabled - reactive getter for whether a chapter nav is actually
|
|
43
|
+
* present. Mirrors the guide's own `initSubnavDock()`
|
|
44
|
+
* (assets/js/jelinek.js:350), which returns early and never attaches a
|
|
45
|
+
* listener at all when `document.querySelector('.chapter-nav')` finds
|
|
46
|
+
* nothing on the page.
|
|
47
|
+
*/
|
|
48
|
+
export function createChapterNavDock(enabled) {
|
|
49
|
+
let scrolled = $state(false);
|
|
50
|
+
$effect(() => {
|
|
51
|
+
if (!enabled())
|
|
52
|
+
return;
|
|
53
|
+
function onScroll() {
|
|
54
|
+
scrolled = window.scrollY > 50;
|
|
55
|
+
}
|
|
56
|
+
onScroll();
|
|
57
|
+
window.addEventListener('scroll', onScroll, { passive: true });
|
|
58
|
+
return () => window.removeEventListener('scroll', onScroll);
|
|
59
|
+
});
|
|
60
|
+
return {
|
|
61
|
+
get docked() {
|
|
62
|
+
return enabled() && !scrolled;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
package/dist/utils/cn.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { clsx } from 'clsx';
|
|
2
|
+
import { extendTailwindMerge } from 'tailwind-merge';
|
|
3
|
+
// The kit adds custom radius, shadow and font-size scale names. tailwind-merge
|
|
4
|
+
// cannot know them, so without this a consumer's `rounded-none` would sit
|
|
5
|
+
// alongside the kit's `rounded-button` instead of replacing it.
|
|
6
|
+
const twMerge = extendTailwindMerge({
|
|
7
|
+
extend: {
|
|
8
|
+
theme: {
|
|
9
|
+
radius: ['button', 'image', 'card', 'section', 'pill'],
|
|
10
|
+
shadow: ['interactive', 'resting'],
|
|
11
|
+
text: [
|
|
12
|
+
'step0',
|
|
13
|
+
'step1',
|
|
14
|
+
'step2',
|
|
15
|
+
'step3',
|
|
16
|
+
'step4',
|
|
17
|
+
'step5',
|
|
18
|
+
'step6',
|
|
19
|
+
'step-down1',
|
|
20
|
+
'step-down2'
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
export function cn(...inputs) {
|
|
26
|
+
return twMerge(clsx(inputs));
|
|
27
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jelinek/ui",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "JELÍNEK Svelte 5 component kit, generated from the brand guide",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=22"
|
|
9
|
+
},
|
|
10
|
+
"packageManager": "pnpm@10.32.1",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/JELINEK-nabytek-a-matrace/brand-guide.git",
|
|
14
|
+
"directory": "svelte"
|
|
15
|
+
},
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"registry": "https://registry.npmjs.org",
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"sideEffects": [
|
|
24
|
+
"**/*.css"
|
|
25
|
+
],
|
|
26
|
+
"svelte": "./dist/index.js",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"svelte": "./dist/index.js",
|
|
32
|
+
"default": "./dist/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./theme.css": "./dist/theme/tokens.css",
|
|
35
|
+
"./extras.css": "./dist/theme/extras.css",
|
|
36
|
+
"./base.css": "./dist/theme/base.css",
|
|
37
|
+
"./fonts.css": "./dist/theme/fonts.css"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"dev": "vite dev",
|
|
41
|
+
"build": "svelte-kit sync && svelte-package && find dist -name '*.test.*' -delete",
|
|
42
|
+
"build:showcase": "vite build",
|
|
43
|
+
"preview": "vite preview",
|
|
44
|
+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
45
|
+
"test": "vitest run",
|
|
46
|
+
"gen:tokens": "node scripts/gen-tokens.js",
|
|
47
|
+
"check:tokens": "node scripts/gen-tokens.js --check",
|
|
48
|
+
"check:css-lock": "node scripts/check-css-lock.js",
|
|
49
|
+
"test:e2e": "pnpm run build:showcase && playwright test",
|
|
50
|
+
"prepublishOnly": "pnpm check:tokens && pnpm check:css-lock && pnpm check && pnpm test && pnpm build"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"svelte": "^5.56.3",
|
|
54
|
+
"tailwindcss": "^4.3.1"
|
|
55
|
+
},
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"clsx": "^2.1.1",
|
|
58
|
+
"tailwind-merge": "^3.3.1"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@playwright/test": "^1.62.0",
|
|
62
|
+
"@sveltejs/adapter-static": "^3.0.10",
|
|
63
|
+
"@sveltejs/kit": "^2.65.1",
|
|
64
|
+
"@sveltejs/package": "^2.5.4",
|
|
65
|
+
"@sveltejs/vite-plugin-svelte": "^7.1.2",
|
|
66
|
+
"@tailwindcss/vite": "^4.3.1",
|
|
67
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
68
|
+
"@testing-library/svelte": "^5.2.6",
|
|
69
|
+
"@types/node": "^22.10.2",
|
|
70
|
+
"jsdom": "^26.0.0",
|
|
71
|
+
"postcss": "^8.5.3",
|
|
72
|
+
"svelte": "^5.56.3",
|
|
73
|
+
"svelte-check": "^4.6.0",
|
|
74
|
+
"tailwindcss": "^4.3.1",
|
|
75
|
+
"typescript": "^5.7.2",
|
|
76
|
+
"vite": "^6.0.7",
|
|
77
|
+
"vitest": "^3.2.7"
|
|
78
|
+
}
|
|
79
|
+
}
|