rizzo-css 0.0.68 → 0.0.69
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 +3 -3
- package/bin/rizzo-css.js +6 -6
- package/dist/rizzo.min.css +8 -5
- package/package.json +1 -1
- package/scaffold/astro/Accordion.astro +1 -1
- package/scaffold/astro/Alert.astro +1 -1
- package/scaffold/astro/AlertDialog.astro +1 -1
- package/scaffold/astro/BackToTop.astro +1 -1
- package/scaffold/astro/Breadcrumb.astro +1 -1
- package/scaffold/astro/Collapsible.astro +1 -1
- package/scaffold/astro/CopyToClipboard.astro +2 -2
- package/scaffold/astro/DocsSidebar.astro +2 -1
- package/scaffold/astro/Dropdown.astro +1 -1
- package/scaffold/astro/FontSwitcher.astro +2 -2
- package/scaffold/astro/Footer.astro +1 -1
- package/scaffold/astro/Modal.astro +1 -1
- package/scaffold/astro/RangeCalendar.astro +215 -0
- package/scaffold/astro/Settings.astro +1 -1
- package/scaffold/astro/Sheet.astro +1 -1
- package/scaffold/astro/Table.astro +2 -2
- package/scaffold/astro/Tabs.astro +25 -8
- package/scaffold/astro/ThemeIcon.astro +17 -17
- package/scaffold/astro/ThemeSwitcher.astro +19 -19
- package/scaffold/astro/base/README-RIZZO.md +1 -1
- package/scaffold/astro/variants/full/README-RIZZO.md +1 -1
- package/scaffold/svelte/Navbar.svelte +14 -3
- package/scaffold/svelte/RangeCalendar.svelte +167 -0
- package/scaffold/svelte/base/README-RIZZO.md +1 -1
- package/scaffold/svelte/index.ts +1 -0
- package/scaffold/svelte/variants/full/README-RIZZO.md +1 -1
- package/scaffold/vanilla/README-RIZZO.md +2 -2
- package/scaffold/vanilla/components/accordion.html +48 -0
- package/scaffold/vanilla/components/alert-dialog.html +48 -0
- package/scaffold/vanilla/components/alert.html +48 -0
- package/scaffold/vanilla/components/aspect-ratio.html +48 -0
- package/scaffold/vanilla/components/avatar.html +48 -0
- package/scaffold/vanilla/components/back-to-top.html +48 -0
- package/scaffold/vanilla/components/badge.html +48 -0
- package/scaffold/vanilla/components/breadcrumb.html +48 -0
- package/scaffold/vanilla/components/button-group.html +48 -0
- package/scaffold/vanilla/components/button.html +48 -0
- package/scaffold/vanilla/components/calendar.html +48 -0
- package/scaffold/vanilla/components/cards.html +48 -0
- package/scaffold/vanilla/components/carousel.html +48 -0
- package/scaffold/vanilla/components/collapsible.html +48 -0
- package/scaffold/vanilla/components/context-menu.html +48 -0
- package/scaffold/vanilla/components/copy-to-clipboard.html +48 -0
- package/scaffold/vanilla/components/dashboard.html +48 -0
- package/scaffold/vanilla/components/divider.html +48 -0
- package/scaffold/vanilla/components/docs-sidebar.html +48 -0
- package/scaffold/vanilla/components/dropdown.html +48 -0
- package/scaffold/vanilla/components/empty.html +48 -0
- package/scaffold/vanilla/components/font-switcher.html +48 -0
- package/scaffold/vanilla/components/footer.html +48 -0
- package/scaffold/vanilla/components/forms.html +48 -0
- package/scaffold/vanilla/components/hover-card.html +48 -0
- package/scaffold/vanilla/components/icons.html +48 -0
- package/scaffold/vanilla/components/index.html +49 -0
- package/scaffold/vanilla/components/input-group.html +48 -0
- package/scaffold/vanilla/components/kbd.html +48 -0
- package/scaffold/vanilla/components/label.html +48 -0
- package/scaffold/vanilla/components/modal.html +48 -0
- package/scaffold/vanilla/components/navbar.html +48 -0
- package/scaffold/vanilla/components/pagination.html +48 -0
- package/scaffold/vanilla/components/popover.html +48 -0
- package/scaffold/vanilla/components/progress-bar.html +48 -0
- package/scaffold/vanilla/components/range-calendar.html +812 -0
- package/scaffold/vanilla/components/resizable.html +48 -0
- package/scaffold/vanilla/components/scroll-area.html +48 -0
- package/scaffold/vanilla/components/search.html +48 -0
- package/scaffold/vanilla/components/separator.html +48 -0
- package/scaffold/vanilla/components/settings.html +48 -0
- package/scaffold/vanilla/components/sheet.html +48 -0
- package/scaffold/vanilla/components/skeleton.html +48 -0
- package/scaffold/vanilla/components/slider.html +48 -0
- package/scaffold/vanilla/components/sound-effects.html +48 -0
- package/scaffold/vanilla/components/spinner.html +48 -0
- package/scaffold/vanilla/components/switch.html +48 -0
- package/scaffold/vanilla/components/table.html +48 -0
- package/scaffold/vanilla/components/tabs.html +48 -0
- package/scaffold/vanilla/components/theme-switcher.html +48 -0
- package/scaffold/vanilla/components/toast.html +48 -0
- package/scaffold/vanilla/components/toggle-group.html +48 -0
- package/scaffold/vanilla/components/toggle.html +48 -0
- package/scaffold/vanilla/components/tooltip.html +48 -0
- package/scaffold/vanilla/index.html +48 -0
|
@@ -13,6 +13,8 @@ interface Props {
|
|
|
13
13
|
tabs: Tab[];
|
|
14
14
|
id?: string;
|
|
15
15
|
defaultTab?: string;
|
|
16
|
+
/** When set, selected tab id is stored and restored so framework tabs stay in sync across pages */
|
|
17
|
+
syncStorageKey?: string;
|
|
16
18
|
variant?: 'default' | 'pills' | 'underline';
|
|
17
19
|
class?: string;
|
|
18
20
|
}
|
|
@@ -21,17 +23,19 @@ const {
|
|
|
21
23
|
tabs,
|
|
22
24
|
id,
|
|
23
25
|
defaultTab,
|
|
26
|
+
syncStorageKey,
|
|
24
27
|
variant = 'default',
|
|
25
28
|
class: className = '',
|
|
26
29
|
} = Astro.props;
|
|
27
30
|
|
|
28
31
|
const tabsId = id || `tabs-${Math.random().toString(36).substr(2, 9)}`;
|
|
29
|
-
const
|
|
32
|
+
const serverDefaultTab = defaultTab || tabs[0]?.id || '';
|
|
33
|
+
const activeTabId = serverDefaultTab;
|
|
30
34
|
const variantClass = variant !== 'default' ? `tabs--${variant}` : '';
|
|
31
35
|
const classes = `tabs ${variantClass} ${className}`.trim();
|
|
32
36
|
---
|
|
33
37
|
|
|
34
|
-
<div class={classes} data-tabs={tabsId}>
|
|
38
|
+
<div class={classes} data-tabs={tabsId} data-sync-storage-key={syncStorageKey || undefined}>
|
|
35
39
|
<div
|
|
36
40
|
class="tabs__list"
|
|
37
41
|
role="tablist"
|
|
@@ -91,7 +95,7 @@ const classes = `tabs ${variantClass} ${className}`.trim();
|
|
|
91
95
|
</div>
|
|
92
96
|
</div>
|
|
93
97
|
|
|
94
|
-
<script define:vars={{ tabsId, activeTabId }}>
|
|
98
|
+
<script define:vars={{ tabsId, activeTabId, syncStorageKey }}>
|
|
95
99
|
(function initTabs() {
|
|
96
100
|
const init = () => {
|
|
97
101
|
const tabsContainer = document.querySelector(`[data-tabs="${tabsId}"]`);
|
|
@@ -110,20 +114,33 @@ const classes = `tabs ${variantClass} ${className}`.trim();
|
|
|
110
114
|
return;
|
|
111
115
|
}
|
|
112
116
|
|
|
113
|
-
|
|
114
|
-
let
|
|
115
|
-
|
|
116
|
-
|
|
117
|
+
const tabIds = Array.from(tabButtons).map((btn) => btn.getAttribute('data-tab-id')).filter(Boolean);
|
|
118
|
+
let initialTabId = activeTabId;
|
|
119
|
+
if (syncStorageKey && typeof sessionStorage !== 'undefined') {
|
|
120
|
+
try {
|
|
121
|
+
const stored = sessionStorage.getItem(syncStorageKey);
|
|
122
|
+
if (stored && tabIds.indexOf(stored) !== -1) {
|
|
123
|
+
initialTabId = stored;
|
|
124
|
+
}
|
|
125
|
+
} catch (_) {}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
let activeIndex = tabIds.indexOf(initialTabId);
|
|
117
129
|
if (activeIndex === -1) activeIndex = 0;
|
|
118
130
|
|
|
119
131
|
const activateTab = (index) => {
|
|
120
|
-
// Validate index
|
|
121
132
|
if (index < 0 || index >= tabButtons.length) return;
|
|
122
133
|
|
|
123
134
|
const targetButton = tabButtons[index];
|
|
124
135
|
const targetTabId = targetButton.getAttribute('data-tab-id');
|
|
125
136
|
if (!targetTabId) return;
|
|
126
137
|
|
|
138
|
+
if (syncStorageKey && typeof sessionStorage !== 'undefined') {
|
|
139
|
+
try {
|
|
140
|
+
sessionStorage.setItem(syncStorageKey, targetTabId);
|
|
141
|
+
} catch (_) {}
|
|
142
|
+
}
|
|
143
|
+
|
|
127
144
|
// Update all buttons
|
|
128
145
|
tabButtons.forEach((btn, idx) => {
|
|
129
146
|
const isActive = idx === index;
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
---
|
|
2
|
-
import type { ThemeIconKey } from '
|
|
3
|
-
import { ALL_THEMES } from '
|
|
4
|
-
import Gear from '
|
|
5
|
-
import Owl from '
|
|
6
|
-
import Palette from '
|
|
7
|
-
import Flame from '
|
|
8
|
-
import Sunset from '
|
|
9
|
-
import Zap from '
|
|
10
|
-
import Shield from '
|
|
11
|
-
import Heart from '
|
|
12
|
-
import Sun from '
|
|
13
|
-
import Cake from '
|
|
14
|
-
import Lemon from '
|
|
15
|
-
import Rainbow from '
|
|
16
|
-
import Leaf from '
|
|
17
|
-
import Cherry from '
|
|
18
|
-
import Brush from '
|
|
2
|
+
import type { ThemeIconKey } from '../../config/themes';
|
|
3
|
+
import { ALL_THEMES } from '../../config/themes';
|
|
4
|
+
import Gear from '../icons/Gear.astro';
|
|
5
|
+
import Owl from '../icons/Owl.astro';
|
|
6
|
+
import Palette from '../icons/Palette.astro';
|
|
7
|
+
import Flame from '../icons/Flame.astro';
|
|
8
|
+
import Sunset from '../icons/Sunset.astro';
|
|
9
|
+
import Zap from '../icons/Zap.astro';
|
|
10
|
+
import Shield from '../icons/Shield.astro';
|
|
11
|
+
import Heart from '../icons/Heart.astro';
|
|
12
|
+
import Sun from '../icons/Sun.astro';
|
|
13
|
+
import Cake from '../icons/Cake.astro';
|
|
14
|
+
import Lemon from '../icons/Lemon.astro';
|
|
15
|
+
import Rainbow from '../icons/Rainbow.astro';
|
|
16
|
+
import Leaf from '../icons/Leaf.astro';
|
|
17
|
+
import Cherry from '../icons/Cherry.astro';
|
|
18
|
+
import Brush from '../icons/Brush.astro';
|
|
19
19
|
|
|
20
20
|
const iconMap: Record<ThemeIconKey, typeof Owl> = {
|
|
21
21
|
gear: Gear,
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
---
|
|
2
|
-
import ChevronDown from '
|
|
3
|
-
import Gear from '
|
|
4
|
-
import Palette from '
|
|
5
|
-
import Owl from '
|
|
6
|
-
import Sun from '
|
|
7
|
-
import Flame from '
|
|
8
|
-
import Heart from '
|
|
9
|
-
import Leaf from '
|
|
10
|
-
import Shield from '
|
|
11
|
-
import Zap from '
|
|
12
|
-
import Cake from '
|
|
13
|
-
import Sunset from '
|
|
14
|
-
import Cherry from '
|
|
15
|
-
import Brush from '
|
|
16
|
-
import Lemon from '
|
|
17
|
-
import Rainbow from '
|
|
18
|
-
import type { ThemeIconKey } from '
|
|
19
|
-
import { THEMES_DARK, THEMES_LIGHT } from '
|
|
2
|
+
import ChevronDown from '../icons/ChevronDown.astro';
|
|
3
|
+
import Gear from '../icons/Gear.astro';
|
|
4
|
+
import Palette from '../icons/Palette.astro';
|
|
5
|
+
import Owl from '../icons/Owl.astro';
|
|
6
|
+
import Sun from '../icons/Sun.astro';
|
|
7
|
+
import Flame from '../icons/Flame.astro';
|
|
8
|
+
import Heart from '../icons/Heart.astro';
|
|
9
|
+
import Leaf from '../icons/Leaf.astro';
|
|
10
|
+
import Shield from '../icons/Shield.astro';
|
|
11
|
+
import Zap from '../icons/Zap.astro';
|
|
12
|
+
import Cake from '../icons/Cake.astro';
|
|
13
|
+
import Sunset from '../icons/Sunset.astro';
|
|
14
|
+
import Cherry from '../icons/Cherry.astro';
|
|
15
|
+
import Brush from '../icons/Brush.astro';
|
|
16
|
+
import Lemon from '../icons/Lemon.astro';
|
|
17
|
+
import Rainbow from '../icons/Rainbow.astro';
|
|
18
|
+
import type { ThemeIconKey } from '../../config/themes';
|
|
19
|
+
import { THEMES_DARK, THEMES_LIGHT } from '../../config/themes';
|
|
20
20
|
|
|
21
21
|
const iconMap: Record<ThemeIconKey, typeof Owl> = {
|
|
22
22
|
gear: Gear,
|
|
@@ -192,7 +192,7 @@ const InitialIcon = initialTheme ? initialTheme.icon : null;
|
|
|
192
192
|
resolveSystemTheme,
|
|
193
193
|
getThemeLabel,
|
|
194
194
|
THEME_SYSTEM,
|
|
195
|
-
} from '
|
|
195
|
+
} from '../../utils/theme';
|
|
196
196
|
|
|
197
197
|
function initThemeSwitcher() {
|
|
198
198
|
const getIconSVG = (themeValue: string) => {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
Design system · Vanilla · Astro · Svelte
|
|
16
16
|
</pre>
|
|
17
17
|
|
|
18
|
-
Astro project with Rizzo CSS. Scaffolded with `npx rizzo-css init` when you chose **Create new** and Astro, then **Landing**, **Docs**, **Dashboard**, or **Full**. **Full** = clone of the docs site. **Landing** / **Docs** / **Dashboard** = base + component picker (all
|
|
18
|
+
Astro project with Rizzo CSS. Scaffolded with `npx rizzo-css init` when you chose **Create new** and Astro, then **Landing**, **Docs**, **Dashboard**, or **Full**. **Full** = clone of the docs site. **Landing** / **Docs** / **Dashboard** = base + component picker (all 53 or pick). Same template choice for **Add to existing** (`npx rizzo-css add`).
|
|
19
19
|
|
|
20
20
|
## Setup
|
|
21
21
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
Design system · Vanilla · Astro · Svelte
|
|
16
16
|
</pre>
|
|
17
17
|
|
|
18
|
-
Astro project with Rizzo CSS. Scaffolded with `npx rizzo-css init` when you chose **Create new** and Astro, then **Full** template. **Full** = clone of the Rizzo docs site (no component picker). **Landing** / **Docs** / **Dashboard** = base + component picker (all
|
|
18
|
+
Astro project with Rizzo CSS. Scaffolded with `npx rizzo-css init` when you chose **Create new** and Astro, then **Full** template. **Full** = clone of the Rizzo docs site (no component picker). **Landing** / **Docs** / **Dashboard** = base + component picker (all 53 or pick). Same template choice for **Add to existing** (`npx rizzo-css add`).
|
|
19
19
|
|
|
20
20
|
## Setup
|
|
21
21
|
|
|
@@ -10,6 +10,13 @@
|
|
|
10
10
|
let { siteName = 'Site', logo }: Props = $props();
|
|
11
11
|
let menuOpen = $state(false);
|
|
12
12
|
|
|
13
|
+
const menuLinks = [
|
|
14
|
+
{ href: '/docs', label: 'Docs' },
|
|
15
|
+
{ href: '/docs/components', label: 'Components' },
|
|
16
|
+
{ href: '/blocks', label: 'Blocks' },
|
|
17
|
+
{ href: '/themes', label: 'Themes' },
|
|
18
|
+
];
|
|
19
|
+
|
|
13
20
|
// Click outside and Escape to close mobile menu
|
|
14
21
|
$effect(() => {
|
|
15
22
|
if (!menuOpen) return;
|
|
@@ -44,7 +51,7 @@
|
|
|
44
51
|
</div>
|
|
45
52
|
<div class="navbar__actions-desktop">
|
|
46
53
|
<Search id="search-navbar" />
|
|
47
|
-
<button type="button" class="navbar__settings-btn" aria-label="Open settings" onclick=
|
|
54
|
+
<button type="button" class="navbar__settings-btn" aria-label="Open settings" onclick={() => window.openSettings?.()}>
|
|
48
55
|
<Gear width={20} height={20} class="navbar__settings-icon" />
|
|
49
56
|
<span class="navbar__settings-label">Settings</span>
|
|
50
57
|
</button>
|
|
@@ -58,8 +65,12 @@
|
|
|
58
65
|
>
|
|
59
66
|
<span class="navbar__toggle-icon" aria-hidden="true"><span></span><span></span><span></span></span>
|
|
60
67
|
</button>
|
|
61
|
-
<div class="navbar__menu" class:navbar__menu--open={menuOpen} aria-hidden={!menuOpen}>
|
|
62
|
-
|
|
68
|
+
<div class="navbar__menu" class:navbar__menu--open={menuOpen} aria-hidden={!menuOpen} role="navigation" aria-label="Mobile menu">
|
|
69
|
+
{#each menuLinks as link}
|
|
70
|
+
<div class="navbar__item">
|
|
71
|
+
<a href={link.href} class="navbar__link" tabindex={menuOpen ? 0 : -1}>{link.label}</a>
|
|
72
|
+
</div>
|
|
73
|
+
{/each}
|
|
63
74
|
</div>
|
|
64
75
|
</div>
|
|
65
76
|
</nav>
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
const MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
|
3
|
+
const WEEKDAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
id?: string;
|
|
7
|
+
initialMonth?: string;
|
|
8
|
+
rangeStart?: string | null;
|
|
9
|
+
rangeEnd?: string | null;
|
|
10
|
+
label?: string;
|
|
11
|
+
class?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let {
|
|
15
|
+
id: calendarId,
|
|
16
|
+
initialMonth,
|
|
17
|
+
rangeStart: controlledStart,
|
|
18
|
+
rangeEnd: controlledEnd,
|
|
19
|
+
label = 'Choose date range',
|
|
20
|
+
class: className = '',
|
|
21
|
+
onRangeSelect,
|
|
22
|
+
}: Props & { onRangeSelect?: (start: string, end: string) => void } = $props();
|
|
23
|
+
|
|
24
|
+
const id = $derived(calendarId ?? `range-calendar-${Math.random().toString(36).slice(2, 9)}`);
|
|
25
|
+
const now = new Date();
|
|
26
|
+
|
|
27
|
+
function parseInitial(): { year: number; month: number } {
|
|
28
|
+
if (!initialMonth) return { year: now.getFullYear(), month: now.getMonth() };
|
|
29
|
+
const [y, m] = initialMonth.split('-').map(Number);
|
|
30
|
+
if (!y || !m || m < 1 || m > 12) return { year: now.getFullYear(), month: now.getMonth() };
|
|
31
|
+
return { year: y, month: m - 1 };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let view = $state(parseInitial());
|
|
35
|
+
let internalStart = $state<string | null>(null);
|
|
36
|
+
let internalEnd = $state<string | null>(null);
|
|
37
|
+
|
|
38
|
+
const start = $derived(controlledStart !== undefined ? controlledStart : internalStart);
|
|
39
|
+
const end = $derived(controlledEnd !== undefined ? controlledEnd : internalEnd);
|
|
40
|
+
|
|
41
|
+
function toYYYYMMDD(year: number, month: number, day: number): string {
|
|
42
|
+
return `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function dateStrToMs(s: string): number | null {
|
|
46
|
+
const d = new Date(s);
|
|
47
|
+
return Number.isNaN(d.getTime()) ? null : d.getTime();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function getMonthGrid(year: number, month: number): { day: number; year: number; month: number; currentMonth: boolean }[][] {
|
|
51
|
+
const first = new Date(year, month, 1);
|
|
52
|
+
const last = new Date(year, month + 1, 0);
|
|
53
|
+
const startDay = first.getDay();
|
|
54
|
+
const daysInMonth = last.getDate();
|
|
55
|
+
const weeks: { day: number; year: number; month: number; currentMonth: boolean }[][] = [];
|
|
56
|
+
let week: { day: number; year: number; month: number; currentMonth: boolean }[] = [];
|
|
57
|
+
const prevMonth = month === 0 ? 11 : month - 1;
|
|
58
|
+
const prevYear = month === 0 ? year - 1 : year;
|
|
59
|
+
const prevLast = new Date(prevYear, prevMonth + 1, 0).getDate();
|
|
60
|
+
for (let i = 0; i < startDay; i++) {
|
|
61
|
+
week.push({ day: prevLast - startDay + i + 1, year: prevYear, month: prevMonth, currentMonth: false });
|
|
62
|
+
}
|
|
63
|
+
for (let d = 1; d <= daysInMonth; d++) {
|
|
64
|
+
week.push({ day: d, year, month, currentMonth: true });
|
|
65
|
+
if (week.length === 7) {
|
|
66
|
+
weeks.push(week);
|
|
67
|
+
week = [];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const nextMonth = month === 11 ? 0 : month + 1;
|
|
71
|
+
const nextYear = month === 11 ? year + 1 : year;
|
|
72
|
+
for (let i = 1; week.length < 7; i++) {
|
|
73
|
+
week.push({ day: i, year: nextYear, month: nextMonth, currentMonth: false });
|
|
74
|
+
}
|
|
75
|
+
weeks.push(week);
|
|
76
|
+
return weeks;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const todayStr = $derived(toYYYYMMDD(now.getFullYear(), now.getMonth(), now.getDate()));
|
|
80
|
+
const weeks = $derived(getMonthGrid(view.year, view.month));
|
|
81
|
+
const monthLabel = $derived(`${MONTHS[view.month]} ${view.year}`);
|
|
82
|
+
|
|
83
|
+
const startMs = $derived(start ? dateStrToMs(start) : null);
|
|
84
|
+
const endMs = $derived(end ? dateStrToMs(end) : null);
|
|
85
|
+
const minMax = $derived(
|
|
86
|
+
startMs != null && endMs != null
|
|
87
|
+
? (startMs <= endMs ? [startMs, endMs] as const : [endMs, startMs] as const)
|
|
88
|
+
: [null, null] as const
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
function isInRange(dateStr: string): boolean {
|
|
92
|
+
const [minMs, maxMs] = minMax;
|
|
93
|
+
if (minMs == null || maxMs == null) return false;
|
|
94
|
+
const ms = dateStrToMs(dateStr);
|
|
95
|
+
if (ms == null) return false;
|
|
96
|
+
if (start === dateStr || end === dateStr) return false;
|
|
97
|
+
return ms >= minMs && ms <= maxMs;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function prevMonth() {
|
|
101
|
+
view = view.month === 0 ? { year: view.year - 1, month: 11 } : { year: view.year, month: view.month - 1 };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function nextMonth() {
|
|
105
|
+
view = view.month === 11 ? { year: view.year + 1, month: 0 } : { year: view.year, month: view.month + 1 };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function onDayClick(dateStr: string) {
|
|
109
|
+
if (controlledStart !== undefined && controlledEnd !== undefined) return;
|
|
110
|
+
if (start === null || (start !== null && end !== null)) {
|
|
111
|
+
internalStart = dateStr;
|
|
112
|
+
internalEnd = null;
|
|
113
|
+
} else {
|
|
114
|
+
const s = dateStrToMs(start!);
|
|
115
|
+
const e = dateStrToMs(dateStr);
|
|
116
|
+
if (s != null && e != null && e < s) {
|
|
117
|
+
internalEnd = start;
|
|
118
|
+
internalStart = dateStr;
|
|
119
|
+
onRangeSelect?.(dateStr, start!);
|
|
120
|
+
} else {
|
|
121
|
+
internalEnd = dateStr;
|
|
122
|
+
onRangeSelect?.(start!, dateStr);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
</script>
|
|
127
|
+
|
|
128
|
+
<div class="calendar calendar--range {className}" {id} role="group" aria-label={label} data-range-calendar>
|
|
129
|
+
<div class="calendar__header">
|
|
130
|
+
<button type="button" class="calendar__prev" aria-label="Previous month" onclick={prevMonth}>
|
|
131
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m15 18-6-6 6-6"/></svg>
|
|
132
|
+
</button>
|
|
133
|
+
<div class="calendar__month" aria-live="polite">{monthLabel}</div>
|
|
134
|
+
<button type="button" class="calendar__next" aria-label="Next month" onclick={nextMonth}>
|
|
135
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 18 6-6-6-6"/></svg>
|
|
136
|
+
</button>
|
|
137
|
+
</div>
|
|
138
|
+
<div class="calendar__grid" role="grid" aria-label={monthLabel}>
|
|
139
|
+
<div class="calendar__row" role="row">
|
|
140
|
+
{#each WEEKDAYS as day}
|
|
141
|
+
<div class="calendar__weekday" role="columnheader" aria-label={day}>{day}</div>
|
|
142
|
+
{/each}
|
|
143
|
+
</div>
|
|
144
|
+
{#each weeks as week}
|
|
145
|
+
<div class="calendar__row" role="row">
|
|
146
|
+
{#each week as cell}
|
|
147
|
+
{@const dateStr = toYYYYMMDD(cell.year, cell.month, cell.day)}
|
|
148
|
+
<div role="gridcell">
|
|
149
|
+
<button
|
|
150
|
+
type="button"
|
|
151
|
+
class="calendar__day
|
|
152
|
+
{!cell.currentMonth ? ' calendar__day--other-month' : ''}
|
|
153
|
+
{dateStr === todayStr ? ' calendar__day--today' : ''}
|
|
154
|
+
{start === dateStr ? ' calendar__day--range-start' : ''}
|
|
155
|
+
{end === dateStr ? ' calendar__day--range-end' : ''}
|
|
156
|
+
{isInRange(dateStr) ? ' calendar__day--in-range' : ''}"
|
|
157
|
+
aria-label="Choose {MONTHS[cell.month]} {cell.day}, {cell.year}"
|
|
158
|
+
onclick={() => onDayClick(dateStr)}
|
|
159
|
+
>
|
|
160
|
+
{cell.day}
|
|
161
|
+
</button>
|
|
162
|
+
</div>
|
|
163
|
+
{/each}
|
|
164
|
+
</div>
|
|
165
|
+
{/each}
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
Design system · Vanilla · Astro · Svelte
|
|
16
16
|
</pre>
|
|
17
17
|
|
|
18
|
-
SvelteKit project with Rizzo CSS. Scaffolded with `npx rizzo-css init` when you chose **Create new** and Svelte, then **Landing**, **Docs**, **Dashboard**, or **Full**. **Full** = clone of the docs site. **Landing** / **Docs** / **Dashboard** = base + component picker (all
|
|
18
|
+
SvelteKit project with Rizzo CSS. Scaffolded with `npx rizzo-css init` when you chose **Create new** and Svelte, then **Landing**, **Docs**, **Dashboard**, or **Full**. **Full** = clone of the docs site. **Landing** / **Docs** / **Dashboard** = base + component picker (all 53 or pick). Same template choice for **Add to existing** (`npx rizzo-css add`).
|
|
19
19
|
|
|
20
20
|
## Setup
|
|
21
21
|
|
package/scaffold/svelte/index.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { default as Button } from './Button.svelte';
|
|
|
6
6
|
export { default as Badge } from './Badge.svelte';
|
|
7
7
|
export { default as Card } from './Card.svelte';
|
|
8
8
|
export { default as Calendar } from './Calendar.svelte';
|
|
9
|
+
export { default as RangeCalendar } from './RangeCalendar.svelte';
|
|
9
10
|
export { default as Carousel } from './Carousel.svelte';
|
|
10
11
|
export { default as Dashboard } from './Dashboard.svelte';
|
|
11
12
|
export { default as Divider } from './Divider.svelte';
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
Design system · Vanilla · Astro · Svelte
|
|
16
16
|
</pre>
|
|
17
17
|
|
|
18
|
-
SvelteKit project with Rizzo CSS. Scaffolded with `npx rizzo-css init` when you chose **Create new** and Svelte, then **Full** template. **Full** = clone of the Rizzo docs site (no component picker). **Landing** / **Docs** / **Dashboard** = base + component picker (all
|
|
18
|
+
SvelteKit project with Rizzo CSS. Scaffolded with `npx rizzo-css init` when you chose **Create new** and Svelte, then **Full** template. **Full** = clone of the Rizzo docs site (no component picker). **Landing** / **Docs** / **Dashboard** = base + component picker (all 53 or pick). Same template choice for **Add to existing** (`npx rizzo-css add`).
|
|
19
19
|
|
|
20
20
|
## Setup
|
|
21
21
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
Design system · Vanilla · Astro · Svelte
|
|
16
16
|
</pre>
|
|
17
17
|
|
|
18
|
-
This project was scaffolded with `npx rizzo-css init` when you chose **Create new project** and Vanilla JS, then **Landing**, **Docs**, **Dashboard**, or **Full**. **Full** = clone of the docs site. **Landing** / **Docs** / **Dashboard** = CSS, fonts, icons, sfx + component picker (all
|
|
18
|
+
This project was scaffolded with `npx rizzo-css init` when you chose **Create new project** and Vanilla JS, then **Landing**, **Docs**, **Dashboard**, or **Full**. **Full** = clone of the docs site. **Landing** / **Docs** / **Dashboard** = CSS, fonts, icons, sfx + component picker (all 53 or pick); Landing adds hero/features; Docs adds sidebar + sample doc; Dashboard adds sidebar + stats/table. **Add to existing project** (or `npx rizzo-css add`) uses the **same template choice**; you must add the stylesheet `<link>` yourself (CLI prints the exact tag).
|
|
19
19
|
|
|
20
20
|
## First-time setup
|
|
21
21
|
|
|
@@ -28,7 +28,7 @@ If you prefer to load CSS from a CDN instead of the local file, replace the `<li
|
|
|
28
28
|
- `<link rel="stylesheet" href="https://unpkg.com/rizzo-css@latest/dist/rizzo.min.css" />`
|
|
29
29
|
- Or jsDelivr: `https://cdn.jsdelivr.net/npm/rizzo-css@latest/dist/rizzo.min.css`
|
|
30
30
|
|
|
31
|
-
(Replace `@latest` with a specific version, e.g. `@0.0.
|
|
31
|
+
(Replace `@latest` with a specific version, e.g. `@0.0.69`, in production.)
|
|
32
32
|
|
|
33
33
|
The CLI replaces placeholders in `index.html` (e.g. `{{DATA_THEME}}`, `{{TITLE}}`) when you run `rizzo-css init`. The theme selected during init is used on first load when you have no saved preference in the browser.
|
|
34
34
|
|
|
@@ -438,6 +438,30 @@
|
|
|
438
438
|
|
|
439
439
|
|
|
440
440
|
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
|
|
441
465
|
|
|
442
466
|
|
|
443
467
|
|
|
@@ -731,6 +755,30 @@
|
|
|
731
755
|
|
|
732
756
|
|
|
733
757
|
|
|
758
|
+
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
|
|
762
|
+
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
|
|
772
|
+
|
|
773
|
+
|
|
774
|
+
|
|
775
|
+
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
|
|
780
|
+
|
|
781
|
+
|
|
734
782
|
|
|
735
783
|
|
|
736
784
|
|
|
@@ -438,6 +438,30 @@
|
|
|
438
438
|
|
|
439
439
|
|
|
440
440
|
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
|
|
441
465
|
|
|
442
466
|
|
|
443
467
|
|
|
@@ -731,6 +755,30 @@
|
|
|
731
755
|
|
|
732
756
|
|
|
733
757
|
|
|
758
|
+
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
|
|
762
|
+
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
|
|
772
|
+
|
|
773
|
+
|
|
774
|
+
|
|
775
|
+
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
|
|
780
|
+
|
|
781
|
+
|
|
734
782
|
|
|
735
783
|
|
|
736
784
|
|
|
@@ -438,6 +438,30 @@
|
|
|
438
438
|
|
|
439
439
|
|
|
440
440
|
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
|
|
441
465
|
|
|
442
466
|
|
|
443
467
|
|
|
@@ -731,6 +755,30 @@
|
|
|
731
755
|
|
|
732
756
|
|
|
733
757
|
|
|
758
|
+
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
|
|
762
|
+
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
|
|
772
|
+
|
|
773
|
+
|
|
774
|
+
|
|
775
|
+
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
|
|
780
|
+
|
|
781
|
+
|
|
734
782
|
|
|
735
783
|
|
|
736
784
|
|