@softwareone/spi-sv5-library 1.1.0 → 1.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.
Files changed (38) hide show
  1. package/dist/Accordion/Accordion.svelte +89 -0
  2. package/dist/Accordion/Accordion.svelte.d.ts +9 -0
  3. package/dist/Card/Card.svelte +5 -21
  4. package/dist/Card/Card.svelte.d.ts +1 -2
  5. package/dist/ErrorPage/ErrorPage.svelte +1 -0
  6. package/dist/Form/Input/Input.svelte +11 -31
  7. package/dist/Form/Input/Input.svelte.d.ts +2 -0
  8. package/dist/Form/Label.svelte +52 -0
  9. package/dist/Form/Label.svelte.d.ts +10 -0
  10. package/dist/Form/Select/Select.svelte +459 -0
  11. package/dist/Form/Select/Select.svelte.d.ts +23 -0
  12. package/dist/Form/Select/selectState.svelte.d.ts +4 -0
  13. package/dist/Form/Select/selectState.svelte.js +1 -0
  14. package/dist/Form/TextArea/TextArea.svelte +5 -24
  15. package/dist/Form/TextArea/TextArea.svelte.d.ts +1 -0
  16. package/dist/HighlightPanel/HighlightPanel.svelte +4 -0
  17. package/dist/Home/Home.svelte +116 -0
  18. package/dist/Home/Home.svelte.d.ts +8 -0
  19. package/dist/Home/homeState.svelte.d.ts +4 -0
  20. package/dist/Home/homeState.svelte.js +1 -0
  21. package/dist/Modal/Modal.svelte +46 -47
  22. package/dist/Modal/modalState.svelte.d.ts +1 -1
  23. package/dist/Notification/Notification.svelte +69 -0
  24. package/dist/Notification/Notification.svelte.d.ts +4 -0
  25. package/dist/Notification/notificationState.svelte.d.ts +9 -0
  26. package/dist/Notification/notificationState.svelte.js +1 -0
  27. package/dist/ProgressPage/ProgressPage.svelte +95 -0
  28. package/dist/ProgressPage/ProgressPage.svelte.d.ts +11 -0
  29. package/dist/ProgressWizard/ProgressWizard.svelte +1 -2
  30. package/dist/Search/Search.svelte +12 -5
  31. package/dist/Spinner/Spinner.svelte +23 -34
  32. package/dist/Spinner/Spinner.svelte.d.ts +3 -2
  33. package/dist/Tabs/Tabs.svelte +3 -0
  34. package/dist/Toast/Toast.svelte +0 -5
  35. package/dist/Tooltip/Tooltip.svelte +0 -2
  36. package/dist/index.d.ts +8 -1
  37. package/dist/index.js +6 -1
  38. package/package.json +1 -1
