@ziyarago/ui 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/LICENSE +25 -0
  3. package/README.md +121 -2
  4. package/THIRD_PARTY_NOTICES.md +12 -0
  5. package/assets/3d/_sheet.png +0 -0
  6. package/assets/3d/archive.png +0 -0
  7. package/assets/3d/bag.png +0 -0
  8. package/assets/3d/cameraoff.png +0 -0
  9. package/assets/3d/comment.png +0 -0
  10. package/assets/3d/crowd.png +0 -0
  11. package/assets/3d/firstaid.png +0 -0
  12. package/assets/3d/flag.png +0 -0
  13. package/assets/3d/grain.png +0 -0
  14. package/assets/3d/guide.png +0 -0
  15. package/assets/3d/hotel.png +0 -0
  16. package/assets/3d/kaaba.png +0 -0
  17. package/assets/3d/logo.png +0 -0
  18. package/assets/3d/luggage.png +0 -0
  19. package/assets/3d/map.png +0 -0
  20. package/assets/3d/mosque.png +0 -0
  21. package/assets/3d/plane.png +0 -0
  22. package/assets/3d/profile.png +0 -0
  23. package/assets/3d/restaurant.png +0 -0
  24. package/assets/3d/ring360.png +0 -0
  25. package/assets/3d/shoes.png +0 -0
  26. package/assets/3d/star.png +0 -0
  27. package/assets/3d/store.png +0 -0
  28. package/assets/3d/taxi.png +0 -0
  29. package/assets/3d/threads.png +0 -0
  30. package/assets/3d/tour360.png +0 -0
  31. package/assets/3d/trash.png +0 -0
  32. package/assets/3d/umbrella.png +0 -0
  33. package/assets/3d/video.png +0 -0
  34. package/assets/3d/water.png +0 -0
  35. package/assets/brand/mark.png +0 -0
  36. package/assets/brand/ziyarago-logo-light.svg +21 -0
  37. package/assets/brand/ziyarago-logo.svg +21 -0
  38. package/assets/brand/ziyarago-mark-light.svg +13 -0
  39. package/assets/brand/ziyarago-mark.svg +13 -0
  40. package/assets/fonts/thmanyah/thmanyahsans-Black.otf +0 -0
  41. package/assets/fonts/thmanyah/thmanyahsans-Bold.otf +0 -0
  42. package/assets/fonts/thmanyah/thmanyahsans-Light.otf +0 -0
  43. package/assets/fonts/thmanyah/thmanyahsans-Medium.otf +0 -0
  44. package/assets/fonts/thmanyah/thmanyahsans-Regular.otf +0 -0
  45. package/assets/fonts/thmanyah/thmanyahserifdisplay-Black.otf +0 -0
  46. package/assets/fonts/thmanyah/thmanyahserifdisplay-Bold.otf +0 -0
  47. package/assets/fonts/thmanyah/thmanyahserifdisplay-Light.otf +0 -0
  48. package/assets/fonts/thmanyah/thmanyahserifdisplay-Medium.otf +0 -0
  49. package/assets/fonts/thmanyah/thmanyahserifdisplay-Regular.otf +0 -0
  50. package/assets/fonts/thmanyah/thmanyahseriftext-Black.otf +0 -0
  51. package/assets/fonts/thmanyah/thmanyahseriftext-Bold.otf +0 -0
  52. package/assets/fonts/thmanyah/thmanyahseriftext-Light.otf +0 -0
  53. package/assets/fonts/thmanyah/thmanyahseriftext-Medium.otf +0 -0
  54. package/assets/fonts/thmanyah/thmanyahseriftext-Regular.otf +0 -0
  55. package/dist/llms-full.txt +2293 -0
  56. package/dist/llms.txt +239 -0
  57. package/dist/manifest.json +10254 -0
  58. package/dist/style.css +1357 -0
  59. package/dist/tokens.css +48 -0
  60. package/package.json +118 -4
  61. package/src/catalog.js +4 -0
  62. package/src/core/components.js +124 -0
  63. package/src/core/components2.js +163 -0
  64. package/src/core/components3.js +35 -0
  65. package/src/core/components4.js +58 -0
  66. package/src/core/components6.js +48 -0
  67. package/src/core/components7.js +42 -0
  68. package/src/core/dialog.js +65 -0
  69. package/src/core/index.js +9 -0
  70. package/src/core/pages.js +51 -0
  71. package/src/meta/README.md +29 -0
  72. package/src/meta/actions.js +161 -0
  73. package/src/meta/data.js +327 -0
  74. package/src/meta/domain.js +212 -0
  75. package/src/meta/feedback.js +153 -0
  76. package/src/meta/forms.js +453 -0
  77. package/src/meta/groups.js +16 -0
  78. package/src/meta/index.js +14 -0
  79. package/src/meta/layout.js +159 -0
  80. package/src/meta/media.js +104 -0
  81. package/src/meta/navigation.js +99 -0
  82. package/src/meta/overlay.js +264 -0
  83. package/src/meta/pages.js +229 -0
  84. package/src/meta/templates.json +2422 -0
  85. package/src/meta/typography.js +58 -0
  86. package/src/nuxt/module.mjs +29 -0
  87. package/src/nuxt/plugin.mjs +9 -0
  88. package/src/react/index.js +31 -0
  89. package/src/styles/components.css +162 -0
  90. package/src/styles/components2.css +68 -0
  91. package/src/styles/components3.css +29 -0
  92. package/src/styles/components4.css +18 -0
  93. package/src/styles/components5.css +5 -0
  94. package/src/styles/components6.css +19 -0
  95. package/src/styles/components7.css +44 -0
  96. package/src/styles/components8.css +47 -0
  97. package/src/styles/effects.css +43 -0
  98. package/src/styles/fonts.css +17 -0
  99. package/src/styles/index.css +21 -0
  100. package/src/styles/sizes/actions.css +126 -0
  101. package/src/styles/sizes/data.css +161 -0
  102. package/src/styles/sizes/domain.css +35 -0
  103. package/src/styles/sizes/feedback.css +69 -0
  104. package/src/styles/sizes/forms.css +122 -0
  105. package/src/styles/sizes/layout.css +15 -0
  106. package/src/styles/sizes/media.css +28 -0
  107. package/src/styles/sizes/navigation.css +146 -0
  108. package/src/styles/sizes/overlay.css +79 -0
  109. package/src/styles/sizes/typography.css +12 -0
  110. package/src/styles/tokens.css +47 -0
  111. package/src/theme.js +52 -0
  112. package/src/vue/index.js +29 -0
  113. package/tokens/tokens.json +9 -0
  114. package/types/core.d.ts +4 -0
  115. package/types/nuxt.d.ts +11 -0
  116. package/types/react.d.ts +189 -0
  117. package/types/shared.d.ts +18 -0
  118. package/types/theme.d.ts +6 -0
  119. package/types/vue.d.ts +192 -0
