@mrintel/villain-ui 0.2.2 → 0.6.3

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.
Files changed (159) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +3490 -1296
  3. package/dist/components/buttons/Button.svelte +27 -0
  4. package/dist/components/buttons/Button.svelte.d.ts +14 -0
  5. package/dist/components/buttons/ButtonGroup.svelte +17 -0
  6. package/dist/components/buttons/ButtonGroup.svelte.d.ts +8 -0
  7. package/dist/components/buttons/FloatingActionButton.svelte +20 -0
  8. package/dist/components/buttons/FloatingActionButton.svelte.d.ts +12 -0
  9. package/dist/components/buttons/IconButton.svelte +23 -0
  10. package/dist/components/buttons/IconButton.svelte.d.ts +14 -0
  11. package/dist/components/buttons/LinkButton.svelte +24 -0
  12. package/dist/components/buttons/LinkButton.svelte.d.ts +15 -0
  13. package/dist/components/buttons/buttonClasses.d.ts +15 -0
  14. package/dist/components/buttons/buttonClasses.js +15 -0
  15. package/dist/components/buttons/index.d.ts +5 -0
  16. package/dist/components/buttons/index.js +5 -0
  17. package/dist/components/cards/Card.svelte +60 -0
  18. package/dist/components/cards/Card.svelte.d.ts +15 -0
  19. package/dist/components/cards/Container.svelte +17 -0
  20. package/dist/components/cards/Container.svelte.d.ts +10 -0
  21. package/dist/components/cards/Divider.svelte +36 -0
  22. package/dist/components/cards/Divider.svelte.d.ts +11 -0
  23. package/dist/components/cards/Grid.svelte +55 -0
  24. package/dist/components/cards/Grid.svelte.d.ts +10 -0
  25. package/dist/components/cards/Panel.svelte +18 -0
  26. package/dist/components/cards/Panel.svelte.d.ts +11 -0
  27. package/dist/components/cards/SectionHeader.svelte +24 -0
  28. package/dist/components/cards/SectionHeader.svelte.d.ts +12 -0
  29. package/dist/components/cards/index.d.ts +6 -0
  30. package/dist/components/cards/index.js +6 -0
  31. package/dist/components/data/Avatar.svelte +48 -0
  32. package/dist/components/data/Avatar.svelte.d.ts +10 -0
  33. package/dist/components/data/Badge.svelte +45 -0
  34. package/dist/components/data/Badge.svelte.d.ts +14 -0
  35. package/dist/components/data/CalendarGrid.svelte +433 -0
  36. package/dist/components/data/CalendarGrid.svelte.d.ts +25 -0
  37. package/dist/components/data/CalendarGrid.types.d.ts +7 -0
  38. package/dist/components/data/CalendarGrid.types.js +1 -0
  39. package/dist/components/data/CodeBlock.svelte +119 -0
  40. package/dist/components/data/CodeBlock.svelte.d.ts +40 -0
  41. package/dist/components/data/List.svelte +87 -0
  42. package/dist/components/data/List.svelte.d.ts +15 -0
  43. package/dist/components/data/Pagination.svelte +121 -0
  44. package/dist/components/data/Pagination.svelte.d.ts +14 -0
  45. package/dist/components/data/Sparkline.svelte +117 -0
  46. package/dist/components/data/Sparkline.svelte.d.ts +43 -0
  47. package/dist/components/data/Stat.svelte +92 -0
  48. package/dist/components/data/Stat.svelte.d.ts +11 -0
  49. package/dist/components/data/Table.svelte +443 -0
  50. package/dist/components/data/Table.svelte.d.ts +30 -0
  51. package/dist/components/data/Table.types.d.ts +14 -0
  52. package/dist/components/data/Table.types.js +1 -0
  53. package/dist/components/data/Tag.svelte +51 -0
  54. package/dist/components/data/Tag.svelte.d.ts +13 -0
  55. package/dist/components/data/index.d.ts +12 -0
  56. package/dist/components/data/index.js +10 -0
  57. package/dist/components/forms/Checkbox.svelte +39 -0
  58. package/dist/components/forms/Checkbox.svelte.d.ts +12 -0
  59. package/dist/components/forms/DatePicker.svelte +61 -0
  60. package/dist/components/forms/DatePicker.svelte.d.ts +15 -0
  61. package/dist/components/forms/DateTimePicker.svelte +63 -0
  62. package/dist/components/forms/DateTimePicker.svelte.d.ts +16 -0
  63. package/dist/components/forms/FileUpload.svelte +136 -0
  64. package/dist/components/forms/FileUpload.svelte.d.ts +23 -0
  65. package/dist/components/forms/Input.svelte +282 -0
  66. package/dist/components/forms/Input.svelte.d.ts +19 -0
  67. package/dist/components/forms/InputGroup.svelte +7 -0
  68. package/dist/components/forms/InputGroup.svelte.d.ts +20 -0
  69. package/dist/components/forms/RadioGroup.svelte +77 -0
  70. package/dist/components/forms/RadioGroup.svelte.d.ts +17 -0
  71. package/dist/components/forms/RangeSlider.svelte +90 -0
  72. package/dist/components/forms/RangeSlider.svelte.d.ts +14 -0
  73. package/dist/components/forms/Select.svelte +106 -0
  74. package/dist/components/forms/Select.svelte.d.ts +18 -0
  75. package/dist/components/forms/Switch.svelte +44 -0
  76. package/dist/components/forms/Switch.svelte.d.ts +12 -0
  77. package/dist/components/forms/Textarea.svelte +52 -0
  78. package/dist/components/forms/Textarea.svelte.d.ts +15 -0
  79. package/dist/components/forms/TimePicker.svelte +63 -0
  80. package/dist/components/forms/TimePicker.svelte.d.ts +16 -0
  81. package/dist/components/forms/formClasses.d.ts +3 -0
  82. package/dist/components/forms/formClasses.js +3 -0
  83. package/dist/components/forms/index.d.ts +12 -0
  84. package/dist/components/forms/index.js +12 -0
  85. package/dist/components/navigation/Breadcrumbs.svelte +56 -0
  86. package/dist/components/navigation/Breadcrumbs.svelte.d.ts +15 -0
  87. package/dist/components/navigation/ContextMenu.svelte +133 -0
  88. package/dist/components/navigation/ContextMenu.svelte.d.ts +18 -0
  89. package/dist/components/navigation/DropdownMenu.svelte +139 -0
  90. package/dist/components/navigation/DropdownMenu.svelte.d.ts +17 -0
  91. package/dist/components/navigation/Menu.svelte +72 -0
  92. package/dist/components/navigation/Menu.svelte.d.ts +15 -0
  93. package/dist/components/navigation/Navbar.svelte +111 -0
  94. package/dist/components/navigation/Navbar.svelte.d.ts +15 -0
  95. package/dist/components/navigation/Sidebar.svelte +236 -0
  96. package/dist/components/navigation/Sidebar.svelte.d.ts +12 -0
  97. package/dist/components/navigation/Tabs.svelte +86 -0
  98. package/dist/components/navigation/Tabs.svelte.d.ts +19 -0
  99. package/dist/components/navigation/index.d.ts +7 -0
  100. package/dist/components/navigation/index.js +7 -0
  101. package/dist/components/overlays/Alert.svelte +81 -0
  102. package/dist/components/overlays/Alert.svelte.d.ts +15 -0
  103. package/dist/components/overlays/CommandPalette.svelte +182 -0
  104. package/dist/components/overlays/CommandPalette.svelte.d.ts +16 -0
  105. package/dist/components/overlays/Drawer.svelte +158 -0
  106. package/dist/components/overlays/Drawer.svelte.d.ts +16 -0
  107. package/dist/components/overlays/Dropdown.svelte +62 -0
  108. package/dist/components/overlays/Dropdown.svelte.d.ts +11 -0
  109. package/dist/components/overlays/Modal.svelte +125 -0
  110. package/dist/components/overlays/Modal.svelte.d.ts +15 -0
  111. package/dist/components/overlays/Popover.svelte +106 -0
  112. package/dist/components/overlays/Popover.svelte.d.ts +11 -0
  113. package/dist/components/overlays/ProgressBar.svelte +29 -0
  114. package/dist/components/overlays/ProgressBar.svelte.d.ts +10 -0
  115. package/dist/components/overlays/SkeletonLoader.svelte +66 -0
  116. package/dist/components/overlays/SkeletonLoader.svelte.d.ts +9 -0
  117. package/dist/components/overlays/Spinner.svelte +33 -0
  118. package/dist/components/overlays/Spinner.svelte.d.ts +7 -0
  119. package/dist/components/overlays/Toast.svelte +111 -0
  120. package/dist/components/overlays/Toast.svelte.d.ts +16 -0
  121. package/dist/components/overlays/Tooltip.svelte +94 -0
  122. package/dist/components/overlays/Tooltip.svelte.d.ts +12 -0
  123. package/dist/components/overlays/index.d.ts +11 -0
  124. package/dist/components/overlays/index.js +11 -0
  125. package/dist/components/typography/Code.svelte +10 -0
  126. package/dist/components/typography/Code.svelte.d.ts +6 -0
  127. package/dist/components/typography/Heading.svelte +15 -0
  128. package/dist/components/typography/Heading.svelte.d.ts +10 -0
  129. package/dist/components/typography/Text.svelte +21 -0
  130. package/dist/components/typography/Text.svelte.d.ts +10 -0
  131. package/dist/components/typography/index.d.ts +3 -0
  132. package/dist/components/typography/index.js +3 -0
  133. package/dist/components/utilities/Accordion.svelte +54 -0
  134. package/dist/components/utilities/Accordion.svelte.d.ts +17 -0
  135. package/dist/components/utilities/Carousel.svelte +124 -0
  136. package/dist/components/utilities/Carousel.svelte.d.ts +16 -0
  137. package/dist/components/utilities/Collapse.svelte +46 -0
  138. package/dist/components/utilities/Collapse.svelte.d.ts +10 -0
  139. package/dist/components/utilities/Hero.svelte +42 -0
  140. package/dist/components/utilities/Hero.svelte.d.ts +10 -0
  141. package/dist/components/utilities/Portal.svelte +47 -0
  142. package/dist/components/utilities/Portal.svelte.d.ts +21 -0
  143. package/dist/components/utilities/ScrollArea.svelte +33 -0
  144. package/dist/components/utilities/ScrollArea.svelte.d.ts +8 -0
  145. package/dist/components/utilities/SystemConsole.svelte +310 -0
  146. package/dist/components/utilities/SystemConsole.svelte.d.ts +20 -0
  147. package/dist/components/utilities/SystemInterface.svelte +726 -0
  148. package/dist/components/utilities/SystemInterface.svelte.d.ts +19 -0
  149. package/dist/components/utilities/index.d.ts +9 -0
  150. package/dist/components/utilities/index.js +8 -0
  151. package/dist/components/utilities/utilities.types.d.ts +46 -0
  152. package/dist/components/utilities/utilities.types.js +4 -0
  153. package/dist/index.d.ts +60 -175
  154. package/dist/index.js +24 -4560
  155. package/dist/lib/internal/id.d.ts +12 -0
  156. package/dist/lib/internal/id.js +15 -0
  157. package/dist/theme.css +2821 -0
  158. package/package.json +83 -75
  159. package/dist/index.css +0 -1