@@ -0,0 +1,459 @@
1
+ <script lang="ts">
2
+ import { onMount, type Snippet } from 'svelte';
3
+ import type { Action } from 'svelte/action';
4
+
5
+ import { Search, type SelectOption } from '../../index.js';
6
+ import Label from '../Label.svelte';
7
+
8
+ interface SelectProps {
9
+ options: string[] | SelectOption[];
10
+ label?: string;
11
+ placeholder?: string;
12
+ required?: boolean;
13
+ optional?: boolean;
14
+ searchable?: boolean;
15
+ clearable?: boolean;
16
+ multiple?: boolean;
17
+ closeAfterSelect?: boolean;
18
+ readonly?: boolean;
19
+ disableValidationColor?: boolean;
20
+ value?: string | string[] | null;
21
+ error?: string | string[];
22
+ customSelection?: Snippet<[option: SelectOption]>;
23
+ customOption?: Snippet<[option: SelectOption]>;
24
+ infoTooltip?: string;
25
+ }
26
+
27
+ let {
28
+ options,
29
+ label,
30
+ placeholder,
31
+ required = false,
32
+ optional = false,
33
+ searchable = false,
34
+ clearable = false,
35
+ multiple = false,
36
+ closeAfterSelect = false,
37
+ readonly = false,
38
+ disableValidationColor = false,
39
+ value = $bindable(),
40
+ error,
41
+ customSelection,
42
+ customOption,
43
+ infoTooltip
44
+ }: SelectProps = $props();
45
+
46
+ let dropdownElement: HTMLElement;
47
+
48
+ const isStringArray = (items: string[] | SelectOption[]): items is string[] =>
49
+ typeof items[0] === 'string';
50
+
51
+ const originalOptions: SelectOption[] = isStringArray(options)
52
+ ? options.map((value) => ({ label: value, value }))
53
+ : options;
54
+
55
+ let searchText = $state('');
56
+ let showInTopPosition = $state(false);
57
+ let showListOptions = $state(false);
58
+ let filteredOptions = $state(originalOptions);
59
+ let selectedOptions = $state<SelectOption[]>([]);
60
+ let selectedOption = $state<SelectOption | undefined>();
61
+
62
+ const isInvalid: boolean = $derived(!!error && !disableValidationColor);
63
+ const isValid: boolean = $derived(!isInvalid && (!!value || optional) && !disableValidationColor);
64
+ const noOptionsAvailable: boolean = $derived(
65
+ options.length === 0 || (multiple && selectedOptions?.length === options.length)
66
+ );
67
+
68
+ const generateSelectOption = (value: string): SelectOption => ({ label: value, value });
69
+ const generateMultiselectValue = (option: SelectOption): string => option.value;
70
+
71
+ const canBeVisible = (option: SelectOption): boolean =>
72
+ !selectedOptions.some((selectedOption) => selectedOption.value === option.value);
73
+
74
+ const onCloseAfterSelect = () => {
75
+ if (closeAfterSelect && showListOptions) {
76
+ showListOptions = false;
77
+ }
78
+ };
79
+
80
+ const onSelectOption = (option: SelectOption) => {
81
+ if (multiple) {
82
+ selectedOptions = [...selectedOptions, option];
83
+ value = selectedOptions.map(generateMultiselectValue);
84
+ } else {
85
+ selectedOption = option;
86
+ value = option.value;
87
+ }
88
+ onCloseAfterSelect();
89
+ };
90
+
91
+ const onClearAll = () => {
92
+ if (multiple) {
93
+ selectedOptions = [];
94
+ value = [];
95
+ } else {
96
+ selectedOption = undefined;
97
+ value = '';
98
+ }
99
+
100
+ onCloseAfterSelect();
101
+ };
102
+
103
+ const onRemoveSelectedOption = (index: number) => {
104
+ const newSelectedOptions = [...selectedOptions];
105
+ newSelectedOptions.splice(index, 1);
106
+ selectedOptions = newSelectedOptions;
107
+ value = selectedOptions.map(generateMultiselectValue);
108
+ };
109
+
110
+ const onInputSearch = () => {
111
+ const text = searchText.toLowerCase();
112
+
113
+ filteredOptions = text
114
+ ? originalOptions.filter((option) => option.label.toLowerCase().includes(text))
115
+ : originalOptions;
116
+ };
117
+
118
+ const onClearSearch = () => {
119
+ filteredOptions = originalOptions;
120
+ };
121
+
122
+ const onHandleClickOutside = (event: MouseEvent) => {
123
+ if (showListOptions && dropdownElement && !dropdownElement.contains(event.target as Node)) {
124
+ showListOptions = false;
125
+ }
126
+ };
127
+
128
+ const activeOptionScroll: Action<HTMLElement, boolean> = (node, isActive) => {
129
+ $effect(() => {
130
+ if (isActive) {
131
+ node.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
132
+ }
133
+ });
134
+ };
135
+
136
+ const autoDirection: Action = () => {
137
+ $effect(() => {
138
+ const rect = dropdownElement.getBoundingClientRect();
139
+ const viewportHeight = window.innerHeight;
140
+ const footer = 300;
141
+
142
+ showInTopPosition = rect.bottom + footer > viewportHeight;
143
+ });
144
+ };
145
+
146
+ onMount(() => {
147
+ if (!value) return;
148
+
149
+ if (multiple && Array.isArray(value)) {
150
+ selectedOptions = value.map(generateSelectOption);
151
+ } else if (!multiple && typeof value === 'string') {
152
+ selectedOption = generateSelectOption(value);
153
+ }
154
+ });
155
+ </script>
156
+
157
+ <svelte:window on:click={onHandleClickOutside} />
158
+
159
+ <div class="form-container">
160
+ {#if label}
161
+ <Label {label} {required} {optional} {infoTooltip} />
162
+ {/if}
163
+
164
+ <div
165
+ class={['dropdown', readonly ? 'readonly' : [isInvalid && 'invalid', isValid && 'valid']]}
166
+ bind:this={dropdownElement}
167
+ >
168
+ <section
169
+ class="dropdown-container"
170
+ role="button"
171
+ tabindex="0"
172
+ onclick={() => (showListOptions = !showListOptions)}
173
+ onkeypress={() => {}}
174
+ >
175
+ <div class="dropdown-container-selected-options">
176
+ {#if selectedOption || selectedOptions.length}
177
+ {#if multiple}
178
+ {#each selectedOptions as selectedOption, index}
179
+ {@render selectedOptionTemplate(selectedOption, index)}
180
+ {/each}
181
+ {:else if customSelection}
182
+ <p>
183
+ {@render customSelection({
184
+ label: selectedOption?.label,
185
+ value: selectedOption?.value
186
+ } as SelectOption)}
187
+ </p>
188
+ {:else}
189
+ <p>{selectedOption?.label}</p>
190
+ {/if}
191
+ {:else}
192
+ <p class="placeholder">{placeholder}</p>
193
+ {/if}
194
+ </div>
195
+
196
+ {#if clearable && (selectedOption || selectedOptions.length)}
197
+ {@render removeButton(onClearAll)}
198
+ {/if}
199
+ </section>
200
+
201
+ {#if showListOptions}
202
+ <section class="dropdown-list" class:upwards={showInTopPosition} use:autoDirection>
203
+ {#if noOptionsAvailable}
204
+ <p class="dropdown-list-no-options-message">No options</p>
205
+ {:else}
206
+ {#if searchable}
207
+ <Search
208
+ placeholder="Search"
209
+ bind:value={searchText}
210
+ oninput={onInputSearch}
211
+ onclear={onClearSearch}
212
+ />
213
+ {/if}
214
+ <ul class="dropdown-list-options-container">
215
+ {#each filteredOptions as filteredOption}
216
+ {@const isVisible = multiple ? canBeVisible(filteredOption) : true}
217
+ {@const isActive = !multiple && filteredOption.value === selectedOption?.value}
218
+
219
+ {#if isVisible}
220
+ <li
221
+ class={['dropdown-list-option', isActive && 'active']}
222
+ use:activeOptionScroll={!multiple && isActive}
223
+ >
224
+ {@render dropdownOptionTemplate(filteredOption)}
225
+ </li>
226
+ {/if}
227
+ {/each}
228
+ </ul>
229
+ {/if}
230
+ </section>
231
+ {/if}
232
+ </div>
233
+ {#if isInvalid}
234
+ <p class="form-message-error">
235
+ {Array.isArray(error) ? error[0] : error}
236
+ </p>
237
+ {/if}
238
+ </div>
239
+
240
+ {#snippet dropdownOptionTemplate(option: SelectOption)}
241
+ <button
242
+ type="button"
243
+ onclick={(event) => {
244
+ event.stopPropagation();
245
+ onSelectOption(option);
246
+ }}
247
+ >
248
+ {#if customOption}
249
+ {@render customOption(option)}
250
+ {:else}
251
+ {option.label}
252
+ {/if}
253
+ </button>
254
+ {/snippet}
255
+
256
+ {#snippet selectedOptionTemplate(option: SelectOption, index: number)}
257
+ <div class="dropdown-container-selected-option">
258
+ {#if customSelection}
259
+ <p>{@render customSelection(option)}</p>
260
+ {:else}
261
+ <p>{option.label}</p>
262
+ {/if}
263
+
264
+ {@render removeButton(() => onRemoveSelectedOption(index))}
265
+ </div>
266
+ {/snippet}
267
+
268
+ {#snippet removeButton(event: VoidFunction)}
269
+ <button
270
+ type="button"
271
+ class="clear-button"
272
+ onclick={(e) => {
273
+ e.stopPropagation();
274
+ event();
275
+ }}
276
+ >
277
+
278
+ </button>
279
+ {/snippet}
280
+
281
+ <style>
282
+ .form-container {
283
+ --primary-color: #472aff;
284
+ --white: #fff;
285
+ --black: #000;
286
+ --error: #dc2626;
287
+ --success: #10b981;
288
+ --info-1: #eaecff;
289
+ --gray-1: #f4f6f8;
290
+ --gray-2: #e0e5e8;
291
+ --gray-3: #aeb1b9;
292
+ --gray-4: #6b7180;
293
+ --border: 1px solid var(--gray-3);
294
+
295
+ display: flex;
296
+ flex-direction: column;
297
+ width: 100%;
298
+ gap: 8px;
299
+ font-size: 14px;
300
+ }
301
+
302
+ .form-container > .form-message-error {
303
+ font-size: 12px;
304
+ color: var(--error);
305
+ }
306
+
307
+ .dropdown {
308
+ position: relative;
309
+ border: var(--border);
310
+ border-radius: 8px;
311
+ background: transparent;
312
+ transition:
313
+ border-color 0.2s ease-in-out,
314
+ box-shadow 0.2s ease-in-out;
315
+ }
316
+
317
+ .dropdown.readonly {
318
+ cursor: not-allowed;
319
+
320
+ > .dropdown-container {
321
+ pointer-events: none;
322
+ background: var(--gray-2);
323
+ }
324
+ }
325
+
326
+ .dropdown:not(.readonly, .invalid, .valid):hover {
327
+ border: 1px solid var(--primary-color);
328
+ }
329
+
330
+ .dropdown:not(.readonly, .invalid, .valid):focus-within {
331
+ border: 1px solid var(--primary-color);
332
+ box-shadow: 0 0 0 3px rgba(149, 155, 255, 0.3);
333
+ }
334
+
335
+ .dropdown.valid {
336
+ border: 1px solid var(--success);
337
+ }
338
+
339
+ .dropdown.valid:focus-within {
340
+ box-shadow: 0px 0px 0px 3px rgba(16, 185, 129, 0.15);
341
+ }
342
+
343
+ .dropdown.invalid {
344
+ border-color: var(--error);
345
+ }
346
+
347
+ .dropdown.invalid:focus-within {
348
+ box-shadow: 0px 0px 0px 3px rgba(220, 38, 38, 0.2);
349
+ }
350
+
351
+ .dropdown > .dropdown-container {
352
+ display: grid;
353
+ grid-template-columns: 1fr auto;
354
+ min-height: 42px;
355
+ padding: 8px;
356
+ gap: 8px;
357
+ align-items: center;
358
+ cursor: pointer;
359
+ border: none;
360
+ border-radius: 8px;
361
+ background: var(--white);
362
+ }
363
+
364
+ .dropdown > .dropdown-container > .dropdown-container-selected-options {
365
+ display: flex;
366
+ flex-wrap: wrap;
367
+ max-height: 250px;
368
+ gap: 8px;
369
+ align-items: center;
370
+ overflow-y: auto;
371
+
372
+ > .placeholder {
373
+ color: var(--gray-4);
374
+ opacity: 1;
375
+ }
376
+
377
+ > .dropdown-container-selected-option {
378
+ display: grid;
379
+ grid-template-columns: auto auto;
380
+ padding: 8px;
381
+ gap: 8px;
382
+ align-items: center;
383
+ cursor: default;
384
+ border-radius: 8px;
385
+ background: var(--gray-1);
386
+ }
387
+ }
388
+
389
+ .dropdown > .dropdown-list {
390
+ position: absolute;
391
+ display: flex;
392
+ flex-direction: column;
393
+ z-index: 100;
394
+ width: 100%;
395
+ padding: 8px;
396
+ margin-top: 8px;
397
+ gap: 8px;
398
+ border-radius: 8px;
399
+ background: var(--white);
400
+ box-shadow:
401
+ 0px 4px 5px rgba(51, 56, 64, 0.15),
402
+ 0px 1px 3px rgba(51, 56, 64, 0.2),
403
+ 0px 1px 16px rgba(51, 56, 64, 0.1);
404
+
405
+ > .dropdown-list-no-options-message {
406
+ text-align: center;
407
+ color: var(--gray-4);
408
+ }
409
+ }
410
+
411
+ .dropdown > .dropdown-list.upwards {
412
+ top: auto;
413
+ transform-origin: bottom;
414
+ bottom: 100%;
415
+ margin-bottom: 8px;
416
+ }
417
+
418
+ .dropdown > .dropdown-list > .dropdown-list-options-container {
419
+ display: flex;
420
+ flex-direction: column;
421
+ max-height: 200px;
422
+ gap: 8px;
423
+ overflow-y: auto;
424
+
425
+ .dropdown-list-option {
426
+ > button {
427
+ display: flex;
428
+ align-items: center;
429
+ text-align: left;
430
+ width: 100%;
431
+ min-height: 40px;
432
+ padding: 0px 8px;
433
+ cursor: pointer;
434
+ border: none;
435
+ background: transparent;
436
+ }
437
+ }
438
+
439
+ .dropdown-list-option:not(.active) > button:hover {
440
+ background: var(--gray-1);
441
+ }
442
+
443
+ .dropdown-list-option.active {
444
+ background: var(--info-1);
445
+ }
446
+ }
447
+
448
+ .clear-button {
449
+ border: none;
450
+ color: var(--gray-4);
451
+ background: transparent;
452
+ transition: color 0.2s ease-in-out;
453
+ }
454
+
455
+ .clear-button:hover {
456
+ cursor: pointer;
457
+ color: var(--black);
458
+ }
459
+ </style>
@@ -0,0 +1,23 @@
1
+ import { type Snippet } from 'svelte';
2
+ import { type SelectOption } from '../../index.js';
3
+ interface SelectProps {
4
+ options: string[] | SelectOption[];
5
+ label?: string;
6
+ placeholder?: string;
7
+ required?: boolean;
8
+ optional?: boolean;
9
+ searchable?: boolean;
10
+ clearable?: boolean;
11
+ multiple?: boolean;
12
+ closeAfterSelect?: boolean;
13
+ readonly?: boolean;
14
+ disableValidationColor?: boolean;
15
+ value?: string | string[] | null;
16
+ error?: string | string[];
17
+ customSelection?: Snippet<[option: SelectOption]>;
18
+ customOption?: Snippet<[option: SelectOption]>;
19
+ infoTooltip?: string;
20
+ }
21
+ declare const Select: import("svelte").Component<SelectProps, {}, "value">;
22
+ type Select = ReturnType<typeof Select>;
23
+ export default Select;
@@ -0,0 +1,4 @@
1
+ export interface SelectOption {
2
+ value: string;
3
+ label: string;
4
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import type { HTMLTextareaAttributes } from 'svelte/elements';
3
+ import Label from '../Label.svelte';
3
4
 
4
5
  interface TextAreaProps extends Omit<HTMLTextareaAttributes, 'value'> {
5
6
  label?: string;
@@ -9,17 +10,20 @@
9
10
  description?: string;
10
11
  maximumCharactersAllowed?: number;
11
12
  resize?: boolean;
13
+ infoTooltip?: string;
12
14
  }
13
15
 
14
16
  let {
15
17
  label,
16
18
  value = $bindable(''),
17
19
  optional = false,
20
+ required = false,
18
21
  error,
19
22
  description,
20
23
  maximumCharactersAllowed,
21
24
  resize = false,
22
25
  id,
26
+ infoTooltip,
23
27
  ...props
24
28
  }: TextAreaProps = $props();
25
29
 
@@ -36,16 +40,7 @@
36
40
  </script>
37
41
 
38
42
  <div class="form-container">
39
- {#if label}
40
- <div class="form-label-container">
41
- <label for={textareaId}>{label}</label>
42
- {#if props.required}
43
- <span class="form-label-required">Required</span>
44
- {:else if optional}
45
- <span class="form-label-optional">Optional</span>
46
- {/if}
47
- </div>
48
- {/if}
43
+ <Label {label} {id} {optional} {required} {infoTooltip} />
49
44
 
50
45
  <div class={['form-textarea-wrapper', isInvalid && 'error', isValid && 'success']}>
51
46
  <textarea
@@ -94,20 +89,6 @@
94
89
  line-height: 20px;
95
90
  }
96
91
 
97
- .form-label-container {
98
- display: flex;
99
- gap: 8px;
100
- font-weight: 500;
101
- }
102
-
103
- .form-label-optional {
104
- color: #6b7180;
105
- }
106
-
107
- .form-label-required {
108
- color: #dc2626;
109
- }
110
-
111
92
  .form-message {
112
93
  font-size: 12px;
113
94
  }
@@ -7,6 +7,7 @@ interface TextAreaProps extends Omit<HTMLTextareaAttributes, 'value'> {
7
7
  description?: string;
8
8
  maximumCharactersAllowed?: number;
9
9
  resize?: boolean;
10
+ infoTooltip?: string;
10
11
  }
11
12
  declare const TextArea: import("svelte").Component<TextAreaProps, {}, "value">;
12
13
  type TextArea = ReturnType<typeof TextArea>;
@@ -65,6 +65,10 @@
65
65
  line-height: 20px;
66
66
  }
67
67
 
68
+ h2 {
69
+ font-weight: bold;
70
+ }
71
+
68
72
  .text-description {
69
73
  color: #6b7180;
70
74
  }
@@ -0,0 +1,116 @@
1
+ <script lang="ts">
2
+ import type { HomeItem } from '../index.js';
3
+
4
+ interface HomeProps {
5
+ title: string;
6
+ homeItems: HomeItem[];
7
+ }
8
+
9
+ let { title, homeItems }: HomeProps = $props();
10
+
11
+ const hasSingleItem: boolean = homeItems.length === 1;
12
+ const hasManyItems: boolean = homeItems.length > 1;
13
+ </script>
14
+
15
+ <h1 class={['home-title', hasSingleItem && 'centered']}>
16
+ {title}
17
+ </h1>
18
+
19
+ <section class={['home-container', hasSingleItem && 'centered', hasManyItems && 'grid']}>
20
+ {#each homeItems as homeItem}
21
+ <a href={homeItem.url} class="home-item">
22
+ <span>
23
+ <img src={homeItem.icon} alt={homeItem.text} />
24
+ </span>
25
+ <div>
26
+ <h2>{homeItem.text}</h2>
27
+ <p>{homeItem.detail}</p>
28
+ </div>
29
+ </a>
30
+ {/each}
31
+ </section>
32
+
33
+ <style>
34
+ .home-title {
35
+ padding-bottom: 16px;
36
+ font-size: 18px;
37
+ line-height: 1.55;
38
+ font-weight: 600;
39
+ }
40
+
41
+ .home-title.centered {
42
+ display: flex;
43
+ justify-content: center;
44
+ }
45
+
46
+ .home-container {
47
+ --black-1: #434952;
48
+ --black-2: #273444;
49
+ --white: #fff;
50
+ }
51
+
52
+ .home-container.centered {
53
+ display: flex;
54
+ flex-direction: column;
55
+ align-items: center;
56
+ }
57
+
58
+ .home-container.grid {
59
+ display: grid;
60
+ gap: 24px;
61
+
62
+ @media (width >= 640px) {
63
+ grid-template-columns: repeat(1, minmax(0, 1fr));
64
+ }
65
+
66
+ @media (width >= 1024px) {
67
+ grid-template-columns: repeat(2, minmax(0, 1fr));
68
+ }
69
+
70
+ @media (width >= 1536px) {
71
+ grid-template-columns: repeat(3, minmax(0, 1fr));
72
+ }
73
+ }
74
+
75
+ .home-container > .home-item {
76
+ display: flex;
77
+ max-height: 150px;
78
+ max-width: 770px;
79
+ gap: 16px;
80
+ padding: 12px;
81
+ border-radius: 16px;
82
+ background: var(--black-1);
83
+ transition: background 0.2s ease-in-out;
84
+
85
+ > span {
86
+ display: flex;
87
+ align-items: center;
88
+
89
+ > img {
90
+ width: 40px;
91
+ height: 40px;
92
+ filter: invert(100%);
93
+ }
94
+ }
95
+
96
+ > div {
97
+ color: var(--white);
98
+
99
+ > h2 {
100
+ padding-bottom: 8px;
101
+ font-size: 16px;
102
+ line-height: 1.5;
103
+ font-weight: 600;
104
+ }
105
+
106
+ > p {
107
+ font-size: 14px;
108
+ line-height: 1.42;
109
+ }
110
+ }
111
+ }
112
+
113
+ .home-container > .home-item:hover {
114
+ background: var(--black-2);
115
+ }
116
+ </style>
@@ -0,0 +1,8 @@
1
+ import type { HomeItem } from '../index.js';
2
+ interface HomeProps {
3
+ title: string;
4
+ homeItems: HomeItem[];
5
+ }
6
+ declare const Home: import("svelte").Component<HomeProps, {}, "">;
7
+ type Home = ReturnType<typeof Home>;
8
+ export default Home;
@@ -0,0 +1,4 @@
1
+ import { type MenuItem } from '../index.js';
2
+ export type HomeItem = Omit<MenuItem, 'children'> & {
3
+ detail?: string;
4
+ };
@@ -0,0 +1 @@
1
+ import {} from '../index.js';