@stacksjs/components 0.2.110 → 0.2.112
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/dist/{Sidebar-4hn7vw4n.stx → Sidebar-bg47fqmq.stx} +100 -3
- package/dist/{SidebarItem-gtrcw4ky.stx → SidebarItem-9rvbwhxr.stx} +11 -7
- package/dist/index.js +15 -12
- package/dist/ui/sidebar/themes.d.ts +26 -3
- package/package.json +4 -3
- package/src/components/CodeBlock.stx +54 -0
- package/src/components/Footer.stx +66 -0
- package/src/components/Hero.stx +25 -0
- package/src/components/Installation.stx +37 -0
- package/src/components/index.ts +4 -0
- package/src/composables/index.ts +4 -0
- package/src/composables/useCopyCode.ts +73 -0
- package/src/composables/useDarkMode.ts +100 -0
- package/src/composables/useSEO.ts +230 -0
- package/src/composables/utilities/index.ts +7 -0
- package/src/composables/utilities/useClickOutside.ts +72 -0
- package/src/composables/utilities/useFocusTrap.ts +159 -0
- package/src/composables/utilities/useKeyboard.ts +124 -0
- package/src/composables/utilities/useLocalStorage.ts +132 -0
- package/src/composables/utilities/useMediaQuery.ts +118 -0
- package/src/index.ts +99 -0
- package/src/stx.d.ts +4 -0
- package/src/ui/accordion/Accordion.stx +146 -0
- package/src/ui/accordion/AccordionItem.stx +37 -0
- package/src/ui/accordion/index.ts +47 -0
- package/src/ui/audio/Audio.stx +50 -0
- package/src/ui/audio/README.md +41 -0
- package/src/ui/audio/index.ts +13 -0
- package/src/ui/auth/Login.stx +161 -0
- package/src/ui/auth/README.md +142 -0
- package/src/ui/auth/Signup.stx +159 -0
- package/src/ui/auth/TwoFactorChallenge.stx +111 -0
- package/src/ui/auth/index.ts +32 -0
- package/src/ui/avatar/Avatar.stx +77 -0
- package/src/ui/avatar/index.ts +12 -0
- package/src/ui/badge/Badge.stx +62 -0
- package/src/ui/badge/index.ts +10 -0
- package/src/ui/breadcrumb/Breadcrumb.stx +79 -0
- package/src/ui/breadcrumb/index.ts +15 -0
- package/src/ui/button/Button.stx +74 -0
- package/src/ui/button/README.md +80 -0
- package/src/ui/button/index.ts +85 -0
- package/src/ui/calendar/Calendar.stx +189 -0
- package/src/ui/calendar/README.md +254 -0
- package/src/ui/calendar/index.ts +14 -0
- package/src/ui/card/Card.stx +68 -0
- package/src/ui/card/index.ts +13 -0
- package/src/ui/checkbox/Checkbox.stx +86 -0
- package/src/ui/checkbox/index.ts +16 -0
- package/src/ui/combobox/Combobox.stx +96 -0
- package/src/ui/combobox/ComboboxButton.stx +25 -0
- package/src/ui/combobox/ComboboxInput.stx +32 -0
- package/src/ui/combobox/ComboboxOption.stx +49 -0
- package/src/ui/combobox/ComboboxOptions.stx +16 -0
- package/src/ui/combobox/README.md +150 -0
- package/src/ui/combobox/index.ts +40 -0
- package/src/ui/command-palette/CommandPalette.stx +81 -0
- package/src/ui/command-palette/CommandPaletteItem.stx +27 -0
- package/src/ui/command-palette/README.md +42 -0
- package/src/ui/command-palette/index.ts +15 -0
- package/src/ui/dialog/Dialog.stx +41 -0
- package/src/ui/dialog/DialogBackdrop.stx +9 -0
- package/src/ui/dialog/DialogDescription.stx +11 -0
- package/src/ui/dialog/DialogPanel.stx +16 -0
- package/src/ui/dialog/DialogTitle.stx +11 -0
- package/src/ui/dialog/README.md +121 -0
- package/src/ui/dialog/index.ts +32 -0
- package/src/ui/drawer/Drawer.stx +120 -0
- package/src/ui/drawer/README.md +90 -0
- package/src/ui/drawer/index.ts +9 -0
- package/src/ui/dropdown/Dropdown.stx +82 -0
- package/src/ui/dropdown/DropdownButton.stx +29 -0
- package/src/ui/dropdown/DropdownItem.stx +35 -0
- package/src/ui/dropdown/DropdownItems.stx +18 -0
- package/src/ui/dropdown/README.md +114 -0
- package/src/ui/dropdown/index.ts +29 -0
- package/src/ui/form/Form.stx +95 -0
- package/src/ui/form/index.ts +67 -0
- package/src/ui/heatmap/Heatmap.stx +294 -0
- package/src/ui/image/Image.stx +165 -0
- package/src/ui/image/README.md +164 -0
- package/src/ui/image/index.ts +22 -0
- package/src/ui/input/EmailInput.stx +30 -0
- package/src/ui/input/NumberInput.stx +126 -0
- package/src/ui/input/PasswordInput.stx +143 -0
- package/src/ui/input/SearchInput.stx +44 -0
- package/src/ui/input/TextInput.stx +132 -0
- package/src/ui/input/index.ts +180 -0
- package/src/ui/listbox/Listbox.stx +101 -0
- package/src/ui/listbox/ListboxButton.stx +28 -0
- package/src/ui/listbox/ListboxLabel.stx +11 -0
- package/src/ui/listbox/ListboxOption.stx +49 -0
- package/src/ui/listbox/ListboxOptions.stx +16 -0
- package/src/ui/listbox/README.md +135 -0
- package/src/ui/listbox/index.ts +39 -0
- package/src/ui/navigator/Navigator.stx +113 -0
- package/src/ui/navigator/README.md +352 -0
- package/src/ui/navigator/index.ts +20 -0
- package/src/ui/notification/Notification.stx +117 -0
- package/src/ui/notification/README.md +114 -0
- package/src/ui/notification/index.ts +12 -0
- package/src/ui/pagination/Pagination.stx +150 -0
- package/src/ui/pagination/index.ts +11 -0
- package/src/ui/payment/Checkout.stx +31 -0
- package/src/ui/payment/DefaultPaymentMethod.stx +62 -0
- package/src/ui/payment/PaymentMethods.stx +104 -0
- package/src/ui/payment/README.md +345 -0
- package/src/ui/payment/SubscriptionCheckout.stx +323 -0
- package/src/ui/payment/index.ts +59 -0
- package/src/ui/popover/Popover.stx +60 -0
- package/src/ui/popover/PopoverButton.stx +29 -0
- package/src/ui/popover/PopoverPanel.stx +23 -0
- package/src/ui/popover/README.md +91 -0
- package/src/ui/popover/index.ts +22 -0
- package/src/ui/portal/Portal.stx +57 -0
- package/src/ui/portal/index.ts +6 -0
- package/src/ui/progress/Progress.stx +131 -0
- package/src/ui/progress/index.ts +12 -0
- package/src/ui/radio/Radio.stx +77 -0
- package/src/ui/radio/index.ts +15 -0
- package/src/ui/radio-group/README.md +139 -0
- package/src/ui/radio-group/RadioGroup.stx +60 -0
- package/src/ui/radio-group/RadioGroupDescription.stx +11 -0
- package/src/ui/radio-group/RadioGroupLabel.stx +11 -0
- package/src/ui/radio-group/RadioGroupOption.stx +58 -0
- package/src/ui/radio-group/index.ts +30 -0
- package/src/ui/select/README.md +180 -0
- package/src/ui/select/Select.stx +82 -0
- package/src/ui/select/index.ts +21 -0
- package/src/ui/sidebar/Sidebar.stx +573 -0
- package/src/ui/sidebar/SidebarFooter.stx +71 -0
- package/src/ui/sidebar/SidebarHeader.stx +103 -0
- package/src/ui/sidebar/SidebarItem.stx +90 -0
- package/src/ui/sidebar/SidebarSection.stx +83 -0
- package/src/ui/sidebar/index.ts +146 -0
- package/src/ui/sidebar/themes.ts +288 -0
- package/src/ui/skeleton/Skeleton.stx +48 -0
- package/src/ui/skeleton/index.ts +11 -0
- package/src/ui/spinner/Spinner.stx +109 -0
- package/src/ui/spinner/index.ts +9 -0
- package/src/ui/stepper/README.md +36 -0
- package/src/ui/stepper/Stepper.stx +17 -0
- package/src/ui/stepper/StepperStep.stx +57 -0
- package/src/ui/stepper/index.ts +19 -0
- package/src/ui/storage/README.md +193 -0
- package/src/ui/storage/index.ts +347 -0
- package/src/ui/switch/README.md +114 -0
- package/src/ui/switch/Switch.stx +72 -0
- package/src/ui/switch/index.ts +10 -0
- package/src/ui/table/README.md +39 -0
- package/src/ui/table/Table.stx +14 -0
- package/src/ui/table/TableBody.stx +10 -0
- package/src/ui/table/TableCell.stx +10 -0
- package/src/ui/table/TableHead.stx +10 -0
- package/src/ui/table/TableHeader.stx +20 -0
- package/src/ui/table/TableRow.stx +11 -0
- package/src/ui/table/index.ts +35 -0
- package/src/ui/tabs/TabPanel.stx +25 -0
- package/src/ui/tabs/Tabs.stx +202 -0
- package/src/ui/tabs/index.ts +50 -0
- package/src/ui/teleport/Teleport.stx +65 -0
- package/src/ui/teleport/index.ts +7 -0
- package/src/ui/textarea/Textarea.stx +108 -0
- package/src/ui/textarea/index.ts +20 -0
- package/src/ui/tooltip/Tooltip.stx +71 -0
- package/src/ui/tooltip/index.ts +10 -0
- package/src/ui/transition/README.md +30 -0
- package/src/ui/transition/Transition.stx +102 -0
- package/src/ui/transition/index.ts +25 -0
- package/src/ui/video/README.md +47 -0
- package/src/ui/video/Video.stx +45 -0
- package/src/ui/video/index.ts +16 -0
- package/src/ui/virtual-list/VirtualList.stx +67 -0
- package/src/ui/virtual-list/index.ts +10 -0
- package/src/ui/virtual-table/VirtualTable.stx +103 -0
- package/src/ui/virtual-table/index.ts +21 -0
- package/src/utils/PROP_VALIDATION.md +458 -0
- package/src/utils/THEME_SYSTEM.md +702 -0
- package/src/utils/accessibility.ts +841 -0
- package/src/utils/animation/easing.ts +368 -0
- package/src/utils/animation/helpers.ts +223 -0
- package/src/utils/animation/index.ts +5 -0
- package/src/utils/animation/keyframes.ts +230 -0
- package/src/utils/error-handling.ts +475 -0
- package/src/utils/highlighter.ts +93 -0
- package/src/utils/i18n.ts +634 -0
- package/src/utils/keep-alive.ts +819 -0
- package/src/utils/lazy-loading.ts +530 -0
- package/src/utils/prop-validation.ts +478 -0
- package/src/utils/theme.ts +626 -0
|
@@ -29,7 +29,9 @@ export const className = $props.className || ''
|
|
|
29
29
|
export const sidebarUid = $props.id || `stx-sidebar-${Math.random().toString(36).slice(2, 8)}`
|
|
30
30
|
|
|
31
31
|
const themeStyle = resolveSidebarTheme(theme)
|
|
32
|
+
export const selectionModel = themeStyle.selection
|
|
32
33
|
export const hasShimmerRim = themeStyle.layers.shimmerRim === true
|
|
34
|
+
export const isFrosted = themeStyle.layers.frosted === true
|
|
33
35
|
export const tintClasses = themeStyle.layers.tint || ''
|
|
34
36
|
export const scrollAreaClasses = themeStyle.scrollArea
|
|
35
37
|
|
|
@@ -277,6 +279,24 @@ function toggleCollapse() {
|
|
|
277
279
|
// root element unless the app manages its own theme (data-theme attribute).
|
|
278
280
|
// ---------------------------------------------------------------------------
|
|
279
281
|
|
|
282
|
+
// ---------------------------------------------------------------------------
|
|
283
|
+
// Key-window tracking — AppKit dims a source-list selection from the accent
|
|
284
|
+
// to a neutral fill the moment the window resigns key. `data-window-key` on
|
|
285
|
+
// the pane drives the two selection rule sets in the scoped CSS above.
|
|
286
|
+
// ---------------------------------------------------------------------------
|
|
287
|
+
|
|
288
|
+
function trackKeyWindow() {
|
|
289
|
+
// Driven by real focus/blur events only — never by an initial
|
|
290
|
+
// `document.hasFocus()` reading. A freshly loaded page, a background tab
|
|
291
|
+
// that has not been clicked yet, and an embedded webview that does not
|
|
292
|
+
// report focus at all all answer `false`, which would open the sidebar in
|
|
293
|
+
// the dimmed non-key state and leave it there. Starting from the key state
|
|
294
|
+
// and reacting to an actual blur keeps the default correct everywhere and
|
|
295
|
+
// still dims exactly when AppKit would.
|
|
296
|
+
window.addEventListener('focus', () => pane.setAttribute('data-window-key', 'true'))
|
|
297
|
+
window.addEventListener('blur', () => pane.setAttribute('data-window-key', 'false'))
|
|
298
|
+
}
|
|
299
|
+
|
|
280
300
|
function followSystemAppearance() {
|
|
281
301
|
const media = window.matchMedia('(prefers-color-scheme: dark)')
|
|
282
302
|
function sync() {
|
|
@@ -292,6 +312,7 @@ onMount(() => {
|
|
|
292
312
|
if (!pane) return
|
|
293
313
|
|
|
294
314
|
followSystemAppearance()
|
|
315
|
+
trackKeyWindow()
|
|
295
316
|
|
|
296
317
|
if (persistKeyProp) {
|
|
297
318
|
try {
|
|
@@ -321,6 +342,9 @@ defineExpose({ collapsed, toggle: toggleCollapse })
|
|
|
321
342
|
id="{{ sidebarUid }}"
|
|
322
343
|
data-stx-sidebar
|
|
323
344
|
data-sidebar-theme="{{ theme }}"
|
|
345
|
+
data-sidebar-selection="{{ selectionModel }}"
|
|
346
|
+
@if(isFrosted)data-sidebar-frosted@endif
|
|
347
|
+
data-window-key="true"
|
|
324
348
|
data-active-class="{{ activeClasses }}"
|
|
325
349
|
class="{{ paneClasses }}"
|
|
326
350
|
:style="`width: ${sidebarWidth()}`"
|
|
@@ -430,10 +454,83 @@ defineExpose({ collapsed, toggle: toggleCollapse })
|
|
|
430
454
|
.stx-sidebar-rim::after { animation: none; }
|
|
431
455
|
}
|
|
432
456
|
|
|
433
|
-
/*
|
|
457
|
+
/* Frosted sidebar material. Hand-written CSS on purpose: as the utilities
|
|
458
|
+
`backdrop-blur-[50px]` / `backdrop-saturate-[180%]` the arbitrary values
|
|
459
|
+
did not survive class extraction in the stx dev server, leaving the pane
|
|
460
|
+
with `backdrop-filter: none`; an earlier `backdrop-saturate-[1.7]` lost
|
|
461
|
+
its brackets on the way to the generator, was read as a percentage, and
|
|
462
|
+
compiled to `saturate(0.017)`, which drained the colour out of the whole
|
|
463
|
+
backdrop. In a Craft window with webSidebarMaterial the native
|
|
464
|
+
NSVisualEffectView supplies the real vibrancy; this approximates it
|
|
465
|
+
everywhere else. */
|
|
466
|
+
[data-sidebar-frosted] {
|
|
467
|
+
-webkit-backdrop-filter: saturate(180%) blur(50px);
|
|
468
|
+
backdrop-filter: saturate(180%) blur(50px);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/* ---------------------------------------------------------------------------
|
|
472
|
+
* Selection, `accent` model (macOS and its derivatives).
|
|
473
|
+
*
|
|
474
|
+
* AppKit paints a source-list selection in two states. In a key window the
|
|
475
|
+
* row takes the system accent and its label, icon, count and disclosure
|
|
476
|
+
* chevron all turn white; the label also goes semibold. When the window
|
|
477
|
+
* resigns key the fill drops to a neutral gray and the label stays dark.
|
|
478
|
+
* Measured from Mail.app: key fill is the accent, non-key fill sits about
|
|
479
|
+
* 5.5% black over the pane, and the icons desaturate to secondary gray.
|
|
480
|
+
*
|
|
481
|
+
* These are attribute rules rather than utility classes because the row's
|
|
482
|
+
* children have to recolor together, and because the controller toggles
|
|
483
|
+
* `data-active` on the client — CSS keyed on the attribute keeps the
|
|
484
|
+
* previously selected row's own icon tint intact when selection moves.
|
|
485
|
+
* ------------------------------------------------------------------------- */
|
|
486
|
+
[data-sidebar-selection="accent"] {
|
|
487
|
+
--stx-sidebar-accent: #007aff;
|
|
488
|
+
--stx-sidebar-selection-idle: rgba(0, 0, 0, 0.055);
|
|
489
|
+
--stx-sidebar-on-selection: #fff;
|
|
490
|
+
--stx-sidebar-icon-idle: #8e8e93;
|
|
491
|
+
}
|
|
492
|
+
@media (prefers-color-scheme: dark) {
|
|
493
|
+
[data-sidebar-selection="accent"] {
|
|
494
|
+
--stx-sidebar-accent: #0a84ff;
|
|
495
|
+
--stx-sidebar-selection-idle: rgba(255, 255, 255, 0.11);
|
|
496
|
+
--stx-sidebar-icon-idle: #98989d;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/* Per-item tint, published by SidebarItem as a custom property. */
|
|
501
|
+
[data-sidebar-selection="accent"] [data-sidebar-icon] {
|
|
502
|
+
color: var(--stx-sidebar-icon, currentColor);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
[data-sidebar-selection="accent"][data-window-key="true"] [data-sidebar-item][data-active="true"] {
|
|
506
|
+
background: var(--stx-sidebar-accent);
|
|
507
|
+
color: var(--stx-sidebar-on-selection);
|
|
508
|
+
font-weight: 590;
|
|
509
|
+
}
|
|
510
|
+
[data-sidebar-selection="accent"][data-window-key="true"] [data-sidebar-item][data-active="true"] [data-sidebar-icon],
|
|
511
|
+
[data-sidebar-selection="accent"][data-window-key="true"] [data-sidebar-item][data-active="true"] [data-sidebar-count],
|
|
512
|
+
[data-sidebar-selection="accent"][data-window-key="true"] [data-sidebar-item][data-active="true"] [data-sidebar-chevron] {
|
|
513
|
+
color: var(--stx-sidebar-on-selection);
|
|
514
|
+
}
|
|
515
|
+
/* Hover must not lighten the selected row out from under the accent. */
|
|
516
|
+
[data-sidebar-selection="accent"][data-window-key="true"] [data-sidebar-item][data-active="true"]:hover {
|
|
517
|
+
background: var(--stx-sidebar-accent);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/* Window resigned key: neutral fill, label stays dark, icons desaturate. */
|
|
521
|
+
[data-sidebar-selection="accent"][data-window-key="false"] [data-sidebar-item][data-active="true"] {
|
|
522
|
+
background: var(--stx-sidebar-selection-idle);
|
|
523
|
+
font-weight: 590;
|
|
524
|
+
}
|
|
525
|
+
[data-sidebar-selection="accent"][data-window-key="false"] [data-sidebar-icon] {
|
|
526
|
+
color: var(--stx-sidebar-icon-idle);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/* Rows collapse like AppKit outlines: fixed row height animates to zero.
|
|
530
|
+
The 32px pitch is the row itself — AppKit leaves no gap, so a run of
|
|
531
|
+
selected or hovered rows reads as one continuous block. */
|
|
434
532
|
[data-sidebar-row] {
|
|
435
|
-
height: 32px;
|
|
436
|
-
padding-bottom: 2px;
|
|
533
|
+
height: 32px;
|
|
437
534
|
transition: height 0.22s ease, opacity 0.16s ease;
|
|
438
535
|
}
|
|
439
536
|
[data-sidebar-row][data-collapsed] {
|
|
@@ -36,8 +36,12 @@ export const countClasses = themeStyle.count
|
|
|
36
36
|
// Nested rows are indented; the icon tint accepts macOS system color names
|
|
37
37
|
// ("blue", "yellow", …) or any CSS color.
|
|
38
38
|
export const indentStyle = depth > 0 ? `padding-left: ${depth * themeStyle.indentPerLevel}px` : ''
|
|
39
|
+
// The tint is published as a custom property rather than `color:` directly.
|
|
40
|
+
// An inline `color` would outrank any stylesheet rule, so a selected row
|
|
41
|
+
// could never turn its icon white the way AppKit does, and toggling
|
|
42
|
+
// selection on the client could not restore the original tint afterwards.
|
|
39
43
|
const tint = resolveIconColor(iconColor)
|
|
40
|
-
export const iconStyle = tint ?
|
|
44
|
+
export const iconStyle = tint ? `--stx-sidebar-icon: ${tint}` : ''
|
|
41
45
|
export const isLink = Boolean(href) && !disabled
|
|
42
46
|
</script>
|
|
43
47
|
|
|
@@ -52,34 +56,34 @@ export const isLink = Boolean(href) && !disabled
|
|
|
52
56
|
<a href="{{ href }}" data-sidebar-item data-label="{{ label }}" class="{{ rowClasses }}" @if(active)data-active="true" aria-current="page"@endif>
|
|
53
57
|
<span class="{{ disclosureClasses }}" @if(expandable)data-sidebar-disclosure role="button" aria-label="Toggle {{ label }}"@endif>
|
|
54
58
|
@if(expandable)
|
|
55
|
-
<span class="{{ chevronClasses }}" aria-hidden="true"></span>
|
|
59
|
+
<span data-sidebar-chevron class="{{ chevronClasses }}" aria-hidden="true"></span>
|
|
56
60
|
@endif
|
|
57
61
|
</span>
|
|
58
62
|
@if(image)
|
|
59
63
|
<span class="{{ iconSlotClasses }}"><img src="{{ image }}" alt="" class="{{ imageClasses }}" /></span>
|
|
60
64
|
@elseif(icon)
|
|
61
|
-
<span class="{{ iconSlotClasses }}"><span class="{{ iconClasses }}" @if(iconStyle)style="{{ iconStyle }}"@endif aria-hidden="true"></span></span>
|
|
65
|
+
<span class="{{ iconSlotClasses }}"><span data-sidebar-icon class="{{ iconClasses }}" @if(iconStyle)style="{{ iconStyle }}"@endif aria-hidden="true"></span></span>
|
|
62
66
|
@endif
|
|
63
67
|
<span class="{{ labelClasses }}">{{ label }}</span>
|
|
64
68
|
@if(count !== '' && count !== null && count !== undefined)
|
|
65
|
-
<span class="{{ countClasses }}">{{ count }}</span>
|
|
69
|
+
<span data-sidebar-count class="{{ countClasses }}">{{ count }}</span>
|
|
66
70
|
@endif
|
|
67
71
|
</a>
|
|
68
72
|
@else
|
|
69
73
|
<button type="button" data-sidebar-item data-label="{{ label }}" class="{{ rowClasses }}" @if(active)data-active="true" aria-current="page"@endif @if(disabled)data-disabled disabled aria-disabled="true"@endif>
|
|
70
74
|
<span class="{{ disclosureClasses }}" @if(expandable)data-sidebar-disclosure role="button" aria-label="Toggle {{ label }}"@endif>
|
|
71
75
|
@if(expandable)
|
|
72
|
-
<span class="{{ chevronClasses }}" aria-hidden="true"></span>
|
|
76
|
+
<span data-sidebar-chevron class="{{ chevronClasses }}" aria-hidden="true"></span>
|
|
73
77
|
@endif
|
|
74
78
|
</span>
|
|
75
79
|
@if(image)
|
|
76
80
|
<span class="{{ iconSlotClasses }}"><img src="{{ image }}" alt="" class="{{ imageClasses }}" /></span>
|
|
77
81
|
@elseif(icon)
|
|
78
|
-
<span class="{{ iconSlotClasses }}"><span class="{{ iconClasses }}" @if(iconStyle)style="{{ iconStyle }}"@endif aria-hidden="true"></span></span>
|
|
82
|
+
<span class="{{ iconSlotClasses }}"><span data-sidebar-icon class="{{ iconClasses }}" @if(iconStyle)style="{{ iconStyle }}"@endif aria-hidden="true"></span></span>
|
|
79
83
|
@endif
|
|
80
84
|
<span class="{{ labelClasses }}">{{ label }}</span>
|
|
81
85
|
@if(count !== '' && count !== null && count !== undefined)
|
|
82
|
-
<span class="{{ countClasses }}">{{ count }}</span>
|
|
86
|
+
<span data-sidebar-count class="{{ countClasses }}">{{ count }}</span>
|
|
83
87
|
@endif
|
|
84
88
|
</button>
|
|
85
89
|
@endif
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
// ../../../../../../../tmp/stx-components-build-
|
|
2
|
+
// ../../../../../../../tmp/stx-components-build-ph5rIj/stubs/stub-0.js
|
|
3
3
|
var stub_0_default = { __stx: true, src: "./components/CodeBlock.stx" };
|
|
4
|
-
// ../../../../../../../tmp/stx-components-build-
|
|
4
|
+
// ../../../../../../../tmp/stx-components-build-ph5rIj/stubs/stub-1.js
|
|
5
5
|
var stub_1_default = { __stx: true, src: "./components/Footer.stx" };
|
|
6
|
-
// ../../../../../../../tmp/stx-components-build-
|
|
6
|
+
// ../../../../../../../tmp/stx-components-build-ph5rIj/stubs/stub-2.js
|
|
7
7
|
var stub_2_default = { __stx: true, src: "./components/Hero.stx" };
|
|
8
|
-
// ../../../../../../../tmp/stx-components-build-
|
|
8
|
+
// ../../../../../../../tmp/stx-components-build-ph5rIj/stubs/stub-3.js
|
|
9
9
|
var stub_3_default = { __stx: true, src: "./components/Installation.stx" };
|
|
10
10
|
// src/composables/useCopyCode.ts
|
|
11
11
|
function useCopyCode(options) {
|
|
@@ -1132,13 +1132,13 @@ var RadioGroupOption_default = "./RadioGroupOption-s1d6r221.stx";
|
|
|
1132
1132
|
// src/ui/select/Select.stx
|
|
1133
1133
|
var Select_default = "./Select-1vnd0brz.stx";
|
|
1134
1134
|
// src/ui/sidebar/Sidebar.stx
|
|
1135
|
-
var Sidebar_default = "./Sidebar-
|
|
1135
|
+
var Sidebar_default = "./Sidebar-bg47fqmq.stx";
|
|
1136
1136
|
// src/ui/sidebar/SidebarFooter.stx
|
|
1137
1137
|
var SidebarFooter_default = "./SidebarFooter-0aegr99p.stx";
|
|
1138
1138
|
// src/ui/sidebar/SidebarHeader.stx
|
|
1139
1139
|
var SidebarHeader_default = "./SidebarHeader-ed5wb13t.stx";
|
|
1140
1140
|
// src/ui/sidebar/SidebarItem.stx
|
|
1141
|
-
var SidebarItem_default = "./SidebarItem-
|
|
1141
|
+
var SidebarItem_default = "./SidebarItem-9rvbwhxr.stx";
|
|
1142
1142
|
// src/ui/sidebar/SidebarSection.stx
|
|
1143
1143
|
var SidebarSection_default = "./SidebarSection-qf8fhy55.stx";
|
|
1144
1144
|
// src/ui/sidebar/themes.ts
|
|
@@ -1158,13 +1158,14 @@ var macosColors = {
|
|
|
1158
1158
|
};
|
|
1159
1159
|
var macos = {
|
|
1160
1160
|
pane: [
|
|
1161
|
-
"bg-
|
|
1162
|
-
"backdrop-blur-[60px] backdrop-saturate-[1.8]",
|
|
1161
|
+
"bg-[#f2f2f4]/90 dark:bg-[#1c1c1e]/88",
|
|
1163
1162
|
"text-black dark:text-white",
|
|
1164
1163
|
"select-none"
|
|
1165
1164
|
].join(" "),
|
|
1165
|
+
selection: "accent",
|
|
1166
1166
|
layers: {
|
|
1167
|
-
shimmerRim: true
|
|
1167
|
+
shimmerRim: true,
|
|
1168
|
+
frosted: true
|
|
1168
1169
|
},
|
|
1169
1170
|
scrollArea: "flex-1 overflow-y-auto overflow-x-hidden px-[10px] pb-[10px]",
|
|
1170
1171
|
sectionHeader: [
|
|
@@ -1179,18 +1180,18 @@ var macos = {
|
|
|
1179
1180
|
"opacity-0 group-hover/section:opacity-100 transition-opacity duration-150",
|
|
1180
1181
|
"transition-transform duration-200"
|
|
1181
1182
|
].join(" "),
|
|
1182
|
-
sectionGroup: "flex flex-col
|
|
1183
|
+
sectionGroup: "flex flex-col",
|
|
1183
1184
|
item: {
|
|
1184
1185
|
base: [
|
|
1185
1186
|
"flex w-full items-center",
|
|
1186
|
-
"h-[
|
|
1187
|
+
"h-[32px] rounded-[8px] pl-[4px] pr-[8px]",
|
|
1187
1188
|
"text-[13px] leading-[16px] font-normal",
|
|
1188
1189
|
"text-black dark:text-white",
|
|
1189
1190
|
"transition-colors duration-150 ease-out",
|
|
1190
1191
|
"cursor-default"
|
|
1191
1192
|
].join(" "),
|
|
1192
1193
|
hover: "hover:bg-black/4 dark:hover:bg-white/6",
|
|
1193
|
-
active: "
|
|
1194
|
+
active: "",
|
|
1194
1195
|
pressed: "active:bg-black/10 dark:active:bg-white/18",
|
|
1195
1196
|
disabled: "opacity-40 pointer-events-none",
|
|
1196
1197
|
disclosure: "flex h-[16px] w-[18px] shrink-0 items-center justify-center",
|
|
@@ -1212,6 +1213,7 @@ var macos = {
|
|
|
1212
1213
|
}
|
|
1213
1214
|
};
|
|
1214
1215
|
var workspace = {
|
|
1216
|
+
selection: "classes",
|
|
1215
1217
|
pane: "bg-[#f4f4f3] dark:bg-neutral-950 text-zinc-950 dark:text-white select-none",
|
|
1216
1218
|
layers: {},
|
|
1217
1219
|
scrollArea: "flex-1 overflow-y-auto overflow-x-hidden px-5 py-5",
|
|
@@ -1235,6 +1237,7 @@ var workspace = {
|
|
|
1235
1237
|
}
|
|
1236
1238
|
};
|
|
1237
1239
|
var desktop = {
|
|
1240
|
+
selection: "classes",
|
|
1238
1241
|
pane: "bg-[#f3f3f1]/48 dark:bg-neutral-950/32 backdrop-blur-3xl backdrop-saturate-150 text-zinc-950 dark:text-white select-none",
|
|
1239
1242
|
layers: {
|
|
1240
1243
|
tint: "bg-[linear-gradient(112deg,rgba(255,255,255,0.20)_0%,rgba(255,255,255,0.04)_45%,rgba(226,226,222,0.16)_100%)] dark:bg-[linear-gradient(112deg,rgba(255,255,255,0.08)_0%,rgba(255,255,255,0.02)_46%,rgba(255,255,255,0.06)_100%)]"
|
|
@@ -13,11 +13,22 @@ export declare function resolveIconColor(color?: string): string | undefined;
|
|
|
13
13
|
*
|
|
14
14
|
* The flagship theme is `macos` — a faithful recreation of the sidebar in
|
|
15
15
|
* the latest macOS (Tahoe, macOS 26/27 "Liquid Glass"). Its metrics were
|
|
16
|
-
* measured from
|
|
16
|
+
* measured pixel-by-pixel from Mail.app's source list at @2x:
|
|
17
17
|
*
|
|
18
|
-
* row pitch 32px
|
|
19
|
-
*
|
|
18
|
+
* row pitch 32px, and the highlight fills the whole 32px — AppKit leaves
|
|
19
|
+
* no gap between rows, so consecutive selected/hovered rows touch
|
|
20
|
+
* highlight radius 8px
|
|
21
|
+
* label 13px · count 13px secondary gray · section header 11px semibold,
|
|
22
|
+
* Title Case (NOT uppercase — uppercasing section headers is the single
|
|
23
|
+
* most common tell of a web sidebar imitating macOS)
|
|
20
24
|
* icon 17px in a fixed 22px slot · disclosure gutter 18px · child indent 16px
|
|
25
|
+
* pane 234px wide, #f1f2f3 in light appearance, ~90% opaque so the
|
|
26
|
+
* backdrop bleeds through faintly rather than tinting the pane
|
|
27
|
+
*
|
|
28
|
+
* Selection follows AppKit's two-state model (`selection` below): in a key
|
|
29
|
+
* window the row takes the system accent with a white label, icon and count;
|
|
30
|
+
* when the window resigns key it falls back to a neutral fill with the label
|
|
31
|
+
* left dark. Icons desaturate to gray in the same non-key state.
|
|
21
32
|
*
|
|
22
33
|
* Legacy themes (`workspace`, `desktop`, `solid`, `transparent`, `vibrancy`)
|
|
23
34
|
* are preserved verbatim from the previous variant maps. `tahoe` now aliases
|
|
@@ -46,8 +57,10 @@ export declare const sidebarThemes: {
|
|
|
46
57
|
/** Class groups a sidebar theme provides. All values are utility classes. */
|
|
47
58
|
export declare interface SidebarTheme {
|
|
48
59
|
pane: string
|
|
60
|
+
selection: SidebarSelectionModel
|
|
49
61
|
layers: {
|
|
50
62
|
shimmerRim?: boolean
|
|
63
|
+
frosted?: boolean
|
|
51
64
|
tint?: string
|
|
52
65
|
}
|
|
53
66
|
scrollArea: string
|
|
@@ -71,4 +84,14 @@ export declare interface SidebarTheme {
|
|
|
71
84
|
}
|
|
72
85
|
}
|
|
73
86
|
export type MacosColor = keyof typeof macosColors;
|
|
87
|
+
/**
|
|
88
|
+
* How a theme paints the selected row.
|
|
89
|
+
*
|
|
90
|
+
* `accent` reproduces AppKit: the pane owns CSS custom properties for the
|
|
91
|
+
* key/non-key fills, and scoped rules recolor the row's label, icon, count
|
|
92
|
+
* and chevron together. `classes` is the older utility-class model, where
|
|
93
|
+
* `item.active` is simply added to the row element and children are left
|
|
94
|
+
* alone. Legacy themes stay on `classes` so they render exactly as before.
|
|
95
|
+
*/
|
|
96
|
+
export type SidebarSelectionModel = 'accent' | 'classes';
|
|
74
97
|
export type SidebarThemeName = keyof typeof sidebarThemes;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksjs/components",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.112",
|
|
5
5
|
"description": "A modern component library built with STX, featuring headwind utility classes and TypeScript syntax highlighting.",
|
|
6
6
|
"author": "Chris Breuer <chris@stacksjs.org>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"files": [
|
|
48
48
|
"README.md",
|
|
49
49
|
"dist",
|
|
50
|
+
"src",
|
|
50
51
|
"stx-plugin.ts"
|
|
51
52
|
],
|
|
52
53
|
"scripts": {
|
|
@@ -62,8 +63,8 @@
|
|
|
62
63
|
},
|
|
63
64
|
"dependencies": {
|
|
64
65
|
"@cwcss/crosswind": "^0.2.6",
|
|
65
|
-
"@stacksjs/stx": "0.2.
|
|
66
|
-
"bun-plugin-stx": "0.2.
|
|
66
|
+
"@stacksjs/stx": "0.2.112",
|
|
67
|
+
"bun-plugin-stx": "0.2.112",
|
|
67
68
|
"ts-syntax-highlighter": "^0.2.1"
|
|
68
69
|
},
|
|
69
70
|
"devDependencies": {
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<script server>
|
|
2
|
+
import { applyHeadwindClasses, highlight } from '../utils/highlighter'
|
|
3
|
+
|
|
4
|
+
export const code = $props.code || ''
|
|
5
|
+
export const language = $props.language || 'typescript'
|
|
6
|
+
export const theme = $props.theme || 'auto'
|
|
7
|
+
export const lineNumbers = $props.lineNumbers !== false
|
|
8
|
+
export const copyable = $props.copyable !== false
|
|
9
|
+
export const className = $props.className || ''
|
|
10
|
+
|
|
11
|
+
const result = await highlight(code, { language, theme, lineNumbers })
|
|
12
|
+
export const highlightedCode = applyHeadwindClasses(result.html, className)
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<script client>
|
|
16
|
+
const code = {{ code }}
|
|
17
|
+
const copied = state(false)
|
|
18
|
+
|
|
19
|
+
async function copyToClipboard() {
|
|
20
|
+
try {
|
|
21
|
+
await navigator.clipboard.writeText(code)
|
|
22
|
+
copied.set(true)
|
|
23
|
+
setTimeout(() => copied.set(false), 2000)
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
console.error('Failed to copy code:', err)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<div class="relative group">
|
|
32
|
+
{!! highlightedCode !!}
|
|
33
|
+
|
|
34
|
+
@if(copyable)
|
|
35
|
+
<button
|
|
36
|
+
@click="copyToClipboard()"
|
|
37
|
+
class="absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity duration-200 px-3 py-1.5 bg-neutral-800 hover:bg-neutral-700 text-white text-xs rounded-md font-medium"
|
|
38
|
+
aria-label="Copy code"
|
|
39
|
+
>
|
|
40
|
+
<span :show="copied()" class="flex items-center gap-1.5">
|
|
41
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
42
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
|
43
|
+
</svg>
|
|
44
|
+
Copied!
|
|
45
|
+
</span>
|
|
46
|
+
<span :show="!copied()" class="flex items-center gap-1.5">
|
|
47
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
|
|
49
|
+
</svg>
|
|
50
|
+
Copy
|
|
51
|
+
</span>
|
|
52
|
+
</button>
|
|
53
|
+
@endif
|
|
54
|
+
</div>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<script server>
|
|
2
|
+
export const author = $props.author || '@chrisbbreuer'
|
|
3
|
+
export const authorUrl = $props.authorUrl || 'https://github.com/chrisbbreuer'
|
|
4
|
+
export const project = $props.project || '@stacksjs'
|
|
5
|
+
export const projectUrl = $props.projectUrl || 'https://github.com/stacksjs/stacks'
|
|
6
|
+
export const twitterUrl = $props.twitterUrl || 'https://twitter.com/chrisbbreuer'
|
|
7
|
+
export const sponsorUrl = $props.sponsorUrl || 'https://github.com/sponsors/chrisbbreuer'
|
|
8
|
+
export const coffeeUrl = $props.coffeeUrl || 'https://www.buymeacoffee.com/xlbd'
|
|
9
|
+
|
|
10
|
+
export const currentYear = new Date().getFullYear()
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<footer class="flex items-center justify-center mt-16 w-full pb-4 text-neutral-600 dark:text-neutral-400 opacity-60">
|
|
14
|
+
<div class="flex flex-col items-center justify-center">
|
|
15
|
+
<p class="text-sm">
|
|
16
|
+
With 💙 by
|
|
17
|
+
<a href="{{ authorUrl }}" class="text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300 transition-colors">
|
|
18
|
+
{{ author }}
|
|
19
|
+
</a>
|
|
20
|
+
&
|
|
21
|
+
<a href="{{ projectUrl }}" class="text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300 transition-colors">
|
|
22
|
+
{{ project }}
|
|
23
|
+
</a>
|
|
24
|
+
<span> © {{ currentYear }}</span>
|
|
25
|
+
</p>
|
|
26
|
+
|
|
27
|
+
<div class="mt-2 flex flex-col items-center sm:flex-row space-x-1 space-y-2 sm:space-y-0">
|
|
28
|
+
<div class="flex items-center space-x-1">
|
|
29
|
+
<svg class="w-4 h-4 text-blue-500" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
30
|
+
<path d="M8.29 20.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0022 5.92a8.19 8.19 0 01-2.357.646 4.118 4.118 0 001.804-2.27 8.224 8.224 0 01-2.605.996 4.107 4.107 0 00-6.993 3.743 11.65 11.65 0 01-8.457-4.287 4.106 4.106 0 001.27 5.477A4.072 4.072 0 012.8 9.713v.052a4.105 4.105 0 003.292 4.022 4.095 4.095 0 01-1.853.07 4.108 4.108 0 003.834 2.85A8.233 8.233 0 012 18.407a11.616 11.616 0 006.29 1.84" />
|
|
31
|
+
</svg>
|
|
32
|
+
<span class="text-sm">
|
|
33
|
+
<a href="{{ twitterUrl }}" target="_blank" rel="noopener noreferrer" class="text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300 transition-colors">
|
|
34
|
+
Follow me on Twitter
|
|
35
|
+
</a>
|
|
36
|
+
</span>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<span class="hidden px-2 text-neutral-400 sm:block">|</span>
|
|
40
|
+
|
|
41
|
+
<div class="flex items-center space-x-1">
|
|
42
|
+
<svg class="w-4 h-4 text-blue-500" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
43
|
+
<path d="M20.216 6.415l-.132-.666c-.119-.598-.388-1.163-1.001-1.379-.197-.069-.42-.098-.57-.241-.152-.143-.196-.366-.231-.572-.065-.378-.125-.756-.192-1.133-.057-.325-.102-.69-.25-.987-.195-.4-.597-.634-.996-.788a5.723 5.723 0 00-.626-.194c-1-.263-2.05-.36-3.077-.416a25.834 25.834 0 00-3.7.062c-.915.083-1.88.184-2.75.5-.318.116-.646.256-.888.501-.297.302-.393.77-.177 1.146.154.267.415.456.692.58.36.162.737.284 1.123.366 1.075.238 2.189.331 3.287.37 1.218.05 2.437.01 3.65-.118.299-.033.598-.073.896-.119.352-.054.578-.513.474-.834-.124-.383-.457-.531-.834-.473-.466.074-.96.108-1.382.146-1.177.08-2.358.082-3.536.006a22.228 22.228 0 01-1.157-.107c-.086-.01-.18-.025-.258-.036-.243-.036-.484-.08-.724-.13-.111-.027-.111-.185 0-.212h.005c.277-.06.557-.108.838-.147h.002c.131-.009.263-.032.394-.048a25.076 25.076 0 013.426-.12c.674.019 1.347.067 2.017.144l.228.031c.267.04.533.088.798.145.392.085.895.113 1.07.542.055.137.08.288.111.431l.319 1.484a.237.237 0 01-.199.284h-.003c-.037.006-.075.01-.112.015a36.704 36.704 0 01-4.743.295 37.059 37.059 0 01-4.699-.304c-.14-.017-.293-.042-.417-.06-.326-.048-.649-.108-.973-.161-.393-.065-.768-.032-1.123.161-.29.16-.527.404-.675.701-.154.316-.199.66-.267 1-.069.34-.176.707-.135 1.056.087.753.613 1.365 1.37 1.502a39.69 39.69 0 0011.343.376.483.483 0 01.535.53l-.071.697-1.018 9.907c-.041.41-.047.832-.125 1.237-.122.637-.553 1.028-1.182 1.171-.577.131-1.165.2-1.756.205-.656.004-1.31-.025-1.966-.022-.699.004-1.556-.06-2.095-.58-.475-.458-.54-1.174-.605-1.793l-.731-7.013-.322-3.094c-.037-.351-.286-.695-.678-.678-.336.015-.718.3-.678.679l.228 2.185.949 9.112c.147 1.344 1.174 2.068 2.446 2.272.742.12 1.503.144 2.257.156.966.016 1.942.053 2.892-.122 1.408-.258 2.465-1.198 2.616-2.657.34-3.332.683-6.663 1.024-9.995l.215-2.087a.484.484 0 01.39-.426c.402-.078.787-.212 1.074-.518.455-.488.546-1.124.385-1.766zm-1.478.772c-.145.137-.363.201-.578.233-2.416.359-4.866.54-7.308.46-1.748-.06-3.477-.254-5.207-.498-.17-.024-.353-.055-.47-.18-.22-.236-.111-.71-.054-.995.052-.26.152-.609.463-.646.484-.057 1.046.148 1.526.22.577.088 1.156.16 1.737.212 2.48.226 5.002.19 7.472-.14.45-.06.899-.13 1.345-.21.399-.072.84-.206 1.08.206.166.281.188.657.162.974a.544.544 0 01-.169.364zm-6.159 3.9c-.862.37-1.84.788-3.109.788a5.884 5.884 0 01-1.569-.217l.877 9.004c.065.78.717 1.38 1.5 1.38 0 0 1.243.065 1.658.065.447 0 1.786-.065 1.786-.065.783 0 1.434-.6 1.499-1.38l.94-9.95a3.996 3.996 0 00-1.322-.238c-.826 0-1.491.284-2.26.613z" />
|
|
44
|
+
</svg>
|
|
45
|
+
<span class="text-sm">
|
|
46
|
+
<a href="{{ coffeeUrl }}" target="_blank" rel="noopener noreferrer" class="text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300 transition-colors">
|
|
47
|
+
Buy me a coffee
|
|
48
|
+
</a>
|
|
49
|
+
</span>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<span class="hidden px-2 text-neutral-400 sm:block">|</span>
|
|
53
|
+
|
|
54
|
+
<div class="flex items-center space-x-1">
|
|
55
|
+
<svg class="w-4 h-4 text-blue-500" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
56
|
+
<path d="m11.645 20.91-.007-.003-.022-.012a15.247 15.247 0 0 1-.383-.218 25.18 25.18 0 0 1-4.244-3.17C4.688 15.36 2.25 12.174 2.25 8.25 2.25 5.322 4.714 3 7.688 3A5.5 5.5 0 0 1 12 5.052 5.5 5.5 0 0 1 16.313 3c2.973 0 5.437 2.322 5.437 5.25 0 3.925-2.438 7.111-4.739 9.256a25.175 25.175 0 0 1-4.244 3.17 15.247 15.247 0 0 1-.383.219l-.022.012-.007.004-.003.001a.752.752 0 0 1-.704 0l-.003-.001Z" />
|
|
57
|
+
</svg>
|
|
58
|
+
<span class="text-sm">
|
|
59
|
+
<a href="{{ sponsorUrl }}" target="_blank" rel="noopener noreferrer" class="text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300 transition-colors">
|
|
60
|
+
Sponsor me on GitHub
|
|
61
|
+
</a>
|
|
62
|
+
</span>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</footer>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script server>
|
|
2
|
+
export const title = $props.title || 'Component'
|
|
3
|
+
export const description = $props.description || 'A modern component built with STX'
|
|
4
|
+
export const githubUrl = $props.githubUrl || '#'
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<div class="flex flex-col items-center gap-3">
|
|
8
|
+
<h1 class="text-5xl font-bold mb-3 -mt-5 bg-gradient-to-r from-blue-500 to-purple-600 bg-clip-text text-transparent">
|
|
9
|
+
{{ title }}
|
|
10
|
+
</h1>
|
|
11
|
+
<p class="mb-3 mt-0 text-lg text-neutral-600 dark:text-neutral-400">
|
|
12
|
+
{{ description }}
|
|
13
|
+
</p>
|
|
14
|
+
<div class="flex gap-2">
|
|
15
|
+
<slot name="demo" />
|
|
16
|
+
<a
|
|
17
|
+
href="{{ githubUrl }}"
|
|
18
|
+
target="_blank"
|
|
19
|
+
rel="noopener noreferrer"
|
|
20
|
+
class="inline-flex items-center justify-center h-10 px-8 rounded-md text-sm font-semibold bg-gradient-to-b from-white to-neutral-100 dark:from-neutral-800 dark:to-neutral-900 text-neutral-900 dark:text-white shadow-md hover:shadow-lg transition-all duration-200"
|
|
21
|
+
>
|
|
22
|
+
GitHub
|
|
23
|
+
</a>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<script server>
|
|
2
|
+
export const packageName = $props.packageName || '@stacksjs/component'
|
|
3
|
+
export const installCode = `bun add ${packageName}`
|
|
4
|
+
export const npmCode = `npm install ${packageName}`
|
|
5
|
+
export const pnpmCode = `pnpm add ${packageName}`
|
|
6
|
+
export const yarnCode = `yarn add ${packageName}`
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<div class="installation">
|
|
10
|
+
<h2 class="my-2 text-lg font-semibold">Installation</h2>
|
|
11
|
+
|
|
12
|
+
<p class="my-3 text-base">
|
|
13
|
+
Install the component using your preferred package manager:
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
<div class="space-y-4">
|
|
17
|
+
<div>
|
|
18
|
+
<h3 class="text-sm font-medium mb-2 text-neutral-700 dark:text-neutral-300">Bun (recommended)</h3>
|
|
19
|
+
<CodeBlock :code="installCode" language="bash" />
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div>
|
|
23
|
+
<h3 class="text-sm font-medium mb-2 text-neutral-700 dark:text-neutral-300">npm</h3>
|
|
24
|
+
<CodeBlock :code="npmCode" language="bash" />
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<div>
|
|
28
|
+
<h3 class="text-sm font-medium mb-2 text-neutral-700 dark:text-neutral-300">pnpm</h3>
|
|
29
|
+
<CodeBlock :code="pnpmCode" language="bash" />
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<div>
|
|
33
|
+
<h3 class="text-sm font-medium mb-2 text-neutral-700 dark:text-neutral-300">Yarn</h3>
|
|
34
|
+
<CodeBlock :code="yarnCode" language="bash" />
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copy code to clipboard with visual feedback
|
|
3
|
+
*/
|
|
4
|
+
export interface CopyCodeOptions {
|
|
5
|
+
code: string
|
|
6
|
+
onSuccess?: () => void
|
|
7
|
+
onError?: (error: Error) => void
|
|
8
|
+
timeout?: number
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface CopyCodeResult {
|
|
12
|
+
copied: boolean
|
|
13
|
+
copy: () => Promise<void>
|
|
14
|
+
reset: () => void
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function useCopyCode(options: CopyCodeOptions): CopyCodeResult {
|
|
18
|
+
const { code, onSuccess, onError, timeout = 2000 } = options
|
|
19
|
+
|
|
20
|
+
let copied = false
|
|
21
|
+
let timeoutId: ReturnType<typeof setTimeout> | null = null
|
|
22
|
+
|
|
23
|
+
const reset = () => {
|
|
24
|
+
copied = false
|
|
25
|
+
if (timeoutId) {
|
|
26
|
+
clearTimeout(timeoutId)
|
|
27
|
+
timeoutId = null
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const copy = async () => {
|
|
32
|
+
try {
|
|
33
|
+
if (!navigator.clipboard) {
|
|
34
|
+
throw new Error('Clipboard API not available')
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
await navigator.clipboard.writeText(code)
|
|
38
|
+
copied = true
|
|
39
|
+
onSuccess?.()
|
|
40
|
+
|
|
41
|
+
// Auto-reset after timeout
|
|
42
|
+
timeoutId = setTimeout(() => {
|
|
43
|
+
copied = false
|
|
44
|
+
timeoutId = null
|
|
45
|
+
}, timeout)
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
const err = error instanceof Error ? error : new Error('Failed to copy code')
|
|
49
|
+
onError?.(err)
|
|
50
|
+
console.error('Failed to copy code:', err)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
copied,
|
|
56
|
+
copy,
|
|
57
|
+
reset,
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Simple synchronous copy function for direct use
|
|
63
|
+
*/
|
|
64
|
+
export async function copyToClipboard(text: string): Promise<boolean> {
|
|
65
|
+
try {
|
|
66
|
+
await navigator.clipboard.writeText(text)
|
|
67
|
+
return true
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
console.error('Failed to copy to clipboard:', error)
|
|
71
|
+
return false
|
|
72
|
+
}
|
|
73
|
+
}
|