@stacksjs/components 0.2.27 → 0.2.53
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/Accordion-19x8q4rj.stx +88 -0
- package/dist/{Audio-vdmg1258.stx → Audio-hjywk3qc.stx} +4 -4
- package/dist/{Avatar-365cvrh4.stx → Avatar-h3jmwcq0.stx} +23 -34
- package/dist/{Badge-8m3qete4.stx → Badge-k8dy3d53.stx} +11 -19
- package/dist/{Button-3tt4vsqt.stx → Button-1vknasy3.stx} +18 -33
- package/dist/Calendar-reny0et7.stx +189 -0
- package/dist/{Card-6wdbexqr.stx → Card-c1g1fd1w.stx} +27 -33
- package/dist/{Checkbox-p3q3e3nf.stx → Checkbox-zgdmy3p5.stx} +36 -44
- package/dist/{Checkout-e4037tyy.stx → Checkout-agt0ngpw.stx} +8 -16
- package/dist/Combobox-fdkr6cdq.stx +96 -0
- package/dist/{ComboboxButton-8gxwkhdx.stx → ComboboxButton-g76stp1e.stx} +14 -2
- package/dist/{ComboboxInput-mk99z65n.stx → ComboboxInput-z1293bbh.stx} +12 -5
- package/dist/ComboboxOption-hmxt3gte.stx +49 -0
- package/dist/{ListboxOptions-8kqvfp7z.stx → ComboboxOptions-sq5360ae.stx} +2 -2
- package/dist/CommandPalette-36mxf05w.stx +81 -0
- package/dist/CommandPaletteItem-mvk6q7a2.stx +27 -0
- package/dist/Dialog-hczpexs4.stx +37 -0
- package/dist/{Drawer-p7m351bn.stx → Drawer-xhevp5cw.stx} +29 -49
- package/dist/Dropdown-vvhemtc0.stx +82 -0
- package/dist/{DropdownButton-9w8zkfwj.stx → DropdownButton-wcz67dxy.stx} +12 -6
- package/dist/DropdownItem-c7rz08e5.stx +35 -0
- package/dist/{DropdownItems-aygjpxkx.stx → DropdownItems-1sxnd5qn.stx} +2 -2
- package/dist/EmailInput-vak3kkmk.stx +30 -0
- package/dist/Form-mas630hy.stx +95 -0
- package/dist/{Image-jhkm6w1f.stx → Image-yhxcvgzs.stx} +68 -100
- package/dist/Listbox-q49tnr90.stx +101 -0
- package/dist/{ListboxButton-spwx7513.stx → ListboxButton-keb8gm0q.stx} +12 -1
- package/dist/ListboxOption-e0dtv1gc.stx +49 -0
- package/dist/{ComboboxOptions-6b5ywc5x.stx → ListboxOptions-ejkatcfg.stx} +7 -3
- package/dist/{Login-rx9gyqhx.stx → Login-gepemsth.stx} +17 -19
- package/dist/Navigator-rk2a5wvk.stx +113 -0
- package/dist/Notification-tb9b525s.stx +78 -0
- package/dist/{NumberInput-nzpkx1ry.stx → NumberInput-drnvtqej.stx} +40 -53
- package/dist/{Pagination-h61eq390.stx → Pagination-n3d31cns.stx} +73 -108
- package/dist/PasswordInput-n02x6053.stx +142 -0
- package/dist/{PaymentMethods-j42jsk5x.stx → PaymentMethods-x4vrx9yb.stx} +21 -30
- package/dist/Popover-et2q44m7.stx +60 -0
- package/dist/{PopoverButton-fnaqc77g.stx → PopoverButton-mffzc9pr.stx} +12 -6
- package/dist/{PopoverPanel-y0vtf5w9.stx → PopoverPanel-054yh38h.stx} +6 -6
- package/dist/{Portal-s2q37yp0.stx → Portal-1vf14s4x.stx} +20 -37
- package/dist/{Progress-vmdkm06p.stx → Progress-yxcntr4x.stx} +36 -48
- package/dist/{Radio-04bs3d21.stx → Radio-cgjv2hb2.stx} +29 -34
- package/dist/RadioGroup-qxmnm3xm.stx +60 -0
- package/dist/RadioGroupOption-s1d6r221.stx +58 -0
- package/dist/SearchInput-pdx7agn0.stx +44 -0
- package/dist/{Select-g4mmvfv8.stx → Select-28y0pg83.stx} +23 -31
- package/dist/Sidebar-73vc78as.stx +236 -0
- package/dist/SidebarFooter-zsfsgcxb.stx +109 -0
- package/dist/SidebarHeader-7v174a9c.stx +122 -0
- package/dist/SidebarItem-3y3e8g2t.stx +92 -0
- package/dist/SidebarSection-z5ey6awe.stx +113 -0
- package/dist/{Signup-c4dyv6f3.stx → Signup-hxm5hwkr.stx} +26 -28
- package/dist/{StepperStep-en4r00zv.stx → StepperStep-wxgembat.stx} +9 -5
- package/dist/{SubscriptionCheckout-gawjzf3q.stx → SubscriptionCheckout-zy2ycrmw.stx} +99 -129
- package/dist/Switch-r5t5w04w.stx +70 -0
- package/dist/{TableHeader-ydys9rzz.stx → TableHeader-0eyzbqpz.stx} +10 -3
- package/dist/Tabs-bzvvn4ke.stx +126 -0
- package/dist/Teleport-tsx4bt4n.stx +65 -0
- package/dist/{TextInput-k2kfkgy1.stx → TextInput-kf084763.stx} +42 -59
- package/dist/{Textarea-szad57dz.stx → Textarea-xg4rr2xz.stx} +42 -54
- package/dist/{Tooltip-em7t551n.stx → Tooltip-m0tqd72e.stx} +34 -40
- package/dist/Transition-7smenaz8.stx +102 -0
- package/dist/{TwoFactorChallenge-an9yvxvq.stx → TwoFactorChallenge-y5m3nk79.stx} +49 -63
- package/dist/{Video-crxva65p.stx → Video-84j4pv6h.stx} +4 -4
- package/dist/VirtualList-fa7v5a3h.stx +67 -0
- package/dist/VirtualTable-f9crbfjr.stx +103 -0
- package/dist/components/CodeBlock.stx +1 -6
- package/dist/index.js +13 -13
- package/dist/ui/accordion/Accordion.stx +1 -3
- package/dist/ui/auth/Login.stx +0 -1
- package/dist/ui/auth/Signup.stx +0 -1
- package/dist/ui/auth/TwoFactorChallenge.stx +1 -3
- package/dist/ui/avatar/Avatar.stx +0 -2
- package/dist/ui/badge/Badge.stx +0 -1
- package/dist/ui/button/Button.stx +1 -2
- package/dist/ui/calendar/Calendar.stx +12 -2
- package/dist/ui/card/Card.stx +0 -2
- package/dist/ui/checkbox/Checkbox.stx +2 -2
- package/dist/ui/combobox/Combobox.stx +2 -1
- package/dist/ui/combobox/ComboboxButton.stx +1 -0
- package/dist/ui/combobox/ComboboxInput.stx +1 -4
- package/dist/ui/combobox/ComboboxOption.stx +2 -9
- package/dist/ui/combobox/ComboboxOptions.stx +1 -1
- package/dist/ui/command-palette/CommandPalette.stx +3 -6
- package/dist/ui/command-palette/CommandPaletteItem.stx +2 -7
- package/dist/ui/dialog/Dialog.stx +1 -3
- package/dist/ui/drawer/Drawer.stx +1 -3
- package/dist/ui/dropdown/Dropdown.stx +2 -5
- package/dist/ui/dropdown/DropdownButton.stx +1 -3
- package/dist/ui/dropdown/DropdownItem.stx +2 -7
- package/dist/ui/dropdown/DropdownItems.stx +1 -1
- package/dist/ui/form/Form.stx +0 -5
- package/dist/ui/image/Image.stx +1 -6
- package/dist/ui/input/EmailInput.stx +1 -1
- package/dist/ui/input/NumberInput.stx +0 -1
- package/dist/ui/input/PasswordInput.stx +1 -4
- package/dist/ui/input/SearchInput.stx +2 -2
- package/dist/ui/input/TextInput.stx +1 -2
- package/dist/ui/listbox/Listbox.stx +2 -1
- package/dist/ui/listbox/ListboxButton.stx +1 -0
- package/dist/ui/listbox/ListboxOption.stx +2 -9
- package/dist/ui/listbox/ListboxOptions.stx +1 -1
- package/dist/ui/navigator/Navigator.stx +4 -4
- package/dist/ui/notification/Notification.stx +1 -5
- package/dist/ui/pagination/Pagination.stx +1 -2
- package/dist/ui/payment/Checkout.stx +0 -4
- package/dist/ui/payment/PaymentMethods.stx +15 -2
- package/dist/ui/payment/SubscriptionCheckout.stx +3 -184
- package/dist/ui/popover/Popover.stx +2 -5
- package/dist/ui/popover/PopoverButton.stx +1 -3
- package/dist/ui/popover/PopoverPanel.stx +1 -1
- package/dist/ui/portal/Portal.stx +1 -0
- package/dist/ui/progress/Progress.stx +6 -1
- package/dist/ui/radio/Radio.stx +1 -1
- package/dist/ui/radio-group/RadioGroup.stx +2 -1
- package/dist/ui/radio-group/RadioGroupOption.stx +2 -9
- package/dist/ui/select/Select.stx +1 -1
- package/dist/ui/sidebar/Sidebar.stx +9 -26
- package/dist/ui/sidebar/SidebarFooter.stx +6 -21
- package/dist/ui/sidebar/SidebarHeader.stx +7 -18
- package/dist/ui/sidebar/SidebarItem.stx +4 -20
- package/dist/ui/sidebar/SidebarSection.stx +5 -18
- package/dist/ui/sidebar/index.d.ts +13 -1
- package/dist/ui/stepper/StepperStep.stx +1 -5
- package/dist/ui/switch/Switch.stx +4 -10
- package/dist/ui/table/TableHeader.stx +1 -1
- package/dist/ui/tabs/Tabs.stx +0 -1
- package/dist/ui/teleport/Teleport.stx +1 -0
- package/dist/ui/textarea/Textarea.stx +1 -1
- package/dist/ui/tooltip/Tooltip.stx +1 -2
- package/dist/ui/transition/Transition.stx +9 -16
- package/dist/ui/virtual-list/VirtualList.stx +2 -4
- package/dist/ui/virtual-table/VirtualTable.stx +1 -1
- package/package.json +3 -3
- package/src/components/CodeBlock.stx +26 -29
- package/src/components/Footer.stx +1 -1
- package/src/components/Hero.stx +1 -1
- package/src/components/Installation.stx +5 -7
- package/src/ui/accordion/Accordion.stx +48 -68
- package/src/ui/audio/Audio.stx +4 -4
- package/src/ui/auth/Login.stx +17 -19
- package/src/ui/auth/Signup.stx +26 -28
- package/src/ui/auth/TwoFactorChallenge.stx +49 -63
- package/src/ui/avatar/Avatar.stx +23 -34
- package/src/ui/badge/Badge.stx +11 -19
- package/src/ui/button/Button.stx +18 -33
- package/src/ui/calendar/Calendar.stx +93 -136
- package/src/ui/card/Card.stx +27 -33
- package/src/ui/checkbox/Checkbox.stx +36 -44
- package/src/ui/combobox/Combobox.stx +87 -4
- package/src/ui/combobox/ComboboxButton.stx +14 -2
- package/src/ui/combobox/ComboboxInput.stx +12 -5
- package/src/ui/combobox/ComboboxOption.stx +29 -32
- package/src/ui/combobox/ComboboxOptions.stx +7 -3
- package/src/ui/command-palette/CommandPalette.stx +70 -28
- package/src/ui/command-palette/CommandPaletteItem.stx +15 -20
- package/src/ui/dialog/Dialog.stx +28 -10
- package/src/ui/drawer/Drawer.stx +29 -49
- package/src/ui/dropdown/Dropdown.stx +69 -11
- package/src/ui/dropdown/DropdownButton.stx +12 -6
- package/src/ui/dropdown/DropdownItem.stx +18 -26
- package/src/ui/dropdown/DropdownItems.stx +2 -2
- package/src/ui/form/Form.stx +50 -164
- package/src/ui/heatmap/Heatmap.stx +16 -37
- package/src/ui/image/Image.stx +68 -100
- package/src/ui/input/EmailInput.stx +16 -27
- package/src/ui/input/NumberInput.stx +40 -53
- package/src/ui/input/PasswordInput.stx +64 -77
- package/src/ui/input/SearchInput.stx +27 -46
- package/src/ui/input/TextInput.stx +42 -59
- package/src/ui/listbox/Listbox.stx +91 -4
- package/src/ui/listbox/ListboxButton.stx +12 -1
- package/src/ui/listbox/ListboxOption.stx +30 -38
- package/src/ui/listbox/ListboxOptions.stx +2 -2
- package/src/ui/navigator/Navigator.stx +52 -77
- package/src/ui/notification/Notification.stx +46 -39
- package/src/ui/pagination/Pagination.stx +73 -108
- package/src/ui/payment/Checkout.stx +8 -16
- package/src/ui/payment/PaymentMethods.stx +21 -30
- package/src/ui/payment/SubscriptionCheckout.stx +99 -129
- package/src/ui/popover/Popover.stx +50 -14
- package/src/ui/popover/PopoverButton.stx +12 -6
- package/src/ui/popover/PopoverPanel.stx +6 -6
- package/src/ui/portal/Portal.stx +20 -37
- package/src/ui/progress/Progress.stx +36 -48
- package/src/ui/radio/Radio.stx +29 -34
- package/src/ui/radio-group/RadioGroup.stx +51 -4
- package/src/ui/radio-group/RadioGroupOption.stx +37 -30
- package/src/ui/select/Select.stx +23 -31
- package/src/ui/sidebar/Sidebar.stx +136 -188
- package/src/ui/sidebar/SidebarFooter.stx +49 -35
- package/src/ui/sidebar/SidebarHeader.stx +52 -30
- package/src/ui/sidebar/SidebarItem.stx +52 -78
- package/src/ui/sidebar/SidebarSection.stx +56 -51
- package/src/ui/sidebar/index.ts +21 -1
- package/src/ui/stepper/StepperStep.stx +9 -5
- package/src/ui/switch/Switch.stx +38 -42
- package/src/ui/table/TableHeader.stx +10 -3
- package/src/ui/tabs/Tabs.stx +68 -87
- package/src/ui/teleport/Teleport.stx +23 -59
- package/src/ui/textarea/Textarea.stx +42 -54
- package/src/ui/tooltip/Tooltip.stx +34 -40
- package/src/ui/transition/Transition.stx +76 -148
- package/src/ui/video/Video.stx +4 -4
- package/src/ui/virtual-list/VirtualList.stx +45 -61
- package/src/ui/virtual-table/VirtualTable.stx +62 -72
- package/dist/Accordion-sbfra0mz.stx +0 -108
- package/dist/Calendar-58nnkdh8.stx +0 -232
- package/dist/Combobox-th5ebw62.stx +0 -13
- package/dist/ComboboxOption-an9zyan6.stx +0 -52
- package/dist/CommandPalette-kwmdf2np.stx +0 -39
- package/dist/CommandPaletteItem-zx2fbpts.stx +0 -32
- package/dist/Dialog-rgmj8q2j.stx +0 -19
- package/dist/Dropdown-jz4jy0n3.stx +0 -24
- package/dist/DropdownItem-wagdspb8.stx +0 -43
- package/dist/EmailInput-ajsp9vw6.stx +0 -41
- package/dist/Form-1mdmx9b6.stx +0 -209
- package/dist/Listbox-pqqh72g8.stx +0 -14
- package/dist/ListboxOption-7nxzaexq.stx +0 -57
- package/dist/Navigator-aay8bjab.stx +0 -138
- package/dist/Notification-gk33gv7b.stx +0 -71
- package/dist/PasswordInput-zv4hm43j.stx +0 -155
- package/dist/Popover-469gbt6r.stx +0 -24
- package/dist/RadioGroup-bvb1mrhd.stx +0 -13
- package/dist/RadioGroupOption-cpdwgnhw.stx +0 -51
- package/dist/SearchInput-2521m475.stx +0 -63
- package/dist/Sidebar-40ckbzh8.stx +0 -288
- package/dist/SidebarFooter-hnth56mg.stx +0 -95
- package/dist/SidebarHeader-3wrte2p2.stx +0 -100
- package/dist/SidebarItem-zqtvvzpc.stx +0 -118
- package/dist/SidebarSection-3etwnbjr.stx +0 -108
- package/dist/Switch-036j9vm1.stx +0 -74
- package/dist/Tabs-svh721m0.stx +0 -145
- package/dist/Teleport-qfch3w0b.stx +0 -101
- package/dist/Transition-0hmr6zxb.stx +0 -174
- package/dist/VirtualList-cndhjejh.stx +0 -83
- package/dist/VirtualTable-ng0b48yp.stx +0 -113
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<script server>
|
|
2
|
+
export const items = $props.items || []
|
|
3
|
+
export const allowMultiple = $props.allowMultiple || false
|
|
4
|
+
export const defaultOpen = $props.defaultOpen || []
|
|
5
|
+
export const className = $props.className || ''
|
|
6
|
+
|
|
7
|
+
export const accordionClasses = `divide-y divide-gray-200 dark:divide-gray-700 border border-gray-200 dark:border-gray-700 rounded-lg ${className}`.trim()
|
|
8
|
+
export const headerClasses = `w-full flex items-center justify-between px-4 py-3 text-left font-medium text-gray-900 dark:text-gray-100 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900`.trim()
|
|
9
|
+
export const iconClasses = `w-5 h-5 text-gray-500 dark:text-gray-400 transition-transform duration-200`.trim()
|
|
10
|
+
export const contentClasses = `px-4 py-3 text-gray-700 dark:text-gray-300`.trim()
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<script client>
|
|
14
|
+
const emit = defineEmits()
|
|
15
|
+
const allowMultiple = {{ allowMultiple }}
|
|
16
|
+
const openItems = state({{ defaultOpen }})
|
|
17
|
+
|
|
18
|
+
function toggleItem(index) {
|
|
19
|
+
const cur = openItems()
|
|
20
|
+
if (allowMultiple) {
|
|
21
|
+
openItems.set(cur.includes(index) ? cur.filter(i => i !== index) : [...cur, index])
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
openItems.set(cur.includes(index) ? [] : [index])
|
|
25
|
+
}
|
|
26
|
+
emit('change', openItems())
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function isOpen(index) {
|
|
30
|
+
return openItems().includes(index)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function onHeaderKey(event, index) {
|
|
34
|
+
const buttons = event.currentTarget.closest('[role="region"]').querySelectorAll('button[data-accordion-header]')
|
|
35
|
+
if (event.key === 'ArrowDown') {
|
|
36
|
+
event.preventDefault()
|
|
37
|
+
buttons[index + 1]?.focus()
|
|
38
|
+
}
|
|
39
|
+
else if (event.key === 'ArrowUp') {
|
|
40
|
+
event.preventDefault()
|
|
41
|
+
buttons[index - 1]?.focus()
|
|
42
|
+
}
|
|
43
|
+
else if (event.key === 'Home') {
|
|
44
|
+
event.preventDefault()
|
|
45
|
+
buttons[0]?.focus()
|
|
46
|
+
}
|
|
47
|
+
else if (event.key === 'End') {
|
|
48
|
+
event.preventDefault()
|
|
49
|
+
buttons[buttons.length - 1]?.focus()
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
<div class="{{ accordionClasses }}" role="region">
|
|
55
|
+
@foreach(item in items)
|
|
56
|
+
<div>
|
|
57
|
+
<button
|
|
58
|
+
type="button"
|
|
59
|
+
data-accordion-header
|
|
60
|
+
class="{{ headerClasses }}"
|
|
61
|
+
@click="toggleItem({{ $loop.index }})"
|
|
62
|
+
@keydown="onHeaderKey($event, {{ $loop.index }})"
|
|
63
|
+
:aria-expanded="isOpen({{ $loop.index }}) ? 'true' : 'false'"
|
|
64
|
+
aria-controls="accordion-content-{{ $loop.index }}"
|
|
65
|
+
>
|
|
66
|
+
<span>{{ item.title }}</span>
|
|
67
|
+
<svg
|
|
68
|
+
class="{{ iconClasses }}"
|
|
69
|
+
:style="`transform: rotate(${isOpen({{ $loop.index }}) ? 180 : 0}deg)`"
|
|
70
|
+
fill="none"
|
|
71
|
+
viewBox="0 0 24 24"
|
|
72
|
+
stroke="currentColor"
|
|
73
|
+
>
|
|
74
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
|
75
|
+
</svg>
|
|
76
|
+
</button>
|
|
77
|
+
|
|
78
|
+
<div
|
|
79
|
+
:show="isOpen({{ $loop.index }})"
|
|
80
|
+
id="accordion-content-{{ $loop.index }}"
|
|
81
|
+
class="{{ contentClasses }}"
|
|
82
|
+
role="region"
|
|
83
|
+
>
|
|
84
|
+
{!! item.content !!}
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
@endforeach
|
|
88
|
+
</div>
|
|
@@ -25,10 +25,10 @@ export const audioClasses = 'w-full rounded-md bg-gray-100 dark:bg-gray-800'
|
|
|
25
25
|
<audio
|
|
26
26
|
class="{{ audioClasses }}"
|
|
27
27
|
src="{{ src }}"
|
|
28
|
-
controls
|
|
29
|
-
autoplay
|
|
30
|
-
loop
|
|
31
|
-
muted
|
|
28
|
+
@if(controls)controls@endif
|
|
29
|
+
@if(autoplay)autoplay@endif
|
|
30
|
+
@if(loop)loop@endif
|
|
31
|
+
@if(muted)muted@endif
|
|
32
32
|
preload="{{ preload }}"
|
|
33
33
|
>
|
|
34
34
|
Your browser does not support the audio element.
|
|
@@ -6,11 +6,7 @@ export const size = $props.size || 'md'
|
|
|
6
6
|
export const shape = $props.shape || 'circle'
|
|
7
7
|
export const status = $props.status || ''
|
|
8
8
|
export const className = $props.className || ''
|
|
9
|
-
export const onError = $props.onError
|
|
10
9
|
|
|
11
|
-
let imageError = false
|
|
12
|
-
|
|
13
|
-
// Size classes
|
|
14
10
|
const sizeClasses = {
|
|
15
11
|
xs: 'w-6 h-6 text-xs',
|
|
16
12
|
sm: 'w-8 h-8 text-sm',
|
|
@@ -20,13 +16,8 @@ const sizeClasses = {
|
|
|
20
16
|
'2xl': 'w-20 h-20 text-2xl',
|
|
21
17
|
}
|
|
22
18
|
|
|
23
|
-
|
|
24
|
-
const shapeClasses = {
|
|
25
|
-
circle: 'rounded-full',
|
|
26
|
-
square: 'rounded-md',
|
|
27
|
-
}
|
|
19
|
+
const shapeClasses = { circle: 'rounded-full', square: 'rounded-md' }
|
|
28
20
|
|
|
29
|
-
// Status indicator size classes
|
|
30
21
|
const statusSizeClasses = {
|
|
31
22
|
xs: 'w-1.5 h-1.5 border',
|
|
32
23
|
sm: 'w-2 h-2 border',
|
|
@@ -36,7 +27,6 @@ const statusSizeClasses = {
|
|
|
36
27
|
'2xl': 'w-4 h-4 border-2',
|
|
37
28
|
}
|
|
38
29
|
|
|
39
|
-
// Status color classes
|
|
40
30
|
const statusColorClasses = {
|
|
41
31
|
online: 'bg-green-500 dark:bg-green-400',
|
|
42
32
|
offline: 'bg-gray-400 dark:bg-gray-600',
|
|
@@ -48,24 +38,33 @@ export const containerClasses = `relative inline-block ${className}`.trim()
|
|
|
48
38
|
export const avatarClasses = `flex items-center justify-center overflow-hidden bg-gray-200 dark:bg-gray-700 ${sizeClasses[size]} ${shapeClasses[shape]}`.trim()
|
|
49
39
|
export const imageClasses = `w-full h-full object-cover`.trim()
|
|
50
40
|
export const initialsClasses = `font-medium text-gray-600 dark:text-gray-300 uppercase select-none`.trim()
|
|
51
|
-
export const statusClasses = `absolute bottom-0 right-0 ${statusSizeClasses[size]} ${statusColorClasses[status]} ${shapeClasses[shape]} border-white dark:border-gray-900`.trim()
|
|
52
|
-
|
|
53
|
-
// Generate initials from name if not provided
|
|
41
|
+
export const statusClasses = status ? `absolute bottom-0 right-0 ${statusSizeClasses[size]} ${statusColorClasses[status]} ${shapeClasses[shape]} border-white dark:border-gray-900`.trim() : ''
|
|
54
42
|
export const displayInitials = initials || (alt ? alt.split(' ').map(n => n[0]).join('').substring(0, 2) : '?')
|
|
55
43
|
</script>
|
|
56
44
|
|
|
45
|
+
<script client>
|
|
46
|
+
const emit = defineEmits()
|
|
47
|
+
const imageError = state(false)
|
|
48
|
+
const hasSrc = {{ !!src }}
|
|
49
|
+
|
|
50
|
+
function onImageError(event) {
|
|
51
|
+
imageError.set(true)
|
|
52
|
+
emit('error', event)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const showImage = derived(() => hasSrc && !imageError())
|
|
56
|
+
</script>
|
|
57
|
+
|
|
57
58
|
<div class="{{ containerClasses }}">
|
|
58
59
|
<div class="{{ avatarClasses }}">
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
<span class="{{ initialsClasses }}">{{ displayInitials }}</span>
|
|
68
|
-
@endif
|
|
60
|
+
<img
|
|
61
|
+
:show="showImage()"
|
|
62
|
+
src="{{ src }}"
|
|
63
|
+
alt="{{ alt }}"
|
|
64
|
+
class="{{ imageClasses }}"
|
|
65
|
+
@error="onImageError($event)"
|
|
66
|
+
/>
|
|
67
|
+
<span :show="!showImage()" class="{{ initialsClasses }}">{{ displayInitials }}</span>
|
|
69
68
|
</div>
|
|
70
69
|
|
|
71
70
|
@if(status)
|
|
@@ -76,13 +75,3 @@ export const displayInitials = initials || (alt ? alt.split(' ').map(n => n[0]).
|
|
|
76
75
|
></span>
|
|
77
76
|
@endif
|
|
78
77
|
</div>
|
|
79
|
-
|
|
80
|
-
<script>
|
|
81
|
-
function handleImageError(event) {
|
|
82
|
-
imageError = true
|
|
83
|
-
|
|
84
|
-
if (onError) {
|
|
85
|
-
onError(event)
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
</script>
|
|
@@ -4,9 +4,7 @@ export const size = $props.size || 'md'
|
|
|
4
4
|
export const dot = $props.dot || false
|
|
5
5
|
export const removable = $props.removable || false
|
|
6
6
|
export const className = $props.className || ''
|
|
7
|
-
export const onRemove = $props.onRemove
|
|
8
7
|
|
|
9
|
-
// Variant classes
|
|
10
8
|
const variantClasses = {
|
|
11
9
|
default: 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300',
|
|
12
10
|
primary: 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200',
|
|
@@ -17,14 +15,8 @@ const variantClasses = {
|
|
|
17
15
|
info: 'bg-cyan-100 text-cyan-800 dark:bg-cyan-900 dark:text-cyan-200',
|
|
18
16
|
}
|
|
19
17
|
|
|
20
|
-
|
|
21
|
-
const sizeClasses = {
|
|
22
|
-
sm: 'px-2 py-0.5 text-xs',
|
|
23
|
-
md: 'px-2.5 py-0.5 text-sm',
|
|
24
|
-
lg: 'px-3 py-1 text-base',
|
|
25
|
-
}
|
|
18
|
+
const sizeClasses = { sm: 'px-2 py-0.5 text-xs', md: 'px-2.5 py-0.5 text-sm', lg: 'px-3 py-1 text-base' }
|
|
26
19
|
|
|
27
|
-
// Dot color classes
|
|
28
20
|
const dotColorClasses = {
|
|
29
21
|
default: 'bg-gray-500 dark:bg-gray-400',
|
|
30
22
|
primary: 'bg-blue-500 dark:bg-blue-400',
|
|
@@ -40,6 +32,14 @@ export const dotClasses = `w-2 h-2 rounded-full ${dotColorClasses[variant]}`.tri
|
|
|
40
32
|
export const removeButtonClasses = `ml-0.5 -mr-1 text-current hover:bg-black hover:bg-opacity-10 dark:hover:bg-white dark:hover:bg-opacity-10 rounded-full p-0.5 transition-colors duration-150`.trim()
|
|
41
33
|
</script>
|
|
42
34
|
|
|
35
|
+
<script client>
|
|
36
|
+
const emit = defineEmits()
|
|
37
|
+
|
|
38
|
+
function onRemove() {
|
|
39
|
+
emit('remove')
|
|
40
|
+
}
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
43
|
<span class="{{ badgeClasses }}" role="status">
|
|
44
44
|
@if(dot)
|
|
45
45
|
<span class="{{ dotClasses }}" aria-hidden="true"></span>
|
|
@@ -47,10 +47,10 @@ export const removeButtonClasses = `ml-0.5 -mr-1 text-current hover:bg-black hov
|
|
|
47
47
|
|
|
48
48
|
<slot />
|
|
49
49
|
|
|
50
|
-
@if(removable
|
|
50
|
+
@if(removable)
|
|
51
51
|
<button
|
|
52
52
|
type="button"
|
|
53
|
-
@click="
|
|
53
|
+
@click="onRemove()"
|
|
54
54
|
class="{{ removeButtonClasses }}"
|
|
55
55
|
aria-label="Remove"
|
|
56
56
|
>
|
|
@@ -60,11 +60,3 @@ export const removeButtonClasses = `ml-0.5 -mr-1 text-current hover:bg-black hov
|
|
|
60
60
|
</button>
|
|
61
61
|
@endif
|
|
62
62
|
</span>
|
|
63
|
-
|
|
64
|
-
<script>
|
|
65
|
-
function handleRemove() {
|
|
66
|
-
if (onRemove) {
|
|
67
|
-
onRemove()
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
</script>
|
|
@@ -8,9 +8,7 @@ export const fullWidth = $props.fullWidth || false
|
|
|
8
8
|
export const leftIcon = $props.leftIcon || ''
|
|
9
9
|
export const rightIcon = $props.rightIcon || ''
|
|
10
10
|
export const className = $props.className || ''
|
|
11
|
-
export const onClick = $props.onClick
|
|
12
11
|
|
|
13
|
-
// Variant styles using headwind
|
|
14
12
|
const variantClasses = {
|
|
15
13
|
primary: 'bg-blue-500 hover:bg-blue-600 text-white shadow-md hover:shadow-lg dark:bg-blue-600 dark:hover:bg-blue-700',
|
|
16
14
|
secondary: 'bg-neutral-200 hover:bg-neutral-300 text-neutral-900 dark:bg-neutral-700 dark:hover:bg-neutral-600 dark:text-white',
|
|
@@ -19,7 +17,6 @@ const variantClasses = {
|
|
|
19
17
|
danger: 'bg-red-500 hover:bg-red-600 text-white shadow-md hover:shadow-lg dark:bg-red-600 dark:hover:bg-red-700',
|
|
20
18
|
}
|
|
21
19
|
|
|
22
|
-
// Size styles using headwind
|
|
23
20
|
const sizeClasses = {
|
|
24
21
|
xs: 'px-2.5 py-1 text-xs h-7 gap-1',
|
|
25
22
|
sm: 'px-3 py-1.5 text-sm h-8 gap-1.5',
|
|
@@ -28,62 +25,50 @@ const sizeClasses = {
|
|
|
28
25
|
xl: 'px-8 py-4 text-xl h-14 gap-3',
|
|
29
26
|
}
|
|
30
27
|
|
|
31
|
-
|
|
32
|
-
const iconSizeClasses = {
|
|
33
|
-
xs: 'h-3 w-3',
|
|
34
|
-
sm: 'h-4 w-4',
|
|
35
|
-
md: 'h-5 w-5',
|
|
36
|
-
lg: 'h-6 w-6',
|
|
37
|
-
xl: 'h-7 w-7',
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Base classes
|
|
28
|
+
const iconSizeClasses = { xs: 'h-3 w-3', sm: 'h-4 w-4', md: 'h-5 w-5', lg: 'h-6 w-6', xl: 'h-7 w-7' }
|
|
41
29
|
const baseClasses = 'inline-flex items-center justify-center font-semibold rounded-md transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none'
|
|
42
|
-
|
|
43
|
-
// Width classes
|
|
44
30
|
const widthClasses = fullWidth ? 'w-full' : ''
|
|
31
|
+
export const isDisabled = disabled || loading
|
|
45
32
|
|
|
46
|
-
// Loading state disables interactions
|
|
47
|
-
const isDisabled = disabled || loading
|
|
48
|
-
|
|
49
|
-
// Combine classes
|
|
50
33
|
export const buttonClasses = `${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]} ${widthClasses} ${className}`.trim()
|
|
51
34
|
export const iconClasses = iconSizeClasses[size]
|
|
52
35
|
export const spinnerClasses = `animate-spin ${iconClasses}`.trim()
|
|
53
36
|
</script>
|
|
54
37
|
|
|
38
|
+
<script client>
|
|
39
|
+
const emit = defineEmits()
|
|
40
|
+
const disabledNow = {{ isDisabled }}
|
|
41
|
+
|
|
42
|
+
function onClick(event) {
|
|
43
|
+
if (disabledNow) {
|
|
44
|
+
event.preventDefault()
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
emit('click', event)
|
|
48
|
+
}
|
|
49
|
+
</script>
|
|
50
|
+
|
|
55
51
|
<button
|
|
56
52
|
type="{{ type }}"
|
|
57
53
|
class="{{ buttonClasses }}"
|
|
58
54
|
@if(isDisabled)disabled@endif
|
|
59
|
-
@
|
|
55
|
+
@click="onClick($event)"
|
|
60
56
|
aria-busy="{{ loading ? 'true' : 'false' }}"
|
|
61
57
|
>
|
|
62
58
|
@if(loading)
|
|
63
|
-
<!-- Loading spinner -->
|
|
64
59
|
<svg class="{{ spinnerClasses }}" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
65
60
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
66
61
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
67
62
|
</svg>
|
|
68
63
|
@else
|
|
69
64
|
@if(leftIcon)
|
|
70
|
-
|
|
71
|
-
<span class="{{ iconClasses }}" innerHTML="{!! leftIcon !!}"></span>
|
|
65
|
+
<span class="{{ iconClasses }}">{!! leftIcon !!}</span>
|
|
72
66
|
@endif
|
|
73
67
|
@endif
|
|
74
68
|
|
|
75
69
|
<slot />
|
|
76
70
|
|
|
77
71
|
@if(!loading && rightIcon)
|
|
78
|
-
|
|
79
|
-
<span class="{{ iconClasses }}" innerHTML="{!! rightIcon !!}"></span>
|
|
72
|
+
<span class="{{ iconClasses }}">{!! rightIcon !!}</span>
|
|
80
73
|
@endif
|
|
81
74
|
</button>
|
|
82
|
-
|
|
83
|
-
<script>
|
|
84
|
-
function handleClick(event) {
|
|
85
|
-
if (!isDisabled && onClick) {
|
|
86
|
-
onClick(event)
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
</script>
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
<script server>
|
|
2
|
+
export const value = $props.value || null
|
|
3
|
+
export const minDate = $props.minDate || null
|
|
4
|
+
export const maxDate = $props.maxDate || null
|
|
5
|
+
export const disabledDates = $props.disabledDates || []
|
|
6
|
+
export const locale = $props.locale || 'en-US'
|
|
7
|
+
export const firstDayOfWeek = $props.firstDayOfWeek || 0
|
|
8
|
+
export const showToday = $props.showToday !== false
|
|
9
|
+
export const className = $props.className || ''
|
|
10
|
+
export const highlightToday = $props.highlightToday !== false
|
|
11
|
+
|
|
12
|
+
const baseClasses = 'bg-white dark:bg-gray-800 rounded-lg shadow-lg p-4 w-full max-w-sm'
|
|
13
|
+
export const calendarClasses = `${baseClasses} ${className}`.trim()
|
|
14
|
+
export const headerClasses = 'flex items-center justify-between mb-4'
|
|
15
|
+
export const monthYearClasses = 'text-lg font-semibold text-gray-900 dark:text-gray-100'
|
|
16
|
+
export const buttonClasses = 'p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-md transition-colors'
|
|
17
|
+
export const weekdaysClasses = 'grid grid-cols-7 gap-1 mb-2'
|
|
18
|
+
export const weekdayClasses = 'text-center text-xs font-medium text-gray-600 dark:text-gray-400 py-2'
|
|
19
|
+
export const daysGridClasses = 'grid grid-cols-7 gap-1'
|
|
20
|
+
|
|
21
|
+
const valueIso = value ? new Date(value).toISOString() : null
|
|
22
|
+
export const initialValueIso = valueIso
|
|
23
|
+
const minIso = minDate ? new Date(minDate).toISOString() : null
|
|
24
|
+
const maxIso = maxDate ? new Date(maxDate).toISOString() : null
|
|
25
|
+
export const minIsoValue = minIso
|
|
26
|
+
export const maxIsoValue = maxIso
|
|
27
|
+
export const disabledIsoList = disabledDates.map(d => new Date(d).toISOString())
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<script client>
|
|
31
|
+
const emit = defineEmits()
|
|
32
|
+
const locale = {{ locale }}
|
|
33
|
+
const firstDayOfWeek = {{ firstDayOfWeek }}
|
|
34
|
+
const highlightToday = {{ highlightToday }}
|
|
35
|
+
const minDate = {{ minIsoValue === null ? 'null' : minIsoValue }} ? new Date({{ minIsoValue === null ? 'null' : minIsoValue }}) : null
|
|
36
|
+
const maxDate = {{ maxIsoValue === null ? 'null' : maxIsoValue }} ? new Date({{ maxIsoValue === null ? 'null' : maxIsoValue }}) : null
|
|
37
|
+
const disabledDates = ({{ disabledIsoList }}).map(s => new Date(s))
|
|
38
|
+
const initialValue = {{ initialValueIso === null ? 'null' : initialValueIso }} ? new Date({{ initialValueIso === null ? 'null' : initialValueIso }}) : null
|
|
39
|
+
|
|
40
|
+
const today = new Date()
|
|
41
|
+
const currentMonth = state(initialValue ? new Date(initialValue) : new Date())
|
|
42
|
+
const selectedDate = state(initialValue)
|
|
43
|
+
|
|
44
|
+
function isSameDay(d1, d2) {
|
|
45
|
+
if (!d1 || !d2) return false
|
|
46
|
+
return d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth() && d1.getDate() === d2.getDate()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function isToday(d) { return isSameDay(d, today) }
|
|
50
|
+
|
|
51
|
+
function isDisabled(d) {
|
|
52
|
+
if (minDate && d < minDate) return true
|
|
53
|
+
if (maxDate && d > maxDate) return true
|
|
54
|
+
return disabledDates.some(x => isSameDay(x, d))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function getDaysInMonth(d) { return new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate() }
|
|
58
|
+
function getFirstDayOfMonth(d) { return new Date(d.getFullYear(), d.getMonth(), 1).getDay() }
|
|
59
|
+
|
|
60
|
+
const monthYearLabel = derived(() => {
|
|
61
|
+
const m = currentMonth()
|
|
62
|
+
return `${m.toLocaleDateString(locale, { month: 'long' })} ${m.getFullYear()}`
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
const dayNames = (() => {
|
|
66
|
+
const days = []
|
|
67
|
+
const baseDate = new Date(2024, 0, firstDayOfWeek)
|
|
68
|
+
for (let i = 0; i < 7; i++) {
|
|
69
|
+
const day = new Date(baseDate)
|
|
70
|
+
day.setDate(baseDate.getDate() + i)
|
|
71
|
+
days.push(day.toLocaleDateString(locale, { weekday: 'short' }))
|
|
72
|
+
}
|
|
73
|
+
return days
|
|
74
|
+
})()
|
|
75
|
+
|
|
76
|
+
const calendarDays = derived(() => {
|
|
77
|
+
const month = currentMonth()
|
|
78
|
+
const daysInMonth = getDaysInMonth(month)
|
|
79
|
+
const firstDay = (getFirstDayOfMonth(month) - firstDayOfWeek + 7) % 7
|
|
80
|
+
const days = []
|
|
81
|
+
const prev = new Date(month.getFullYear(), month.getMonth() - 1, 1)
|
|
82
|
+
const daysInPrev = getDaysInMonth(prev)
|
|
83
|
+
for (let i = firstDay - 1; i >= 0; i--) {
|
|
84
|
+
days.push({ date: new Date(prev.getFullYear(), prev.getMonth(), daysInPrev - i), isCurrentMonth: false })
|
|
85
|
+
}
|
|
86
|
+
for (let i = 1; i <= daysInMonth; i++) {
|
|
87
|
+
days.push({ date: new Date(month.getFullYear(), month.getMonth(), i), isCurrentMonth: true })
|
|
88
|
+
}
|
|
89
|
+
const remaining = 42 - days.length
|
|
90
|
+
const next = new Date(month.getFullYear(), month.getMonth() + 1, 1)
|
|
91
|
+
for (let i = 1; i <= remaining; i++) {
|
|
92
|
+
days.push({ date: new Date(next.getFullYear(), next.getMonth(), i), isCurrentMonth: false })
|
|
93
|
+
}
|
|
94
|
+
return days
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
function previousMonth() {
|
|
98
|
+
const m = currentMonth()
|
|
99
|
+
currentMonth.set(new Date(m.getFullYear(), m.getMonth() - 1, 1))
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function nextMonthFn() {
|
|
103
|
+
const m = currentMonth()
|
|
104
|
+
currentMonth.set(new Date(m.getFullYear(), m.getMonth() + 1, 1))
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function selectDate(date) {
|
|
108
|
+
if (isDisabled(date)) return
|
|
109
|
+
selectedDate.set(date)
|
|
110
|
+
emit('change', date)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function goToToday() {
|
|
114
|
+
currentMonth.set(new Date(today))
|
|
115
|
+
selectDate(today)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function dayClasses(day) {
|
|
119
|
+
const base = 'flex items-center justify-center h-10 w-10 rounded-md text-sm transition-colors'
|
|
120
|
+
const isSelected = isSameDay(day.date, selectedDate())
|
|
121
|
+
const isTodayDate = isToday(day.date)
|
|
122
|
+
const disabled = isDisabled(day.date)
|
|
123
|
+
let cls = base
|
|
124
|
+
cls += day.isCurrentMonth ? ' text-gray-900 dark:text-gray-100' : ' text-gray-400 dark:text-gray-600'
|
|
125
|
+
cls += disabled ? ' opacity-50 cursor-not-allowed' : ' cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700'
|
|
126
|
+
if (isSelected) cls += ' bg-blue-600 text-white hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600'
|
|
127
|
+
if (isTodayDate && highlightToday && !isSelected) cls += ' border-2 border-blue-600 dark:border-blue-400'
|
|
128
|
+
return cls
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
defineExpose({ selectedDate, currentMonth, selectDate })
|
|
132
|
+
</script>
|
|
133
|
+
|
|
134
|
+
<div class="{{ calendarClasses }}">
|
|
135
|
+
<div class="{{ headerClasses }}">
|
|
136
|
+
<button
|
|
137
|
+
type="button"
|
|
138
|
+
class="{{ buttonClasses }}"
|
|
139
|
+
@click="previousMonth()"
|
|
140
|
+
aria-label="Previous month"
|
|
141
|
+
>
|
|
142
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
143
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
|
144
|
+
</svg>
|
|
145
|
+
</button>
|
|
146
|
+
|
|
147
|
+
<div class="{{ monthYearClasses }}" x-text="monthYearLabel()"></div>
|
|
148
|
+
|
|
149
|
+
<button
|
|
150
|
+
type="button"
|
|
151
|
+
class="{{ buttonClasses }}"
|
|
152
|
+
@click="nextMonthFn()"
|
|
153
|
+
aria-label="Next month"
|
|
154
|
+
>
|
|
155
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
156
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
|
157
|
+
</svg>
|
|
158
|
+
</button>
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
<div class="{{ weekdaysClasses }}">
|
|
162
|
+
<div :for="d in dayNames" :key="d" class="{{ weekdayClasses }}" x-text="d"></div>
|
|
163
|
+
</div>
|
|
164
|
+
|
|
165
|
+
<div class="{{ daysGridClasses }}">
|
|
166
|
+
<button
|
|
167
|
+
:for="day in calendarDays()"
|
|
168
|
+
:key="day.date.toISOString()"
|
|
169
|
+
type="button"
|
|
170
|
+
:class="dayClasses(day)"
|
|
171
|
+
@click="selectDate(day.date)"
|
|
172
|
+
:aria-label="day.date.toLocaleDateString(locale)"
|
|
173
|
+
:disabled="isDisabled(day.date)"
|
|
174
|
+
x-text="day.date.getDate()"
|
|
175
|
+
></button>
|
|
176
|
+
</div>
|
|
177
|
+
|
|
178
|
+
@if(showToday)
|
|
179
|
+
<div class="mt-4 flex justify-center">
|
|
180
|
+
<button
|
|
181
|
+
type="button"
|
|
182
|
+
class="px-4 py-2 text-sm font-medium text-blue-600 dark:text-blue-400 hover:bg-blue-50 dark:hover:bg-gray-700 rounded-md transition-colors"
|
|
183
|
+
@click="goToToday()"
|
|
184
|
+
>
|
|
185
|
+
Today
|
|
186
|
+
</button>
|
|
187
|
+
</div>
|
|
188
|
+
@endif
|
|
189
|
+
</div>
|
|
@@ -5,11 +5,8 @@ export const hover = $props.hover || false
|
|
|
5
5
|
export const clickable = $props.clickable || false
|
|
6
6
|
export const image = $props.image || ''
|
|
7
7
|
export const imageAlt = $props.imageAlt || ''
|
|
8
|
-
export const imagePosition = $props.imagePosition || 'top'
|
|
9
8
|
export const className = $props.className || ''
|
|
10
|
-
export const onClick = $props.onClick
|
|
11
9
|
|
|
12
|
-
// Variant classes
|
|
13
10
|
const variantClasses = {
|
|
14
11
|
default: 'bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700',
|
|
15
12
|
outlined: 'bg-transparent border-2 border-gray-300 dark:border-gray-600',
|
|
@@ -17,18 +14,8 @@ const variantClasses = {
|
|
|
17
14
|
flat: 'bg-gray-50 dark:bg-gray-900 border-0',
|
|
18
15
|
}
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
const paddingClasses = {
|
|
22
|
-
none: 'p-0',
|
|
23
|
-
sm: 'p-3',
|
|
24
|
-
default: 'p-6',
|
|
25
|
-
lg: 'p-8',
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Hover effect classes
|
|
17
|
+
const paddingClasses = { none: 'p-0', sm: 'p-3', default: 'p-6', lg: 'p-8' }
|
|
29
18
|
const hoverClasses = hover ? 'transition-all duration-200 hover:shadow-lg hover:-translate-y-0.5' : ''
|
|
30
|
-
|
|
31
|
-
// Clickable classes
|
|
32
19
|
const clickableClasses = clickable ? 'cursor-pointer' : ''
|
|
33
20
|
|
|
34
21
|
export const cardClasses = `rounded-lg overflow-hidden ${variantClasses[variant]} ${paddingClasses[image ? 'none' : padding]} ${hoverClasses} ${clickableClasses} ${className}`.trim()
|
|
@@ -36,12 +23,35 @@ export const imageClasses = `w-full h-48 object-cover`.trim()
|
|
|
36
23
|
export const contentClasses = `${image ? paddingClasses[padding] : ''}`.trim()
|
|
37
24
|
</script>
|
|
38
25
|
|
|
39
|
-
|
|
40
|
-
|
|
26
|
+
<script client>
|
|
27
|
+
const emit = defineEmits()
|
|
28
|
+
const isClickable = {{ clickable }}
|
|
29
|
+
|
|
30
|
+
function onClick(event) {
|
|
31
|
+
if (!isClickable) return
|
|
32
|
+
emit('click', event)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function onKey(event) {
|
|
36
|
+
if (!isClickable) return
|
|
37
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
38
|
+
event.preventDefault()
|
|
39
|
+
emit('click', event)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
@if(clickable)
|
|
45
|
+
<div
|
|
46
|
+
class="{{ cardClasses }}"
|
|
47
|
+
@click="onClick($event)"
|
|
48
|
+
@keydown="onKey($event)"
|
|
49
|
+
role="button"
|
|
50
|
+
tabindex="0"
|
|
51
|
+
>
|
|
41
52
|
@if(image)
|
|
42
53
|
<img src="{{ image }}" alt="{{ imageAlt }}" class="{{ imageClasses }}" />
|
|
43
54
|
@endif
|
|
44
|
-
|
|
45
55
|
<div class="{{ contentClasses }}">
|
|
46
56
|
<slot />
|
|
47
57
|
</div>
|
|
@@ -51,24 +61,8 @@ export const contentClasses = `${image ? paddingClasses[padding] : ''}`.trim()
|
|
|
51
61
|
@if(image)
|
|
52
62
|
<img src="{{ image }}" alt="{{ imageAlt }}" class="{{ imageClasses }}" />
|
|
53
63
|
@endif
|
|
54
|
-
|
|
55
64
|
<div class="{{ contentClasses }}">
|
|
56
65
|
<slot />
|
|
57
66
|
</div>
|
|
58
67
|
</div>
|
|
59
68
|
@endif
|
|
60
|
-
|
|
61
|
-
<script>
|
|
62
|
-
function handleClick(event) {
|
|
63
|
-
if (clickable && onClick) {
|
|
64
|
-
onClick(event)
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function handleKeyDown(event) {
|
|
69
|
-
if ((event.key === 'Enter' || event.key === ' ') && clickable && onClick) {
|
|
70
|
-
event.preventDefault()
|
|
71
|
-
onClick(event)
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
</script>
|