@stacksjs/components 0.2.93 → 0.2.94

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 (187) hide show
  1. package/dist/index.js +4 -4
  2. package/package.json +5 -6
  3. package/src/components/CodeBlock.stx +0 -54
  4. package/src/components/Footer.stx +0 -66
  5. package/src/components/Hero.stx +0 -25
  6. package/src/components/Installation.stx +0 -37
  7. package/src/components/index.ts +0 -4
  8. package/src/composables/index.ts +0 -4
  9. package/src/composables/useCopyCode.ts +0 -73
  10. package/src/composables/useDarkMode.ts +0 -100
  11. package/src/composables/useSEO.ts +0 -230
  12. package/src/composables/utilities/index.ts +0 -7
  13. package/src/composables/utilities/useClickOutside.ts +0 -72
  14. package/src/composables/utilities/useFocusTrap.ts +0 -159
  15. package/src/composables/utilities/useKeyboard.ts +0 -124
  16. package/src/composables/utilities/useLocalStorage.ts +0 -132
  17. package/src/composables/utilities/useMediaQuery.ts +0 -118
  18. package/src/index.ts +0 -99
  19. package/src/stx.d.ts +0 -4
  20. package/src/ui/accordion/Accordion.stx +0 -146
  21. package/src/ui/accordion/AccordionItem.stx +0 -37
  22. package/src/ui/accordion/index.ts +0 -47
  23. package/src/ui/audio/Audio.stx +0 -50
  24. package/src/ui/audio/README.md +0 -41
  25. package/src/ui/audio/index.ts +0 -13
  26. package/src/ui/auth/Login.stx +0 -161
  27. package/src/ui/auth/README.md +0 -142
  28. package/src/ui/auth/Signup.stx +0 -159
  29. package/src/ui/auth/TwoFactorChallenge.stx +0 -111
  30. package/src/ui/auth/index.ts +0 -32
  31. package/src/ui/avatar/Avatar.stx +0 -77
  32. package/src/ui/avatar/index.ts +0 -12
  33. package/src/ui/badge/Badge.stx +0 -62
  34. package/src/ui/badge/index.ts +0 -10
  35. package/src/ui/breadcrumb/Breadcrumb.stx +0 -79
  36. package/src/ui/breadcrumb/index.ts +0 -15
  37. package/src/ui/button/Button.stx +0 -74
  38. package/src/ui/button/README.md +0 -80
  39. package/src/ui/button/index.ts +0 -85
  40. package/src/ui/calendar/Calendar.stx +0 -189
  41. package/src/ui/calendar/README.md +0 -254
  42. package/src/ui/calendar/index.ts +0 -14
  43. package/src/ui/card/Card.stx +0 -68
  44. package/src/ui/card/index.ts +0 -13
  45. package/src/ui/checkbox/Checkbox.stx +0 -86
  46. package/src/ui/checkbox/index.ts +0 -16
  47. package/src/ui/combobox/Combobox.stx +0 -96
  48. package/src/ui/combobox/ComboboxButton.stx +0 -25
  49. package/src/ui/combobox/ComboboxInput.stx +0 -32
  50. package/src/ui/combobox/ComboboxOption.stx +0 -49
  51. package/src/ui/combobox/ComboboxOptions.stx +0 -16
  52. package/src/ui/combobox/README.md +0 -150
  53. package/src/ui/combobox/index.ts +0 -40
  54. package/src/ui/command-palette/CommandPalette.stx +0 -81
  55. package/src/ui/command-palette/CommandPaletteItem.stx +0 -27
  56. package/src/ui/command-palette/README.md +0 -42
  57. package/src/ui/command-palette/index.ts +0 -15
  58. package/src/ui/dialog/Dialog.stx +0 -41
  59. package/src/ui/dialog/DialogBackdrop.stx +0 -9
  60. package/src/ui/dialog/DialogDescription.stx +0 -11
  61. package/src/ui/dialog/DialogPanel.stx +0 -16
  62. package/src/ui/dialog/DialogTitle.stx +0 -11
  63. package/src/ui/dialog/README.md +0 -121
  64. package/src/ui/dialog/index.ts +0 -32
  65. package/src/ui/drawer/Drawer.stx +0 -120
  66. package/src/ui/drawer/README.md +0 -90
  67. package/src/ui/drawer/index.ts +0 -9
  68. package/src/ui/dropdown/Dropdown.stx +0 -82
  69. package/src/ui/dropdown/DropdownButton.stx +0 -29
  70. package/src/ui/dropdown/DropdownItem.stx +0 -35
  71. package/src/ui/dropdown/DropdownItems.stx +0 -18
  72. package/src/ui/dropdown/README.md +0 -114
  73. package/src/ui/dropdown/index.ts +0 -29
  74. package/src/ui/form/Form.stx +0 -95
  75. package/src/ui/form/index.ts +0 -67
  76. package/src/ui/heatmap/Heatmap.stx +0 -294
  77. package/src/ui/image/Image.stx +0 -165
  78. package/src/ui/image/README.md +0 -164
  79. package/src/ui/image/index.ts +0 -22
  80. package/src/ui/input/EmailInput.stx +0 -30
  81. package/src/ui/input/NumberInput.stx +0 -126
  82. package/src/ui/input/PasswordInput.stx +0 -143
  83. package/src/ui/input/SearchInput.stx +0 -44
  84. package/src/ui/input/TextInput.stx +0 -132
  85. package/src/ui/input/index.ts +0 -180
  86. package/src/ui/listbox/Listbox.stx +0 -101
  87. package/src/ui/listbox/ListboxButton.stx +0 -28
  88. package/src/ui/listbox/ListboxLabel.stx +0 -11
  89. package/src/ui/listbox/ListboxOption.stx +0 -49
  90. package/src/ui/listbox/ListboxOptions.stx +0 -16
  91. package/src/ui/listbox/README.md +0 -135
  92. package/src/ui/listbox/index.ts +0 -39
  93. package/src/ui/navigator/Navigator.stx +0 -113
  94. package/src/ui/navigator/README.md +0 -352
  95. package/src/ui/navigator/index.ts +0 -20
  96. package/src/ui/notification/Notification.stx +0 -117
  97. package/src/ui/notification/README.md +0 -114
  98. package/src/ui/notification/index.ts +0 -12
  99. package/src/ui/pagination/Pagination.stx +0 -150
  100. package/src/ui/pagination/index.ts +0 -11
  101. package/src/ui/payment/Checkout.stx +0 -31
  102. package/src/ui/payment/DefaultPaymentMethod.stx +0 -62
  103. package/src/ui/payment/PaymentMethods.stx +0 -104
  104. package/src/ui/payment/README.md +0 -345
  105. package/src/ui/payment/SubscriptionCheckout.stx +0 -323
  106. package/src/ui/payment/index.ts +0 -59
  107. package/src/ui/popover/Popover.stx +0 -60
  108. package/src/ui/popover/PopoverButton.stx +0 -29
  109. package/src/ui/popover/PopoverPanel.stx +0 -23
  110. package/src/ui/popover/README.md +0 -91
  111. package/src/ui/popover/index.ts +0 -22
  112. package/src/ui/portal/Portal.stx +0 -57
  113. package/src/ui/portal/index.ts +0 -6
  114. package/src/ui/progress/Progress.stx +0 -131
  115. package/src/ui/progress/index.ts +0 -12
  116. package/src/ui/radio/Radio.stx +0 -77
  117. package/src/ui/radio/index.ts +0 -15
  118. package/src/ui/radio-group/README.md +0 -139
  119. package/src/ui/radio-group/RadioGroup.stx +0 -60
  120. package/src/ui/radio-group/RadioGroupDescription.stx +0 -11
  121. package/src/ui/radio-group/RadioGroupLabel.stx +0 -11
  122. package/src/ui/radio-group/RadioGroupOption.stx +0 -58
  123. package/src/ui/radio-group/index.ts +0 -30
  124. package/src/ui/select/README.md +0 -180
  125. package/src/ui/select/Select.stx +0 -82
  126. package/src/ui/select/index.ts +0 -21
  127. package/src/ui/sidebar/Sidebar.stx +0 -476
  128. package/src/ui/sidebar/SidebarFooter.stx +0 -71
  129. package/src/ui/sidebar/SidebarHeader.stx +0 -103
  130. package/src/ui/sidebar/SidebarItem.stx +0 -86
  131. package/src/ui/sidebar/SidebarSection.stx +0 -83
  132. package/src/ui/sidebar/index.ts +0 -153
  133. package/src/ui/sidebar/themes.ts +0 -240
  134. package/src/ui/skeleton/Skeleton.stx +0 -48
  135. package/src/ui/skeleton/index.ts +0 -11
  136. package/src/ui/spinner/Spinner.stx +0 -109
  137. package/src/ui/spinner/index.ts +0 -9
  138. package/src/ui/stepper/README.md +0 -36
  139. package/src/ui/stepper/Stepper.stx +0 -17
  140. package/src/ui/stepper/StepperStep.stx +0 -57
  141. package/src/ui/stepper/index.ts +0 -19
  142. package/src/ui/storage/README.md +0 -193
  143. package/src/ui/storage/index.ts +0 -347
  144. package/src/ui/switch/README.md +0 -114
  145. package/src/ui/switch/Switch.stx +0 -72
  146. package/src/ui/switch/index.ts +0 -10
  147. package/src/ui/table/README.md +0 -39
  148. package/src/ui/table/Table.stx +0 -14
  149. package/src/ui/table/TableBody.stx +0 -10
  150. package/src/ui/table/TableCell.stx +0 -10
  151. package/src/ui/table/TableHead.stx +0 -10
  152. package/src/ui/table/TableHeader.stx +0 -20
  153. package/src/ui/table/TableRow.stx +0 -11
  154. package/src/ui/table/index.ts +0 -35
  155. package/src/ui/tabs/TabPanel.stx +0 -25
  156. package/src/ui/tabs/Tabs.stx +0 -202
  157. package/src/ui/tabs/index.ts +0 -50
  158. package/src/ui/teleport/Teleport.stx +0 -65
  159. package/src/ui/teleport/index.ts +0 -7
  160. package/src/ui/textarea/Textarea.stx +0 -108
  161. package/src/ui/textarea/index.ts +0 -20
  162. package/src/ui/tooltip/Tooltip.stx +0 -71
  163. package/src/ui/tooltip/index.ts +0 -10
  164. package/src/ui/transition/README.md +0 -30
  165. package/src/ui/transition/Transition.stx +0 -102
  166. package/src/ui/transition/index.ts +0 -25
  167. package/src/ui/video/README.md +0 -47
  168. package/src/ui/video/Video.stx +0 -45
  169. package/src/ui/video/index.ts +0 -16
  170. package/src/ui/virtual-list/VirtualList.stx +0 -67
  171. package/src/ui/virtual-list/index.ts +0 -10
  172. package/src/ui/virtual-table/VirtualTable.stx +0 -103
  173. package/src/ui/virtual-table/index.ts +0 -21
  174. package/src/utils/PROP_VALIDATION.md +0 -458
  175. package/src/utils/THEME_SYSTEM.md +0 -702
  176. package/src/utils/accessibility.ts +0 -841
  177. package/src/utils/animation/easing.ts +0 -368
  178. package/src/utils/animation/helpers.ts +0 -223
  179. package/src/utils/animation/index.ts +0 -5
  180. package/src/utils/animation/keyframes.ts +0 -230
  181. package/src/utils/error-handling.ts +0 -475
  182. package/src/utils/highlighter.ts +0 -93
  183. package/src/utils/i18n.ts +0 -634
  184. package/src/utils/keep-alive.ts +0 -819
  185. package/src/utils/lazy-loading.ts +0 -530
  186. package/src/utils/prop-validation.ts +0 -478
  187. package/src/utils/theme.ts +0 -626
