@plutocms/supabase 0.0.1-alpha.1

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 (99) hide show
  1. package/.agents/skills/nuxt/GENERATION.md +5 -0
  2. package/.agents/skills/nuxt/SKILL.md +55 -0
  3. package/.agents/skills/nuxt/references/advanced-hooks.md +289 -0
  4. package/.agents/skills/nuxt/references/advanced-layers.md +299 -0
  5. package/.agents/skills/nuxt/references/advanced-module-authoring.md +554 -0
  6. package/.agents/skills/nuxt/references/best-practices-data-fetching.md +357 -0
  7. package/.agents/skills/nuxt/references/best-practices-ssr.md +355 -0
  8. package/.agents/skills/nuxt/references/core-cli.md +263 -0
  9. package/.agents/skills/nuxt/references/core-config.md +162 -0
  10. package/.agents/skills/nuxt/references/core-data-fetching.md +236 -0
  11. package/.agents/skills/nuxt/references/core-deployment.md +224 -0
  12. package/.agents/skills/nuxt/references/core-directory-structure.md +269 -0
  13. package/.agents/skills/nuxt/references/core-modules.md +292 -0
  14. package/.agents/skills/nuxt/references/core-routing.md +226 -0
  15. package/.agents/skills/nuxt/references/features-components-autoimport.md +328 -0
  16. package/.agents/skills/nuxt/references/features-components.md +264 -0
  17. package/.agents/skills/nuxt/references/features-composables.md +276 -0
  18. package/.agents/skills/nuxt/references/features-server.md +265 -0
  19. package/.agents/skills/nuxt/references/features-state.md +194 -0
  20. package/.agents/skills/nuxt/references/rendering-modes.md +237 -0
  21. package/.agents/skills/nuxt-ui/SKILL.md +334 -0
  22. package/.agents/skills/nuxt-ui/references/components.md +377 -0
  23. package/.agents/skills/nuxt-ui/references/composables.md +127 -0
  24. package/.agents/skills/nuxt-ui/references/layouts/chat.md +195 -0
  25. package/.agents/skills/nuxt-ui/references/layouts/dashboard.md +220 -0
  26. package/.agents/skills/nuxt-ui/references/layouts/docs.md +141 -0
  27. package/.agents/skills/nuxt-ui/references/layouts/editor.md +167 -0
  28. package/.agents/skills/nuxt-ui/references/layouts/page.md +260 -0
  29. package/.agents/skills/nuxt-ui/references/theming.md +427 -0
  30. package/.agents/skills/supabase-postgres-best-practices/AGENTS.md +68 -0
  31. package/.agents/skills/supabase-postgres-best-practices/CLAUDE.md +1 -0
  32. package/.agents/skills/supabase-postgres-best-practices/README.md +116 -0
  33. package/.agents/skills/supabase-postgres-best-practices/SKILL.md +64 -0
  34. package/.agents/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +55 -0
  35. package/.agents/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +49 -0
  36. package/.agents/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +46 -0
  37. package/.agents/skills/supabase-postgres-best-practices/references/conn-limits.md +44 -0
  38. package/.agents/skills/supabase-postgres-best-practices/references/conn-pooling.md +41 -0
  39. package/.agents/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +46 -0
  40. package/.agents/skills/supabase-postgres-best-practices/references/data-batch-inserts.md +54 -0
  41. package/.agents/skills/supabase-postgres-best-practices/references/data-n-plus-one.md +53 -0
  42. package/.agents/skills/supabase-postgres-best-practices/references/data-pagination.md +50 -0
  43. package/.agents/skills/supabase-postgres-best-practices/references/data-upsert.md +50 -0
  44. package/.agents/skills/supabase-postgres-best-practices/references/lock-advisory.md +56 -0
  45. package/.agents/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +68 -0
  46. package/.agents/skills/supabase-postgres-best-practices/references/lock-short-transactions.md +50 -0
  47. package/.agents/skills/supabase-postgres-best-practices/references/lock-skip-locked.md +54 -0
  48. package/.agents/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +45 -0
  49. package/.agents/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +55 -0
  50. package/.agents/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +55 -0
  51. package/.agents/skills/supabase-postgres-best-practices/references/query-composite-indexes.md +44 -0
  52. package/.agents/skills/supabase-postgres-best-practices/references/query-covering-indexes.md +40 -0
  53. package/.agents/skills/supabase-postgres-best-practices/references/query-index-types.md +48 -0
  54. package/.agents/skills/supabase-postgres-best-practices/references/query-missing-indexes.md +43 -0
  55. package/.agents/skills/supabase-postgres-best-practices/references/query-partial-indexes.md +45 -0
  56. package/.agents/skills/supabase-postgres-best-practices/references/schema-constraints.md +80 -0
  57. package/.agents/skills/supabase-postgres-best-practices/references/schema-data-types.md +46 -0
  58. package/.agents/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +59 -0
  59. package/.agents/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +55 -0
  60. package/.agents/skills/supabase-postgres-best-practices/references/schema-partitioning.md +55 -0
  61. package/.agents/skills/supabase-postgres-best-practices/references/schema-primary-keys.md +61 -0
  62. package/.agents/skills/supabase-postgres-best-practices/references/security-privileges.md +54 -0
  63. package/.agents/skills/supabase-postgres-best-practices/references/security-rls-basics.md +50 -0
  64. package/.agents/skills/supabase-postgres-best-practices/references/security-rls-performance.md +57 -0
  65. package/.editorconfig +12 -0
  66. package/.env.example +2 -0
  67. package/.eslintignore +1 -0
  68. package/.prettierrc +9 -0
  69. package/.vscode/extensions.json +10 -0
  70. package/.vscode/settings.json +61 -0
  71. package/README.md +62 -0
  72. package/app/components/navbar/NavbarAdmin.vue +169 -0
  73. package/app/composables/auth.ts +81 -0
  74. package/app/layouts/setup.vue +13 -0
  75. package/app/middleware/auth.ts +27 -0
  76. package/app/middleware/setup-check.ts +25 -0
  77. package/app/pages/admin/(auth)/login.vue +84 -0
  78. package/app/pages/admin/(auth)/signup.vue +128 -0
  79. package/app/pages/admin/settings.vue +116 -0
  80. package/app/pages/admin/setup.vue +300 -0
  81. package/app/pages/admin.vue +38 -0
  82. package/bun.lock +2685 -0
  83. package/eslint.config.mjs +88 -0
  84. package/nuxt.config.ts +55 -0
  85. package/package.json +44 -0
  86. package/public/schema.sql +103 -0
  87. package/scripts/supabase-typegen.ts +36 -0
  88. package/server/api/category/list.get.ts +9 -0
  89. package/server/api/category/new.post.ts +31 -0
  90. package/server/api/settings/first_setup.get.ts +39 -0
  91. package/server/api/settings/index.get.ts +27 -0
  92. package/server/api/settings/update.post.ts +36 -0
  93. package/server/api/setup/create.post.ts +58 -0
  94. package/server/api/signup.post.ts +28 -0
  95. package/server/api/users/[id].get.ts +21 -0
  96. package/server/api/users/index.get.ts +16 -0
  97. package/shared/types/supabase.ts +406 -0
  98. package/skills-lock.json +20 -0
  99. package/tsconfig.json +18 -0
