nuxt-unified-ui 0.5.2 → 0.5.3
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.3",
|
|
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.124",
|
|
24
24
|
"@nuxt/kit": "4.5.2",
|
|
25
25
|
"@nuxt/ui": "4.10.0",
|
|
26
26
|
"@nuxtjs/i18n": "10.6.0",
|
|
@@ -50,20 +50,23 @@ This is the **only** installable skill in this repo. Deep topics live under `ref
|
|
|
50
50
|
|
|
51
51
|
## Code style (read [code-style.md](references/code-style.md) before writing code)
|
|
52
52
|
|
|
53
|
-
**Always apply** to Vue SFCs and app/server `.ts` files. Higher-level idea: code should **scan vertically** —
|
|
53
|
+
**Always apply** to Vue SFCs and app/server `.ts` files. Higher-level idea: code should **scan vertically** — named sections, declaration-kind groups, multi-line literals, and predictable template wrapping.
|
|
54
54
|
|
|
55
55
|
Absolute highlights:
|
|
56
56
|
|
|
57
57
|
- `<script setup>` only — **never** `lang="ts"`; no TS annotations in Vue (runtime prop types)
|
|
58
58
|
- 2-space indent; single quotes; semicolons; trailing commas in multi-line literals
|
|
59
59
|
- **`.js` / `.ts` file start:** two leading blank lines, **except** when the file starts with imports — then **no** blank lines before the first `import`
|
|
60
|
-
-
|
|
60
|
+
- Every `<script setup>` section starts with `/* section name */`, then a blank line
|
|
61
|
+
- Within a section, group declarations by kind (imports, refs, computeds, watchers, functions, etc.): two blank lines between groups; no blanks between consecutive refs; one blank between consecutive members of other groups
|
|
61
62
|
- Non-trivial async/functions: blank line after `{`, double blank between major steps, blank before `}`
|
|
63
|
+
- A function dedicated to choosing a return value from multiple criteria uses one exhaustive `if` / `else if` / `else` chain; broader functions may use guard clauses and early returns
|
|
62
64
|
- `else` / `catch` on their own line after `}`
|
|
63
65
|
- Script object literals always multi-line (even one property)
|
|
64
66
|
- Kebab-case tags (`u-button`, `un-card`)
|
|
65
67
|
- `v-if` / `v-for` on `<template>` wrappers — not on rendered nodes
|
|
66
|
-
-
|
|
68
|
+
- If a condition changes several component attributes, prefer explicit `<template v-if>` / `v-else` component variants over nested ternaries and overly dynamic bindings
|
|
69
|
+
- **2+ attributes → one per line** except structural **`template` wrappers** and **`u-modal`** (keep either on one line); attribute order + default omissions (`variant="subtle"`, **Cancel only → `ghost`**, omit neutral `color`, `loading-auto`); non-self-closing `>` on same line as last attr; multi-line self-closing `/>` on its own line
|
|
67
70
|
- `{{ ... }}` on its own line (static + dynamic text may mix)
|
|
68
71
|
- `/* section */` comments; imports co-located under the section that uses them
|
|
69
72
|
- Light naming: `handleXxx` handlers, `it` in short callbacks, descriptive `for...of`, computeds use block + `return`
|
|
@@ -10,20 +10,20 @@ This document is about the **look and shape** of code — whitespace, wrapping,
|
|
|
10
10
|
|
|
11
11
|
Write code so a reader can **scan vertically** and see structure before details.
|
|
12
12
|
|
|
13
|
-
1. **
|
|
14
|
-
|
|
13
|
+
1. **Sections contain declaration-kind groups.**
|
|
14
|
+
Start each logical `<script setup>` domain with a `/* section name */` comment and a blank line. Within that section, group imports, refs, computeds, watchers, functions, and other declarations by kind. Double blank lines separate groups; refs stay tightly stacked; consecutive members of other groups have one blank line between them.
|
|
15
15
|
|
|
16
|
-
2. **
|
|
17
|
-
A non-trivial function
|
|
16
|
+
2. **Function body spacing follows the work.**
|
|
17
|
+
A non-trivial workflow function is a mini-document: blank line after `{`, full-block guards, double blanks between major steps, and a blank before `}`. Small helpers and functions whose whole job is choosing a return value stay compact.
|
|
18
18
|
|
|
19
19
|
3. **One idea per line in structured data.**
|
|
20
20
|
Object/array literals in script are multi-line with trailing commas — even single-property objects passed to helpers (`toastSuccess`, `ufetch` options, etc.). Compact one-liners hide diffs and force horizontal reading.
|
|
21
21
|
|
|
22
22
|
4. **Templates are layout, not mini-scripts.**
|
|
23
|
-
Structural directives live on `<template>` wrappers so the rendered node stays a clean component/element.
|
|
23
|
+
Structural directives live on one-line `<template>` wrappers so the rendered node stays a clean component/element. Rendered component attributes wrap predictably (`u-modal` stays one line); closing `>` / `/>` placement is consistent; interpolations sit on their own line (static + dynamic text may share one `{{ ... }}` or surrounding text).
|
|
24
24
|
|
|
25
25
|
5. **Section comments are the map.**
|
|
26
|
-
`/* section */` labels
|
|
26
|
+
`/* section */` labels define logical domains, while declaration-kind spacing exposes the structure inside each domain. Imports sit in the section that needs them, not in a hoisted pile at the top.
|
|
27
27
|
|
|
28
28
|
6. **Names that match role.**
|
|
29
29
|
Handlers read as actions (`handleLogin`), short callbacks use `it`, loops use real nouns. Shape and naming reinforce each other so you rarely need narrating comments.
|
|
@@ -93,13 +93,18 @@ Vue SFCs are unchanged: `<script setup>` begins immediately inside the script bl
|
|
|
93
93
|
|
|
94
94
|
### Section rhythm
|
|
95
95
|
|
|
96
|
-
-
|
|
97
|
-
-
|
|
98
|
-
-
|
|
96
|
+
- Start every logical `<script setup>` domain with `/* section name */`, followed by a blank line.
|
|
97
|
+
- Within each section, group declarations by kind: imports, props/models, refs, computeds, watchers/lifecycle, functions, and outlets.
|
|
98
|
+
- Use **two blank lines between different declaration groups** within a section.
|
|
99
|
+
- Keep consecutive refs together with **no blank lines**.
|
|
100
|
+
- Use **one blank line between consecutive declarations** in other same-kind groups, including computeds, watchers, and functions.
|
|
101
|
+
- Keep a blank line before each section comment; the preceding group's double-boundary spacing still applies.
|
|
99
102
|
- Blank line before `</script>`.
|
|
100
103
|
- **Two** blank lines between `</script>` and `<template>`.
|
|
101
104
|
|
|
102
|
-
|
|
105
|
+
Declaration-group spacing is independent from spacing inside a function body. Do not add a new section comment merely because the declaration kind changes.
|
|
106
|
+
|
|
107
|
+
### Non-trivial workflow functions
|
|
103
108
|
|
|
104
109
|
Applies to async handlers, multi-step loaders, and non-trivial callbacks:
|
|
105
110
|
|
|
@@ -151,6 +156,26 @@ async function handleSubmitSelection(items) {
|
|
|
151
156
|
|
|
152
157
|
Same for a `finally` that only flips one flag.
|
|
153
158
|
|
|
159
|
+
### Return-only decision functions
|
|
160
|
+
|
|
161
|
+
When a function's whole job is to choose and return a value from multiple criteria, express the complete decision as one compact `if` / `else if` / `else` chain:
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
function getSortLabel(column) {
|
|
165
|
+
if (sortedColumn.value !== column) {
|
|
166
|
+
return `Sort ${column} descending`;
|
|
167
|
+
}
|
|
168
|
+
else if (sortDirection.value === 'desc') {
|
|
169
|
+
return `Sort ${column} ascending`;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
return `Clear ${column} sorting`;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Use this pattern only when value selection is essentially the function's entire body. Functions that perform broader work may use guard clauses and early returns when those make the workflow clearer; do not force their logic into an exhaustive chain.
|
|
178
|
+
|
|
154
179
|
### `else` / `catch`
|
|
155
180
|
|
|
156
181
|
```ts
|
|
@@ -223,6 +248,33 @@ const response = await ufetch(
|
|
|
223
248
|
- Single-key object binding may stay inline: `:ui="{ content: 'max-w-7xl' }"`
|
|
224
249
|
- Multi-key template object/array bindings are multi-line
|
|
225
250
|
- Simple scalars and simple ternaries stay inline; break only when branches become objects/arrays or nested structure
|
|
251
|
+
- When one condition changes several attributes, labels/icons, or an object-shaped binding such as `to`, use adjacent `<template v-if>` / `v-else-if` / `v-else` branches with explicit component variants. Prefer small markup duplication over nested ternaries and overly dynamic attributes.
|
|
252
|
+
|
|
253
|
+
```vue
|
|
254
|
+
<template v-if="state === 'complete'">
|
|
255
|
+
<u-badge
|
|
256
|
+
variant="subtle"
|
|
257
|
+
color="success"
|
|
258
|
+
icon="lucide:circle-check"
|
|
259
|
+
label="Completed"
|
|
260
|
+
/>
|
|
261
|
+
</template>
|
|
262
|
+
<template v-else-if="state === 'in-progress'">
|
|
263
|
+
<u-badge
|
|
264
|
+
variant="subtle"
|
|
265
|
+
color="warning"
|
|
266
|
+
icon="lucide:clock"
|
|
267
|
+
label="In Progress"
|
|
268
|
+
/>
|
|
269
|
+
</template>
|
|
270
|
+
<template v-else>
|
|
271
|
+
<u-badge
|
|
272
|
+
variant="subtle"
|
|
273
|
+
icon="lucide:circle"
|
|
274
|
+
label="Not Started"
|
|
275
|
+
/>
|
|
276
|
+
</template>
|
|
277
|
+
```
|
|
226
278
|
|
|
227
279
|
---
|
|
228
280
|
|
|
@@ -262,18 +314,49 @@ Group with `/* name */`:
|
|
|
262
314
|
| domain names | `/* login */`, `/* resource */`, `/* captcha */`, … |
|
|
263
315
|
| `/* outlets */` | `defineExpose` |
|
|
264
316
|
|
|
265
|
-
|
|
317
|
+
The comment names a logical domain, not a declaration kind. Follow it with a blank line, then organize that domain into declaration-kind groups. Avoid comments that only restate obvious option names.
|
|
318
|
+
|
|
319
|
+
```ts
|
|
320
|
+
/* resource */
|
|
321
|
+
|
|
322
|
+
import ResourceExplorerCell from '~/atoms/resource-explorer-cell.vue';
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
const itemsPerPage = ref(20);
|
|
326
|
+
const currentPage = ref(1);
|
|
327
|
+
const sortedColumn = ref('createdAt');
|
|
328
|
+
const sortDirection = ref('desc');
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
const sort = computed(() => {
|
|
332
|
+
return `${sortedColumn.value}:${sortDirection.value}`;
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
const hasResources = computed(() => {
|
|
336
|
+
return !!resourcesData.value?.length;
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
watchImmediate(resourcePath, refreshResources);
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
function getSortIcon(column) {
|
|
344
|
+
return sortedColumn.value === column ? 'lucide:arrow-down' : 'lucide:arrow-up-down';
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function refreshAll() {
|
|
348
|
+
refreshResources();
|
|
349
|
+
}
|
|
350
|
+
```
|
|
266
351
|
|
|
267
352
|
### Script ordering
|
|
268
353
|
|
|
269
354
|
**Components / dialogs**
|
|
270
355
|
|
|
271
|
-
1. `/* interface */`
|
|
272
|
-
2.
|
|
273
|
-
3.
|
|
274
|
-
4.
|
|
275
|
-
5. Handlers / async functions
|
|
276
|
-
6. `/* outlets */` / `defineExpose` if needed
|
|
356
|
+
1. `/* interface */` section
|
|
357
|
+
2. Domain sections in reading order
|
|
358
|
+
3. Within each section: imports, refs, computeds, watchers/lifecycle, functions
|
|
359
|
+
4. `/* outlets */` / `defineExpose` section if needed
|
|
277
360
|
|
|
278
361
|
**Pages**
|
|
279
362
|
|
|
@@ -338,7 +421,8 @@ Keep tight `v-if` / `v-else` chains adjacent (no blank line between matching bra
|
|
|
338
421
|
### Attribute wrapping (hard rule)
|
|
339
422
|
|
|
340
423
|
- **0–1 attributes:** may stay on one line with the tag
|
|
341
|
-
- **
|
|
424
|
+
- **Structural `<template>` wrappers:** keep the opening tag on one line, even with several directives, keys, or dynamic slot bindings
|
|
425
|
+
- **2+ attributes on rendered elements/components:** one attribute per line — **except `u-modal`**
|
|
342
426
|
- **`u-modal` only:** keep **all** attributes on the **same single line** as the tag (do not wrap), even when there are many
|
|
343
427
|
|
|
344
428
|
```vue
|
|
@@ -349,6 +433,11 @@ Keep tight `v-if` / `v-else` chains adjacent (no blank line between matching bra
|
|
|
349
433
|
</u-form-field>
|
|
350
434
|
<u-icon name="lucide:check" />
|
|
351
435
|
|
|
436
|
+
<!-- ✅ structural template wrappers stay on one line -->
|
|
437
|
+
<template v-for="column in columns" :key="column.accessorKey" #[column.accessorKey+'-cell']="{ row }">
|
|
438
|
+
...
|
|
439
|
+
</template>
|
|
440
|
+
|
|
352
441
|
<!-- ✅ u-modal — always one line (exception) -->
|
|
353
442
|
<u-modal :ui="{ content: 'max-w-5xl' }" scrollable @update:open="!$event && emit('close')">
|
|
354
443
|
...
|
|
@@ -621,13 +710,15 @@ export default defineEventHandler(async event => {
|
|
|
621
710
|
| `if (!x) return;` | braced block |
|
|
622
711
|
| `} else {` | `}\nelse {` |
|
|
623
712
|
| `toastSuccess({ title: 'x' })` one-liner object | multi-line object + trailing comma |
|
|
624
|
-
| 3 attrs on one line (
|
|
713
|
+
| 3 attrs on one line (rendered element/component other than `u-modal`) | one attr per line |
|
|
625
714
|
| Multi-line `u-modal` attrs | keep `u-modal` attrs on one line |
|
|
626
715
|
| `>` on its own line after attrs | `>` after last attr |
|
|
627
716
|
| `{{ x }}` glued to tags | interpolation on its own line (static + dynamic mix OK) |
|
|
628
717
|
| `ghost` on non-Cancel buttons | `ghost` only for Cancel |
|
|
629
718
|
| Hoisted import block | imports co-located under section |
|
|
630
719
|
| `computed(() => [ ... ])` | `computed(() => { return [ ... ]; })` |
|
|
720
|
+
| Early-return ladder in a return-only decision function | Compact exhaustive `if` / `else if` / `else` |
|
|
721
|
+
| Multiple nested ternaries across component attributes | Explicit component variants in `<template v-if>` / `v-else` branches |
|
|
631
722
|
| `color="neutral"` on badge | omit `color` / use `undefined` |
|
|
632
723
|
| `ufetch(\n url,\n {` | `ufetch(url, {` on one line |
|
|
633
724
|
| One-line `useUFetch(...)` | URL on next line; options multi-line |
|
|
@@ -641,17 +732,20 @@ export default defineEventHandler(async event => {
|
|
|
641
732
|
- [ ] `<script setup>` without `lang="ts"`; no TS annotations in Vue
|
|
642
733
|
- [ ] 2-space indent; single quotes; semicolons; trailing commas in multi-line literals
|
|
643
734
|
- [ ] `.js`/`.ts`: two leading blank lines, or imports flush at line 1 (no blanks before first import)
|
|
644
|
-
- [ ]
|
|
645
|
-
- [ ]
|
|
735
|
+
- [ ] Every `<script setup>` section starts with `/* section name */`, followed by a blank line
|
|
736
|
+
- [ ] Declarations are grouped by kind inside each section: two blanks between groups; no blanks between refs; one blank between other same-kind declarations
|
|
737
|
+
- [ ] Non-trivial workflow functions: blank after `{`, double blanks between major steps, blank before `}`
|
|
646
738
|
- [ ] Tiny helpers stay tight
|
|
739
|
+
- [ ] Return-only multi-criteria functions use a compact exhaustive `if` / `else if` / `else`; broader functions may use early returns
|
|
647
740
|
- [ ] `else` / `catch` on new line
|
|
648
741
|
- [ ] Script objects multi-line; template single-key objects may be inline
|
|
649
742
|
- [ ] Kebab-case component tags
|
|
650
743
|
- [ ] `v-if` / `v-for` on `<template>` wrappers
|
|
651
|
-
- [ ]
|
|
744
|
+
- [ ] Conditional states that change several attributes use explicit `<template v-if>` component variants, not nested ternaries
|
|
745
|
+
- [ ] Structural `<template>` wrappers stay on one line; rendered elements/components with 2+ attributes wrap one per line (**`u-modal` stays on one line**); closing `>` / `/>` placement is correct
|
|
652
746
|
- [ ] Attribute order + default-value omissions respected (`subtle`, **Cancel → `ghost` only**, no neutral color noise, `loading-auto`)
|
|
653
747
|
- [ ] `{{ }}` on own line (static + dynamic mix OK)
|
|
654
|
-
- [ ]
|
|
748
|
+
- [ ] Every section is named; imports are co-located with the section that uses them
|
|
655
749
|
- [ ] `handleXxx` for action handlers; `it` for short callbacks; descriptive loop names
|
|
656
750
|
- [ ] Computeds that return structures use block + `return`
|
|
657
751
|
- [ ] Pages: explicit `definePageMeta.name`, reactive route params, named navigation ([pages.md](pages.md))
|