nuxt-unified-ui 0.5.7 → 0.5.9
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/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-unified-ui",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.9",
|
|
5
5
|
"main": "./nuxt.config.ts",
|
|
6
6
|
"types": "./index.d.ts",
|
|
7
7
|
"exports": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@formkit/tempo": "1.1.0",
|
|
23
|
-
"@iconify-json/lucide": "1.2.
|
|
23
|
+
"@iconify-json/lucide": "1.2.129",
|
|
24
24
|
"@nuxt/kit": "4.5.2",
|
|
25
25
|
"@nuxt/ui": "4.11.0",
|
|
26
26
|
"@nuxtjs/i18n": "10.6.0",
|
|
@@ -4,8 +4,8 @@ description: >-
|
|
|
4
4
|
Single skill for the nuxt-unified-ui Nuxt layer and mandatory Nuxt code style:
|
|
5
5
|
install/extend the layer, required CSS, modules/config, radashi radXxx
|
|
6
6
|
auto-imports, un-form / useForm, launchFormPickerDialog /
|
|
7
|
-
launchChoicePickerDialog, toast helpers,
|
|
8
|
-
definePageMeta, ufetch / useUFetch wrapping, unified resources
|
|
7
|
+
launchChoicePickerDialog, toast helpers, un-card / un-typography, pages /
|
|
8
|
+
definePageMeta, page /* params */ and /* seo */ blocks, ufetch / useUFetch wrapping, unified resources
|
|
9
9
|
(server plugins, REST handleResource*, resource-manager dashboard /
|
|
10
10
|
customization), attribute order/defaults, and whitespace/formatting
|
|
11
11
|
conventions for all Nuxt-generated code. Use when working in or consuming
|
|
@@ -71,7 +71,7 @@ Absolute highlights:
|
|
|
71
71
|
- `{{ ... }}` on its own line (static + dynamic text may mix)
|
|
72
72
|
- `/* section */` comments; imports co-located under the section that uses them
|
|
73
73
|
- Light naming: `handleXxx` handlers, `it` in short callbacks, descriptive `for...of`, computeds use block + `return`
|
|
74
|
-
- Pages: explicit `definePageMeta.name`,
|
|
74
|
+
- Pages: explicit `definePageMeta.name`, `/* params */` for `route.params` / `route.query`, required `/* seo */` (`useHead` + `useSeoMeta`, `useJsonld` when installed) → [pages.md](references/pages.md)
|
|
75
75
|
- Fetching: `ufetch(url, {` one line; `useUFetch` with URL on next line + `data*Data` / `is*Loading` / `refresh*` → [data-fetching.md](references/data-fetching.md)
|
|
76
76
|
|
|
77
77
|
---
|
|
@@ -361,7 +361,9 @@ Group with `/* name */`:
|
|
|
361
361
|
| Common section | Contents |
|
|
362
362
|
|----------------|----------|
|
|
363
363
|
| `/* interface */` | props, emits, models |
|
|
364
|
-
| `/* page */` | `definePageMeta
|
|
364
|
+
| `/* page */` | `definePageMeta` only |
|
|
365
|
+
| `/* params */` | `useRoute` + reactive computeds for `route.params` and `route.query` |
|
|
366
|
+
| `/* seo */` | `useHead` + `useSeoMeta` (and `useJsonld` when the project has it) |
|
|
365
367
|
| domain names | `/* login */`, `/* resource */`, `/* captcha */`, … |
|
|
366
368
|
| `/* outlets */` | `defineExpose` |
|
|
367
369
|
|
|
@@ -411,11 +413,13 @@ function refreshAll() {
|
|
|
411
413
|
|
|
412
414
|
**Pages**
|
|
413
415
|
|
|
414
|
-
1. `/* page */`
|
|
415
|
-
2.
|
|
416
|
-
3.
|
|
417
|
-
4.
|
|
418
|
-
5.
|
|
416
|
+
1. `/* page */` — `definePageMeta` only
|
|
417
|
+
2. `/* params */` — only when the page reads `route.params` or `route.query`
|
|
418
|
+
3. Domain sections SEO needs (fetches / derived data)
|
|
419
|
+
4. `/* seo */` — required; under the last block it reads
|
|
420
|
+
5. Remaining domain sections
|
|
421
|
+
6. Watchers / lifecycle
|
|
422
|
+
7. Handlers
|
|
419
423
|
|
|
420
424
|
### Import co-location
|
|
421
425
|
|
|
@@ -648,7 +652,7 @@ Refs unwrap automatically — do not write `.value` in template expressions or i
|
|
|
648
652
|
|
|
649
653
|
These are part of the same “shape” conventions when generating app code:
|
|
650
654
|
|
|
651
|
-
- Pages / named routes /
|
|
655
|
+
- Pages / named routes / `/* params */` / `/* seo */` → [pages.md](pages.md)
|
|
652
656
|
- `ufetch` / `useUFetch` wrapping, naming, options order → [data-fetching.md](data-fetching.md)
|
|
653
657
|
|
|
654
658
|
### `useUFetch` wrapping (summary)
|
|
@@ -801,5 +805,5 @@ export default defineEventHandler(async event => {
|
|
|
801
805
|
- [ ] Every section is named; imports are co-located with the section that uses them
|
|
802
806
|
- [ ] `handleXxx` for action handlers; `it` for short callbacks; descriptive loop names
|
|
803
807
|
- [ ] Computeds that return structures use block + `return`
|
|
804
|
-
- [ ] Pages: explicit `definePageMeta.name`,
|
|
808
|
+
- [ ] Pages: explicit `definePageMeta.name`, `/* params */` + `/* seo */` placement, named navigation ([pages.md](pages.md))
|
|
805
809
|
- [ ] Fetching: `ufetch` / `useUFetch` wrap styles and destructure names ([data-fetching.md](data-fetching.md))
|
|
@@ -13,13 +13,12 @@ definePageMeta({
|
|
|
13
13
|
name: 'dashboard.patients.single',
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
-
useHead({
|
|
17
|
-
title: $t('patients.single.pageTitle'),
|
|
18
|
-
});
|
|
19
16
|
|
|
17
|
+
/* params */
|
|
20
18
|
|
|
21
19
|
const route = useRoute();
|
|
22
20
|
|
|
21
|
+
|
|
23
22
|
const patientUid = computed(() => {
|
|
24
23
|
return route.params.patientUid;
|
|
25
24
|
});
|
|
@@ -27,11 +26,22 @@ const patientUid = computed(() => {
|
|
|
27
26
|
|
|
28
27
|
/* data */
|
|
29
28
|
|
|
30
|
-
const { data: patientData, pending:
|
|
29
|
+
const { data: patientData, pending: isPatientPending, refresh: refreshPatient } = useUFetch(
|
|
31
30
|
computed(() => `/api/patients/${patientUid.value}`),
|
|
32
31
|
);
|
|
33
32
|
|
|
34
33
|
|
|
34
|
+
/* seo */
|
|
35
|
+
|
|
36
|
+
useHead({
|
|
37
|
+
title: () => patientData.value?.name,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
useSeoMeta({
|
|
41
|
+
description: () => patientData.value?.description,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
|
|
35
45
|
/* handlers */
|
|
36
46
|
|
|
37
47
|
async function handleAction() {
|
|
@@ -56,40 +66,147 @@ async function handleAction() {
|
|
|
56
66
|
</template>
|
|
57
67
|
```
|
|
58
68
|
|
|
69
|
+
A page with no dynamic params and no fetched SEO fields puts `/* seo */` directly under `/* page */`.
|
|
70
|
+
|
|
59
71
|
## Script ordering (pages)
|
|
60
72
|
|
|
61
|
-
1. `/* page */` — `definePageMeta
|
|
62
|
-
2.
|
|
63
|
-
3. Domain sections (
|
|
64
|
-
4.
|
|
65
|
-
5.
|
|
73
|
+
1. `/* page */` — only `definePageMeta`
|
|
74
|
+
2. `/* params */` — only when the page reads `route.params` or `route.query` (see Page params)
|
|
75
|
+
3. Domain sections the SEO block needs (`useUFetch`, derived data, …)
|
|
76
|
+
4. `/* seo */` — required on every page (see Page SEO)
|
|
77
|
+
5. Remaining domain sections (forms, sessions, UI state, …)
|
|
78
|
+
6. Watchers / lifecycle
|
|
79
|
+
7. Handlers (`handleXxx`)
|
|
66
80
|
|
|
67
|
-
|
|
81
|
+
Do **not** put `useHead` / `useSeoMeta` / `useJsonld` inside `/* page */`. Those belong in `/* seo */`.
|
|
68
82
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
83
|
+
## Page params
|
|
84
|
+
|
|
85
|
+
If a page reads `route.params` or `route.query`, add a `/* params */` block **immediately under** `/* page */`.
|
|
86
|
+
|
|
87
|
+
1. Declare `const route = useRoute();`
|
|
88
|
+
2. Two blank lines
|
|
89
|
+
3. One `computed` per value — `route.params` first, then `route.query` — keep each reactive; do not snapshot into a bare `const`
|
|
90
|
+
|
|
91
|
+
Consecutive computeds: **one** blank line between them.
|
|
73
92
|
|
|
74
93
|
```ts
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
94
|
+
/* params */
|
|
95
|
+
|
|
96
|
+
const route = useRoute();
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
const flashCardSlug = computed(() => {
|
|
100
|
+
return route.params.flashCardSlug;
|
|
78
101
|
});
|
|
79
102
|
```
|
|
80
103
|
|
|
81
|
-
|
|
104
|
+
```ts
|
|
105
|
+
/* params */
|
|
82
106
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
107
|
+
const route = useRoute();
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
const returnUrl = computed(() => {
|
|
111
|
+
return route.query.returnUrl;
|
|
112
|
+
});
|
|
113
|
+
```
|
|
86
114
|
|
|
87
115
|
```ts
|
|
116
|
+
/* params */
|
|
117
|
+
|
|
88
118
|
const route = useRoute();
|
|
89
119
|
|
|
120
|
+
|
|
90
121
|
const flashCardSlug = computed(() => {
|
|
91
122
|
return route.params.flashCardSlug;
|
|
92
123
|
});
|
|
124
|
+
|
|
125
|
+
const journeySlug = computed(() => {
|
|
126
|
+
return route.query.journey;
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
- Files: `[patientUid].vue`, `[flashCardSlug]/index.vue`
|
|
131
|
+
- Params: **camelCase** in brackets and when reading `route.params`
|
|
132
|
+
- Query keys stay as they appear on the URL; the computed name is camelCase (`returnUrl` for `returnUrl`)
|
|
133
|
+
- Omit `/* params */` entirely on pages that read neither `route.params` nor `route.query` — do not create an empty block. If something else needs `route` (for example `route.fullPath`), call `useRoute()` in that domain section instead.
|
|
134
|
+
|
|
135
|
+
## Page SEO
|
|
136
|
+
|
|
137
|
+
Every page **must** have a `/* seo */` block.
|
|
138
|
+
|
|
139
|
+
**Placement**
|
|
140
|
+
|
|
141
|
+
1. Default: directly under `/* page */`
|
|
142
|
+
2. If the page has `/* params */`: under `/* params */`
|
|
143
|
+
3. If `/* seo */` needs data from any other block: under **that** block (after the fetch / derived computeds), not above it
|
|
144
|
+
|
|
145
|
+
Blocks that SEO does not read (sessions, local UI state, handlers) stay **below** `/* seo */`.
|
|
146
|
+
|
|
147
|
+
**Contents (in this order, one blank line between calls)**
|
|
148
|
+
|
|
149
|
+
1. `useHead({ title })` — required
|
|
150
|
+
2. `useSeoMeta({ description })` — required
|
|
151
|
+
3. `useJsonld(() => …)` — only when the project has `nuxt-jsonld` set up (`package.json` / `nuxt.config` modules), and only on public indexable pages. Skip it on `noindex` / dashboard / auth pages.
|
|
152
|
+
|
|
153
|
+
Static strings when the copy is fixed; getters when the value comes from fetched data (`() => flashCardData.value?.name`). Optional chaining is fine on title/description getters.
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
/* seo */
|
|
157
|
+
|
|
158
|
+
useHead({
|
|
159
|
+
title: 'Flash Cards',
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
useSeoMeta({
|
|
163
|
+
description: 'Browse free flash card decks for practice and study.',
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
/* seo */
|
|
169
|
+
|
|
170
|
+
useHead({
|
|
171
|
+
title: () => flashCardData.value?.name,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
useSeoMeta({
|
|
175
|
+
description: () => flashCardData.value?.description,
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**`useJsonld` data guard**
|
|
180
|
+
|
|
181
|
+
When JSON-LD is included, inline the schema in the page (no shared `makeXxxJsonld` helpers). Guard absent data with a ternary — return `null` so no tag is emitted; do **not** replace this guard with optional chaining inside the object:
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
useJsonld(() => !flashCardData.value ? null : {
|
|
185
|
+
'@context': 'https://schema.org',
|
|
186
|
+
'@graph': [
|
|
187
|
+
{
|
|
188
|
+
'@type': 'LearningResource',
|
|
189
|
+
'name': flashCardData.value.name,
|
|
190
|
+
'url': `https://khoshghadam.com/flash-cards/${flashCardData.value.slug}`,
|
|
191
|
+
},
|
|
192
|
+
],
|
|
193
|
+
});
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Keep `useJsonld(() => !data ? null : {` on **one line**. Object properties follow the usual multi-line literal rules. `data` is the fetched document or list the schema reads.
|
|
197
|
+
|
|
198
|
+
## `definePageMeta`
|
|
199
|
+
|
|
200
|
+
- **Always** set an explicit `name`
|
|
201
|
+
- Dot notation: `dashboard.home`, `flash-cards.single`, `authentication.login`
|
|
202
|
+
- `layout: 'empty'` for login / full-bleed auth-style pages only
|
|
203
|
+
- Never use `layout: false`
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
definePageMeta({
|
|
207
|
+
name: 'authentication.login',
|
|
208
|
+
layout: 'empty',
|
|
209
|
+
});
|
|
93
210
|
```
|
|
94
211
|
|
|
95
212
|
## Navigation
|