@jelinek/ui 0.9.0 → 0.9.2
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 +33 -10
- package/dist/components/ChapterNav.svelte +1 -1
- package/dist/components/Checkbox.svelte +13 -15
- package/dist/components/Checkbox.svelte.d.ts +1 -0
- package/dist/components/ContentLogo.svelte +18 -13
- package/dist/components/ContentLogo.svelte.d.ts +6 -5
- package/dist/components/Grid.svelte +9 -5
- package/dist/components/Icon.svelte +52 -0
- package/dist/components/Icon.svelte.d.ts +30 -0
- package/dist/components/InfoBar.svelte +254 -0
- package/dist/components/InfoBar.svelte.d.ts +46 -0
- package/dist/components/Label.svelte +12 -1
- package/dist/components/Label.svelte.d.ts +8 -0
- package/dist/components/PageHero.svelte +12 -9
- package/dist/components/Pager.svelte +5 -2
- package/dist/components/PhotoTile.svelte +4 -2
- package/dist/components/ProductCard.svelte +66 -44
- package/dist/components/ProductCard.svelte.d.ts +17 -4
- package/dist/components/Radio.svelte +12 -8
- package/dist/components/Radio.svelte.d.ts +1 -0
- package/dist/components/Select.svelte +70 -12
- package/dist/components/Select.svelte.d.ts +11 -0
- package/dist/components/SiteFooter.svelte +19 -0
- package/dist/components/SiteFooter.svelte.d.ts +8 -0
- package/dist/components/SiteHeader.svelte +70 -9
- package/dist/components/SiteHeader.svelte.d.ts +16 -0
- package/dist/components/Slider.svelte +6 -11
- package/dist/components/Switch.svelte +76 -0
- package/dist/components/Switch.svelte.d.ts +12 -0
- package/dist/components/Tab.svelte +29 -1
- package/dist/components/TextField.svelte +61 -10
- package/dist/components/TextField.svelte.d.ts +13 -0
- package/dist/components/Textarea.svelte +92 -0
- package/dist/components/Textarea.svelte.d.ts +23 -0
- package/dist/components/Tile.svelte +12 -11
- package/dist/components/Tile.svelte.d.ts +8 -2
- package/dist/components/blocks/CmsButton.svelte +36 -0
- package/dist/components/blocks/CmsButton.svelte.d.ts +12 -0
- package/dist/components/blocks/CmsColumns.svelte +20 -0
- package/dist/components/blocks/CmsColumns.svelte.d.ts +9 -0
- package/dist/components/blocks/CmsCover.svelte +71 -0
- package/dist/components/blocks/CmsCover.svelte.d.ts +17 -0
- package/dist/components/blocks/CmsHeading.svelte +50 -0
- package/dist/components/blocks/CmsHeading.svelte.d.ts +14 -0
- package/dist/components/blocks/CmsImage.svelte +43 -0
- package/dist/components/blocks/CmsImage.svelte.d.ts +13 -0
- package/dist/components/blocks/CmsMediaText.svelte +64 -0
- package/dist/components/blocks/CmsMediaText.svelte.d.ts +16 -0
- package/dist/components/blocks/CmsText.svelte +53 -0
- package/dist/components/blocks/CmsText.svelte.d.ts +10 -0
- package/dist/components/commerce/Breadcrumbs.svelte +22 -5
- package/dist/components/commerce/CartDrawer.svelte +7 -4
- package/dist/components/commerce/CartLineItem.svelte +1 -1
- package/dist/components/commerce/CheckoutProgress.svelte +1 -1
- package/dist/components/commerce/ConfigSection.svelte +2 -2
- package/dist/components/commerce/DimensionSlider.svelte +1 -1
- package/dist/components/commerce/Drawer.svelte +38 -24
- package/dist/components/commerce/Drawer.svelte.d.ts +0 -2
- package/dist/components/commerce/EmptyState.svelte +37 -0
- package/dist/components/commerce/EmptyState.svelte.d.ts +13 -0
- package/dist/components/commerce/FilterChip.svelte +35 -0
- package/dist/components/commerce/FilterChip.svelte.d.ts +10 -0
- package/dist/components/commerce/FreeShippingBar.svelte +1 -1
- package/dist/components/commerce/Gallery.svelte +4 -2
- package/dist/components/commerce/ListingToolbar.svelte +62 -0
- package/dist/components/commerce/ListingToolbar.svelte.d.ts +19 -0
- package/dist/components/commerce/Modal.svelte +31 -21
- package/dist/components/commerce/Modal.svelte.d.ts +0 -2
- package/dist/components/commerce/OrderSummary.svelte +1 -1
- package/dist/components/commerce/Pagination.svelte +115 -0
- package/dist/components/commerce/Pagination.svelte.d.ts +14 -0
- package/dist/components/commerce/PriceDisplay.svelte +3 -3
- package/dist/components/commerce/ProductHeader.svelte +2 -2
- package/dist/components/commerce/QuantityStepper.svelte +1 -1
- package/dist/components/commerce/RatingStars.svelte +1 -1
- package/dist/components/commerce/SearchField.svelte +92 -0
- package/dist/components/commerce/SearchField.svelte.d.ts +15 -0
- package/dist/components/commerce/SideToggle.svelte +1 -1
- package/dist/components/commerce/Skeleton.svelte +4 -1
- package/dist/components/commerce/StickyBar.svelte +4 -4
- package/dist/components/commerce/StockBadge.svelte +2 -2
- package/dist/components/commerce/Toaster.svelte +9 -5
- package/dist/components/commerce/TrustBadges.svelte +1 -1
- package/dist/components/commerce/overlay.d.ts +14 -0
- package/dist/components/commerce/overlay.js +49 -0
- package/dist/components/info-bar.d.ts +26 -0
- package/dist/components/info-bar.js +23 -0
- package/dist/icons/material-icons.generated.d.ts +4 -0
- package/dist/icons/material-icons.generated.js +118 -0
- package/dist/icons/material.d.ts +17 -0
- package/dist/icons/material.js +52 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +17 -0
- package/dist/theme/base.css +22 -0
- package/dist/theme/extras.css +62 -0
- package/dist/theme/fonts.css +9 -42
- package/dist/theme/tokens.css +23 -9
- package/package.json +4 -2
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
3
|
+
import { cn } from '../../utils/cn.js';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
value?: string;
|
|
7
|
+
/** Popisek pro čtečky (pole nemá viditelný label). */
|
|
8
|
+
label?: string;
|
|
9
|
+
placeholder?: string;
|
|
10
|
+
/** Zavolá se při odeslání (Enter) s aktuálním dotazem. */
|
|
11
|
+
onsearch?: (query: string) => void;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
class?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let {
|
|
17
|
+
value = $bindable(''),
|
|
18
|
+
label = 'Hledat',
|
|
19
|
+
placeholder = 'Hledat…',
|
|
20
|
+
onsearch,
|
|
21
|
+
disabled = false,
|
|
22
|
+
class: className,
|
|
23
|
+
...rest
|
|
24
|
+
}: Props & Omit<HTMLInputAttributes, 'value'> = $props();
|
|
25
|
+
|
|
26
|
+
// Field chrome is TextField's BASE verbatim (border-fg-muted2, 11px/14px
|
|
27
|
+
// padding, 0.98rem, tokenised focus ring — see TextField.svelte for the
|
|
28
|
+
// full provenance notes), with left padding widened for the magnifier and
|
|
29
|
+
// right padding for the clear button. type="search" is NOT used: WebKit
|
|
30
|
+
// draws its own clear control there, which would double up with ours.
|
|
31
|
+
const FIELD =
|
|
32
|
+
'w-full rounded-button border border-fg-muted2 bg-surface py-[11px] pr-11 pl-11 ' +
|
|
33
|
+
'font-secondary font-light text-[0.98rem] text-fg placeholder:text-fg-muted2 ' +
|
|
34
|
+
'focus:outline-[length:var(--focus-width)] focus:outline-offset-1 ' +
|
|
35
|
+
'focus:outline-[var(--focus-color)] focus:border-[var(--focus-color)]';
|
|
36
|
+
const DISABLED =
|
|
37
|
+
'cursor-not-allowed border-border-subtle bg-surface-gray text-fg-muted2 ' +
|
|
38
|
+
'placeholder:text-fg-muted2';
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<!-- role="search" comes with the <search>/form pattern: submit = Enter, which
|
|
42
|
+
is how people actually search. The magnifier is decorative (the field's
|
|
43
|
+
accessible name carries the meaning), the clear button is a real button. -->
|
|
44
|
+
<form
|
|
45
|
+
role="search"
|
|
46
|
+
class={cn('relative', className)}
|
|
47
|
+
onsubmit={(e) => {
|
|
48
|
+
e.preventDefault();
|
|
49
|
+
onsearch?.(value);
|
|
50
|
+
}}
|
|
51
|
+
>
|
|
52
|
+
<svg
|
|
53
|
+
viewBox="0 0 24 24"
|
|
54
|
+
class="pointer-events-none absolute top-1/2 left-3.5 size-5 -translate-y-1/2 text-fg-muted1"
|
|
55
|
+
fill="none"
|
|
56
|
+
stroke="currentColor"
|
|
57
|
+
stroke-width="2"
|
|
58
|
+
stroke-linecap="round"
|
|
59
|
+
aria-hidden="true"
|
|
60
|
+
>
|
|
61
|
+
<circle cx="11" cy="11" r="7" /><path d="m21 21-4.3-4.3" />
|
|
62
|
+
</svg>
|
|
63
|
+
<input
|
|
64
|
+
{...rest}
|
|
65
|
+
type="text"
|
|
66
|
+
aria-label={label}
|
|
67
|
+
{placeholder}
|
|
68
|
+
{disabled}
|
|
69
|
+
bind:value
|
|
70
|
+
class={cn(FIELD, disabled && DISABLED)}
|
|
71
|
+
/>
|
|
72
|
+
{#if value && !disabled}
|
|
73
|
+
<button
|
|
74
|
+
type="button"
|
|
75
|
+
aria-label="Vymazat hledání"
|
|
76
|
+
class="absolute top-1/2 right-2 inline-flex size-8 -translate-y-1/2 cursor-pointer
|
|
77
|
+
items-center justify-center rounded-button text-fg-muted1 transition-colors
|
|
78
|
+
duration-[var(--dur-base)] ease-[var(--ease)] hover:text-fg"
|
|
79
|
+
onclick={() => (value = '')}
|
|
80
|
+
>
|
|
81
|
+
<svg
|
|
82
|
+
viewBox="0 0 24 24"
|
|
83
|
+
class="size-4"
|
|
84
|
+
fill="none"
|
|
85
|
+
stroke="currentColor"
|
|
86
|
+
stroke-width="2"
|
|
87
|
+
stroke-linecap="round"
|
|
88
|
+
aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" /></svg
|
|
89
|
+
>
|
|
90
|
+
</button>
|
|
91
|
+
{/if}
|
|
92
|
+
</form>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
2
|
+
interface Props {
|
|
3
|
+
value?: string;
|
|
4
|
+
/** Popisek pro čtečky (pole nemá viditelný label). */
|
|
5
|
+
label?: string;
|
|
6
|
+
placeholder?: string;
|
|
7
|
+
/** Zavolá se při odeslání (Enter) s aktuálním dotazem. */
|
|
8
|
+
onsearch?: (query: string) => void;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
class?: string;
|
|
11
|
+
}
|
|
12
|
+
type $$ComponentProps = Props & Omit<HTMLInputAttributes, 'value'>;
|
|
13
|
+
declare const SearchField: import("svelte").Component<$$ComponentProps, {}, "value">;
|
|
14
|
+
type SearchField = ReturnType<typeof SearchField>;
|
|
15
|
+
export default SearchField;
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
|
|
28
28
|
<button
|
|
29
29
|
type="button"
|
|
30
|
-
class="rounded-card cursor-pointer border px-3 py-2.5 text-left transition-all duration-200 max-sm:px-2 max-sm:py-2 {active
|
|
30
|
+
class="rounded-card cursor-pointer border px-3 py-2.5 text-left font-secondary font-light transition-all duration-200 max-sm:px-2 max-sm:py-2 {active
|
|
31
31
|
? 'border-(--JELINEK-BROWN) bg-surface-gray shadow-resting'
|
|
32
32
|
: 'border-border-subtle bg-surface hover:border-(--text-muted2)'}"
|
|
33
33
|
aria-pressed={active}
|
|
@@ -7,4 +7,7 @@
|
|
|
7
7
|
let { class: className = '' }: Props = $props();
|
|
8
8
|
</script>
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
<!-- Shimmer místo pulzu (majitel, 14. 8. 2026) — projíždějící gradient,
|
|
11
|
+
definovaný v theme/extras.css (.skeleton-shimmer); tam je i klidová
|
|
12
|
+
varianta pro prefers-reduced-motion. -->
|
|
13
|
+
<div class="skeleton-shimmer rounded-card {className}" aria-hidden="true"></div>
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
let { visible, children }: Props = $props();
|
|
10
10
|
</script>
|
|
11
11
|
|
|
12
|
-
<!-- Glass strip under the kit's floating header card. z-40 keeps it
|
|
13
|
-
header (
|
|
12
|
+
<!-- Glass strip under the kit's floating header card. --z-bar (40) keeps it
|
|
13
|
+
BELOW the header (--z-header, 50) — any higher and the strip renders over the
|
|
14
14
|
card and its backdrop blur smears the whole top of the page. Top offset:
|
|
15
15
|
var(--header-h) from 640px up so the strip hangs under the fixed card;
|
|
16
16
|
top-0 on a phone, where the kit bar is absolute and has already scrolled
|
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
left the viewport). -->
|
|
19
19
|
<div
|
|
20
20
|
aria-hidden={!visible}
|
|
21
|
-
class="fixed inset-x-0 top-0 z-
|
|
21
|
+
class="fixed inset-x-0 top-0 z-(--z-bar) border-b border-(--glass-border) bg-(--glass-fill) backdrop-blur-[25px] backdrop-saturate-140 transition-transform duration-(--dur-base) min-[640px]:top-(--header-h)
|
|
22
22
|
{visible ? 'translate-y-0' : 'pointer-events-none -translate-y-[calc(100%+var(--header-h))]'}"
|
|
23
23
|
>
|
|
24
|
-
<div class="max-w-page mx-auto flex w-full items-center gap-4 px-6 py-3">
|
|
24
|
+
<div class="max-w-page mx-auto flex w-full items-center gap-4 px-6 py-3 font-secondary font-light">
|
|
25
25
|
{@render children()}
|
|
26
26
|
</div>
|
|
27
27
|
</div>
|
|
@@ -33,12 +33,12 @@
|
|
|
33
33
|
</script>
|
|
34
34
|
|
|
35
35
|
{#if compact}
|
|
36
|
-
<span class="inline-flex items-center gap-1.5 text-(length:--step-down1) font-medium {config.cls}">
|
|
36
|
+
<span class="inline-flex items-center gap-1.5 font-secondary text-(length:--step-down1) font-medium {config.cls}">
|
|
37
37
|
<span class="size-2 rounded-pill {config.dot}"></span>{text}
|
|
38
38
|
</span>
|
|
39
39
|
{:else}
|
|
40
40
|
<span
|
|
41
|
-
class="rounded-pill bg-surface-gray inline-flex items-center gap-2 px-3 py-1 text-(length:--step-down1) font-medium {config.cls}"
|
|
41
|
+
class="rounded-pill bg-surface-gray inline-flex items-center gap-2 px-3 py-1 font-secondary text-(length:--step-down1) font-medium {config.cls}"
|
|
42
42
|
>
|
|
43
43
|
<span class="size-2 rounded-pill {config.dot}"></span>{text}
|
|
44
44
|
</span>
|
|
@@ -17,16 +17,20 @@
|
|
|
17
17
|
onMount(() => toasts.subscribe((next) => (items = next)));
|
|
18
18
|
</script>
|
|
19
19
|
|
|
20
|
-
<!--
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
<!-- Škála vrstev (jelinek.css :root): hlavička --z-header (50), Drawer/Modal
|
|
21
|
+
--z-overlay (1200), toasty nade vším — --z-toast (1500; potvrzení
|
|
22
|
+
o přidání do košíku nesmí zmizet pod drawerem). role="status"
|
|
23
|
+
+ aria-live="polite": kontejner tu je trvale, takže čtečky ohlásí každý
|
|
24
|
+
toast, který do něj přibude — dřív byly hlášky pro čtečky němé (EAA). -->
|
|
23
25
|
<div
|
|
24
|
-
|
|
26
|
+
role="status"
|
|
27
|
+
aria-live="polite"
|
|
28
|
+
class="pointer-events-none fixed inset-x-0 bottom-6 z-(--z-toast) flex flex-col items-center gap-2 {className}"
|
|
25
29
|
>
|
|
26
30
|
{#each items as t (t.id)}
|
|
27
31
|
<div
|
|
28
32
|
transition:fly={{ y: 16, duration: 200 }}
|
|
29
|
-
class="rounded-pill text-fg-inverse shadow-interactive pointer-events-auto bg-(--bg-black) px-5 py-2.5 text-(length:--step-down1) font-medium"
|
|
33
|
+
class="rounded-pill text-fg-inverse shadow-interactive pointer-events-auto bg-(--bg-black) px-5 py-2.5 font-secondary text-(length:--step-down1) font-medium"
|
|
30
34
|
>
|
|
31
35
|
{t.message}
|
|
32
36
|
</div>
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
<div class={overlay ? 'absolute inset-x-3 bottom-3 flex flex-wrap gap-2' : 'flex flex-wrap gap-2'}>
|
|
18
18
|
{#each items as item (item.label)}
|
|
19
19
|
<span
|
|
20
|
-
class="rounded-pill flex items-center gap-1.5 bg-(--glass-fill) px-3 py-1.5 text-(length:--step-down2) font-medium backdrop-blur-[25px]"
|
|
20
|
+
class="rounded-pill flex items-center gap-1.5 bg-(--glass-fill) px-3 py-1.5 font-secondary text-(length:--step-down2) font-medium backdrop-blur-[25px]"
|
|
21
21
|
>
|
|
22
22
|
<item.icon class="size-3.5" />
|
|
23
23
|
{item.label}
|
|
@@ -10,3 +10,17 @@ export declare function portal(node: HTMLElement): {
|
|
|
10
10
|
};
|
|
11
11
|
/** Lock body scroll; returns the unlock function (for use inside $effect). */
|
|
12
12
|
export declare function lockScroll(): () => void;
|
|
13
|
+
/**
|
|
14
|
+
* Past na fokus (zákonná přístupnost překryvů — EAA): Tab a Shift+Tab
|
|
15
|
+
* cyklí UVNITŘ containeru, do stránky pod overlayem se tabulátorem nedá
|
|
16
|
+
* vyjet. Myš ani Escape to nijak neomezuje. Vrací úklidovou funkci
|
|
17
|
+
* (pro $effect), stejná smlouva jako lockScroll().
|
|
18
|
+
*/
|
|
19
|
+
export declare function trapFocus(container: HTMLElement): () => void;
|
|
20
|
+
/**
|
|
21
|
+
* Zapamatuje si prvek zaostřený PŘED otevřením overlaye a vrátí funkci,
|
|
22
|
+
* která na něj fokus vrátí (pokud mezitím nezmizel ze stránky). Čtenář
|
|
23
|
+
* s klávesnicí tak po zavření pokračuje přesně tam, kde byl — typicky
|
|
24
|
+
* na tlačítku, kterým overlay otevřel.
|
|
25
|
+
*/
|
|
26
|
+
export declare function rememberFocus(): () => void;
|
|
@@ -18,3 +18,52 @@ export function lockScroll() {
|
|
|
18
18
|
document.body.style.overflow = prev;
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
|
+
// Co se v překryvu dá zaostřit tabulátorem. Bez filtru viditelnosti —
|
|
22
|
+
// otevřený overlay svůj obsah zobrazuje celý a jsdom (unit testy)
|
|
23
|
+
// offsetParent nezná.
|
|
24
|
+
const FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]), ' +
|
|
25
|
+
'select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
|
26
|
+
/**
|
|
27
|
+
* Past na fokus (zákonná přístupnost překryvů — EAA): Tab a Shift+Tab
|
|
28
|
+
* cyklí UVNITŘ containeru, do stránky pod overlayem se tabulátorem nedá
|
|
29
|
+
* vyjet. Myš ani Escape to nijak neomezuje. Vrací úklidovou funkci
|
|
30
|
+
* (pro $effect), stejná smlouva jako lockScroll().
|
|
31
|
+
*/
|
|
32
|
+
export function trapFocus(container) {
|
|
33
|
+
const onKey = (e) => {
|
|
34
|
+
if (e.key !== 'Tab')
|
|
35
|
+
return;
|
|
36
|
+
const items = Array.from(container.querySelectorAll(FOCUSABLE));
|
|
37
|
+
if (items.length === 0) {
|
|
38
|
+
e.preventDefault();
|
|
39
|
+
container.focus();
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const first = items[0];
|
|
43
|
+
const last = items[items.length - 1];
|
|
44
|
+
const active = document.activeElement;
|
|
45
|
+
if (e.shiftKey && (active === first || active === container)) {
|
|
46
|
+
e.preventDefault();
|
|
47
|
+
last.focus();
|
|
48
|
+
}
|
|
49
|
+
else if (!e.shiftKey && active === last) {
|
|
50
|
+
e.preventDefault();
|
|
51
|
+
first.focus();
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
container.addEventListener('keydown', onKey);
|
|
55
|
+
return () => container.removeEventListener('keydown', onKey);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Zapamatuje si prvek zaostřený PŘED otevřením overlaye a vrátí funkci,
|
|
59
|
+
* která na něj fokus vrátí (pokud mezitím nezmizel ze stránky). Čtenář
|
|
60
|
+
* s klávesnicí tak po zavření pokračuje přesně tam, kde byl — typicky
|
|
61
|
+
* na tlačítku, kterým overlay otevřel.
|
|
62
|
+
*/
|
|
63
|
+
export function rememberFocus() {
|
|
64
|
+
const opener = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
65
|
+
return () => {
|
|
66
|
+
if (opener && document.contains(opener))
|
|
67
|
+
opener.focus();
|
|
68
|
+
};
|
|
69
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typy a pomocné funkce informační lišty (InfoBar.svelte) — v samostatném
|
|
3
|
+
* souboru, aby komponenta měla jediný <script> s `interface Props` (tak ji
|
|
4
|
+
* čte generátor API v routes/api/props.ts).
|
|
5
|
+
*/
|
|
6
|
+
/** Barvy lišty — plné plochy značky a světlá pozadí (majitel, 4. 9. 2026). */
|
|
7
|
+
export type InfoBarColor = 'black' | 'brown' | 'magenta' | 'gray' | 'beige' | 'pink';
|
|
8
|
+
export interface InfoBarItem {
|
|
9
|
+
/** Stálý identifikátor sdělení — podle něj si web pamatuje zavření. */
|
|
10
|
+
id: string;
|
|
11
|
+
text: string;
|
|
12
|
+
/** Tučný titulek nad textem (lišta pak má dva řádky). */
|
|
13
|
+
title?: string;
|
|
14
|
+
/** Tlačítko vpravo (např. „Naše služby“) — neutrální černé podle Tlačítek. */
|
|
15
|
+
href?: string;
|
|
16
|
+
linkLabel?: string;
|
|
17
|
+
/** Ikona ze sady rozhraní (/ui/ikony), jméno souboru bez .svg. */
|
|
18
|
+
icon?: string;
|
|
19
|
+
color?: InfoBarColor;
|
|
20
|
+
/** Zobrazovat od / do — datum s časem (`2026-12-20T00:00`), místní čas. */
|
|
21
|
+
from?: string | Date;
|
|
22
|
+
to?: string | Date;
|
|
23
|
+
}
|
|
24
|
+
export declare const INFO_BAR_COLORS: Record<InfoBarColor, string>;
|
|
25
|
+
/** Je sdělení v čase `now` v platném okně? */
|
|
26
|
+
export declare function isActive(item: InfoBarItem, now: Date): boolean;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typy a pomocné funkce informační lišty (InfoBar.svelte) — v samostatném
|
|
3
|
+
* souboru, aby komponenta měla jediný <script> s `interface Props` (tak ji
|
|
4
|
+
* čte generátor API v routes/api/props.ts).
|
|
5
|
+
*/
|
|
6
|
+
export const INFO_BAR_COLORS = {
|
|
7
|
+
// Černá lišta = tmavá plocha: pozadí --bg-black (v obou režimech černé) a
|
|
8
|
+
// lokální přemapování neutrálních tokenů na hodnoty tmavého režimu
|
|
9
|
+
// (tokens.css, stejná technika jako .demo--black), aby černé tlačítko
|
|
10
|
+
// a černý focus ring uvnitř zůstaly vidět a měly hover podle pravidel.
|
|
11
|
+
black: 'bg-surface-black text-fg-inverse [--JELINEK-BLACK:hsl(0,0%,95%)] [--JELINEK-BLACK-HIGHLIGHT:hsl(0,0%,60%)] [--ON-JELINEK-BLACK:hsl(0,0%,5%)]',
|
|
12
|
+
brown: 'bg-jelinek-brown text-white',
|
|
13
|
+
magenta: 'bg-jelinek-magenta text-white',
|
|
14
|
+
gray: 'bg-surface-gray text-fg',
|
|
15
|
+
beige: 'bg-surface-brown text-fg',
|
|
16
|
+
pink: 'bg-surface-magenta text-fg'
|
|
17
|
+
};
|
|
18
|
+
/** Je sdělení v čase `now` v platném okně? */
|
|
19
|
+
export function isActive(item, now) {
|
|
20
|
+
const from = item.from ? new Date(item.from) : null;
|
|
21
|
+
const to = item.to ? new Date(item.to) : null;
|
|
22
|
+
return (!from || now >= from) && (!to || now <= to);
|
|
23
|
+
}
|