@@ -0,0 +1,377 @@
1
+ # Components
2
+
3
+ 125+ Vue components powered by Tailwind CSS and Reka UI. For any component's theme slots, read the generated theme file (Nuxt: `.nuxt/ui/<component>.ts`, Vue: `node_modules/.nuxt-ui/ui/<component>.ts`).
4
+
5
+ ## Layout
6
+
7
+ Core structural components for organizing your application's layout.
8
+
9
+ | Component | Purpose |
10
+ |---|---|
11
+ | `UApp` | **Required** root wrapper for toasts, tooltips, overlays |
12
+ | `UHeader` | Responsive header with mobile menu (`#title`, `#default`, `#right`, `#body`) |
13
+ | `UFooter` | Footer (`#left`, `#default`, `#right`, `#top`, `#bottom`) |
14
+ | `UFooterColumns` | Multi-column footer with link groups |
15
+ | `UMain` | Main content area (respects `--ui-header-height`) |
16
+ | `UContainer` | Centered max-width container (`--ui-container`) |
17
+
18
+ ## Element
19
+
20
+ Essential UI building blocks.
21
+
22
+ | Component | Key props |
23
+ |---|---|
24
+ | `UButton` | `label`, `icon`, `color`, `variant`, `size`, `loading`, `disabled`, `to` |
25
+ | `UBadge` | `label`, `color`, `variant`, `size` |
26
+ | `UAvatar` | `src`, `alt`, `icon`, `text`, `size` |
27
+ | `UAvatarGroup` | `max`, `size` — wraps multiple `UAvatar` |
28
+ | `UIcon` | `name`, `size` |
29
+ | `UCard` | `variant` — slots: `#header`, `#default`, `#footer` |
30
+ | `UAlert` | `title`, `description`, `icon`, `color`, `variant`, `close` |
31
+ | `UBanner` | `title`, `icon`, `close` — sticky top banner |
32
+ | `UChip` | `color`, `size`, `position` — notification dot on children |
33
+ | `UKbd` | `value` — keyboard key display |
34
+ | `USeparator` | `label`, `icon`, `orientation`, `type` |
35
+ | `USkeleton` | `class` — loading placeholder |
36
+ | `UProgress` | `value`, `max`, `color`, `size` |
37
+ | `UCalendar` | `v-model`, `range` (boolean), `multiple` (boolean) |
38
+ | `UCollapsible` | `v-model:open` — animated expand/collapse |
39
+ | `UFieldGroup` | Groups form inputs horizontally/vertically |
40
+
41
+ ## Form
42
+
43
+ Comprehensive form components for user input.
44
+
45
+ | Component | Key props |
46
+ |---|---|
47
+ | `UInput` | `v-model`, `type`, `placeholder`, `icon`, `loading` |
48
+ | `UTextarea` | `v-model`, `rows`, `autoresize`, `maxrows` |
49
+ | `USelect` | `v-model`, `items` (flat `T[]` or grouped `T[][]`), `placeholder` |
50
+ | `USelectMenu` | `v-model`, `items` (flat `T[]` or grouped `T[][]`), `searchable`, `multiple` |
51
+ | `UInputMenu` | `v-model`, `items` (flat `T[]` or grouped `T[][]`), `searchable` — autocomplete |
52
+ | `UInputNumber` | `v-model`, `min`, `max`, `step` |
53
+ | `UInputDate` | `v-model`, `range` (boolean for range selection), `locale` |
54
+ | `UInputTime` | `v-model`, `hour-cycle` (12/24), `granularity` |
55
+ | `UInputTags` | `v-model`, `max`, `placeholder` |
56
+ | `UPinInput` | `v-model`, `length`, `type`, `mask` |
57
+ | `UCheckbox` | `v-model`, `label`, `description` |
58
+ | `UCheckboxGroup` | `v-model`, `items`, `orientation` |
59
+ | `URadioGroup` | `v-model`, `items`, `orientation` |
60
+ | `USwitch` | `v-model`, `label`, `on-icon`, `off-icon` |
61
+ | `USlider` | `v-model`, `min`, `max`, `step` |
62
+ | `UColorPicker` | `v-model`, `format` (hex/rgb/hsl/cmyk/lab), `size` |
63
+ | `UFileUpload` | `v-model`, `accept`, `multiple`, `variant` (area/button) |
64
+ | `UForm` | `schema`, `state`, `@submit` — validation wrapper |
65
+ | `UFormField` | `name`, `label`, `description`, `hint`, `required` |
66
+
67
+ ### Form validation
68
+
69
+ Uses Standard Schema — works with Zod, Valibot, Yup, or Joi.
70
+
71
+ ```vue
72
+ <script setup lang="ts">
73
+ import { z } from 'zod'
74
+
75
+ const schema = z.object({
76
+ email: z.string().email('Invalid email'),
77
+ password: z.string().min(8, 'Min 8 characters')
78
+ })
79
+
80
+ type Schema = z.output<typeof schema>
81
+ const state = reactive<Partial<Schema>>({ email: '', password: '' })
82
+ const form = ref()
83
+
84
+ async function onSubmit() {
85
+ await form.value.validate()
86
+ }
87
+ </script>
88
+
89
+ <template>
90
+ <UForm ref="form" :schema="schema" :state="state" @submit="onSubmit">
91
+ <UFormField name="email" label="Email" required>
92
+ <UInput v-model="state.email" type="email" />
93
+ </UFormField>
94
+
95
+ <UFormField name="password" label="Password" required>
96
+ <UInput v-model="state.password" type="password" />
97
+ </UFormField>
98
+
99
+ <UButton type="submit">Submit</UButton>
100
+ </UForm>
101
+ </template>
102
+ ```
103
+
104
+ With Valibot:
105
+
106
+ ```vue
107
+ <script setup lang="ts">
108
+ import * as v from 'valibot'
109
+
110
+ const schema = v.object({
111
+ email: v.pipe(v.string(), v.email('Invalid email')),
112
+ password: v.pipe(v.string(), v.minLength(8, 'Min 8 characters'))
113
+ })
114
+ </script>
115
+ ```
116
+
117
+ ### File upload
118
+
119
+ ```vue
120
+ <script setup>
121
+ const files = ref<File[]>([])
122
+ </script>
123
+
124
+ <template>
125
+ <UFileUpload v-model="files" accept="image/*" multiple>
126
+ <template #actions="{ open }">
127
+ <UButton label="Upload" icon="i-lucide-upload" color="neutral" variant="outline" @click="open()" />
128
+ </template>
129
+ </UFileUpload>
130
+ </template>
131
+ ```
132
+
133
+ ## Data
134
+
135
+ Components for displaying and organizing data.
136
+
137
+ | Component | Key props |
138
+ |---|---|
139
+ | `UTable` | `data`, `columns`, `loading`, `sticky` |
140
+ | `UAccordion` | `items`, `type` (single/multiple), `collapsible` |
141
+ | `UCarousel` | `items`, `orientation`, `arrows`, `dots` |
142
+ | `UTimeline` | `items` — vertical timeline |
143
+ | `UTree` | `items` — hierarchical tree |
144
+ | `UUser` | `name`, `description`, `avatar` — user display |
145
+ | `UEmpty` | `icon`, `title`, `description` — empty state |
146
+ | `UMarquee` | `repeat`, `reverse`, `orientation`, `pauseOnHover` — infinite scroll |
147
+ | `UScrollArea` | Custom scrollbar wrapper |
148
+
149
+ ## Navigation
150
+
151
+ Components for user navigation and wayfinding.
152
+
153
+ | Component | Key props |
154
+ |---|---|
155
+ | `UNavigationMenu` | `items` (flat `T[]` or grouped `T[][]`), `orientation` (horizontal/vertical) |
156
+ | `UBreadcrumb` | `items` |
157
+ | `UTabs` | `items`, `orientation`, `variant` |
158
+ | `UStepper` | `items`, `orientation`, `color` |
159
+ | `UPagination` | `v-model`, `total`, `items-per-page` |
160
+ | `ULink` | `to`, `active`, `inactive` — styled NuxtLink |
161
+ | `UCommandPalette` | `v-model:open`, `groups` (`{ id, label, items }[]`), `placeholder` |
162
+
163
+ ## Overlay
164
+
165
+ Floating UI elements that appear above the main content. **All require `<UApp>` wrapper.**
166
+
167
+ | Component | Key props |
168
+ |---|---|
169
+ | `UModal` | `v-model:open`, `title`, `description`, `fullscreen`, `scrollable` |
170
+ | `USlideover` | `v-model:open`, `title`, `side` (left/right/top/bottom) |
171
+ | `UDrawer` | `v-model:open`, `title`, `handle` |
172
+ | `UPopover` | `arrow`, `content: { side, align }`, `openDelay`, `closeDelay` |
173
+ | `UTooltip` | `text`, `content: { side }`, `delayDuration` |
174
+ | `UDropdownMenu` | `items` (flat `T[]` or grouped `T[][]` with separators, supports nested `children`) |
175
+ | `UContextMenu` | `items` (flat `T[]` or grouped `T[][]`) — right-click menu |
176
+ | `UToast` | Used via `useToast()` composable |
177
+
178
+ ### Modal
179
+
180
+ ```vue
181
+ <UModal v-model:open="isOpen" title="Edit" description="Edit your profile">
182
+ <template #body>Content</template>
183
+ <template #footer>
184
+ <UButton variant="ghost" @click="isOpen = false">Cancel</UButton>
185
+ <UButton @click="save">Save</UButton>
186
+ </template>
187
+ </UModal>
188
+ ```
189
+
190
+ Slots: `#content`, `#header`, `#body`, `#footer`
191
+
192
+ ### Slideover
193
+
194
+ ```vue
195
+ <USlideover v-model:open="isOpen" title="Settings" side="right">
196
+ <template #body>Content</template>
197
+ </USlideover>
198
+ ```
199
+
200
+ ### Drawer
201
+
202
+ ```vue
203
+ <UDrawer v-model:open="isOpen" title="Options" handle>
204
+ <template #body>Content</template>
205
+ </UDrawer>
206
+ ```
207
+
208
+ ### DropdownMenu
209
+
210
+ Items accept a flat array or a nested array (each sub-array is rendered as a group separated by dividers):
211
+
212
+ ```vue
213
+ <!-- Flat array -->
214
+ <UDropdownMenu :items="[
215
+ { label: 'Edit', icon: 'i-lucide-pencil', onSelect: () => edit() },
216
+ { type: 'separator' },
217
+ { label: 'Delete', icon: 'i-lucide-trash', color: 'error' }
218
+ ]">
219
+ <UButton icon="i-lucide-ellipsis-vertical" variant="ghost" />
220
+ </UDropdownMenu>
221
+
222
+ <!-- Nested array (groups with automatic separators) -->
223
+ <UDropdownMenu :items="[
224
+ [{ label: 'Edit', icon: 'i-lucide-pencil' }, { label: 'Duplicate', icon: 'i-lucide-copy' }],
225
+ [{ label: 'Delete', icon: 'i-lucide-trash', color: 'error' }]
226
+ ]">
227
+ <UButton icon="i-lucide-ellipsis-vertical" variant="ghost" />
228
+ </UDropdownMenu>
229
+ ```
230
+
231
+ ### Toast
232
+
233
+ ```ts
234
+ const toast = useToast()
235
+
236
+ toast.add({
237
+ title: 'Success',
238
+ description: 'Changes saved',
239
+ color: 'success',
240
+ icon: 'i-lucide-check-circle',
241
+ duration: 5000,
242
+ actions: [{ label: 'Undo', onClick: () => undo() }]
243
+ })
244
+ ```
245
+
246
+ ### Programmatic overlays
247
+
248
+ ```ts
249
+ const overlay = useOverlay()
250
+
251
+ // create() returns a reusable instance
252
+ const confirmDialog = overlay.create(ConfirmDialog)
253
+
254
+ // open() returns an object with .result (a Promise)
255
+ const { result } = confirmDialog.open({
256
+ title: 'Delete?',
257
+ message: 'This cannot be undone.'
258
+ })
259
+
260
+ if (await result) {
261
+ // User confirmed
262
+ }
263
+
264
+ // Inside the overlay component, emit close with a value:
265
+ // emit('close', true) or emit('close', false)
266
+ ```
267
+
268
+ ### CommandPalette
269
+
270
+ ```vue
271
+ <script setup>
272
+ const groups = [{
273
+ id: 'actions',
274
+ label: 'Actions',
275
+ items: [
276
+ { label: 'New file', icon: 'i-lucide-file-plus', onSelect: () => {} },
277
+ { label: 'Settings', to: '/settings' }
278
+ ]
279
+ }]
280
+
281
+ defineShortcuts({ meta_k: () => { isOpen.value = true } })
282
+ </script>
283
+
284
+ <UCommandPalette v-model:open="isOpen" :groups="groups" placeholder="Search..." />
285
+ ```
286
+
287
+ ## Page
288
+
289
+ Pre-built sections for marketing and content pages.
290
+
291
+ | Component | Purpose |
292
+ |---|---|
293
+ | `UPage` | Multi-column grid (`#left`, `#default`, `#right`) |
294
+ | `UPageAside` | Sticky sidebar wrapper (visible from `lg`) |
295
+ | `UPageHero` | Hero section with title, description, links, media |
296
+ | `UPageSection` | Content section with headline, features grid |
297
+ | `UPageCTA` | Call to action block |
298
+ | `UPageHeader` | Page title and description |
299
+ | `UPageBody` | Main content area with prose styling |
300
+ | `UPageFeature` | Individual feature item |
301
+ | `UPageGrid` | Grid layout for cards |
302
+ | `UPageColumns` | Multi-column layout |
303
+ | `UPageCard` | Content card for grids |
304
+ | `UPageLogos` | Logo wall |
305
+ | `UPageAnchors` | Anchor links (simpler TOC) |
306
+ | `UPageLinks` | Related resource links |
307
+ | `UPageList` | List items |
308
+ | `UBlogPosts` | Responsive grid of blog posts (`orientation`) |
309
+ | `UBlogPost` | Individual blog post card |
310
+ | `UChangelogVersions` | Changelog version list |
311
+ | `UChangelogVersion` | Individual changelog entry |
312
+ | `UPricingPlans` | Pricing plan cards |
313
+ | `UPricingTable` | Feature comparison table |
314
+
315
+ ## Dashboard
316
+
317
+ Specialized components for admin interfaces with resizable panels and sidebars.
318
+
319
+ | Component | Purpose |
320
+ |---|---|
321
+ | `UDashboardGroup` | Root wrapper — manages sidebar state |
322
+ | `UDashboardSidebar` | Resizable/collapsible sidebar (`#header`, `#default`, `#footer`) |
323
+ | `UDashboardPanel` | Content panel (`#header`, `#body`, `#footer`) |
324
+ | `UDashboardNavbar` | Panel navbar (`#left`, `#default`, `#right`) |
325
+ | `UDashboardToolbar` | Toolbar for filters/actions |
326
+ | `UDashboardSearch` | Command palette for dashboards |
327
+ | `UDashboardSearchButton` | Search trigger button |
328
+ | `UDashboardSidebarToggle` | Mobile sidebar toggle |
329
+ | `UDashboardSidebarCollapse` | Desktop collapse button |
330
+ | `UDashboardResizeHandle` | Custom resize handle |
331
+
332
+ ## Chat
333
+
334
+ Components for conversational AI interfaces, powered by [Vercel AI SDK](https://ai-sdk.dev/).
335
+
336
+ | Component | Purpose |
337
+ |---|---|
338
+ | `UChatMessages` | Scrollable message list with auto-scroll |
339
+ | `UChatMessage` | Individual message display |
340
+ | `UChatPrompt` | Enhanced textarea for prompts |
341
+ | `UChatPromptSubmit` | Submit button with status handling |
342
+ | `UChatPalette` | Chat layout for overlays |
343
+
344
+ ## Editor
345
+
346
+ Rich text editor powered by [TipTap](https://tiptap.dev/).
347
+
348
+ | Component | Purpose |
349
+ |---|---|
350
+ | `UEditor` | Editor (`v-model`, `content-type`: json/html/markdown) |
351
+ | `UEditorToolbar` | Toolbar (`layout`: fixed/bubble/floating) |
352
+ | `UEditorDragHandle` | Block drag-and-drop |
353
+ | `UEditorSuggestionMenu` | Slash command menu |
354
+ | `UEditorMentionMenu` | @ mention menu |
355
+ | `UEditorEmojiMenu` | Emoji picker |
356
+
357
+ ## Content
358
+
359
+ Components integrating with `@nuxt/content`.
360
+
361
+ | Component | Purpose |
362
+ |---|---|
363
+ | `UContentNavigation` | Sidebar navigation tree |
364
+ | `UContentToc` | Table of contents |
365
+ | `UContentSurround` | Prev/next links |
366
+ | `UContentSearch` | Search command palette |
367
+ | `UContentSearchButton` | Search trigger button |
368
+
369
+ ## Color Mode
370
+
371
+ | Component | Purpose |
372
+ |---|---|
373
+ | `UColorModeButton` | Toggle light/dark button |
374
+ | `UColorModeSwitch` | Toggle light/dark switch |
375
+ | `UColorModeSelect` | Dropdown selector |
376
+ | `UColorModeAvatar` | Avatar with different src per mode |
377
+ | `UColorModeImage` | Image with different src per mode |
@@ -0,0 +1,127 @@
1
+ # Composables
2
+
3
+ ## useToast
4
+
5
+ Show notifications. Requires `<UApp>` wrapper.
6
+
7
+ ```ts
8
+ const toast = useToast()
9
+
10
+ toast.add({
11
+ title: 'Success',
12
+ description: 'Item saved',
13
+ color: 'success', // primary, success, error, warning, info
14
+ icon: 'i-lucide-check-circle',
15
+ duration: 5000, // 0 = never dismiss
16
+ actions: [{ label: 'Undo', onClick: () => {} }]
17
+ })
18
+
19
+ toast.remove('toast-id')
20
+ toast.clear()
21
+ ```
22
+
23
+ ## useOverlay
24
+
25
+ Programmatically create modals, slideovers, drawers.
26
+
27
+ ```ts
28
+ const overlay = useOverlay()
29
+
30
+ // create() returns a reusable instance with open(), close(), patch()
31
+ const modal = overlay.create(MyComponent)
32
+
33
+ // open() accepts props and returns an object with .result (a Promise)
34
+ const { result } = modal.open({ title: 'Confirm' })
35
+
36
+ if (await result) {
37
+ // User confirmed
38
+ }
39
+
40
+ // Inside the overlay component, emit close with a value:
41
+ // emit('close', true) or emit('close', false)
42
+
43
+ // You can also close from outside:
44
+ modal.close(false)
45
+ ```
46
+
47
+ ## defineShortcuts
48
+
49
+ Define keyboard shortcuts.
50
+
51
+ ```ts
52
+ defineShortcuts({
53
+ meta_k: () => openSearch(), // Cmd+K (Mac) / Ctrl+K (Win)
54
+ meta_shift_p: () => openPalette(), // Cmd+Shift+P
55
+ escape: () => close(),
56
+ ctrl_s: () => save(),
57
+
58
+ // With condition
59
+ meta_enter: {
60
+ handler: () => submit(),
61
+ whenever: [isFormValid]
62
+ }
63
+ })
64
+ ```
65
+
66
+ | Key | Meaning |
67
+ |---|---|
68
+ | `meta` | Cmd (Mac) / Ctrl (Windows) |
69
+ | `ctrl` | Ctrl key |
70
+ | `alt` | Alt / Option key |
71
+ | `shift` | Shift key |
72
+ | `_` | Key separator |
73
+
74
+ ## defineLocale / extendLocale
75
+
76
+ i18n locale definition.
77
+
78
+ ```ts
79
+ import { fr } from '@nuxt/ui/locale'
80
+
81
+ // Use a built-in locale (50+ available)
82
+ // <UApp :locale="fr">
83
+
84
+ // Define custom locale
85
+ const locale = defineLocale({
86
+ name: 'Español',
87
+ code: 'es',
88
+ dir: 'ltr',
89
+ messages: {
90
+ select: { placeholder: 'Seleccionar...' }
91
+ }
92
+ })
93
+
94
+ // Extend existing locale
95
+ import { en } from '@nuxt/ui/locale'
96
+
97
+ const customEn = extendLocale(en, {
98
+ messages: { commandPalette: { placeholder: 'Search a component...' } }
99
+ })
100
+ ```
101
+
102
+ ```vue
103
+ <UApp :locale="fr"><NuxtPage /></UApp>
104
+ ```
105
+
106
+ ## extractShortcuts
107
+
108
+ Extract shortcut keys from a list of items (e.g., dropdown menu items) into a shortcuts map for `defineShortcuts`.
109
+
110
+ ```ts
111
+ const items = [
112
+ { label: 'New file', kbds: ['meta', 'n'], onSelect: () => newFile() },
113
+ { label: 'Save', kbds: ['meta', 's'], onSelect: () => save() }
114
+ ]
115
+
116
+ defineShortcuts(extractShortcuts(items))
117
+ ```
118
+
119
+ ## Quick reference
120
+
121
+ | Composable | Purpose |
122
+ |---|---|
123
+ | `useToast` | Show notifications |
124
+ | `useOverlay` | Programmatic modals/slideovers |
125
+ | `defineShortcuts` | Keyboard shortcuts |
126
+ | `defineLocale` / `extendLocale` | i18n locale |
127
+ | `extractShortcuts` | Parse shortcut definitions |
@@ -0,0 +1,195 @@
1
+ # Chat Layout
2
+
3
+ Build AI chat interfaces with message streams, prompts, and Vercel AI SDK integration.
4
+
5
+ ## Component tree
6
+
7
+ ```
8
+ UApp
9
+ └── NuxtLayout (dashboard)
10
+ └── UDashboardGroup
11
+ ├── UDashboardSidebar (conversations)
12
+ └── NuxtPage
13
+ └── UDashboardPanel
14
+ ├── #header → UDashboardNavbar
15
+ ├── #body → UContainer → UChatMessages
16
+ └── #footer → UContainer → UChatPrompt
17
+ └── UChatPromptSubmit
18
+ ```
19
+
20
+ ## Setup
21
+
22
+ ### Install AI SDK
23
+
24
+ ```bash
25
+ pnpm add ai @ai-sdk/gateway @ai-sdk/vue
26
+ ```
27
+
28
+ ### Server endpoint
29
+
30
+ ```ts [server/api/chat.post.ts]
31
+ import { streamText, convertToModelMessages } from 'ai'
32
+ import { gateway } from '@ai-sdk/gateway'
33
+
34
+ export default defineEventHandler(async (event) => {
35
+ const { messages } = await readBody(event)
36
+
37
+ return streamText({
38
+ model: gateway('openai/gpt-4o-mini'),
39
+ system: 'You are a helpful assistant.',
40
+ messages: await convertToModelMessages(messages)
41
+ }).toUIMessageStreamResponse()
42
+ })
43
+ ```
44
+
45
+ ## Full page chat
46
+
47
+ ```vue [pages/chat/[id].vue]
48
+ <script setup lang="ts">
49
+ import { Chat } from '@ai-sdk/vue'
50
+
51
+ definePageMeta({ layout: 'dashboard' })
52
+
53
+ const input = ref('')
54
+
55
+ const chat = new Chat({
56
+ onError(error) {
57
+ console.error(error)
58
+ }
59
+ })
60
+
61
+ function onSubmit() {
62
+ chat.sendMessage({ text: input.value })
63
+ input.value = ''
64
+ }
65
+ </script>
66
+
67
+ <template>
68
+ <UDashboardPanel>
69
+ <template #header>
70
+ <UDashboardNavbar title="Chat" />
71
+ </template>
72
+
73
+ <template #body>
74
+ <UContainer>
75
+ <UChatMessages :messages="chat.messages" :status="chat.status">
76
+ <template #content="{ message }">
77
+ <template v-for="(part, index) in message.parts" :key="`${message.id}-${part.type}-${index}`">
78
+ <MDC
79
+ v-if="part.type === 'text' && message.role === 'assistant'"
80
+ :value="part.text"
81
+ :cache-key="`${message.id}-${index}`"
82
+ class="*:first:mt-0 *:last:mb-0"
83
+ />
84
+ <p v-else-if="part.type === 'text' && message.role === 'user'" class="whitespace-pre-wrap">
85
+ {{ part.text }}
86
+ </p>
87
+ </template>
88
+ </template>
89
+ </UChatMessages>
90
+ </UContainer>
91
+ </template>
92
+
93
+ <template #footer>
94
+ <UContainer class="pb-4 sm:pb-6">
95
+ <UChatPrompt v-model="input" :error="chat.error" @submit="onSubmit">
96
+ <UChatPromptSubmit :status="chat.status" @stop="chat.stop()" @reload="chat.regenerate()" />
97
+ </UChatPrompt>
98
+ </UContainer>
99
+ </template>
100
+ </UDashboardPanel>
101
+ </template>
102
+ ```
103
+
104
+ ## Key components
105
+
106
+ ### ChatMessages
107
+
108
+ Scrollable message list with auto-scroll and loading indicator.
109
+
110
+ | Prop | Description |
111
+ |---|---|
112
+ | `messages` | Array of AI SDK messages |
113
+ | `status` | `'submitted'`, `'streaming'`, `'ready'`, `'error'` |
114
+
115
+ Slots: `#content` (receives `{ message }`), `#actions` (per-message), `#indicator` (loading)
116
+
117
+ ### ChatPrompt
118
+
119
+ Enhanced textarea form for prompts. Accepts all Textarea props.
120
+
121
+ | Prop | Description |
122
+ |---|---|
123
+ | `v-model` | Input text binding |
124
+ | `error` | Error from chat instance |
125
+ | `variant` | `'outline'` (default), `'subtle'`, `'soft'`, `'ghost'`, `'none'` |
126
+
127
+ Slots: `#default` (submit button), `#footer` (below input, e.g. model selector)
128
+
129
+ ### ChatPromptSubmit
130
+
131
+ Submit button with automatic status handling (send/stop/reload).
132
+
133
+ ### ChatPalette
134
+
135
+ Layout wrapper for chat inside overlays (Modal, Slideover, Drawer).
136
+
137
+ ## Chat in a modal
138
+
139
+ ```vue
140
+ <UModal v-model:open="isOpen">
141
+ <template #content>
142
+ <UChatPalette>
143
+ <UChatMessages :messages="chat.messages" :status="chat.status" />
144
+
145
+ <template #prompt>
146
+ <UChatPrompt v-model="input" @submit="onSubmit">
147
+ <UChatPromptSubmit :status="chat.status" />
148
+ </UChatPrompt>
149
+ </template>
150
+ </UChatPalette>
151
+ </template>
152
+ </UModal>
153
+ ```
154
+
155
+ ## With model selector
156
+
157
+ ```vue
158
+ <UChatPrompt v-model="input" @submit="onSubmit">
159
+ <UChatPromptSubmit :status="chat.status" />
160
+
161
+ <template #footer>
162
+ <USelect
163
+ v-model="model"
164
+ placeholder="Select a model"
165
+ variant="ghost"
166
+ icon="i-simple-icons-openai"
167
+ :items="[
168
+ { label: 'GPT-4o', value: 'gpt-4o' },
169
+ { label: 'Claude 3.5 Sonnet', value: 'claude-3.5-sonnet' },
170
+ { label: 'Gemini 2.5 Pro', value: 'gemini-2.5-pro' }
171
+ ]"
172
+ />
173
+ </template>
174
+ </UChatPrompt>
175
+ ```
176
+
177
+ ## Conversation sidebar
178
+
179
+ ```vue [layouts/dashboard.vue]
180
+ <template>
181
+ <UDashboardGroup>
182
+ <UDashboardSidebar collapsible resizable>
183
+ <template #header>
184
+ <UButton icon="i-lucide-plus" label="New chat" block />
185
+ </template>
186
+
187
+ <template #default>
188
+ <UNavigationMenu :items="conversations" orientation="vertical" />
189
+ </template>
190
+ </UDashboardSidebar>
191
+
192
+ <slot />
193
+ </UDashboardGroup>
194
+ </template>
195
+ ```