@@ -0,0 +1,264 @@
1
+ // API metadata for the overlay group. Format: see src/meta/README.md
2
+ const SIZE = "'xs' | 'sm' | 'md' | 'lg' | 'xl'";
3
+ const SIZES = ['xs', 'sm', 'md', 'lg', 'xl'];
4
+ const size = (what, def = 'md') => ({ type: SIZE, values: SIZES, default: def, description: `Scale of ${what}.` });
5
+ const open = (what) => ({ type: 'boolean', default: false, description: `Shows the ${what} when true; renders nothing when false.` });
6
+ const title = (d) => ({ type: 'string', description: d });
7
+ const menuItems = {
8
+ type: '{ label: string; value?: string; icon?: string; shortcut?: string; tone?: \'danger\'; disabled?: boolean; onClick?: (item) => void; separator?: boolean }[]',
9
+ default: '[]',
10
+ description: 'Menu entries. Item fields: label, value (passed to select), icon (icon name), shortcut (kbd hint on the right), tone "danger" (red), disabled true (dimmed, not clickable), onClick (called with the item when clicked, before the select event), separator true (renders a divider; other fields ignored).',
11
+ };
12
+ const select = 'Called with the item value when an entry is clicked.';
13
+
14
+ export default {
15
+ Modal: {
16
+ description: 'Centered dialog with a title, close button, body and optional footer; use for forms and focused tasks that block the page.',
17
+ props: {
18
+ open: open('dialog'),
19
+ title: { type: 'string', description: 'Header text and aria-label of the dialog.' },
20
+ size: size('width (320 to 720 px max), padding and text'),
21
+ },
22
+ slots: { default: 'Dialog body.', footer: 'Footer area, usually action buttons. Rendered only when provided.' },
23
+ events: { close: 'Called on the close button, a click on the scrim or the Escape key. Set open to false in the handler.' },
24
+ notes: ['Has role="dialog" and aria-modal. Escape calls close; on open focus moves into the dialog, Tab is trapped inside it and focus returns to the previously focused element on close.', 'Put data-autofocus on an element to choose which one receives initial focus (default: first focusable).', 'Closed state renders nothing, so inner state is lost on close.'],
25
+ },
26
+
27
+ Drawer: {
28
+ description: 'Side panel that slides over the page; use for filters, details and secondary forms.',
29
+ props: {
30
+ open: open('drawer'),
31
+ title: { type: 'string', description: 'Header text and aria-label.' },
32
+ side: { type: "'start' | 'end'", values: ['start', 'end'], default: 'end', description: 'Edge the drawer attaches to; start and end follow text direction.' },
33
+ size: size('width (280 to 640 px)'),
34
+ },
35
+ slots: { default: 'Drawer body.', footer: 'Footer area, usually action buttons. Rendered only when provided.' },
36
+ events: { close: 'Called on the close button, a click on the scrim or the Escape key.' },
37
+ notes: ['Has role="dialog" and aria-modal. Escape calls close; on open focus moves into the dialog, Tab is trapped inside it and focus returns to the previously focused element on close.'],
38
+ },
39
+
40
+ ConfirmDialog: {
41
+ description: 'Small Modal with a message and Cancel/Confirm buttons; use to confirm destructive or irreversible actions.',
42
+ props: {
43
+ open: open('dialog'),
44
+ title: { type: 'string', description: 'Dialog heading.' },
45
+ description: { type: 'string', description: 'Explanation shown in the body.' },
46
+ tone: { type: "'default' | 'danger'", values: ['default', 'danger'], default: 'default', description: 'Danger turns the confirm button red; any other value gives the primary button.' },
47
+ confirmLabel: { type: 'string', default: 'Confirm', description: 'Confirm button text.' },
48
+ cancelLabel: { type: 'string', default: 'Cancel', description: 'Cancel button text.' },
49
+ loading: { type: 'boolean', default: false, description: 'Shows a spinner on the confirm button.' },
50
+ size: size('dialog width and padding'),
51
+ },
52
+ events: { confirm: 'Called when the confirm button is clicked.', cancel: 'Called on Cancel, the close icon, the Escape key or a click on the scrim.' },
53
+ notes: ['Close handling goes through cancel, there is no separate close event.', 'The dialog does not close itself: set open to false in both handlers.'],
54
+ },
55
+
56
+ Popconfirm: {
57
+ description: 'Button that opens a small confirmation popover with cancel/confirm buttons (No/Yes by default); use for quick inline confirmation of a single action.',
58
+ props: {
59
+ label: { type: 'string', description: 'Text of the trigger button.' },
60
+ title: { type: 'string', description: 'Question shown in the popover.' },
61
+ variant: { type: "'primary' | 'secondary' | 'ghost' | 'danger' | 'inverse' | 'tonal' | 'outlined' | 'text' | 'elevated'", values: ['primary', 'secondary', 'ghost', 'danger', 'inverse', 'tonal', 'outlined', 'text', 'elevated'], default: 'danger', description: 'Button variant of the trigger.' },
62
+ confirmLabel: { type: 'string', default: 'Yes', description: 'Text of the confirm button.' },
63
+ cancelLabel: { type: 'string', default: 'No', description: 'Text of the cancel button.' },
64
+ size: size('trigger button and popover', 'sm'),
65
+ },
66
+ events: { confirm: 'Called when the confirm button is clicked; the popover closes first.' },
67
+ notes: ['Open state is internal. The popover closes on outside click and on Escape.'],
68
+ },
69
+
70
+ StepDialog: {
71
+ description: 'Wide Modal with a vertical step list on the left and Previous/Next buttons; use for multi-step wizards.',
72
+ props: {
73
+ open: open('dialog'),
74
+ title: { type: 'string', description: 'Header text and aria-label.' },
75
+ steps: { type: '{ title: string; sub?: string }[]', default: '[]', description: 'Steps in the left rail; sub is a hint under the title.' },
76
+ current: { type: 'number', description: 'Zero-based index of the active step. Earlier steps are shown as done.' },
77
+ size: size('dialog width (640 to 1100 px) and padding'),
78
+ },
79
+ slots: { default: 'Content of the current step.' },
80
+ events: { back: 'Previous button; disabled on the first step.', next: 'Next button; labelled "Submit" on the last step, so also handle submit here.', close: 'Close icon, scrim click or the Escape key.' },
81
+ notes: ['You own the current index: update it in the back and next handlers.', 'Has aria-modal. Escape calls close; on open focus moves into the dialog, Tab is trapped inside it and focus returns to the previously focused element on close.'],
82
+ },
83
+
84
+ FullscreenDialog: {
85
+ description: 'Full-screen dialog with a close button, title and Save action in the header; use for long editing flows on mobile.',
86
+ props: {
87
+ open: open('dialog'),
88
+ title: { type: 'string', description: 'Header text and aria-label.' },
89
+ saveLabel: { type: 'string', default: 'Save', description: 'Text of the save button in the header.' },
90
+ },
91
+ slots: { default: 'Dialog content.' },
92
+ events: { close: 'Called on the close icon button or the Escape key.', save: 'Called on the header save button.' },
93
+ notes: ['Has aria-modal. Escape calls close; on open focus moves into the dialog, Tab is trapped inside it and focus returns to the previously focused element on close.'],
94
+ },
95
+
96
+ BottomSheet: {
97
+ description: 'Panel anchored to the bottom of the screen with a grab handle; use for mobile pickers and short forms.',
98
+ props: {
99
+ open: open('sheet'),
100
+ title: { type: 'string', description: 'Optional heading; also the aria-label.' },
101
+ maxHeight: { type: 'string | number', default: '85vh', description: 'Maximum height: a CSS length or a number of pixels.' },
102
+ size: size('sheet width (360 to 800 px) and padding'),
103
+ },
104
+ slots: { default: 'Sheet content.', footer: 'Sticky footer, e.g. buttons. Rendered only when provided.' },
105
+ events: { close: 'Called on a click on the scrim or the Escape key.' },
106
+ notes: ['The handle is decorative: it does not support dragging.', 'There is no close button; always handle close (scrim click and Escape). Escape calls close; on open focus moves into the dialog, Tab is trapped inside it and focus returns to the previously focused element on close.'],
107
+ },
108
+
109
+ Actionsheet: {
110
+ description: 'Bottom sheet with a list of actions and a Cancel button; use for mobile "more actions" menus.',
111
+ props: {
112
+ open: open('sheet'),
113
+ title: { type: 'string', description: 'Optional heading.' },
114
+ items: {
115
+ type: "{ label: string; icon?: string; tone?: 'danger'; disabled?: boolean; onClick?: () => void }[]",
116
+ default: '[]',
117
+ description: 'Actions. Each item runs its own onClick, then select, then the sheet closes. Tone "danger" colors it red.',
118
+ },
119
+ cancelLabel: { type: 'string', default: 'Cancel', description: 'Text of the cancel row.' },
120
+ size: size('sheet width and padding'),
121
+ },
122
+ events: { select: 'Called with the whole clicked item after its onClick.', close: 'Called after any item is chosen, on Cancel, on the Escape key and on a scrim click.' },
123
+ },
124
+
125
+ Popover: {
126
+ description: 'Button that toggles a floating panel with arbitrary content; use for small forms and extra info next to a control.',
127
+ props: {
128
+ label: { type: 'string', description: 'Text of the trigger button.' },
129
+ size: size('trigger button and panel padding'),
130
+ },
131
+ slots: { default: 'Panel content.' },
132
+ notes: ['Open state is internal and toggled by the trigger. The panel closes on outside click and on Escape (focus returns to the trigger).'],
133
+ },
134
+
135
+ HoverCard: {
136
+ description: 'Rich card shown on hover or keyboard focus of a trigger; use for previews of users, links or entities.',
137
+ props: {
138
+ trigger: { type: 'string | VNode', description: 'Content that triggers the card.' },
139
+ size: size('card width (200 to 400 px) and padding'),
140
+ },
141
+ slots: { default: 'Card content.' },
142
+ notes: ['The wrapper is focusable (tabIndex 0), so the card also opens on focus.'],
143
+ },
144
+
145
+ Tooltip: {
146
+ description: 'Short text bubble shown on hover or focus of the wrapped element; use for icon-only controls and hints.',
147
+ props: {
148
+ text: { type: 'string', required: true, description: 'Tooltip text.' },
149
+ size: size('bubble padding and font'),
150
+ },
151
+ slots: { default: 'The element the tooltip is attached to.' },
152
+ notes: ['Pure CSS bubble with fixed placement; it cannot contain markup. For rich content use HoverCard.'],
153
+ },
154
+
155
+ Dropdown: {
156
+ description: 'Button that opens a menu of actions; use for "more" menus and action lists.',
157
+ props: {
158
+ label: { type: 'string', description: 'Text of the trigger button.' },
159
+ icon: { type: 'string', description: 'Icon name before the label.' },
160
+ items: menuItems,
161
+ disabled: { type: 'boolean', default: false, description: 'Disables the trigger button so the menu cannot open.' },
162
+ size: size('trigger button and menu'),
163
+ },
164
+ events: { select: select + ' The menu closes first.' },
165
+ notes: ['Each item may also have its own onClick and disabled. Open state is internal; the menu closes on outside click and on Escape.'],
166
+ },
167
+
168
+ Menu: {
169
+ description: 'Static vertical list of actions rendered inline; use in sidebars and custom popovers.',
170
+ props: {
171
+ items: menuItems,
172
+ open: { type: 'boolean', description: 'Optional. false renders nothing, true shows the menu; leave unset for an always visible menu.' },
173
+ size: size('row height and text'),
174
+ },
175
+ events: { select, close: 'Called on outside click or Escape while open is true. Pass it as onClose.' },
176
+ notes: ['Always visible unless open is set. For a self-toggling menu use Dropdown, for a right-click menu use ContextMenu.'],
177
+ },
178
+
179
+ ContextMenu: {
180
+ description: 'Wraps an area and shows a menu at the cursor on right click; use for row and canvas actions.',
181
+ props: {
182
+ items: menuItems,
183
+ size: size('row height and text'),
184
+ },
185
+ slots: { default: 'The area that reacts to right click.' },
186
+ events: { select: select + ' The menu closes first.' },
187
+ notes: ['The native context menu is prevented inside the area. Clicking outside, right-clicking again or pressing Escape closes it.', 'The menu is clamped to the viewport using a rough 42 px per row.'],
188
+ },
189
+
190
+ CommandBar: {
191
+ description: 'Floating glass toolbar of icon buttons; use for selection actions or editor tools.',
192
+ props: {
193
+ items: {
194
+ type: '{ id: string; icon?: string; label: string; disabled?: boolean; separator?: boolean }[]',
195
+ default: '[]',
196
+ description: 'Buttons. label is the tooltip and aria-label, icon defaults to "circle", separator true draws a divider.',
197
+ },
198
+ size: size('button size and padding'),
199
+ },
200
+ events: { action: 'Called with the item id when a button is clicked.' },
201
+ },
202
+
203
+ CommandPalette: {
204
+ description: 'Searchable list of commands in a top-aligned dialog; use for a Cmd+K launcher.',
205
+ props: {
206
+ open: open('palette'),
207
+ commands: {
208
+ type: '{ id: string; label: string; icon?: string; shortcut?: string; keywords?: string }[]',
209
+ default: '[]',
210
+ description: 'Commands. Filtering is a case-insensitive substring match on label plus keywords.',
211
+ },
212
+ placeholder: { type: 'string', default: 'Type a command…', description: 'Search input placeholder.' },
213
+ size: size('dialog max width (400 to 720 px)'),
214
+ },
215
+ events: { run: 'Called with the command id on click or Enter; the palette then requests close.', close: 'Called on a scrim click, the Escape key and after a command runs.' },
216
+ notes: ['Keyboard: ArrowDown/ArrowUp move the active command (wraps around, aria-selected), Enter runs it, Escape closes. The active item resets to the first one when the query changes.', 'The input receives focus on open and Tab stays inside the dialog. There is no global hotkey; bind Cmd+K yourself.'],
217
+ },
218
+
219
+ ImageViewer: {
220
+ description: 'Full-screen lightbox for one or several images with previous/next buttons and a counter.',
221
+ props: {
222
+ open: open('viewer'),
223
+ images: { type: 'string[]', default: '[]', description: 'Image URLs.' },
224
+ index: { type: 'number', default: 0, description: 'Index of the image to start on.' },
225
+ alt: { type: 'string', description: 'Alt text of the image and aria-label of the dialog (default "Image viewer").' },
226
+ },
227
+ events: { close: 'Called on the close button or a click on the backdrop.' },
228
+ notes: ['Navigation buttons appear only when there is more than one image.'],
229
+ },
230
+
231
+ Tour: {
232
+ description: 'Guided product tour that dims the page, highlights a target element and shows a step popover.',
233
+ props: {
234
+ open: open('tour'),
235
+ steps: { type: '{ target?: string; title: string; text: string }[]', default: '[]', description: 'Steps. target is a CSS selector of the element to highlight; without it the step is shown centered over a full dim.' },
236
+ step: { type: 'number', description: 'Controlled zero-based step index. When omitted the tour keeps it internally (reset to 0 on close). Update it from the step event.' },
237
+ },
238
+ events: { close: 'Called on the close icon, the Escape key and after Finish on the last step.', step: 'Called with the new zero-based step index on Next, Back and the arrow keys.' },
239
+ notes: ['Keyboard: ArrowRight/ArrowLeft go to the next/previous step (reversed in RTL), Escape closes. Focus is not moved, so the page stays usable.', 'Targets are looked up with document.querySelector and scrolled into view.', 'The internal step resets to 0 whenever the tour closes.'],
240
+ },
241
+
242
+ TourPopover: {
243
+ description: 'Step card of a tour with title, text, step counter and Back/Next buttons; used by Tour and usable standalone.',
244
+ props: {
245
+ title: { type: 'string', description: 'Step heading.' },
246
+ text: { type: 'string', description: 'Step body text.' },
247
+ step: { type: 'string', description: 'Counter text such as "2 / 5".' },
248
+ last: { type: 'boolean', default: false, description: 'Changes the Next button label to "Finish".' },
249
+ },
250
+ events: { back: 'Back button; the button is rendered only when this handler is set.', next: 'Next or Finish button.', close: 'Close icon.' },
251
+ },
252
+
253
+ Screensaver: {
254
+ description: 'Full-screen idle screen with a large clock, date and the brand mark; show it after inactivity.',
255
+ props: {
256
+ open: open('screensaver'),
257
+ locale: { type: 'string', default: 'en-GB', description: 'BCP 47 locale for the date line.' },
258
+ hint: { type: 'string', description: 'Small hint under the date, e.g. "Tap to continue".' },
259
+ idleMs: { type: 'number', default: 0, description: 'When greater than 0 and the screensaver is closed, a hidden sentinel listens for pointer, key, wheel and touch activity and calls idle after this many milliseconds without any. 0 disables it.' },
260
+ },
261
+ events: { close: 'Called on click or any key (including Escape) while open.', idle: 'Called once the idleMs period passes without activity while closed; set open to true in the handler.' },
262
+ notes: ['The clock re-renders from one interval created when the screensaver opens and cleared when it closes; the idle timer is re-armed on each interaction. Nothing runs during server rendering.'],
263
+ },
264
+ };
@@ -0,0 +1,229 @@
1
+ // API metadata for the pages group. Format: see src/meta/README.md
2
+ // Page templates render named regions. In Vue fill them with <template #slot>, in React pass the same names as props. Empty slots render nothing.
3
+ const crumbs = { forwarded: true, type: '{ label: string; href?: string }[]', description: 'Breadcrumb trail above the title.' };
4
+ const header = {
5
+ title: { forwarded: true, type: 'string', description: 'Page heading. The built-in header renders only when title is set and the header slot is empty.' },
6
+ subtitle: { forwarded: true, type: 'string', description: 'Caption under the heading.' },
7
+ crumbs,
8
+ };
9
+ const HEAD = 'Custom page header; replaces the built-in title/subtitle/crumbs header.';
10
+ const ACT = 'Buttons on the right of the built-in header. With a title they sit beside it; without a title they render alone, right-aligned (unless the header slot is filled).';
11
+ const headSlots = { header: HEAD, actions: ACT };
12
+ const hdrNote = 'Place inside AppShell; fill only the slots you need.';
13
+
14
+ export default {
15
+ PageDashboard: {
16
+ description: 'Dashboard template: greeting hero, KPI tiles, occupancy chart, sales funnel, top list and activity feed.',
17
+ props: header,
18
+ slots: {
19
+ ...headSlots,
20
+ hero: 'Large greeting/plan block; Card variant="inverse" with Ring and a Button.',
21
+ kpis: 'Four key figures; KpiTile, StatsCard or KpiInline.',
22
+ occupancy: 'Per-day occupancy chart; OccupancyChart or MiniChart.',
23
+ funnel: 'Inquiry-to-payment funnel; SalesFunnel.',
24
+ top: 'Revenue leaderboard; DataTable with Progress share bars.',
25
+ activity: 'Recent actions, newest first; Timeline.',
26
+ },
27
+ notes: [hdrNote, 'hero and kpis share a row, as do occupancy/funnel and top/activity; they wrap on narrow screens.'],
28
+ },
29
+ PagePatterns: {
30
+ description: 'Showcase template combining twelve recurring dashboard card patterns (banner, strips, stat lines, charts, lists).',
31
+ props: header,
32
+ slots: {
33
+ ...headSlots,
34
+ hero: 'Large banner; HeroBanner.',
35
+ strip: 'One card with four metrics; StatStrip with IconTile.',
36
+ statlines: 'Row of toned stat lines; StatLine (tone brand, sky, success, warning, danger).',
37
+ chartcard: 'Titled chart with menu and period select; ChartCard with PillSelect and OccupancyChart or MiniChart.',
38
+ tiles: 'Selectable tiles plus an add tile; TabTiles.',
39
+ listrows: 'Icon, title and value rows; StatRow.',
40
+ countries: 'Country amount rows; CountryRow.',
41
+ versus: 'Two values with a share bar; VersusBar.',
42
+ segbar: 'Composition bar with legend; SegBar.',
43
+ activity: 'Timeline of events; Timeline.',
44
+ actioncard: 'Card with collapse, refresh and close actions; ActionCard.',
45
+ },
46
+ notes: [hdrNote],
47
+ },
48
+ PageCrm: {
49
+ description: 'CRM template: summary tiles, filters, pipeline board and call queue.',
50
+ props: header,
51
+ slots: {
52
+ ...headSlots,
53
+ summary: 'Tiles above the board (leads, amount, conversion, overdue); StatsCard or KpiTile.',
54
+ filters: 'Status tabs, search and period switch; Tabs, SearchInput, SegmentedControl, FilterChips.',
55
+ board: 'Stage columns with deal cards; PipelineBoard, KanbanColumn, DealCard.',
56
+ calls: 'Recent call queue; CallRow, CallCard, IncomingCall.',
57
+ },
58
+ notes: [hdrNote],
59
+ },
60
+ PageBookings: {
61
+ description: 'Bookings list template: stats, toolbar, bulk-action bar, table and pagination.',
62
+ props: header,
63
+ slots: {
64
+ ...headSlots,
65
+ stats: 'Booking figures for the period; StatsCard.',
66
+ toolbar: 'Search, quick filters and export menu above the table; SearchInput, FilterChips, Dropdown.',
67
+ bulk: 'Selection bar shown when rows are selected; Alert with Buttons. Render it conditionally.',
68
+ table: 'Sortable, selectable table; DataTable.',
69
+ pager: 'Page numbers below the table; Pagination.',
70
+ },
71
+ notes: [hdrNote],
72
+ },
73
+ PageCatalog: {
74
+ description: 'Catalog template with a filter sidebar and a card grid (hotels, tours).',
75
+ props: header,
76
+ slots: {
77
+ ...headSlots,
78
+ filters: 'Left filter column (price, rating, services); Slider, Rating, RadioGroup, Checkbox.',
79
+ toolbar: 'Search, view switch and sort above the grid; SearchInput, ToggleGroup, Select.',
80
+ grid: 'Responsive grid of cards; HotelCard or TourCard.',
81
+ pager: 'Pagination at the bottom; Pagination.',
82
+ },
83
+ notes: [hdrNote, 'The filter column is 260 px wide; on phones put filters in a Drawer yourself.'],
84
+ },
85
+ PageDetail: {
86
+ description: 'Detail page template (hotel, tour): gallery, summary, tabs, history and a booking side card.',
87
+ props: header,
88
+ slots: {
89
+ ...headSlots,
90
+ gallery: 'Main photo with thumbnails; Gallery, Carousel, LazyImage.',
91
+ summary: 'Name, stars, rating, badges; Card with Badge and Rating.',
92
+ tabs: 'Description, amenities, reviews; Tabs with Descriptions or Accordion.',
93
+ history: 'What changed (status, notes, price); Timeline.',
94
+ booking: 'Right-hand booking card with dates, guests, price and CTA; Card, Select, NumberInput, Button.',
95
+ },
96
+ notes: [hdrNote, 'gallery, summary, tabs and history are the main column; booking is the side column.'],
97
+ },
98
+ PageSettings: {
99
+ description: 'Settings template with a section sub-navigation and stacked settings sections.',
100
+ props: header,
101
+ slots: {
102
+ ...headSlots,
103
+ subnav: 'Left section menu; SubNav or Tabs.',
104
+ profile: 'Profile section; SettingsSection with TextField, PhoneInput.',
105
+ notifications: 'Delivery channels; SettingsSection with Switch.',
106
+ integrations: 'Service cards (connected, off, error); IntegrationCard.',
107
+ danger: 'Irreversible actions; Alert, red Button, ConfirmDialog.',
108
+ },
109
+ notes: [hdrNote],
110
+ },
111
+ PageUserList: {
112
+ description: 'User or customer list template: stats, filters, toolbar, table and a right-hand add/edit drawer.',
113
+ props: header,
114
+ slots: {
115
+ ...headSlots,
116
+ stats: 'Figures above the table; StatStrip.',
117
+ filters: 'Filter selects in a card; Select.',
118
+ toolbar: 'Page size, search, export and Add button; Select, SearchInput, Button.',
119
+ table: 'Users table with checkboxes and actions; DataTable with UserCell, Chip, IconButton.',
120
+ drawer: 'Side panel rendered in the side column; Drawer with TextField, Select, Button.',
121
+ },
122
+ notes: [hdrNote],
123
+ },
124
+ PageProfile: {
125
+ description: 'User profile template: cover header, tabs and two columns of about, activity and plan cards.',
126
+ props: header,
127
+ slots: {
128
+ ...headSlots,
129
+ profile: 'Cover with avatar, name and meta; ProfileHeader.',
130
+ tabs: 'Section tabs; PillTabs.',
131
+ about: 'Left column key-value info; Card with Descriptions.',
132
+ activity: 'Right column activity feed; Timeline.',
133
+ plan: 'Right column plan card and upgrade button; Card, Badge, Progress, Button.',
134
+ },
135
+ notes: [hdrNote],
136
+ },
137
+ PageForm: {
138
+ description: 'Create/edit form template: main column, media, side column and header actions.',
139
+ props: header,
140
+ slots: {
141
+ header: HEAD,
142
+ actions: 'Discard, Save draft and Publish buttons in the top-right of the built-in header; Button. Rendered right-aligned on their own when title is not set.',
143
+ main: 'Main column cards (info, options); Card, TextField, Textarea.',
144
+ media: 'Below main; upload dropzone; FileUpload or Gallery.',
145
+ side: 'Side column cards (price, status, tags); Card, NumberInput, Select, ChipInput.',
146
+ },
147
+ notes: [hdrNote],
148
+ },
149
+ PageOrder: {
150
+ description: 'Order/booking details template: status chips, items table, timeline and side info cards.',
151
+ props: header,
152
+ slots: {
153
+ ...headSlots,
154
+ status: 'Payment and fulfillment chips; Chip (tone success, warning, danger).',
155
+ items: 'Items table with totals; DataTable.',
156
+ shipping: 'Event timeline; Timeline.',
157
+ side: 'Customer, address and payment cards; UserCell, Descriptions, Button.',
158
+ },
159
+ notes: [hdrNote],
160
+ },
161
+ PageAccount: {
162
+ description: 'Account settings template with pill tabs and a swappable panel.',
163
+ props: header,
164
+ slots: {
165
+ ...headSlots,
166
+ tabs: 'Section tabs (account, security, billing, notifications); PillTabs.',
167
+ panel: 'Content of the active tab; Card or SettingsSection with Switch and TextField.',
168
+ },
169
+ notes: [hdrNote, 'The template does not switch panels by itself: keep the active tab in your own state (PillTabs v-model) and render only that tab content in the panel slot.'],
170
+ },
171
+ PagePricing: {
172
+ description: 'Pricing template: billing-period toggle, plan cards and an FAQ.',
173
+ props: header,
174
+ slots: {
175
+ ...headSlots,
176
+ toggle: 'Monthly/annual switch with a savings badge; Switch, Chip.',
177
+ plans: 'Plan cards, one marked featured; PricingCard.',
178
+ faq: 'Questions accordion; Accordion.',
179
+ },
180
+ notes: [hdrNote],
181
+ },
182
+ PageFaq: {
183
+ description: 'Help center template: search, categories, answers accordion and a contact block.',
184
+ props: header,
185
+ slots: {
186
+ ...headSlots,
187
+ search: 'Large search field; SearchInput.',
188
+ cats: 'Category list on the left; vertical PillTabs.',
189
+ answers: 'Answers on the right; Accordion.',
190
+ contact: 'Contact cards below; Card, IconTile, Button.',
191
+ },
192
+ notes: [hdrNote],
193
+ },
194
+ PageAuth: {
195
+ description: 'Sign-in page template without the app shell, as a centered card or a split layout.',
196
+ props: {
197
+ layout: { forwarded: true, type: "'card' | 'split'", values: ['card', 'split'], default: 'card', description: "'split' uses AuthSplit with a side panel; anything else renders a centered AuthLayout card over the background." },
198
+ title: { forwarded: true, type: 'string', description: 'Form heading.' },
199
+ subtitle: { forwarded: true, type: 'string', description: 'Text under the heading.' },
200
+ },
201
+ slots: {
202
+ background: 'Decorative glows behind the card; card layout only.',
203
+ logo: 'Logo above the heading.',
204
+ aside: 'Brand panel on the left; split layout only, hidden below 820 px.',
205
+ form: 'Sign-in fields and button; LoginForm, TextField, PasswordInput, CodeInput, Button.',
206
+ footer: 'Links such as help, create account, back to login.',
207
+ },
208
+ notes: ['Designed for the dark theme and used without AppShell.'],
209
+ },
210
+ PageStatus: {
211
+ description: 'Full-page status screen (404, 401, maintenance, coming soon) with one action.',
212
+ props: {
213
+ kind: { forwarded: true, type: "'404' | '401' | 'maintenance' | 'soon'", values: ['404', '401', 'maintenance', 'soon'], default: '404', description: 'Preset screen; selects default texts, the big code or icon, and the button label. Filled into every part whose slot is empty.' },
214
+ title: { forwarded: true, type: 'string', description: 'Overrides the preset heading.' },
215
+ description: { forwarded: true, type: 'string', description: 'Overrides the preset description.' },
216
+ onAction: { type: '() => void', description: 'Primary button click.' },
217
+ actionLabel: { forwarded: true, type: 'string', description: 'Overrides the preset button text (404, 401, maintenance).' },
218
+ notifyLabel: { forwarded: true, type: 'string', default: 'Notify me', description: 'Button text for kind "soon".' },
219
+ emailLabel: { forwarded: true, type: 'string', default: 'name@email.com', description: 'Placeholder of the email field for kind "soon".' },
220
+ },
221
+ slots: {
222
+ code: 'Large code or icon; replaces the preset code only.',
223
+ message: 'Heading and description; replaces title and description.',
224
+ action: 'The primary button or an email form; replaces the preset action (onAction and actionLabel are then unused).',
225
+ },
226
+ events: { action: 'Preset primary button clicked (not fired when the action slot is filled).', notify: 'Called with the typed email when the Notify button of kind "soon" is clicked (not fired when the action slot is filled).' },
227
+ notes: ['Slots replace only their own part: fill message and the preset code and button remain; kind, title, description, onAction and actionLabel apply to the parts whose slot is empty.', 'kind="soon" shows an email field and a Notify me button; handle onNotify(email) to collect the address.'],
228
+ },
229
+ };