@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,111 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
|
+
import { cn } from '../utils/cn.js';
|
|
5
|
+
|
|
6
|
+
type Variant = 'light' | 'brown' | 'magenta' | 'black';
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
variant?: Variant;
|
|
10
|
+
class?: string;
|
|
11
|
+
children: Snippet;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let {
|
|
15
|
+
variant,
|
|
16
|
+
class: className,
|
|
17
|
+
children,
|
|
18
|
+
...rest
|
|
19
|
+
}: Props & HTMLAttributes<HTMLDivElement> = $props();
|
|
20
|
+
|
|
21
|
+
// CSS FIDELITY — the brief gave Demo a `dark` boolean that only applied
|
|
22
|
+
// `bg-surface-black text-fg-inverse`. jelinek.css defines no `.demo--dark`
|
|
23
|
+
// at all; Demo's variants are `--light`/`--brown`/`--magenta` (shared with
|
|
24
|
+
// .panel/.card, jelinek.css:486/491-492) plus its OWN `--black`
|
|
25
|
+
// (jelinek.css:792-796) — a different and much bigger rule than a plain
|
|
26
|
+
// dark background. Replaced the boolean with a `variant` prop, same shape
|
|
27
|
+
// as Panel, but with `black` instead of `dark` because that's the class
|
|
28
|
+
// that actually exists for .demo, and — critically — it is not a drop-in
|
|
29
|
+
// synonym for Panel's `dark` (see below).
|
|
30
|
+
//
|
|
31
|
+
// jelinek.css:474-482/483 (shared box system + 24px padding, same as
|
|
32
|
+
// Panel — see Panel.svelte's comment for the border-gradient-collapse and
|
|
33
|
+
// dropped-margin reasoning, identical here) and :322-325/327-331 (shared
|
|
34
|
+
// font-secondary/font-light + nested strong/b→font-medium) all apply
|
|
35
|
+
// identically to .demo.
|
|
36
|
+
//
|
|
37
|
+
// jelinek.css:486 `.demo--light { --box-fill: var(--bg-gray) }` →
|
|
38
|
+
// bg-surface-gray.
|
|
39
|
+
// jelinek.css:491 `.demo--brown { --box-fill: var(--bg-brown) }` →
|
|
40
|
+
// bg-surface-brown. jelinek.css:492 `.demo--magenta` → bg-surface-magenta.
|
|
41
|
+
//
|
|
42
|
+
// TASK 34 — CORRECTION. --box-primary used to be dropped here on the
|
|
43
|
+
// "inert for this component" reasoning Panel.svelte carried. That reasoning
|
|
44
|
+
// was false: jelinek.css:251-257 names `.demo` among the five surfaces that
|
|
45
|
+
// take `box-shadow: inset 0 2px 1px -1px var(--box-primary)` in dark mode.
|
|
46
|
+
// See Panel.svelte for the full note. The highlight is in BASE below and the
|
|
47
|
+
// two divisional overrides are back on the variants.
|
|
48
|
+
//
|
|
49
|
+
// `.demo--black` (jelinek.css:1129-1133) does NOT override --box-primary, so
|
|
50
|
+
// a black demo keeps the :root 50% grey highlight — matching the guide.
|
|
51
|
+
//
|
|
52
|
+
// jelinek.css:790-796 `.demo--black` — the serious one. It is NOT just a
|
|
53
|
+
// dark background: it locally re-maps the neutral brand tokens so
|
|
54
|
+
// black-accented content nested inside (e.g. a `<Button color="black">`)
|
|
55
|
+
// stays readable on a black surface, exactly the same technique the
|
|
56
|
+
// site's own dark mode and the mattress-division re-theme
|
|
57
|
+
// (tokens.css:161-166, `[data-division="mattress"]`) use — overriding the
|
|
58
|
+
// *source* custom property (`--JELINEK-BLACK`, `--text-muted1`, …), not
|
|
59
|
+
// the derived Tailwind token (`--color-jelinek-black`). Because
|
|
60
|
+
// tokens.css's `@theme inline` makes every `--color-*` an unresolved
|
|
61
|
+
// `var(--GUIDE-NAME)` reference (not a baked-in value), overriding the
|
|
62
|
+
// guide-name variable locally on this element cascades correctly to any
|
|
63
|
+
// descendant using the mapped utility (`bg-jelinek-black`,
|
|
64
|
+
// `text-fg-muted1`, …), the same mechanism already used by
|
|
65
|
+
// SiteHeader.svelte's `[--logo-mark:46px]` and by the mattress division
|
|
66
|
+
// override:
|
|
67
|
+
// --box-fill: var(--bg-black); color: var(--text-white);
|
|
68
|
+
// → bg-surface-black text-fg-inverse
|
|
69
|
+
// --JELINEK-BLACK: hsl(0,0%,50%); --JELINEK-BLACK-HIGHLIGHT: hsl(0,0%,60%);
|
|
70
|
+
// --ON-JELINEK-BLACK: hsl(0,0%,5%); --text-muted1: hsl(0,0%,62%);
|
|
71
|
+
// --text-muted2: hsl(0,0%,42%);
|
|
72
|
+
// → arbitrary-property utilities re-declaring those exact five
|
|
73
|
+
// custom properties locally. These are hardcoded literals in
|
|
74
|
+
// the guide itself (not references to other tokens), so arbitrary
|
|
75
|
+
// values are the correct, faithful reproduction, not a shortcut.
|
|
76
|
+
//
|
|
77
|
+
// Task 33 — the five moved from hex to hsl() in the designer's b45c536.
|
|
78
|
+
// Three are exact (#808080 = 50%, #999999 = 60%, #0D0D0D = 5%); TWO ARE NOT,
|
|
79
|
+
// and it is worth writing down that we checked rather than trusting the
|
|
80
|
+
// commit message's "bit-identical": --text-muted1 went #9F9F9F (159) →
|
|
81
|
+
// hsl(0,0%,62%) (158) and --text-muted2 went #6A6A6A (106) →
|
|
82
|
+
// hsl(0,0%,42%) (107). One step of 255 on a muted grey, in a demo panel —
|
|
83
|
+
// non-visual, and taken as-is rather than "corrected" back, because the
|
|
84
|
+
// round number is what the designer is now authoring against.
|
|
85
|
+
//
|
|
86
|
+
// Deliberately NOT named `dark` to match Panel: Panel's `--dark` is the
|
|
87
|
+
// simple case (fill + text colour only, no token remap) and Demo has no
|
|
88
|
+
// equivalent of it — offering a `dark` option here would invite exactly
|
|
89
|
+
// the bug this task flagged (black-on-near-black content going
|
|
90
|
+
// invisible), so the option that exists is spelled `black` and does the
|
|
91
|
+
// full remap, full stop.
|
|
92
|
+
const BASE =
|
|
93
|
+
'rounded-card border border-border-subtle bg-surface p-6 font-secondary font-light ' +
|
|
94
|
+
'[&_strong]:font-medium [&_b]:font-medium ' +
|
|
95
|
+
'dark:shadow-[inset_0_2px_1px_-1px_var(--box-primary)]';
|
|
96
|
+
|
|
97
|
+
const VARIANT: Record<Variant, string> = {
|
|
98
|
+
light: 'bg-surface-gray',
|
|
99
|
+
brown: 'bg-surface-brown [--box-primary:var(--JELINEK-BROWN)]',
|
|
100
|
+
magenta: 'bg-surface-magenta [--box-primary:var(--JELINEK-MAGENTA)]',
|
|
101
|
+
black:
|
|
102
|
+
'bg-surface-black text-fg-inverse ' +
|
|
103
|
+
'[--JELINEK-BLACK:hsl(0,0%,50%)] [--JELINEK-BLACK-HIGHLIGHT:hsl(0,0%,60%)] ' +
|
|
104
|
+
'[--ON-JELINEK-BLACK:hsl(0,0%,5%)] ' +
|
|
105
|
+
'[--text-muted1:hsl(0,0%,62%)] [--text-muted2:hsl(0,0%,42%)]'
|
|
106
|
+
};
|
|
107
|
+
</script>
|
|
108
|
+
|
|
109
|
+
<div {...rest} class={cn(BASE, variant && VARIANT[variant], className)}>
|
|
110
|
+
{@render children()}
|
|
111
|
+
</div>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
type Variant = 'light' | 'brown' | 'magenta' | 'black';
|
|
4
|
+
interface Props {
|
|
5
|
+
variant?: Variant;
|
|
6
|
+
class?: string;
|
|
7
|
+
children: Snippet;
|
|
8
|
+
}
|
|
9
|
+
type $$ComponentProps = Props & HTMLAttributes<HTMLDivElement>;
|
|
10
|
+
declare const Demo: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
11
|
+
type Demo = ReturnType<typeof Demo>;
|
|
12
|
+
export default Demo;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
|
+
import { cn } from '../utils/cn.js';
|
|
5
|
+
|
|
6
|
+
type Variant = 'brown' | 'magenta' | 'black';
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
variant?: Variant;
|
|
10
|
+
class?: string;
|
|
11
|
+
children: Snippet;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let {
|
|
15
|
+
variant = 'brown',
|
|
16
|
+
class: className,
|
|
17
|
+
children,
|
|
18
|
+
...rest
|
|
19
|
+
}: Props & HTMLAttributes<HTMLParagraphElement> = $props();
|
|
20
|
+
|
|
21
|
+
// jelinek.css:394-399 (.eyebrow): font-weight 700, margin-bottom 0.35em
|
|
22
|
+
// (mb-[0.35em] — not on Tailwind's spacing scale).
|
|
23
|
+
//
|
|
24
|
+
// TASK 31 — THE SIZE IS NOW ON THE MODULAR SCALE. It was a fixed 1.05rem
|
|
25
|
+
// literal (16.8px, deliberately off-scale); the guide replaced it with
|
|
26
|
+
// `font-size: var(--step2)` (jelinek.css:398), which is
|
|
27
|
+
// clamp(1.3125rem, …, 1.5rem) — 21px on a phone growing to 24px from 1024px
|
|
28
|
+
// up. So this is a real, visible size increase of roughly 25-43%, not a
|
|
29
|
+
// re-spelling, and it is deliberate: the guide's own comment on that line
|
|
30
|
+
// calls --step2 the "velikost „h5" (o stupeň pod h4)" — h5's size, one step
|
|
31
|
+
// below h4 — and the section header above it (:343) states the hierarchy
|
|
32
|
+
// this belongs to, "eyebrow / číslo kapitoly (velikost „h5") → H1 → H2 …".
|
|
33
|
+
// The eyebrow is a kicker in the heading hierarchy, so it is sized from the
|
|
34
|
+
// scale like every other member of it. --step2 IS mapped (tokens.css's
|
|
35
|
+
// @theme inline block), so this is the named `text-step2` utility rather
|
|
36
|
+
// than an arbitrary value — and it therefore stays fluid with the viewport
|
|
37
|
+
// on its own, with no variant needed.
|
|
38
|
+
//
|
|
39
|
+
// jelinek.css:373-377 puts .eyebrow in the shared font-secondary selector
|
|
40
|
+
// list (`.eyebrow, .small, .tag, .tab, figcaption, label.field-label, …`)
|
|
41
|
+
// — Avenir/GT Walsheim Pro per tokens.css, NOT the Archer serif body
|
|
42
|
+
// inherits — reproduced as font-secondary.
|
|
43
|
+
const BASE = 'font-secondary font-bold text-step2 mb-[0.35em]';
|
|
44
|
+
|
|
45
|
+
// jelinek.css:396 (.eyebrow, the bare/default rule): color is
|
|
46
|
+
// var(--JELINEK-BROWN), NOT a hardcoded brown — tokens.css:193-200
|
|
47
|
+
// ([data-division="mattress"]) reassigns --JELINEK-BROWN itself to
|
|
48
|
+
// --JELINEK-MAGENTA, so text-jelinek-brown (which resolves through
|
|
49
|
+
// var(--color-jelinek-brown) -> var(--JELINEK-BROWN)) automatically
|
|
50
|
+
// follows the division switch, same mechanism Button/Checkbox already
|
|
51
|
+
// rely on for their own default brown. jelinek.css:400 (.eyebrow--magenta)
|
|
52
|
+
// uses text-jelinek-magenta instead: --JELINEK-MAGENTA is only ever READ
|
|
53
|
+
// by the division re-theme, never itself reassigned by it, so this variant
|
|
54
|
+
// stays magenta regardless of division — verified by reading
|
|
55
|
+
// tokens.css:193-200, which touches --JELINEK-BROWN/-HIGHLIGHT/--bg-brown
|
|
56
|
+
// only. jelinek.css:401 (.eyebrow--black) -> text-jelinek-black, which
|
|
57
|
+
// still correctly inverts under dark mode via --JELINEK-BLACK's own
|
|
58
|
+
// tokens.css dark-mode block (no dark: override needed here, same
|
|
59
|
+
// reasoning Tab.svelte/Tag.svelte document for their own bare
|
|
60
|
+
// jelinek-black usage).
|
|
61
|
+
const VARIANT: Record<Variant, string> = {
|
|
62
|
+
brown: 'text-jelinek-brown',
|
|
63
|
+
magenta: 'text-jelinek-magenta',
|
|
64
|
+
black: 'text-jelinek-black'
|
|
65
|
+
};
|
|
66
|
+
</script>
|
|
67
|
+
|
|
68
|
+
<p {...rest} class={cn(BASE, VARIANT[variant], className)}>
|
|
69
|
+
{@render children()}
|
|
70
|
+
</p>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
type Variant = 'brown' | 'magenta' | 'black';
|
|
4
|
+
interface Props {
|
|
5
|
+
variant?: Variant;
|
|
6
|
+
class?: string;
|
|
7
|
+
children: Snippet;
|
|
8
|
+
}
|
|
9
|
+
type $$ComponentProps = Props & HTMLAttributes<HTMLParagraphElement>;
|
|
10
|
+
declare const Eyebrow: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
11
|
+
type Eyebrow = ReturnType<typeof Eyebrow>;
|
|
12
|
+
export default Eyebrow;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
|
+
import { cn } from '../utils/cn.js';
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
class?: string;
|
|
8
|
+
children: Snippet;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let { class: className, children, ...rest }: Props & HTMLAttributes<HTMLDivElement> = $props();
|
|
12
|
+
|
|
13
|
+
// jelinek.css:1144-1151 (.glassmorphism) — a standalone surface primitive
|
|
14
|
+
// (per task direction, its own component rather than a boolean bolted
|
|
15
|
+
// onto Panel/Card/Demo: the guide treats it as one rule, unrelated to the
|
|
16
|
+
// shared box system those three use — no --box-fill/--box-primary custom
|
|
17
|
+
// properties, no border-border-subtle, no p-6/rounded-card). `backdrop-
|
|
18
|
+
// filter` only produces a visible effect when something behind the
|
|
19
|
+
// element is actually rendered — a flat card in front of a flat
|
|
20
|
+
// background demonstrates nothing, which is why the showcase demo (Task
|
|
21
|
+
// 23 report) places this over a photo, not another surface colour.
|
|
22
|
+
//
|
|
23
|
+
// TASK 31 — THE GUIDE NOW HAS ONE SHARED DEFINITION OF GLASS, and this
|
|
24
|
+
// component is no longer the only thing that uses it. The designer pulled
|
|
25
|
+
// the fill, the border and the filter out into three tokens
|
|
26
|
+
// (jelinek.css:132-136) and pointed .glassmorphism, .site-header__inner,
|
|
27
|
+
// .chapter-nav__inner and the sticky .is-sticky switcher at all three. Every
|
|
28
|
+
// value in this component therefore changed:
|
|
29
|
+
// - background-color: was the literal `rgba(0,0,0,0)` — fully transparent,
|
|
30
|
+
// which is why this component previously emitted no bg-* utility at all.
|
|
31
|
+
// It is now `var(--glass-fill)`: rgba(255,255,255,0.5) light,
|
|
32
|
+
// rgba(0,0,0,0.6) dark. So the glass finally has a fill, and the dark
|
|
33
|
+
// mode difference is carried entirely by that token.
|
|
34
|
+
// - border: was the literal `rgba(255,255,255,0.125)`, now
|
|
35
|
+
// `var(--glass-border)` = rgba(255,255,255,0.75) — SIX TIMES more
|
|
36
|
+
// opaque, and deliberately the same hairline in both themes (the token's
|
|
37
|
+
// own comment says so: "stejná hrana v obou režimech").
|
|
38
|
+
// - backdrop-filter: was `blur(5px) brightness(140%)`, now
|
|
39
|
+
// `var(--glass-filter)` = `blur(25px) saturate(140%)`. Five times the
|
|
40
|
+
// blur, and brightness is replaced by saturation.
|
|
41
|
+
// - the `:root[data-theme="dark"] .glassmorphism` rule is GONE from the
|
|
42
|
+
// guide entirely, so the `dark:` brightness override here goes with it.
|
|
43
|
+
// Dark mode no longer darkens the glass with a filter; it darkens the
|
|
44
|
+
// FILL (--glass-fill flips to rgba(0,0,0,0.6)). One less rule, same
|
|
45
|
+
// effect. The old `dark:backdrop-brightness-[60%]` would now fight the
|
|
46
|
+
// shared filter for no reason.
|
|
47
|
+
// border-radius: 15px is unchanged and still off the radius scale
|
|
48
|
+
// (--radius-card is clamp(10px,1vw,15px), fluid, not a fixed 15px), so it
|
|
49
|
+
// stays arbitrary.
|
|
50
|
+
//
|
|
51
|
+
// WHY THE FILTER IS AN ARBITRARY *PROPERTY* PAIR and not
|
|
52
|
+
// `backdrop-blur-[25px] backdrop-saturate-[140%]`: both compile, but only
|
|
53
|
+
// this form REFERENCES the token. If the designer retunes --glass-filter
|
|
54
|
+
// (he already has, twice), a component holding `blur(25px)` as a literal
|
|
55
|
+
// diverges silently and NO gate catches it — check:css-lock hashes
|
|
56
|
+
// `.glassmorphism`'s rule text, which would still read
|
|
57
|
+
// `var(--glass-filter)` and so would not have changed, and gen-tokens only
|
|
58
|
+
// checks tokens.css. Referencing the token is what makes the retune flow
|
|
59
|
+
// through. Both the prefixed and unprefixed properties are written out
|
|
60
|
+
// because, unlike Tailwind's backdrop-* utilities, an arbitrary property
|
|
61
|
+
// emits exactly what it is given — verified against compiled output, not
|
|
62
|
+
// assumed.
|
|
63
|
+
//
|
|
64
|
+
// box-shadow: var(--shadow-interactive) -> shadow-interactive, the
|
|
65
|
+
// mapped Tailwind token (tokens.css's @theme inline block), tracking
|
|
66
|
+
// both light/dark automatically like every other shadow-* usage in this
|
|
67
|
+
// kit.
|
|
68
|
+
const BASE =
|
|
69
|
+
'rounded-[15px] bg-[var(--glass-fill)] border border-[var(--glass-border)] shadow-interactive ' +
|
|
70
|
+
'[-webkit-backdrop-filter:var(--glass-filter)] [backdrop-filter:var(--glass-filter)]';
|
|
71
|
+
</script>
|
|
72
|
+
|
|
73
|
+
<div {...rest} class={cn(BASE, className)}>
|
|
74
|
+
{@render children()}
|
|
75
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
interface Props {
|
|
4
|
+
class?: string;
|
|
5
|
+
children: Snippet;
|
|
6
|
+
}
|
|
7
|
+
type $$ComponentProps = Props & HTMLAttributes<HTMLDivElement>;
|
|
8
|
+
declare const Glass: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
9
|
+
type Glass = ReturnType<typeof Glass>;
|
|
10
|
+
export default Glass;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
|
+
import { cn } from '../utils/cn.js';
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
cols?: 2 | 3 | 4;
|
|
8
|
+
class?: string;
|
|
9
|
+
children: Snippet;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let {
|
|
13
|
+
cols = 3,
|
|
14
|
+
class: className,
|
|
15
|
+
children,
|
|
16
|
+
...rest
|
|
17
|
+
}: Props & HTMLAttributes<HTMLDivElement> = $props();
|
|
18
|
+
|
|
19
|
+
// jelinek.css:709-717 (.grid/.grid--2/--3/--4): as of the Task 30 merge the
|
|
20
|
+
// guide is MOBILE-FIRST here — base `grid-template-columns: 1fr` for every
|
|
21
|
+
// variant, `@media (min-width: 640px)` gives 2 columns,
|
|
22
|
+
// `@media (min-width: 1024px)` gives .grid--3 three and .grid--4 four.
|
|
23
|
+
// Reproduced 1:1 below.
|
|
24
|
+
//
|
|
25
|
+
// Task 31 RE-VERIFIED this against the merged stylesheet rather than
|
|
26
|
+
// trusting the merge report's claim that grid already matched, and it does —
|
|
27
|
+
// declaration for declaration, including that the old desktop-first
|
|
28
|
+
// `@media (max-width: 900px)` tier became `min-width: 1024px`, not 900. The
|
|
29
|
+
// group's other rule, `.grid .panel, .grid .card, .grid .demo
|
|
30
|
+
// { margin-bottom: 0 }` (:699), has nothing to reproduce either: Card, Panel
|
|
31
|
+
// and Demo all deliberately drop their own `margin-bottom` (see e.g.
|
|
32
|
+
// Panel.svelte's comment on standing rule 5), so there is no margin here for
|
|
33
|
+
// a grid to zero out.
|
|
34
|
+
//
|
|
35
|
+
// THE `min-[620.02px]` / `min-[900.02px]` EPSILON IS GONE, and this is the
|
|
36
|
+
// one place in the kit where removing it is not a rounding decision. The
|
|
37
|
+
// epsilon existed for exactly one reason: the guide expressed this component
|
|
38
|
+
// desktop-first with INCLUSIVE `max-width` boundaries
|
|
39
|
+
// (`@media (max-width: 900px)` / `@media (max-width: 620px)`, both true AT
|
|
40
|
+
// the boundary value), and Tailwind's `max-[620px]:` compiles to the
|
|
41
|
+
// EXCLUSIVE `width < 620px`. `min-[620.02px]:` was the gapless,
|
|
42
|
+
// non-overlapping inverse of `<= 620px`. The brand designer rewrote these
|
|
43
|
+
// rules mobile-first with `min-width` queries, so the inclusive boundary
|
|
44
|
+
// this component was compensating for no longer exists: `min-[640px]:` and
|
|
45
|
+
// `min-[1024px]:` are now EXACT translations of the guide's own queries,
|
|
46
|
+
// character for character. Do not reintroduce an epsilon here — it would
|
|
47
|
+
// now put the kit 0.02px away from the stylesheet instead of onto it.
|
|
48
|
+
//
|
|
49
|
+
// Behaviour by width (the guide's, verbatim):
|
|
50
|
+
// w < 640 -> 1 column, every cols value
|
|
51
|
+
// 640 <= w < 1024 -> 2 columns, every cols value
|
|
52
|
+
// w >= 1024 -> the cols value itself (2/3/4)
|
|
53
|
+
// (.grid--3 and .grid--4 both collapse to 2 columns between 640 and 1024,
|
|
54
|
+
// so cols=4 goes 4 -> 2 -> 1 and never passes through 3; cols=2 has no
|
|
55
|
+
// 1024px rule at all, it is already 2-up from 640px.)
|
|
56
|
+
//
|
|
57
|
+
// Why Tailwind's native `min-*` variant family and NOT arbitrary *media*
|
|
58
|
+
// variants (`[@media(min-width:1024px)]:...`), even though those can express
|
|
59
|
+
// any query verbatim: a prior attempt at the desktop-first version used that
|
|
60
|
+
// form and was reverted after a real `vite build` showed Tailwind sorts
|
|
61
|
+
// arbitrary media variants by the *query text itself*, not by breakpoint
|
|
62
|
+
// magnitude — "620" sorts before "900" lexically regardless of which is
|
|
63
|
+
// numerically narrower. That put the narrow rule after the wide one in the
|
|
64
|
+
// compiled stylesheet and, at equal specificity, the later rule won the
|
|
65
|
+
// cascade across the whole range. Tailwind's native `min-*` family sorts
|
|
66
|
+
// ascending by magnitude instead — confirmed against the compiled CSS for
|
|
67
|
+
// this component, not assumed. Never paper over a future regression here
|
|
68
|
+
// with `!important`: it would break the class-override contract
|
|
69
|
+
// `cn.test.ts` guarantees.
|
|
70
|
+
//
|
|
71
|
+
// gap: var(--space-3) (24px) = gap-6 on the default Tailwind spacing scale
|
|
72
|
+
// (--space-3 is listed passthrough-but-equal to Tailwind's spacing scale in
|
|
73
|
+
// global-constraints.md).
|
|
74
|
+
// Classes are written out per-cols-value in full, not built from a
|
|
75
|
+
// `min-[1024px]:grid-cols-${n}` template, so Tailwind's static scanner can
|
|
76
|
+
// see each one literally — a template string is invisible to it and the
|
|
77
|
+
// class would never be generated.
|
|
78
|
+
const COLS: Record<2 | 3 | 4, string> = {
|
|
79
|
+
2: 'grid-cols-1 min-[640px]:grid-cols-2',
|
|
80
|
+
3: 'grid-cols-1 min-[640px]:grid-cols-2 min-[1024px]:grid-cols-3',
|
|
81
|
+
4: 'grid-cols-1 min-[640px]:grid-cols-2 min-[1024px]:grid-cols-4'
|
|
82
|
+
};
|
|
83
|
+
</script>
|
|
84
|
+
|
|
85
|
+
<div {...rest} class={cn('grid gap-6', COLS[cols], className)}>
|
|
86
|
+
{@render children()}
|
|
87
|
+
</div>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
interface Props {
|
|
4
|
+
cols?: 2 | 3 | 4;
|
|
5
|
+
class?: string;
|
|
6
|
+
children: Snippet;
|
|
7
|
+
}
|
|
8
|
+
type $$ComponentProps = Props & HTMLAttributes<HTMLDivElement>;
|
|
9
|
+
declare const Grid: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
10
|
+
type Grid = ReturnType<typeof Grid>;
|
|
11
|
+
export default Grid;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { HTMLLabelAttributes } from 'svelte/elements';
|
|
4
|
+
import { cn } from '../utils/cn.js';
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
for?: string;
|
|
8
|
+
class?: string;
|
|
9
|
+
children: Snippet;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let {
|
|
13
|
+
for: forId,
|
|
14
|
+
class: className,
|
|
15
|
+
children,
|
|
16
|
+
...rest
|
|
17
|
+
}: Props & HTMLLabelAttributes = $props();
|
|
18
|
+
|
|
19
|
+
// jelinek.css:662 (`label.field-label`): display:block, font-weight:500,
|
|
20
|
+
// font-size:0.88rem (fixed literal, not on the --step scale), margin
|
|
21
|
+
// 0 0 6px (mb-1.5). The selector only matches an actual <label> element,
|
|
22
|
+
// which this component always renders, so it always applies. Crucially
|
|
23
|
+
// this rule declares no `color` at all — text colour is left to inherit
|
|
24
|
+
// from context, so it must NOT be forced to text-fg-muted1 as the draft
|
|
25
|
+
// brief did. font-family IS legitimately font-secondary, but from a
|
|
26
|
+
// *separate* rule at jelinek.css:313-318 (the shared Avenir group that
|
|
27
|
+
// also covers .eyebrow/.tag/.tab/etc.), which targets the same
|
|
28
|
+
// `label.field-label` selector — not from the :662 block itself.
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<label
|
|
32
|
+
{...rest}
|
|
33
|
+
for={forId}
|
|
34
|
+
class={cn('mb-1.5 block font-secondary text-[0.88rem] font-medium', className)}
|
|
35
|
+
>
|
|
36
|
+
{@render children()}
|
|
37
|
+
</label>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLLabelAttributes } from 'svelte/elements';
|
|
3
|
+
interface Props {
|
|
4
|
+
for?: string;
|
|
5
|
+
class?: string;
|
|
6
|
+
children: Snippet;
|
|
7
|
+
}
|
|
8
|
+
type $$ComponentProps = Props & HTMLLabelAttributes;
|
|
9
|
+
declare const Label: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
10
|
+
type Label = ReturnType<typeof Label>;
|
|
11
|
+
export default Label;
|