@@ -1,117 +0,0 @@
1
- <script server>
2
- // Initial defaults captured at render time. The client script wraps these
3
- // in signals so consumers can mutate them after mount (fetch-then-toast,
4
- // auto-dismiss, etc.). See stacksjs/stx#1692.
5
- export const initialShow = $props.show !== false
6
- export const initialTitle = $props.title || ''
7
- export const initialMessage = $props.message || ''
8
- export const initialType = $props.type || 'info'
9
- export const initialPosition = $props.position || 'top-right'
10
- export const initialDuration = Number($props.duration ?? 5000)
11
- export const className = $props.className || ''
12
- </script>
13
-
14
- <script client>
15
- const emit = defineEmits()
16
-
17
- const isVisible = state({{ initialShow }})
18
- const title = state({{ initialTitle }})
19
- const message = state({{ initialMessage }})
20
- const type = state({{ initialType }})
21
- const position = state({{ initialPosition }})
22
- const duration = state({{ initialDuration }})
23
-
24
- const typeColors = {
25
- info: 'bg-blue-50 text-blue-900 dark:bg-blue-900 dark:text-blue-100',
26
- success: 'bg-green-50 text-green-900 dark:bg-green-900 dark:text-green-100',
27
- warning: 'bg-yellow-50 text-yellow-900 dark:bg-yellow-900 dark:text-yellow-100',
28
- error: 'bg-red-50 text-red-900 dark:bg-red-900 dark:text-red-100',
29
- }
30
-
31
- const positions = {
32
- 'top-left': 'top-0 left-0',
33
- 'top-right': 'top-0 right-0',
34
- 'top-center': 'top-0 left-1/2 -translate-x-1/2',
35
- 'bottom-left': 'bottom-0 left-0',
36
- 'bottom-right': 'bottom-0 right-0',
37
- 'bottom-center': 'bottom-0 left-1/2 -translate-x-1/2',
38
- }
39
-
40
- const baseClasses = 'fixed z-50 m-4 max-w-md w-full pointer-events-auto rounded-lg p-4 shadow-lg ring-1 ring-black ring-opacity-5 transition-all'
41
- const extraClassName = {{ JSON.stringify(className) }}
42
-
43
- const notificationClasses = derived(() => {
44
- const color = typeColors[type()] || typeColors.info
45
- const pos = positions[position()] || positions['top-right']
46
- return `${baseClasses} ${color} ${pos} ${extraClassName}`.trim()
47
- })
48
-
49
- let autoHideTimer = null
50
- function clearAutoHide() {
51
- if (autoHideTimer) {
52
- clearTimeout(autoHideTimer)
53
- autoHideTimer = null
54
- }
55
- }
56
- function scheduleAutoHide() {
57
- clearAutoHide()
58
- const d = duration()
59
- if (d > 0 && isVisible()) {
60
- autoHideTimer = setTimeout(() => close(), d)
61
- }
62
- }
63
-
64
- function close() {
65
- isVisible.set(false)
66
- clearAutoHide()
67
- emit('close')
68
- }
69
-
70
- function open(opts) {
71
- if (opts && typeof opts === 'object') {
72
- if (opts.title !== undefined) title.set(opts.title)
73
- if (opts.message !== undefined) message.set(opts.message)
74
- if (opts.type !== undefined) type.set(opts.type)
75
- if (opts.position !== undefined) position.set(opts.position)
76
- if (opts.duration !== undefined) duration.set(Number(opts.duration))
77
- }
78
- isVisible.set(true)
79
- scheduleAutoHide()
80
- }
81
-
82
- onMount(() => {
83
- if (isVisible()) scheduleAutoHide()
84
- })
85
-
86
- defineExpose({
87
- open,
88
- close,
89
- isVisible,
90
- title,
91
- message,
92
- type,
93
- position,
94
- duration,
95
- })
96
- </script>
97
-
98
- <div :if="isVisible()" :class="notificationClasses()" role="alert">
99
- <div class="flex items-start">
100
- <div class="flex-1">
101
- <p :if="title()" class="text-sm font-medium" :text="title()"></p>
102
- <p :if="message()" class="mt-1 text-sm" :class="title() ? 'opacity-90' : ''" :text="message()"></p>
103
- <slot :if="!title() && !message()" />
104
- </div>
105
-
106
- <button
107
- type="button"
108
- @click="close()"
109
- class="ml-4 inline-flex rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2"
110
- >
111
- <span class="sr-only">Close</span>
112
- <svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
113
- <path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
114
- </svg>
115
- </button>
116
- </div>
117
- </div>
@@ -1,114 +0,0 @@
1
- # Notification Component
2
-
3
- Toast notifications for user feedback and alerts.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- bun add @stacksjs/components
9
- ```
10
-
11
- ## Usage
12
-
13
- ```stx
14
- <script server>
15
- let showNotification = true
16
-
17
- function closeNotification() {
18
- showNotification = false
19
- }
20
- </script>
21
-
22
- <Notification
23
- :show="showNotification"
24
- title="Success!"
25
- message="Your changes have been saved."
26
- type="success"
27
- :onClose="closeNotification"
28
- />
29
- ```
30
-
31
- ## Props
32
-
33
- | Prop | Type | Default | Description |
34
- |------|------|---------|-------------|
35
- | `show` | `boolean` | `true` | Whether notification is visible |
36
- | `title` | `string` | `''` | Notification title |
37
- | `message` | `string` | `''` | Notification message |
38
- | `type` | `'info' \| 'success' \| 'warning' \| 'error'` | `'info'` | Notification type |
39
- | `position` | `'top-left' \| 'top-right' \| 'top-center' \| 'bottom-left' \| 'bottom-right' \| 'bottom-center'` | `'top-right'` | Position on screen |
40
- | `duration` | `number` | `5000` | Auto-hide duration (0 = no auto-hide) |
41
- | `onClose` | `() => void` | - | Close handler |
42
- | `className` | `string` | `''` | Additional CSS classes |
43
-
44
- ## Examples
45
-
46
- ### Types
47
-
48
- ```stx
49
- <Notification type="info" title="Information" message="This is an info message" />
50
-
51
- <Notification type="success" title="Success" message="Operation completed" />
52
-
53
- <Notification type="warning" title="Warning" message="Please be careful" />
54
-
55
- <Notification type="error" title="Error" message="Something went wrong" />
56
- ```
57
-
58
- ### Positions
59
-
60
- ```stx
61
- <Notification position="top-left" title="Top Left" />
62
- <Notification position="top-center" title="Top Center" />
63
- <Notification position="bottom-right" title="Bottom Right" />
64
- ```
65
-
66
- ### No Auto-Hide
67
-
68
- ```stx
69
- <Notification
70
- :duration="0"
71
- title="Important"
72
- message="This will not auto-hide"
73
- />
74
- ```
75
-
76
- ### Custom Content
77
-
78
- ```stx
79
- <Notification type="info">
80
- <div class="flex items-start gap-3">
81
- <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
82
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
83
- </svg>
84
- <div>
85
- <p class="font-medium">Custom notification</p>
86
- <p class="mt-1 text-sm">With custom content and layout</p>
87
- </div>
88
- </div>
89
- </Notification>
90
- ```
91
-
92
- ### With Actions
93
-
94
- ```stx
95
- <Notification type="info" title="New message">
96
- <p>You have a new message from John</p>
97
- <div class="mt-3 flex gap-2">
98
- <Button size="sm" variant="primary">View</Button>
99
- <Button size="sm" variant="ghost">Dismiss</Button>
100
- </div>
101
- </Notification>
102
- ```
103
-
104
- ## Features
105
-
106
- - 4 types (info, success, warning, error)
107
- - 6 position options
108
- - Auto-hide with configurable duration
109
- - Dark mode support
110
- - Accessible (WAI-ARIA)
111
- - Close button
112
- - Custom content support
113
- - Smooth transitions
114
- - Customizable styling
@@ -1,12 +0,0 @@
1
- export { default as Notification } from './Notification.stx'
2
-
3
- export interface NotificationProps {
4
- show?: boolean
5
- title?: string
6
- message?: string
7
- type?: 'info' | 'success' | 'warning' | 'error'
8
- position?: 'top-left' | 'top-right' | 'top-center' | 'bottom-left' | 'bottom-right' | 'bottom-center'
9
- duration?: number
10
- onClose?: () => void
11
- className?: string
12
- }
@@ -1,150 +0,0 @@
1
- <script server>
2
- export const currentPage = $props.currentPage || 1
3
- export const totalPages = $props.totalPages || 1
4
- export const siblingCount = $props.siblingCount || 1
5
- export const showFirstLast = $props.showFirstLast ?? true
6
- export const showPrevNext = $props.showPrevNext ?? true
7
- export const className = $props.className || ''
8
-
9
- export const paginationClasses = `flex items-center gap-1 ${className}`.trim()
10
- export const buttonClasses = `px-3 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-white dark:disabled:hover:bg-gray-800 transition-colors duration-150`.trim()
11
- export const activeButtonClasses = `px-3 py-2 text-sm font-medium text-white bg-blue-600 dark:bg-blue-500 border border-blue-600 dark:border-blue-500 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900`.trim()
12
- export const ellipsisClasses = `px-3 py-2 text-sm font-medium text-gray-400 dark:text-gray-600`.trim()
13
- export const iconClasses = `w-5 h-5`.trim()
14
- </script>
15
-
16
- <script client>
17
- const emit = defineEmits()
18
- const totalPages = {{ totalPages }}
19
- const siblingCount = {{ siblingCount }}
20
- // Reactive prop binding — parent can drive `current-page` via signals
21
- // (useful for URL-driven pagination via useSearchParams). See #1704.
22
- const page = useReactiveProp('current-page', {{ currentPage }})
23
-
24
- function goToPage(target) {
25
- if (target >= 1 && target <= totalPages && target !== page()) {
26
- page.set(target)
27
- emit('change', target)
28
- }
29
- }
30
-
31
- function goToPrevious() { goToPage(page() - 1) }
32
- function goToNext() { goToPage(page() + 1) }
33
- function goToFirst() { goToPage(1) }
34
- function goToLast() { goToPage(totalPages) }
35
-
36
- const pageNumbers = derived(() => {
37
- const cur = page()
38
- const pages = []
39
- const totalNumbers = siblingCount * 2 + 3
40
- const totalBlocks = totalNumbers + 2
41
-
42
- if (totalPages <= totalBlocks) {
43
- for (let i = 1; i <= totalPages; i++) pages.push(i)
44
- return pages
45
- }
46
-
47
- const leftSibling = Math.max(cur - siblingCount, 1)
48
- const rightSibling = Math.min(cur + siblingCount, totalPages)
49
- const showLeftEllipsis = leftSibling > 2
50
- const showRightEllipsis = rightSibling < totalPages - 1
51
-
52
- if (!showLeftEllipsis && showRightEllipsis) {
53
- const leftCount = 3 + 2 * siblingCount
54
- for (let i = 1; i <= leftCount; i++) pages.push(i)
55
- pages.push('ellipsis-right')
56
- pages.push(totalPages)
57
- }
58
- else if (showLeftEllipsis && !showRightEllipsis) {
59
- pages.push(1)
60
- pages.push('ellipsis-left')
61
- const rightCount = 3 + 2 * siblingCount
62
- for (let i = totalPages - rightCount + 1; i <= totalPages; i++) pages.push(i)
63
- }
64
- else {
65
- pages.push(1)
66
- pages.push('ellipsis-left')
67
- for (let i = leftSibling; i <= rightSibling; i++) pages.push(i)
68
- pages.push('ellipsis-right')
69
- pages.push(totalPages)
70
- }
71
- return pages
72
- })
73
-
74
- const isFirstPage = derived(() => page() === 1)
75
- const isLastPage = derived(() => page() === totalPages)
76
-
77
- defineExpose({ page, goToPage })
78
- </script>
79
-
80
- <nav class="{{ paginationClasses }}" role="navigation" aria-label="Pagination">
81
- @if(showFirstLast)
82
- <button
83
- type="button"
84
- @click="goToFirst()"
85
- class="{{ buttonClasses }}"
86
- aria-label="Go to first page"
87
- :disabled="isFirstPage()"
88
- >
89
- <svg class="{{ iconClasses }}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
90
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 19l-7-7 7-7m8 14l-7-7 7-7" />
91
- </svg>
92
- </button>
93
- @endif
94
-
95
- @if(showPrevNext)
96
- <button
97
- type="button"
98
- @click="goToPrevious()"
99
- class="{{ buttonClasses }}"
100
- aria-label="Go to previous page"
101
- :disabled="isFirstPage()"
102
- >
103
- <svg class="{{ iconClasses }}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
104
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
105
- </svg>
106
- </button>
107
- @endif
108
-
109
- <span :for="p in pageNumbers()" :key="p" class="contents">
110
- <span :if="typeof p === 'string'" class="{{ ellipsisClasses }}" aria-hidden="true">...</span>
111
- <button
112
- :if="typeof p !== 'string'"
113
- type="button"
114
- :class="p === page() ? '{{ activeButtonClasses }}' : '{{ buttonClasses }}'"
115
- :aria-label="`Go to page ${p}`"
116
- :aria-current="p === page() ? 'page' : null"
117
- :disabled="p === page()"
118
- @click="goToPage(p)"
119
- x-text="p"
120
- ></button>
121
- </span>
122
-
123
- @if(showPrevNext)
124
- <button
125
- type="button"
126
- @click="goToNext()"
127
- class="{{ buttonClasses }}"
128
- aria-label="Go to next page"
129
- :disabled="isLastPage()"
130
- >
131
- <svg class="{{ iconClasses }}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
132
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
133
- </svg>
134
- </button>
135
- @endif
136
-
137
- @if(showFirstLast)
138
- <button
139
- type="button"
140
- @click="goToLast()"
141
- class="{{ buttonClasses }}"
142
- aria-label="Go to last page"
143
- :disabled="isLastPage()"
144
- >
145
- <svg class="{{ iconClasses }}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
146
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 5l7 7-7 7M5 5l7 7-7 7" />
147
- </svg>
148
- </button>
149
- @endif
150
- </nav>
@@ -1,11 +0,0 @@
1
- export { default as Pagination } from './Pagination.stx'
2
-
3
- export interface PaginationProps {
4
- currentPage: number
5
- totalPages: number
6
- siblingCount?: number
7
- showFirstLast?: boolean
8
- showPrevNext?: boolean
9
- onChange?: (page: number) => void
10
- className?: string
11
- }
@@ -1,31 +0,0 @@
1
- <script server>
2
- export const products = $props.products || []
3
- export const mode = $props.mode || 'subscription'
4
- export const stripePublicKey = $props.stripePublicKey || ''
5
- export const apiUrl = $props.apiUrl || ''
6
- export const shipping = $props.shipping || 0
7
- export const taxes = $props.taxes || 0
8
- export const className = $props.className || ''
9
-
10
- export const isSubscription = mode === 'subscription'
11
- export const isOneTime = mode === 'one-time'
12
- </script>
13
-
14
- @if(isSubscription)
15
- <SubscriptionCheckout
16
- :products="products"
17
- :stripePublicKey="stripePublicKey"
18
- :apiUrl="apiUrl"
19
- :shipping="shipping"
20
- :taxes="taxes"
21
- :className="className"
22
- />
23
- @endif
24
-
25
- @if(isOneTime)
26
- <div class="p-8 text-center">
27
- <p class="text-gray-600 dark:text-gray-400">
28
- One-time payment mode is not yet implemented.
29
- </p>
30
- </div>
31
- @endif
@@ -1,62 +0,0 @@
1
- <script server>
2
- export const paymentMethod = $props.paymentMethod
3
- export const isLoading = $props.isLoading || false
4
- export const className = $props.className || ''
5
-
6
- const brandIcons = {
7
- visa: '💳',
8
- mastercard: '💳',
9
- amex: '💳',
10
- discover: '💳',
11
- default: '💳',
12
- }
13
-
14
- export const containerClasses = `mt-16 w-2/3 bg-white dark:bg-blue-gray-800 px-8 py-6 shadow ring-1 ring-black dark:ring-gray-700 ring-opacity-5 sm:rounded-lg ${className}`.trim()
15
- </script>
16
-
17
- <div class="{{ containerClasses }}">
18
- <h2 class="text-lg text-gray-900 dark:text-gray-100 font-medium">
19
- Payment Info
20
- </h2>
21
-
22
- @if(isLoading)
23
- <!-- Loading skeleton -->
24
- <div class="mt-8 animate-pulse">
25
- <div class="h-20 bg-gray-200 dark:bg-gray-700 rounded-lg"></div>
26
- </div>
27
- @else
28
- @if(paymentMethod)
29
- <div class="col-span-1 mt-8 border border-gray-200 dark:border-gray-700 rounded-lg bg-white dark:bg-blue-gray-800 shadow divide-y divide-gray-200 dark:divide-gray-700">
30
- <div class="w-full p-3">
31
- <div class="flex items-center justify-between">
32
- <div class="flex items-center space-x-4">
33
- <!-- Card Brand Icon -->
34
- <div class="flex-shrink-0 h-10 w-10 flex items-center justify-center bg-gray-100 dark:bg-gray-700 rounded-md">
35
- <span class="text-2xl">{{ brandIcons[paymentMethod.brand.toLowerCase()] || brandIcons.default }}</span>
36
- </div>
37
-
38
- <!-- Card Details -->
39
- <div>
40
- <h2 class="text-sm text-gray-600 dark:text-gray-300">
41
- {{ paymentMethod.brand }} •••• {{ paymentMethod.last_four }}
42
- <span class="ml-4 inline-flex items-center rounded-md bg-indigo-50 dark:bg-indigo-900/30 px-2 py-1 text-xs text-indigo-700 dark:text-indigo-300 font-medium ring-1 ring-indigo-700/10 dark:ring-indigo-300/20 ring-inset">Default</span>
43
- <br>
44
- <span class="text-xs text-gray-500 dark:text-gray-400 italic">Expires {{ paymentMethod.exp_month }} / {{ paymentMethod.exp_year }}</span>
45
- </h2>
46
- </div>
47
- </div>
48
- </div>
49
- </div>
50
- </div>
51
- @else
52
- <!-- Empty state -->
53
- <div class="col-span-1 mt-8 border border-gray-200 dark:border-gray-700 rounded-lg bg-white dark:bg-blue-gray-800 shadow divide-y divide-gray-200 dark:divide-gray-700">
54
- <div class="w-full px-4 py-5">
55
- <h2 class="text-center text-sm text-gray-600 dark:text-gray-300">
56
- You haven't added any payment methods yet.
57
- </h2>
58
- </div>
59
- </div>
60
- @endif
61
- @endif
62
- </div>
@@ -1,104 +0,0 @@
1
- <script server>
2
- export const paymentMethods = $props.paymentMethods || []
3
- export const isLoading = $props.isLoading || false
4
- export const showMakeDefault = $props.showMakeDefault ?? true
5
- export const showDelete = $props.showDelete ?? true
6
- export const className = $props.className || ''
7
-
8
- export const brandIcons = {
9
- visa: '💳',
10
- mastercard: '💳',
11
- amex: '💳',
12
- discover: '💳',
13
- default: '💳',
14
- }
15
-
16
- export const containerClasses = `mt-4 ${className}`.trim()
17
- </script>
18
-
19
- <script client>
20
- const emit = defineEmits()
21
-
22
- function onMakeDefault(methodId) {
23
- emit('makeDefault', methodId)
24
- }
25
-
26
- function onDelete(methodId) {
27
- if (confirm('Are you sure you want to delete this payment method?')) {
28
- emit('deletePaymentMethod', methodId)
29
- }
30
- }
31
- </script>
32
-
33
- <div class="{{ containerClasses }}">
34
- @if(isLoading)
35
- <div class="animate-pulse">
36
- <div class="h-24 bg-gray-200 dark:bg-gray-700 rounded-lg"></div>
37
- </div>
38
- @else
39
- @if(paymentMethods.length > 0)
40
- <ul role="list" class="grid grid-cols-1 gap-6 lg:grid-cols-1 sm:grid-cols-1">
41
- @foreach(method in paymentMethods)
42
- <li class="col-span-1 border border-gray-200 dark:border-gray-700 rounded-lg bg-white dark:bg-blue-gray-800 shadow divide-y divide-gray-200 dark:divide-gray-700">
43
- <div class="w-full p-3">
44
- <div class="flex items-center justify-between">
45
- <div class="flex items-center space-x-4">
46
- <div class="flex-shrink-0 h-10 w-10 flex items-center justify-center bg-gray-100 dark:bg-gray-700 rounded-md">
47
- <span class="text-2xl">{{ brandIcons[method.brand.toLowerCase()] || brandIcons.default }}</span>
48
- </div>
49
-
50
- <div>
51
- <h2 class="text-sm text-gray-600 dark:text-gray-300">
52
- {{ method.brand }} •••• {{ method.last_four }}
53
- </h2>
54
- <span class="text-xs text-gray-500 dark:text-gray-400 italic">
55
- Expires {{ method.exp_month }} / {{ method.exp_year }}
56
- </span>
57
- </div>
58
- </div>
59
-
60
- <div class="flex justify-end space-x-4">
61
- @if(showMakeDefault)
62
- <button
63
- type="button"
64
- class="border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-blue-gray-700 px-2 py-1 text-sm text-gray-700 dark:text-gray-300 font-semibold shadow-sm hover:bg-gray-50 dark:hover:bg-blue-gray-600 focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2 disabled:opacity-50 disabled:cursor-not-allowed"
65
- @click="onMakeDefault('{{ method.id }}')"
66
- title="Make default"
67
- >
68
- <svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
69
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z" />
70
- </svg>
71
- </button>
72
- @endif
73
-
74
- @if(showDelete)
75
- <button
76
- type="button"
77
- class="border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-blue-gray-700 px-2 py-1 text-sm text-red-600 dark:text-red-400 font-semibold shadow-sm hover:bg-red-50 dark:hover:bg-red-900/20 focus-visible:outline-2 focus-visible:outline-red-600 focus-visible:outline-offset-2 disabled:opacity-50 disabled:cursor-not-allowed"
78
- @click="onDelete('{{ method.id }}')"
79
- title="Delete payment method"
80
- >
81
- <svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
82
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
83
- </svg>
84
- </button>
85
- @endif
86
- </div>
87
- </div>
88
- </div>
89
- </li>
90
- @endforeach
91
- </ul>
92
- @else
93
- <div class="text-center py-12 bg-white dark:bg-blue-gray-800 rounded-lg border border-gray-200 dark:border-gray-700">
94
- <svg class="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
95
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" />
96
- </svg>
97
- <h3 class="mt-2 text-sm text-gray-900 dark:text-gray-100 font-medium">No payment methods</h3>
98
- <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
99
- You haven't added any payment methods yet.
100
- </p>
101
- </div>
102
- @endif
103
- @endif
104
- </div>