@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.
- package/.agents/skills/nuxt/GENERATION.md +5 -0
- package/.agents/skills/nuxt/SKILL.md +55 -0
- package/.agents/skills/nuxt/references/advanced-hooks.md +289 -0
- package/.agents/skills/nuxt/references/advanced-layers.md +299 -0
- package/.agents/skills/nuxt/references/advanced-module-authoring.md +554 -0
- package/.agents/skills/nuxt/references/best-practices-data-fetching.md +357 -0
- package/.agents/skills/nuxt/references/best-practices-ssr.md +355 -0
- package/.agents/skills/nuxt/references/core-cli.md +263 -0
- package/.agents/skills/nuxt/references/core-config.md +162 -0
- package/.agents/skills/nuxt/references/core-data-fetching.md +236 -0
- package/.agents/skills/nuxt/references/core-deployment.md +224 -0
- package/.agents/skills/nuxt/references/core-directory-structure.md +269 -0
- package/.agents/skills/nuxt/references/core-modules.md +292 -0
- package/.agents/skills/nuxt/references/core-routing.md +226 -0
- package/.agents/skills/nuxt/references/features-components-autoimport.md +328 -0
- package/.agents/skills/nuxt/references/features-components.md +264 -0
- package/.agents/skills/nuxt/references/features-composables.md +276 -0
- package/.agents/skills/nuxt/references/features-server.md +265 -0
- package/.agents/skills/nuxt/references/features-state.md +194 -0
- package/.agents/skills/nuxt/references/rendering-modes.md +237 -0
- package/.agents/skills/nuxt-ui/SKILL.md +334 -0
- package/.agents/skills/nuxt-ui/references/components.md +377 -0
- package/.agents/skills/nuxt-ui/references/composables.md +127 -0
- package/.agents/skills/nuxt-ui/references/layouts/chat.md +195 -0
- package/.agents/skills/nuxt-ui/references/layouts/dashboard.md +220 -0
- package/.agents/skills/nuxt-ui/references/layouts/docs.md +141 -0
- package/.agents/skills/nuxt-ui/references/layouts/editor.md +167 -0
- package/.agents/skills/nuxt-ui/references/layouts/page.md +260 -0
- package/.agents/skills/nuxt-ui/references/theming.md +427 -0
- package/.agents/skills/supabase-postgres-best-practices/AGENTS.md +68 -0
- package/.agents/skills/supabase-postgres-best-practices/CLAUDE.md +1 -0
- package/.agents/skills/supabase-postgres-best-practices/README.md +116 -0
- package/.agents/skills/supabase-postgres-best-practices/SKILL.md +64 -0
- package/.agents/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +55 -0
- package/.agents/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +49 -0
- package/.agents/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +46 -0
- package/.agents/skills/supabase-postgres-best-practices/references/conn-limits.md +44 -0
- package/.agents/skills/supabase-postgres-best-practices/references/conn-pooling.md +41 -0
- package/.agents/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +46 -0
- package/.agents/skills/supabase-postgres-best-practices/references/data-batch-inserts.md +54 -0
- package/.agents/skills/supabase-postgres-best-practices/references/data-n-plus-one.md +53 -0
- package/.agents/skills/supabase-postgres-best-practices/references/data-pagination.md +50 -0
- package/.agents/skills/supabase-postgres-best-practices/references/data-upsert.md +50 -0
- package/.agents/skills/supabase-postgres-best-practices/references/lock-advisory.md +56 -0
- package/.agents/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +68 -0
- package/.agents/skills/supabase-postgres-best-practices/references/lock-short-transactions.md +50 -0
- package/.agents/skills/supabase-postgres-best-practices/references/lock-skip-locked.md +54 -0
- package/.agents/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +45 -0
- package/.agents/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +55 -0
- package/.agents/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +55 -0
- package/.agents/skills/supabase-postgres-best-practices/references/query-composite-indexes.md +44 -0
- package/.agents/skills/supabase-postgres-best-practices/references/query-covering-indexes.md +40 -0
- package/.agents/skills/supabase-postgres-best-practices/references/query-index-types.md +48 -0
- package/.agents/skills/supabase-postgres-best-practices/references/query-missing-indexes.md +43 -0
- package/.agents/skills/supabase-postgres-best-practices/references/query-partial-indexes.md +45 -0
- package/.agents/skills/supabase-postgres-best-practices/references/schema-constraints.md +80 -0
- package/.agents/skills/supabase-postgres-best-practices/references/schema-data-types.md +46 -0
- package/.agents/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +59 -0
- package/.agents/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +55 -0
- package/.agents/skills/supabase-postgres-best-practices/references/schema-partitioning.md +55 -0
- package/.agents/skills/supabase-postgres-best-practices/references/schema-primary-keys.md +61 -0
- package/.agents/skills/supabase-postgres-best-practices/references/security-privileges.md +54 -0
- package/.agents/skills/supabase-postgres-best-practices/references/security-rls-basics.md +50 -0
- package/.agents/skills/supabase-postgres-best-practices/references/security-rls-performance.md +57 -0
- package/.editorconfig +12 -0
- package/.env.example +2 -0
- package/.eslintignore +1 -0
- package/.prettierrc +9 -0
- package/.vscode/extensions.json +10 -0
- package/.vscode/settings.json +61 -0
- package/README.md +62 -0
- package/app/components/navbar/NavbarAdmin.vue +169 -0
- package/app/composables/auth.ts +81 -0
- package/app/layouts/setup.vue +13 -0
- package/app/middleware/auth.ts +27 -0
- package/app/middleware/setup-check.ts +25 -0
- package/app/pages/admin/(auth)/login.vue +84 -0
- package/app/pages/admin/(auth)/signup.vue +128 -0
- package/app/pages/admin/settings.vue +116 -0
- package/app/pages/admin/setup.vue +300 -0
- package/app/pages/admin.vue +38 -0
- package/bun.lock +2685 -0
- package/eslint.config.mjs +88 -0
- package/nuxt.config.ts +55 -0
- package/package.json +44 -0
- package/public/schema.sql +103 -0
- package/scripts/supabase-typegen.ts +36 -0
- package/server/api/category/list.get.ts +9 -0
- package/server/api/category/new.post.ts +31 -0
- package/server/api/settings/first_setup.get.ts +39 -0
- package/server/api/settings/index.get.ts +27 -0
- package/server/api/settings/update.post.ts +36 -0
- package/server/api/setup/create.post.ts +58 -0
- package/server/api/signup.post.ts +28 -0
- package/server/api/users/[id].get.ts +21 -0
- package/server/api/users/index.get.ts +16 -0
- package/shared/types/supabase.ts +406 -0
- package/skills-lock.json +20 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: components-auto-imports
|
|
3
|
+
description: Auto-imported components, lazy loading, and hydration strategies
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Components Auto-imports
|
|
7
|
+
|
|
8
|
+
Nuxt automatically imports Vue components from `app/components/` directory.
|
|
9
|
+
|
|
10
|
+
## Basic Auto-imports
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
components/
|
|
14
|
+
├── Button.vue → <Button />
|
|
15
|
+
├── Card.vue → <Card />
|
|
16
|
+
└── AppHeader.vue → <AppHeader />
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```vue
|
|
20
|
+
<template>
|
|
21
|
+
<!-- No imports needed -->
|
|
22
|
+
<AppHeader />
|
|
23
|
+
<Card>
|
|
24
|
+
<Button>Click me</Button>
|
|
25
|
+
</Card>
|
|
26
|
+
</template>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Naming Conventions
|
|
30
|
+
|
|
31
|
+
### Nested Directory Names
|
|
32
|
+
|
|
33
|
+
Component names include directory path:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
components/
|
|
37
|
+
├── base/
|
|
38
|
+
│ └── Button.vue → <BaseButton />
|
|
39
|
+
├── form/
|
|
40
|
+
│ ├── Input.vue → <FormInput />
|
|
41
|
+
│ └── Select.vue → <FormSelect />
|
|
42
|
+
└── ui/
|
|
43
|
+
└── modal/
|
|
44
|
+
└── Dialog.vue → <UiModalDialog />
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Disable Path Prefix
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
// nuxt.config.ts
|
|
51
|
+
export default defineNuxtConfig({
|
|
52
|
+
components: [
|
|
53
|
+
{
|
|
54
|
+
path: '~/components',
|
|
55
|
+
pathPrefix: false, // Use filename only
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
})
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
With `pathPrefix: false`:
|
|
62
|
+
```
|
|
63
|
+
components/base/Button.vue → <Button />
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Lazy Loading
|
|
67
|
+
|
|
68
|
+
Prefix with `Lazy` for dynamic imports:
|
|
69
|
+
|
|
70
|
+
```vue
|
|
71
|
+
<script setup lang="ts">
|
|
72
|
+
const showChart = ref(false)
|
|
73
|
+
</script>
|
|
74
|
+
|
|
75
|
+
<template>
|
|
76
|
+
<!-- Component code loaded only when rendered -->
|
|
77
|
+
<LazyHeavyChart v-if="showChart" />
|
|
78
|
+
<button @click="showChart = true">Show Chart</button>
|
|
79
|
+
</template>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Benefits:
|
|
83
|
+
- Reduces initial bundle size
|
|
84
|
+
- Code-splits component into separate chunk
|
|
85
|
+
- Loads on-demand
|
|
86
|
+
|
|
87
|
+
## Lazy Hydration Strategies
|
|
88
|
+
|
|
89
|
+
Control when lazy components become interactive:
|
|
90
|
+
|
|
91
|
+
### `hydrate-on-visible`
|
|
92
|
+
|
|
93
|
+
Hydrate when component enters viewport:
|
|
94
|
+
|
|
95
|
+
```vue
|
|
96
|
+
<template>
|
|
97
|
+
<LazyComments hydrate-on-visible />
|
|
98
|
+
</template>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### `hydrate-on-idle`
|
|
102
|
+
|
|
103
|
+
Hydrate when browser is idle:
|
|
104
|
+
|
|
105
|
+
```vue
|
|
106
|
+
<template>
|
|
107
|
+
<LazyAnalytics hydrate-on-idle />
|
|
108
|
+
</template>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### `hydrate-on-interaction`
|
|
112
|
+
|
|
113
|
+
Hydrate on user interaction:
|
|
114
|
+
|
|
115
|
+
```vue
|
|
116
|
+
<template>
|
|
117
|
+
<!-- Hydrates on click, focus, or pointerenter -->
|
|
118
|
+
<LazyDropdown hydrate-on-interaction />
|
|
119
|
+
|
|
120
|
+
<!-- Specific event -->
|
|
121
|
+
<LazyTooltip hydrate-on-interaction="mouseover" />
|
|
122
|
+
</template>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### `hydrate-on-media-query`
|
|
126
|
+
|
|
127
|
+
Hydrate when media query matches:
|
|
128
|
+
|
|
129
|
+
```vue
|
|
130
|
+
<template>
|
|
131
|
+
<LazyMobileMenu hydrate-on-media-query="(max-width: 768px)" />
|
|
132
|
+
</template>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### `hydrate-after`
|
|
136
|
+
|
|
137
|
+
Hydrate after delay (milliseconds):
|
|
138
|
+
|
|
139
|
+
```vue
|
|
140
|
+
<template>
|
|
141
|
+
<LazyAds :hydrate-after="3000" />
|
|
142
|
+
</template>
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### `hydrate-when`
|
|
146
|
+
|
|
147
|
+
Hydrate on condition:
|
|
148
|
+
|
|
149
|
+
```vue
|
|
150
|
+
<script setup lang="ts">
|
|
151
|
+
const isReady = ref(false)
|
|
152
|
+
</script>
|
|
153
|
+
|
|
154
|
+
<template>
|
|
155
|
+
<LazyEditor :hydrate-when="isReady" />
|
|
156
|
+
</template>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### `hydrate-never`
|
|
160
|
+
|
|
161
|
+
Never hydrate (static only):
|
|
162
|
+
|
|
163
|
+
```vue
|
|
164
|
+
<template>
|
|
165
|
+
<LazyStaticFooter hydrate-never />
|
|
166
|
+
</template>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Hydration Event
|
|
170
|
+
|
|
171
|
+
```vue
|
|
172
|
+
<template>
|
|
173
|
+
<LazyChart hydrate-on-visible @hydrated="onChartReady" />
|
|
174
|
+
</template>
|
|
175
|
+
|
|
176
|
+
<script setup>
|
|
177
|
+
function onChartReady() {
|
|
178
|
+
console.log('Chart is now interactive')
|
|
179
|
+
}
|
|
180
|
+
</script>
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Client/Server Components
|
|
184
|
+
|
|
185
|
+
### Client-only (`.client.vue`)
|
|
186
|
+
|
|
187
|
+
```
|
|
188
|
+
components/
|
|
189
|
+
└── BrowserChart.client.vue
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
```vue
|
|
193
|
+
<template>
|
|
194
|
+
<!-- Only rendered in browser -->
|
|
195
|
+
<BrowserChart />
|
|
196
|
+
</template>
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Server-only (`.server.vue`)
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
components/
|
|
203
|
+
└── ServerMarkdown.server.vue
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
```vue
|
|
207
|
+
<template>
|
|
208
|
+
<!-- Rendered on server, not hydrated -->
|
|
209
|
+
<ServerMarkdown :content="markdown" />
|
|
210
|
+
</template>
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Requires experimental flag:
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
// nuxt.config.ts
|
|
217
|
+
export default defineNuxtConfig({
|
|
218
|
+
experimental: {
|
|
219
|
+
componentIslands: true,
|
|
220
|
+
},
|
|
221
|
+
})
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Paired Components
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
components/
|
|
228
|
+
├── Comments.client.vue # Browser version
|
|
229
|
+
└── Comments.server.vue # SSR version
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Server version renders during SSR, client version takes over after hydration.
|
|
233
|
+
|
|
234
|
+
## Dynamic Components
|
|
235
|
+
|
|
236
|
+
```vue
|
|
237
|
+
<script setup lang="ts">
|
|
238
|
+
import { SomeComponent } from '#components'
|
|
239
|
+
|
|
240
|
+
const dynamicComponent = resolveComponent('MyButton')
|
|
241
|
+
</script>
|
|
242
|
+
|
|
243
|
+
<template>
|
|
244
|
+
<component :is="dynamicComponent" />
|
|
245
|
+
<component :is="SomeComponent" />
|
|
246
|
+
</template>
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Direct Imports
|
|
250
|
+
|
|
251
|
+
Bypass auto-imports when needed:
|
|
252
|
+
|
|
253
|
+
```vue
|
|
254
|
+
<script setup lang="ts">
|
|
255
|
+
import { LazyMountainsList, NuxtLink } from '#components'
|
|
256
|
+
</script>
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Custom Directories
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
// nuxt.config.ts
|
|
263
|
+
export default defineNuxtConfig({
|
|
264
|
+
components: [
|
|
265
|
+
{ path: '~/components/ui', prefix: 'Ui' },
|
|
266
|
+
{ path: '~/components/forms', prefix: 'Form' },
|
|
267
|
+
'~/components', // Default, should come last
|
|
268
|
+
],
|
|
269
|
+
})
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## Global Components
|
|
273
|
+
|
|
274
|
+
Register globally (creates async chunks):
|
|
275
|
+
|
|
276
|
+
```ts
|
|
277
|
+
// nuxt.config.ts
|
|
278
|
+
export default defineNuxtConfig({
|
|
279
|
+
components: {
|
|
280
|
+
global: true,
|
|
281
|
+
dirs: ['~/components'],
|
|
282
|
+
},
|
|
283
|
+
})
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Or use `.global.vue` suffix:
|
|
287
|
+
|
|
288
|
+
```
|
|
289
|
+
components/
|
|
290
|
+
└── Icon.global.vue → Available globally
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
## Disabling Component Auto-imports
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
// nuxt.config.ts
|
|
297
|
+
export default defineNuxtConfig({
|
|
298
|
+
components: {
|
|
299
|
+
dirs: [], // Disable auto-imports
|
|
300
|
+
},
|
|
301
|
+
})
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Library Authors
|
|
305
|
+
|
|
306
|
+
Register components from npm package:
|
|
307
|
+
|
|
308
|
+
```ts
|
|
309
|
+
// my-ui-lib/nuxt.ts
|
|
310
|
+
import { addComponentsDir, createResolver, defineNuxtModule } from '@nuxt/kit'
|
|
311
|
+
|
|
312
|
+
export default defineNuxtModule({
|
|
313
|
+
setup() {
|
|
314
|
+
const resolver = createResolver(import.meta.url)
|
|
315
|
+
|
|
316
|
+
addComponentsDir({
|
|
317
|
+
path: resolver.resolve('./components'),
|
|
318
|
+
prefix: 'MyUi',
|
|
319
|
+
})
|
|
320
|
+
},
|
|
321
|
+
})
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
<!--
|
|
325
|
+
Source references:
|
|
326
|
+
- https://nuxt.com/docs/directory-structure/app/components
|
|
327
|
+
- https://nuxt.com/docs/guide/concepts/auto-imports#auto-imported-components
|
|
328
|
+
-->
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: built-in-components
|
|
3
|
+
description: NuxtLink, NuxtPage, NuxtLayout, and other built-in Nuxt components
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Built-in Components
|
|
7
|
+
|
|
8
|
+
Nuxt provides several built-in components for common functionality.
|
|
9
|
+
|
|
10
|
+
## NuxtLink
|
|
11
|
+
|
|
12
|
+
Optimized link component with prefetching:
|
|
13
|
+
|
|
14
|
+
```vue
|
|
15
|
+
<template>
|
|
16
|
+
<!-- Basic usage -->
|
|
17
|
+
<NuxtLink to="/about">About</NuxtLink>
|
|
18
|
+
|
|
19
|
+
<!-- With route object -->
|
|
20
|
+
<NuxtLink :to="{ name: 'posts-id', params: { id: 1 } }">Post 1</NuxtLink>
|
|
21
|
+
|
|
22
|
+
<!-- External link (opens in new tab) -->
|
|
23
|
+
<NuxtLink to="https://nuxt.com" external>Nuxt</NuxtLink>
|
|
24
|
+
|
|
25
|
+
<!-- Disable prefetching -->
|
|
26
|
+
<NuxtLink to="/heavy-page" :prefetch="false">Heavy Page</NuxtLink>
|
|
27
|
+
|
|
28
|
+
<!-- Replace history instead of push -->
|
|
29
|
+
<NuxtLink to="/page" replace>Replace</NuxtLink>
|
|
30
|
+
|
|
31
|
+
<!-- Custom active class -->
|
|
32
|
+
<NuxtLink
|
|
33
|
+
to="/dashboard"
|
|
34
|
+
active-class="text-primary"
|
|
35
|
+
exact-active-class="font-bold"
|
|
36
|
+
>
|
|
37
|
+
Dashboard
|
|
38
|
+
</NuxtLink>
|
|
39
|
+
</template>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## NuxtPage
|
|
43
|
+
|
|
44
|
+
Renders the current page component (used in layouts):
|
|
45
|
+
|
|
46
|
+
```vue
|
|
47
|
+
<!-- app/app.vue -->
|
|
48
|
+
<template>
|
|
49
|
+
<NuxtLayout>
|
|
50
|
+
<NuxtPage />
|
|
51
|
+
</NuxtLayout>
|
|
52
|
+
</template>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
With page transitions:
|
|
56
|
+
|
|
57
|
+
```vue
|
|
58
|
+
<template>
|
|
59
|
+
<NuxtPage :transition="{ name: 'fade', mode: 'out-in' }" />
|
|
60
|
+
</template>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Pass props to page:
|
|
64
|
+
|
|
65
|
+
```vue
|
|
66
|
+
<template>
|
|
67
|
+
<NuxtPage :page-key="route.fullPath" :foobar="123" />
|
|
68
|
+
</template>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## NuxtLayout
|
|
72
|
+
|
|
73
|
+
Controls layout rendering:
|
|
74
|
+
|
|
75
|
+
```vue
|
|
76
|
+
<!-- app/app.vue -->
|
|
77
|
+
<template>
|
|
78
|
+
<NuxtLayout>
|
|
79
|
+
<NuxtPage />
|
|
80
|
+
</NuxtLayout>
|
|
81
|
+
</template>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Dynamic layout:
|
|
85
|
+
|
|
86
|
+
```vue
|
|
87
|
+
<template>
|
|
88
|
+
<NuxtLayout :name="layout">
|
|
89
|
+
<NuxtPage />
|
|
90
|
+
</NuxtLayout>
|
|
91
|
+
</template>
|
|
92
|
+
|
|
93
|
+
<script setup>
|
|
94
|
+
const layout = computed(() => isAdmin ? 'admin' : 'default')
|
|
95
|
+
</script>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Layout with transitions:
|
|
99
|
+
|
|
100
|
+
```vue
|
|
101
|
+
<template>
|
|
102
|
+
<NuxtLayout :transition="{ name: 'slide', mode: 'out-in' }">
|
|
103
|
+
<NuxtPage />
|
|
104
|
+
</NuxtLayout>
|
|
105
|
+
</template>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## NuxtLoadingIndicator
|
|
109
|
+
|
|
110
|
+
Progress bar for page navigation:
|
|
111
|
+
|
|
112
|
+
```vue
|
|
113
|
+
<!-- app/app.vue -->
|
|
114
|
+
<template>
|
|
115
|
+
<NuxtLoadingIndicator
|
|
116
|
+
color="repeating-linear-gradient(to right, #00dc82 0%, #34cdfe 50%, #0047e1 100%)"
|
|
117
|
+
:height="3"
|
|
118
|
+
:duration="2000"
|
|
119
|
+
:throttle="200"
|
|
120
|
+
/>
|
|
121
|
+
<NuxtLayout>
|
|
122
|
+
<NuxtPage />
|
|
123
|
+
</NuxtLayout>
|
|
124
|
+
</template>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## NuxtErrorBoundary
|
|
128
|
+
|
|
129
|
+
Catch and handle errors in child components:
|
|
130
|
+
|
|
131
|
+
```vue
|
|
132
|
+
<template>
|
|
133
|
+
<NuxtErrorBoundary @error="handleError">
|
|
134
|
+
<ComponentThatMightFail />
|
|
135
|
+
|
|
136
|
+
<template #error="{ error, clearError }">
|
|
137
|
+
<div class="error">
|
|
138
|
+
<p>Something went wrong: {{ error.message }}</p>
|
|
139
|
+
<button @click="clearError">Try again</button>
|
|
140
|
+
</div>
|
|
141
|
+
</template>
|
|
142
|
+
</NuxtErrorBoundary>
|
|
143
|
+
</template>
|
|
144
|
+
|
|
145
|
+
<script setup>
|
|
146
|
+
function handleError(error) {
|
|
147
|
+
console.error('Error caught:', error)
|
|
148
|
+
}
|
|
149
|
+
</script>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## ClientOnly
|
|
153
|
+
|
|
154
|
+
Render content only on client-side:
|
|
155
|
+
|
|
156
|
+
```vue
|
|
157
|
+
<template>
|
|
158
|
+
<ClientOnly>
|
|
159
|
+
<!-- Browser-only component -->
|
|
160
|
+
<BrowserOnlyChart :data="chartData" />
|
|
161
|
+
|
|
162
|
+
<template #fallback>
|
|
163
|
+
<p>Loading chart...</p>
|
|
164
|
+
</template>
|
|
165
|
+
</ClientOnly>
|
|
166
|
+
</template>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## DevOnly
|
|
170
|
+
|
|
171
|
+
Render content only in development:
|
|
172
|
+
|
|
173
|
+
```vue
|
|
174
|
+
<template>
|
|
175
|
+
<DevOnly>
|
|
176
|
+
<DebugPanel />
|
|
177
|
+
</DevOnly>
|
|
178
|
+
</template>
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## NuxtIsland
|
|
182
|
+
|
|
183
|
+
Server components (experimental):
|
|
184
|
+
|
|
185
|
+
```vue
|
|
186
|
+
<template>
|
|
187
|
+
<NuxtIsland name="HeavyComponent" :props="{ data: complexData }" />
|
|
188
|
+
</template>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## NuxtImg and NuxtPicture
|
|
192
|
+
|
|
193
|
+
Optimized images (requires `@nuxt/image` module):
|
|
194
|
+
|
|
195
|
+
```vue
|
|
196
|
+
<template>
|
|
197
|
+
<!-- Basic optimized image -->
|
|
198
|
+
<NuxtImg src="/images/hero.jpg" width="800" height="600" />
|
|
199
|
+
|
|
200
|
+
<!-- Responsive with srcset -->
|
|
201
|
+
<NuxtImg
|
|
202
|
+
src="/images/hero.jpg"
|
|
203
|
+
sizes="sm:100vw md:50vw lg:400px"
|
|
204
|
+
:modifiers="{ format: 'webp' }"
|
|
205
|
+
/>
|
|
206
|
+
|
|
207
|
+
<!-- Art direction with picture -->
|
|
208
|
+
<NuxtPicture
|
|
209
|
+
src="/images/hero.jpg"
|
|
210
|
+
:img-attrs="{ alt: 'Hero image' }"
|
|
211
|
+
/>
|
|
212
|
+
</template>
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Teleport
|
|
216
|
+
|
|
217
|
+
Render content outside component tree:
|
|
218
|
+
|
|
219
|
+
```vue
|
|
220
|
+
<template>
|
|
221
|
+
<button @click="showModal = true">Open Modal</button>
|
|
222
|
+
|
|
223
|
+
<Teleport to="body">
|
|
224
|
+
<div v-if="showModal" class="modal">
|
|
225
|
+
<p>Modal content</p>
|
|
226
|
+
<button @click="showModal = false">Close</button>
|
|
227
|
+
</div>
|
|
228
|
+
</Teleport>
|
|
229
|
+
</template>
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
For SSR, use `<ClientOnly>` with Teleport:
|
|
233
|
+
|
|
234
|
+
```vue
|
|
235
|
+
<template>
|
|
236
|
+
<ClientOnly>
|
|
237
|
+
<Teleport to="#teleports">
|
|
238
|
+
<Modal />
|
|
239
|
+
</Teleport>
|
|
240
|
+
</ClientOnly>
|
|
241
|
+
</template>
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## NuxtRouteAnnouncer
|
|
245
|
+
|
|
246
|
+
Accessibility: announces page changes to screen readers:
|
|
247
|
+
|
|
248
|
+
```vue
|
|
249
|
+
<!-- app/app.vue -->
|
|
250
|
+
<template>
|
|
251
|
+
<NuxtRouteAnnouncer />
|
|
252
|
+
<NuxtLayout>
|
|
253
|
+
<NuxtPage />
|
|
254
|
+
</NuxtLayout>
|
|
255
|
+
</template>
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
<!--
|
|
259
|
+
Source references:
|
|
260
|
+
- https://nuxt.com/docs/api/components/nuxt-link
|
|
261
|
+
- https://nuxt.com/docs/api/components/nuxt-page
|
|
262
|
+
- https://nuxt.com/docs/api/components/nuxt-layout
|
|
263
|
+
- https://nuxt.com/docs/api/components/client-only
|
|
264
|
+
-->
|