@@ -0,0 +1,14 @@
1
+ interface Props {
2
+ variant?: 'default' | 'success' | 'warning' | 'error' | 'accent' | 'feature';
3
+ size?: 'sm' | 'md';
4
+ icon?: import('svelte').Snippet;
5
+ children?: import('svelte').Snippet;
6
+ hover?: boolean;
7
+ glow?: boolean;
8
+ statusDot?: boolean;
9
+ uppercase?: boolean;
10
+ class?: string;
11
+ }
12
+ declare const Badge: import("svelte").Component<Props, {}, "">;
13
+ type Badge = ReturnType<typeof Badge>;
14
+ export default Badge;
@@ -0,0 +1,433 @@
1
+ <script lang="ts">let { month = $bindable(new Date()), events = [], selectedDate = $bindable(undefined), onDateSelect, onMonthChange, renderCell, weekStartsOn = 0, showWeekNumbers = false, highlightToday = true, class: className = '' } = $props();
2
+ const today = new Date();
3
+ today.setHours(0, 0, 0, 0);
4
+ // Get calendar days for the current month
5
+ const calendarDays = $derived.by(() => {
6
+ const year = month.getFullYear();
7
+ const monthIndex = month.getMonth();
8
+ const firstDay = new Date(year, monthIndex, 1);
9
+ const lastDay = new Date(year, monthIndex + 1, 0);
10
+ const startingDayOfWeek = firstDay.getDay();
11
+ const daysInMonth = lastDay.getDate();
12
+ // Adjust for week start day
13
+ const offset = weekStartsOn === 1 ? (startingDayOfWeek === 0 ? 6 : startingDayOfWeek - 1) : startingDayOfWeek;
14
+ const days = [];
15
+ // Previous month days
16
+ const prevMonthLastDay = new Date(year, monthIndex, 0);
17
+ for (let i = offset - 1; i >= 0; i--) {
18
+ days.push(new Date(year, monthIndex - 1, prevMonthLastDay.getDate() - i));
19
+ }
20
+ // Current month days
21
+ for (let i = 1; i <= daysInMonth; i++) {
22
+ days.push(new Date(year, monthIndex, i));
23
+ }
24
+ // Next month days to fill grid
25
+ const remainingCells = 42 - days.length; // 6 weeks * 7 days
26
+ for (let i = 1; i <= remainingCells; i++) {
27
+ days.push(new Date(year, monthIndex + 1, i));
28
+ }
29
+ return days;
30
+ });
31
+ // Group events by date string
32
+ const eventsByDate = $derived.by(() => {
33
+ const map = new Map();
34
+ events.forEach((event) => {
35
+ const eventDate = typeof event.date === 'string' ? new Date(event.date) : event.date;
36
+ const key = eventDate.toISOString().split('T')[0];
37
+ if (!map.has(key)) {
38
+ map.set(key, []);
39
+ }
40
+ map.get(key).push(event);
41
+ });
42
+ return map;
43
+ });
44
+ function isSameDay(date1, date2) {
45
+ return (date1.getFullYear() === date2.getFullYear() &&
46
+ date1.getMonth() === date2.getMonth() &&
47
+ date1.getDate() === date2.getDate());
48
+ }
49
+ function isSameMonth(date) {
50
+ return date.getMonth() === month.getMonth() && date.getFullYear() === month.getFullYear();
51
+ }
52
+ function getCellData(date) {
53
+ const dateKey = date.toISOString().split('T')[0];
54
+ const cellEvents = eventsByDate.get(dateKey) || [];
55
+ return {
56
+ date,
57
+ events: cellEvents,
58
+ isToday: highlightToday && isSameDay(date, today),
59
+ isSelected: selectedDate ? isSameDay(date, selectedDate) : false,
60
+ isCurrentMonth: isSameMonth(date),
61
+ isEmpty: cellEvents.length === 0 && !isSameMonth(date)
62
+ };
63
+ }
64
+ function handleDateClick(date, isCurrentMonth) {
65
+ if (!isCurrentMonth) {
66
+ // Navigate to that month
67
+ const newMonth = new Date(date);
68
+ month = newMonth;
69
+ onMonthChange?.(newMonth);
70
+ }
71
+ selectedDate = date;
72
+ onDateSelect?.(date);
73
+ }
74
+ function handleKeyDown(event, date, index) {
75
+ const days = calendarDays;
76
+ let newIndex = index;
77
+ switch (event.key) {
78
+ case 'ArrowLeft':
79
+ event.preventDefault();
80
+ newIndex = index > 0 ? index - 1 : index;
81
+ break;
82
+ case 'ArrowRight':
83
+ event.preventDefault();
84
+ newIndex = index < days.length - 1 ? index + 1 : index;
85
+ break;
86
+ case 'ArrowUp':
87
+ event.preventDefault();
88
+ newIndex = index >= 7 ? index - 7 : index;
89
+ break;
90
+ case 'ArrowDown':
91
+ event.preventDefault();
92
+ newIndex = index + 7 < days.length ? index + 7 : index;
93
+ break;
94
+ case 'Home':
95
+ event.preventDefault();
96
+ newIndex = Math.floor(index / 7) * 7;
97
+ break;
98
+ case 'End':
99
+ event.preventDefault();
100
+ newIndex = Math.floor(index / 7) * 7 + 6;
101
+ break;
102
+ case 'Enter':
103
+ case ' ':
104
+ event.preventDefault();
105
+ handleDateClick(date, isSameMonth(date));
106
+ return;
107
+ default:
108
+ return;
109
+ }
110
+ if (newIndex !== index) {
111
+ const newDate = days[newIndex];
112
+ requestAnimationFrame(() => {
113
+ const cell = document.querySelector(`[data-date="${newDate.toISOString()}"]`);
114
+ cell?.focus();
115
+ });
116
+ }
117
+ }
118
+ function previousMonth() {
119
+ const newMonth = new Date(month.getFullYear(), month.getMonth() - 1, 1);
120
+ month = newMonth;
121
+ onMonthChange?.(newMonth);
122
+ }
123
+ function nextMonth() {
124
+ const newMonth = new Date(month.getFullYear(), month.getMonth() + 1, 1);
125
+ month = newMonth;
126
+ onMonthChange?.(newMonth);
127
+ }
128
+ const weekDayNames = $derived(weekStartsOn === 1
129
+ ? ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
130
+ : ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']);
131
+ const monthNames = [
132
+ 'January',
133
+ 'February',
134
+ 'March',
135
+ 'April',
136
+ 'May',
137
+ 'June',
138
+ 'July',
139
+ 'August',
140
+ 'September',
141
+ 'October',
142
+ 'November',
143
+ 'December'
144
+ ];
145
+ const currentMonthYear = $derived(`${monthNames[month.getMonth()]} ${month.getFullYear()}`);
146
+ const variantColors = {
147
+ default: 'var(--color-base-3)',
148
+ success: 'var(--color-success)',
149
+ warning: 'var(--color-warning)',
150
+ error: 'var(--color-error)',
151
+ accent: 'var(--color-accent)'
152
+ };
153
+ export {};
154
+ </script>
155
+
156
+ <div class="calendar-grid {className}">
157
+ <!-- Header with month navigation -->
158
+ <div class="calendar-header">
159
+ <button
160
+ type="button"
161
+ onclick={previousMonth}
162
+ class="nav-button"
163
+ aria-label="Previous month"
164
+ >
165
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
166
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
167
+ </svg>
168
+ </button>
169
+
170
+ <h2 class="month-title">{currentMonthYear}</h2>
171
+
172
+ <button
173
+ type="button"
174
+ onclick={nextMonth}
175
+ class="nav-button"
176
+ aria-label="Next month"
177
+ >
178
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
179
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
180
+ </svg>
181
+ </button>
182
+ </div>
183
+
184
+ <!-- Calendar grid -->
185
+ <div role="grid" aria-label="Calendar" class="calendar-body">
186
+ <!-- Week day headers -->
187
+ <div role="row" class="week-header">
188
+ {#if showWeekNumbers}
189
+ <div class="week-number-header"></div>
190
+ {/if}
191
+ {#each weekDayNames as day}
192
+ <div role="columnheader" class="day-header">
193
+ {day}
194
+ </div>
195
+ {/each}
196
+ </div>
197
+
198
+ <!-- Date cells -->
199
+ {#each { length: 6 } as _, weekIndex}
200
+ <div role="row" class="calendar-week">
201
+ {#if showWeekNumbers}
202
+ <div class="week-number">W{weekIndex + 1}</div>
203
+ {/if}
204
+ {#each calendarDays.slice(weekIndex * 7, (weekIndex + 1) * 7) as date, dayIndex}
205
+ {@const cellData = getCellData(date)}
206
+ {@const globalIndex = weekIndex * 7 + dayIndex}
207
+ <button
208
+ role="gridcell"
209
+ type="button"
210
+ data-date={date.toISOString()}
211
+ class="calendar-cell"
212
+ class:current-month={cellData.isCurrentMonth}
213
+ class:other-month={!cellData.isCurrentMonth}
214
+ class:is-today={cellData.isToday}
215
+ class:is-selected={cellData.isSelected}
216
+ class:has-events={cellData.events.length > 0}
217
+ tabindex={globalIndex === 0 ? 0 : -1}
218
+ onclick={() => handleDateClick(date, cellData.isCurrentMonth)}
219
+ onkeydown={(e) => handleKeyDown(e, date, globalIndex)}
220
+ aria-label="{date.getDate()} {monthNames[date.getMonth()]} {date.getFullYear()}"
221
+ aria-selected={cellData.isSelected}
222
+ >
223
+ {#if renderCell}
224
+ {@render renderCell(cellData)}
225
+ {:else}
226
+ <div class="cell-content">
227
+ <span class="day-number">{date.getDate()}</span>
228
+ {#if cellData.events.length > 0}
229
+ <div class="event-indicators">
230
+ {#each cellData.events.slice(0, 3) as event}
231
+ <span
232
+ class="event-dot"
233
+ style="background-color: {variantColors[event.variant || 'default']}"
234
+ title={event.title}
235
+ ></span>
236
+ {/each}
237
+ {#if cellData.events.length > 3}
238
+ <span class="event-more">+{cellData.events.length - 3}</span>
239
+ {/if}
240
+ </div>
241
+ {/if}
242
+ </div>
243
+ {/if}
244
+ </button>
245
+ {/each}
246
+ </div>
247
+ {/each}
248
+ </div>
249
+ </div>
250
+
251
+ <style>
252
+ .calendar-grid {
253
+ width: 100%;
254
+ font-family: var(--font-body);
255
+ color: var(--color-text);
256
+ }
257
+
258
+ .calendar-header {
259
+ display: flex;
260
+ align-items: center;
261
+ justify-content: space-between;
262
+ padding: 1.5rem;
263
+ border-bottom: 1px solid var(--color-border);
264
+ }
265
+
266
+ .month-title {
267
+ font-family: var(--font-heading);
268
+ font-size: 1.5rem;
269
+ font-weight: 700;
270
+ color: var(--color-text);
271
+ margin: 0;
272
+ }
273
+
274
+ .nav-button {
275
+ display: flex;
276
+ align-items: center;
277
+ justify-content: center;
278
+ width: 2.5rem;
279
+ height: 2.5rem;
280
+ background: transparent;
281
+ border: 1px solid var(--color-border);
282
+ border-radius: var(--radius-md);
283
+ color: var(--color-text-soft);
284
+ cursor: pointer;
285
+ transition: all var(--duration-200) var(--ease-sharp);
286
+ }
287
+
288
+ .nav-button:hover {
289
+ background: var(--color-base-3);
290
+ color: var(--color-accent);
291
+ border-color: var(--color-accent);
292
+ }
293
+
294
+ .nav-button:active {
295
+ transform: scale(0.95);
296
+ }
297
+
298
+ .calendar-body {
299
+ padding: 1rem;
300
+ }
301
+
302
+ .week-header {
303
+ display: grid;
304
+ grid-template-columns: repeat(7, 1fr);
305
+ gap: 0.5rem;
306
+ margin-bottom: 0.5rem;
307
+ }
308
+
309
+ .week-header.with-numbers {
310
+ grid-template-columns: 2.5rem repeat(7, 1fr);
311
+ }
312
+
313
+ .day-header {
314
+ text-align: center;
315
+ font-size: 0.875rem;
316
+ font-weight: 600;
317
+ color: var(--color-text-soft);
318
+ text-transform: uppercase;
319
+ letter-spacing: 0.05em;
320
+ padding: 0.5rem;
321
+ }
322
+
323
+ .calendar-week {
324
+ display: grid;
325
+ grid-template-columns: repeat(7, 1fr);
326
+ gap: 0.5rem;
327
+ margin-bottom: 0.5rem;
328
+ }
329
+
330
+ .week-number-header,
331
+ .week-number {
332
+ display: flex;
333
+ align-items: center;
334
+ justify-content: center;
335
+ font-size: 0.75rem;
336
+ font-weight: 600;
337
+ color: var(--color-text-muted);
338
+ }
339
+
340
+ .calendar-cell {
341
+ position: relative;
342
+ aspect-ratio: 1;
343
+ background: var(--color-base-1);
344
+ border: 1px solid var(--color-border);
345
+ border-radius: var(--radius-md);
346
+ padding: 0.5rem;
347
+ cursor: pointer;
348
+ transition: all var(--duration-200) var(--ease-sharp);
349
+ font-family: inherit;
350
+ color: inherit;
351
+ }
352
+
353
+ .calendar-cell:hover {
354
+ background: var(--color-base-2);
355
+ border-color: var(--color-accent-soft);
356
+ transform: translateY(-2px);
357
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
358
+ }
359
+
360
+ .calendar-cell:focus-visible {
361
+ outline: 2px solid var(--color-accent);
362
+ outline-offset: 2px;
363
+ z-index: 1;
364
+ }
365
+
366
+ .calendar-cell.other-month {
367
+ opacity: 0.4;
368
+ }
369
+
370
+ .calendar-cell.is-today {
371
+ background: var(--color-accent-overlay-10);
372
+ border-color: var(--color-accent);
373
+ }
374
+
375
+ .calendar-cell.is-selected {
376
+ background: var(--color-accent);
377
+ border-color: var(--color-accent);
378
+ color: var(--color-text);
379
+ box-shadow: 0 0 20px var(--color-accent-glow);
380
+ }
381
+
382
+ .calendar-cell.is-selected .day-number {
383
+ color: var(--color-base-0);
384
+ font-weight: 700;
385
+ }
386
+
387
+ .cell-content {
388
+ display: flex;
389
+ flex-direction: column;
390
+ align-items: center;
391
+ justify-content: space-between;
392
+ height: 100%;
393
+ gap: 0.25rem;
394
+ }
395
+
396
+ .day-number {
397
+ font-size: 0.875rem;
398
+ font-weight: 600;
399
+ color: var(--color-text);
400
+ }
401
+
402
+ .event-indicators {
403
+ display: flex;
404
+ gap: 0.25rem;
405
+ align-items: center;
406
+ flex-wrap: wrap;
407
+ justify-content: center;
408
+ }
409
+
410
+ .event-dot {
411
+ width: 0.375rem;
412
+ height: 0.375rem;
413
+ border-radius: 50%;
414
+ background: var(--color-accent);
415
+ box-shadow: 0 0 6px currentColor;
416
+ }
417
+
418
+ .event-more {
419
+ font-size: 0.625rem;
420
+ color: var(--color-text-muted);
421
+ font-weight: 600;
422
+ }
423
+
424
+ /* Accessibility: Reduced motion */
425
+ @media (prefers-reduced-motion: reduce) {
426
+ .calendar-cell {
427
+ transition: none;
428
+ }
429
+
430
+ .calendar-cell:hover {
431
+ transform: none;
432
+ }
433
+ }</style>
@@ -0,0 +1,25 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { CalendarEvent } from './CalendarGrid.types';
3
+ interface CellData {
4
+ date: Date;
5
+ events: CalendarEvent[];
6
+ isToday: boolean;
7
+ isSelected: boolean;
8
+ isCurrentMonth: boolean;
9
+ isEmpty: boolean;
10
+ }
11
+ interface Props {
12
+ month?: Date;
13
+ events?: CalendarEvent[];
14
+ selectedDate?: Date;
15
+ onDateSelect?: (date: Date) => void;
16
+ onMonthChange?: (date: Date) => void;
17
+ renderCell?: Snippet<[CellData]>;
18
+ weekStartsOn?: 0 | 1;
19
+ showWeekNumbers?: boolean;
20
+ highlightToday?: boolean;
21
+ class?: string;
22
+ }
23
+ declare const CalendarGrid: import("svelte").Component<Props, {}, "month" | "selectedDate">;
24
+ type CalendarGrid = ReturnType<typeof CalendarGrid>;
25
+ export default CalendarGrid;
@@ -0,0 +1,7 @@
1
+ export interface CalendarEvent {
2
+ id: string;
3
+ date: Date | string;
4
+ title?: string;
5
+ variant?: 'default' | 'success' | 'warning' | 'error' | 'accent';
6
+ metadata?: any;
7
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,119 @@
1
+ <script lang="ts">"use strict";
2
+ let { filename, showLineNumbers = false, lineCount = 0, highlightLines = [], showCopy = true, code, children } = $props();
3
+ let codeContainer;
4
+ let copied = $state(false);
5
+ async function copyCode() {
6
+ try {
7
+ const textToCopy = code || codeContainer?.textContent || '';
8
+ await navigator.clipboard.writeText(textToCopy);
9
+ copied = true;
10
+ setTimeout(() => {
11
+ copied = false;
12
+ }, 2000);
13
+ }
14
+ catch (err) {
15
+ console.error('Failed to copy code:', err);
16
+ }
17
+ }
18
+ </script>
19
+
20
+ <div class="panel-raised rounded-[var(--radius-lg)] overflow-hidden relative">
21
+ {#if filename || showCopy}
22
+ <div
23
+ class="px-4 py-2 border-b border-border flex items-center justify-between"
24
+ style="background: var(--color-base-2); color: var(--color-text-soft); font-family: var(--font-mono); font-size: 0.875rem;"
25
+ >
26
+ <span>{filename || ''}</span>
27
+ {#if showCopy}
28
+ <button
29
+ onclick={copyCode}
30
+ class="copy-button px-3 py-1 rounded-sm transition-all text-xs"
31
+ aria-label="Copy code"
32
+ >
33
+ {copied ? 'Copied!' : 'Copy'}
34
+ </button>
35
+ {/if}
36
+ </div>
37
+ {/if} <div
38
+ bind:this={codeContainer}
39
+ class="p-4 overflow-x-auto"
40
+ style="background: var(--color-base-1); font-family: var(--font-mono); font-size: 0.875rem; line-height: 1.6;"
41
+ >
42
+ {#if showLineNumbers}
43
+ <div class="flex">
44
+ <div
45
+ class="pr-4 border-r border-border select-none"
46
+ style="color: var(--color-text-muted);"
47
+ >
48
+ {#each Array.from({ length: lineCount }, (_, i) => i + 1) as lineNum}
49
+ <div
50
+ class:highlighted={highlightLines.includes(lineNum)}
51
+ style={highlightLines.includes(lineNum)
52
+ ? 'background: var(--color-accent-overlay-10);'
53
+ : ''}
54
+ >
55
+ {lineNum}
56
+ </div>
57
+ {/each}
58
+ </div>
59
+ <div class="pl-4 flex-1">
60
+ {@render children?.()}
61
+ </div>
62
+ </div>
63
+ {:else}
64
+ <div>
65
+ {@render children?.()}
66
+ </div>
67
+ {/if}
68
+ </div>
69
+ </div>
70
+
71
+ <style>
72
+ /* Custom scrollbar styling */
73
+ div::-webkit-scrollbar {
74
+ height: 8px;
75
+ }
76
+
77
+ div::-webkit-scrollbar-track {
78
+ background: var(--color-base-1);
79
+ }
80
+
81
+ div::-webkit-scrollbar-thumb {
82
+ background: var(--color-accent);
83
+ border-radius: var(--radius-sm);
84
+ }
85
+
86
+ div::-webkit-scrollbar-thumb:hover {
87
+ background: var(--color-accent-soft);
88
+ }
89
+
90
+ /* Copy button styling */
91
+ .copy-button {
92
+ background: var(--color-base-3);
93
+ color: var(--color-text-soft);
94
+ border: 1px solid var(--color-border);
95
+ font-size: 0.75rem;
96
+ }
97
+
98
+ .copy-button:hover {
99
+ background: var(--color-accent);
100
+ color: var(--color-text);
101
+ border-color: var(--color-accent);
102
+ }
103
+
104
+ /* Highlight gutter numbers */
105
+ .highlighted {
106
+ background: var(--color-accent-overlay-10);
107
+ }
108
+
109
+ /*
110
+ * Consumer-provided line highlighting:
111
+ * Consumers should apply the `.line` class to each code line element
112
+ * and the `.highlighted` class to lines that should be highlighted.
113
+ * This ensures consistent styling with the component's luxury aesthetic.
114
+ */
115
+ :global(.line.highlighted) {
116
+ background: var(--color-accent-overlay-10);
117
+ display: inline-block;
118
+ width: 100%;
119
+ }</style>
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Props for the CodeBlock component.
3
+ *
4
+ * This is a presentational component that provides layout and styling for syntax-highlighted code.
5
+ * Consumers are responsible for providing pre-highlighted HTML via the default slot and ensuring
6
+ * the content is properly sanitized to prevent XSS attacks.
7
+ */
8
+ interface Props {
9
+ /**
10
+ * Optional filename to display in the header.
11
+ */
12
+ filename?: string;
13
+ /**
14
+ * Whether to show line numbers in the gutter.
15
+ */
16
+ showLineNumbers?: boolean;
17
+ /**
18
+ * Total number of lines in the code. Required when showLineNumbers is true.
19
+ */
20
+ lineCount?: number;
21
+ /**
22
+ * Array of line numbers (1-indexed) to highlight in the gutter.
23
+ */
24
+ highlightLines?: number[];
25
+ /**
26
+ * Whether to show the copy button. Default: true.
27
+ */
28
+ showCopy?: boolean;
29
+ /**
30
+ * Raw code text for copying. If not provided, copy functionality attempts to extract text from the rendered content.
31
+ */
32
+ code?: string;
33
+ /**
34
+ * Slot for pre-highlighted code HTML.
35
+ */
36
+ children?: import('svelte').Snippet;
37
+ }
38
+ declare const CodeBlock: import("svelte").Component<Props, {}, "">;
39
+ type CodeBlock = ReturnType<typeof CodeBlock>;
40
+ export default CodeBlock;