nuxt-unified-ui 0.5.16 → 0.5.17
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/README.md +1 -1
- package/app/components/un-table.vue +22 -2
- package/app/utils/unified-set.ts +8 -1
- package/package.json +3 -3
- package/skills/nuxt-unified-ui/SKILL.md +115 -174
- package/skills/nuxt-unified-ui/references/apply.md +135 -0
- package/skills/nuxt-unified-ui/references/code-style.md +534 -489
- package/skills/nuxt-unified-ui/references/data-fetching.md +10 -98
- package/skills/nuxt-unified-ui/references/dialogs.md +29 -72
- package/skills/nuxt-unified-ui/references/forms.md +92 -54
- package/skills/nuxt-unified-ui/references/layer-setup.md +9 -2
- package/skills/nuxt-unified-ui/references/pages.md +23 -116
- package/skills/nuxt-unified-ui/references/resources.md +142 -12
- package/skills/nuxt-unified-ui/references/tables.md +11 -53
- package/skills/nuxt-unified-ui/references/toast-and-ui.md +56 -41
- package/skills/nuxt-unified-ui/references/dialogs-impl.md +0 -57
- package/skills/nuxt-unified-ui/references/form-elements.md +0 -59
- package/skills/nuxt-unified-ui/references/form-field-schema.md +0 -50
- package/skills/nuxt-unified-ui/references/public-surface.md +0 -77
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ vpr serve
|
|
|
20
20
|
|
|
21
21
|
## Agent Skills
|
|
22
22
|
|
|
23
|
-
One installable Agent Skill lives under `skills/nuxt-unified-ui/` (`npx skills` compatible). It covers the layer API **and** mandatory Nuxt code style (forms, dialogs, radashi, formatting).
|
|
23
|
+
One installable Agent Skill lives under `skills/nuxt-unified-ui/` (`npx skills` compatible). It covers the layer API **and** mandatory Nuxt code style (forms, dialogs, radashi, formatting). When an agent finishes implementing work, it runs `/nuxt-unified-ui apply`: one subagent per `.vue`, `.ts`, or `.js` file applies the skill's logical, structural, and code-style rules — to every file on `dev` / `main` / `master`, or to the current branch's changed files elsewhere. You can also invoke `/nuxt-unified-ui apply` directly.
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
26
|
npx skills add . --list
|
|
@@ -134,15 +134,34 @@ function getExtraActionItems(row) {
|
|
|
134
134
|
'href',
|
|
135
135
|
'disabled',
|
|
136
136
|
'onClick',
|
|
137
|
+
'onSelect',
|
|
137
138
|
]),
|
|
138
139
|
href: resolveActionValue(it.href, row),
|
|
139
140
|
to: resolveActionValue(it.to, row),
|
|
140
141
|
disabled: resolveActionValue(it.disabled, row),
|
|
141
|
-
|
|
142
|
+
onSelect: () => it.onClick?.(row.original),
|
|
142
143
|
};
|
|
143
144
|
});
|
|
144
145
|
}
|
|
145
146
|
|
|
147
|
+
function handleRowSelect(_event, row) {
|
|
148
|
+
|
|
149
|
+
if (!props.rowTo) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
const destination = props.rowTo(row.original);
|
|
155
|
+
|
|
156
|
+
if (!destination) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
return navigateTo(destination);
|
|
162
|
+
|
|
163
|
+
}
|
|
164
|
+
|
|
146
165
|
|
|
147
166
|
/* pagination */
|
|
148
167
|
|
|
@@ -174,7 +193,8 @@ const pageSizeItems = computed(() => {
|
|
|
174
193
|
:data="props.data || []"
|
|
175
194
|
:column-pinning="columnPinning"
|
|
176
195
|
:ui="tableUi"
|
|
177
|
-
:meta="props.meta"
|
|
196
|
+
:meta="props.meta"
|
|
197
|
+
@select="props.rowTo ? handleRowSelect : undefined">
|
|
178
198
|
|
|
179
199
|
<template v-for="(_, name) in $slots" #[name]="slotData">
|
|
180
200
|
<slot
|
package/app/utils/unified-set.ts
CHANGED
|
@@ -11,8 +11,15 @@
|
|
|
11
11
|
* @example
|
|
12
12
|
* unSet({}, 'cards[0].value', 2)
|
|
13
13
|
* // => { cards: [{ value: 2 }] }
|
|
14
|
+
*
|
|
15
|
+
* Paths that contain `__proto__`, `prototype`, or `constructor` are ignored.
|
|
14
16
|
*/
|
|
15
17
|
|
|
18
|
+
function isUnsafePathSegment(segment: string) {
|
|
19
|
+
return segment === '__proto__' || segment === 'prototype' || segment === 'constructor';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
16
23
|
export function unSet(target: any, key: string, value: any) {
|
|
17
24
|
|
|
18
25
|
const segments = (
|
|
@@ -22,7 +29,7 @@ export function unSet(target: any, key: string, value: any) {
|
|
|
22
29
|
.filter(Boolean)
|
|
23
30
|
);
|
|
24
31
|
|
|
25
|
-
if (segments.length === 0) {
|
|
32
|
+
if (segments.length === 0 || segments.some(isUnsafePathSegment)) {
|
|
26
33
|
return target;
|
|
27
34
|
}
|
|
28
35
|
|
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.17",
|
|
5
5
|
"main": "./nuxt.config.ts",
|
|
6
6
|
"types": "./index.d.ts",
|
|
7
7
|
"exports": {
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@formkit/tempo": "1.1.0",
|
|
23
|
-
"@iconify-json/lucide": "1.2.
|
|
23
|
+
"@iconify-json/lucide": "1.2.138",
|
|
24
24
|
"@nuxt/kit": "4.5.2",
|
|
25
|
-
"@nuxt/ui": "4.11.
|
|
25
|
+
"@nuxt/ui": "4.11.3",
|
|
26
26
|
"@nuxtjs/i18n": "10.6.0",
|
|
27
27
|
"@types/canvas-confetti": "1.9.0",
|
|
28
28
|
"@vueuse/core": "15.0.0",
|
|
@@ -1,181 +1,122 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: nuxt-unified-ui
|
|
3
3
|
description: >-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
working in or consuming nuxt-unified-ui, declaring or customizing resources,
|
|
15
|
-
or whenever generating Vue/Nuxt code that must match unified code style.
|
|
4
|
+
Builds and edits Nuxt apps and layers that use nuxt-unified-ui: un-form /
|
|
5
|
+
useForm schema forms, un-card, un-table, launchFormPickerDialog /
|
|
6
|
+
launchChoicePickerDialog / launchDialog, toast helpers, radXxx radashi
|
|
7
|
+
auto-imports, and the companion unified stack (ufetch, useUFetch,
|
|
8
|
+
resource-manager, createUnifiedResourceController). Use when package.json
|
|
9
|
+
depends on nuxt-unified-ui, nuxt.config extends it, or code uses these
|
|
10
|
+
APIs. Whenever implementation work is finished, run `/nuxt-unified-ui
|
|
11
|
+
apply`, which applies the skill file by file to the whole project (on dev,
|
|
12
|
+
main, or master) or to the current branch's changed files; users can also
|
|
13
|
+
invoke it directly.
|
|
16
14
|
---
|
|
17
15
|
|
|
18
16
|
# nuxt-unified-ui
|
|
19
17
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
|
36
|
-
|
|
37
|
-
|
|
|
38
|
-
|
|
|
39
|
-
|
|
|
40
|
-
|
|
|
41
|
-
|
|
|
42
|
-
|
|
|
43
|
-
|
|
|
44
|
-
|
|
|
45
|
-
|
|
|
46
|
-
|
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
|
|
|
50
|
-
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
## Mental model (`app/`)
|
|
126
|
-
|
|
127
|
-
| Path | Role |
|
|
128
|
-
|------|------|
|
|
129
|
-
| `app/components/` | `un-form`, `un-card`, `un-typography`, `un-spinner`, `un-table` |
|
|
130
|
-
| `app/composables/` | `useForm`, `useFormExtraElements` |
|
|
131
|
-
| `app/elements/` | Built-in form field renderers |
|
|
132
|
-
| `app/dialogs/` | Form / choice picker modal UIs |
|
|
133
|
-
| `app/utils/` | `launchDialog*`, `toast*`, `smartMatch`, `unSet`, dates, … |
|
|
134
|
-
| `app/plugins/` | `$toaster` via `useToast()` |
|
|
135
|
-
| `modules/radashi.ts` | Auto-imports radashi as `rad*` |
|
|
136
|
-
| `i18n/locales/` | `en.json`, `de.json` |
|
|
137
|
-
|
|
138
|
-
## Layer config (inherited)
|
|
139
|
-
|
|
140
|
-
From `nuxt.config.ts`: `@vueuse/nuxt`, `@nuxt/ui`, `@nuxtjs/i18n`; `ui.colorMode: false`; default variant `neutral`; i18n `no_prefix` with `en`/`de`; `experimental.typedPages: true`.
|
|
141
|
-
|
|
142
|
-
## Common tasks
|
|
143
|
-
|
|
144
|
-
| Task | Prefer |
|
|
145
|
-
|------|--------|
|
|
146
|
-
| Schema form | `useForm` + `<form-tag />` / `<un-form>` → [forms.md](references/forms.md) |
|
|
147
|
-
| Modal form | `launchFormPickerDialog` + `submitButton.onClick` → [dialogs.md](references/dialogs.md) |
|
|
148
|
-
| Confirm / choice | `launchChoicePickerDialog` + button `onClick` (avoid `value`) |
|
|
149
|
-
| Feedback | `toastSuccess` / `toastError` / `toastWarning` / `toastInfo` / `toast` |
|
|
150
|
-
| Page chrome | `un-typography` + `un-card` |
|
|
151
|
-
| Data table | `un-table` + parent-owned fetch / sort / filter → [tables.md](references/tables.md) |
|
|
152
|
-
| Custom field | `registerFormExtraElement` in a plugin |
|
|
153
|
-
| Utilities | `radXxx` → [radashi.md](references/radashi.md) |
|
|
154
|
-
| New page / route | [pages.md](references/pages.md) |
|
|
155
|
-
| List/detail fetch or mutation | [data-fetching.md](references/data-fetching.md) |
|
|
156
|
-
| New / custom resource | [resources.md](references/resources.md) |
|
|
157
|
-
| New component / util in a layer | Start in `app/atoms/` or `app/libs/`; relative imports; promote to `components/` / `utils/` only if another layer needs it → [code-style.md](references/code-style.md) |
|
|
158
|
-
| Formatting any of the above | [code-style.md](references/code-style.md) |
|
|
159
|
-
|
|
160
|
-
## Do / don’t
|
|
161
|
-
|
|
162
|
-
**Do**
|
|
163
|
-
|
|
164
|
-
- Extend via `extends: ['nuxt-unified-ui']`
|
|
165
|
-
- Keep required host `main.css` + `pathRelativeToBase` CSS entry + `nuxt-ui-fixes.css`
|
|
166
|
-
- Use field `identifier` for element kind; `type` only for HTML input types
|
|
167
|
-
- Handle dialog actions in `onClick`
|
|
168
|
-
- Follow code style for every generated file
|
|
169
|
-
- Resources: plugin → full REST set → dashboard nav / custom `<resource-manager>` page → [resources.md](references/resources.md)
|
|
170
|
-
- Start generated layer components in `app/atoms/` and functions in `app/libs/`; import them with relative paths; move to `app/components/` / `app/utils/` only when another layer needs them
|
|
171
|
-
|
|
172
|
-
**Don’t**
|
|
173
|
-
|
|
174
|
-
- Invent APIs not in source
|
|
175
|
-
- Reference any local playground as consumer docs
|
|
176
|
-
- Use PascalCase component tags in templates
|
|
177
|
-
- Set choice-button `value` unless the await result must distinguish buttons
|
|
178
|
-
- Assume color mode is enabled (layer disables it)
|
|
179
|
-
- Reimplement resource CRUD in route files (use `handleResource*`; customize via dedicated pages + domain APIs)
|
|
180
|
-
- Put a layer-private component or util in `components/` or `utils/` (becomes app-global)
|
|
181
|
-
- Import `atoms`/`libs` via `~/`, `#layers`, or from another layer — use relative paths; promote first if another layer needs them
|
|
18
|
+
The main agent decides what code exists, where it lives, and which APIs it calls. When the work is done, the apply pipeline runs one subagent per file to check the skill's rules and apply the code style; it is the only place formatting rules apply. The main agent does not load `references/code-style.md`.
|
|
19
|
+
|
|
20
|
+
## Finishing work: `/nuxt-unified-ui apply`
|
|
21
|
+
|
|
22
|
+
Whenever you finish implementing work that added or edited a `.vue`, `.js`, or `.ts` file, run `/nuxt-unified-ui apply` before your final reply: follow [references/apply.md](references/apply.md). Do the same when the skill is invoked with the argument `apply`, or the user asks to apply nuxt-unified-ui across the project or the current branch. Invoked without an argument, the skill only loads its guidance for the task at hand.
|
|
23
|
+
|
|
24
|
+
On `dev`, `main`, or `master` it processes every `.vue`, `.js`, and `.ts` file; on any other branch, only the files that branch added or changed relative to its base branch. One subagent per file applies the logical, structural, and code-style rules, then the main agent carries out the cross-file follow-ups.
|
|
25
|
+
|
|
26
|
+
## APIs
|
|
27
|
+
|
|
28
|
+
**Layer** APIs come from this layer and are auto-imported across the app and every layer. **Companion** APIs come from the companion unified layers, which real projects always include next to this one. When an API is not listed here, check the source before using it.
|
|
29
|
+
|
|
30
|
+
| API | Use it to | From | Reference |
|
|
31
|
+
|---|---|---|---|
|
|
32
|
+
| `un-form` / `useForm` | Render a schema-driven form; `useForm` returns `{ form, formTag }` | layer | [forms.md](references/forms.md) |
|
|
33
|
+
| `registerFormExtraElement` | Add a custom form element `identifier` (call from a Nuxt plugin) | layer | [forms.md](references/forms.md) |
|
|
34
|
+
| `useFormExtraElements` | Read the registered custom elements (add them with `registerFormExtraElement`) | layer | [forms.md](references/forms.md) |
|
|
35
|
+
| `un-card` | Card with icon / title / subtitle header, body, and action rows | layer | [toast-and-ui.md](references/toast-and-ui.md) |
|
|
36
|
+
| `un-typography` | Icon + title + subtitle + text block | layer | [toast-and-ui.md](references/toast-and-ui.md) |
|
|
37
|
+
| `un-spinner` | Show a loading spinner | layer | [toast-and-ui.md](references/toast-and-ui.md) |
|
|
38
|
+
| `un-table` | Show one page of rows with row actions and a pagination footer | layer | [tables.md](references/tables.md) |
|
|
39
|
+
| `launchFormPickerDialog` | Ask for form input in a modal; submit logic goes in `submitButton.onClick` | layer | [dialogs.md](references/dialogs.md) |
|
|
40
|
+
| `launchChoicePickerDialog` | Confirm or choose in a modal; logic goes in each button's `onClick` | layer | [dialogs.md](references/dialogs.md) |
|
|
41
|
+
| `launchDialog` | Open any dialog component; resolves with its `close` payload | layer | [dialogs.md](references/dialogs.md) |
|
|
42
|
+
| `toast`, `toastSuccess`, `toastError`, `toastWarning`, `toastInfo` | Show a toast (typed helpers set icon and color) | layer | [toast-and-ui.md](references/toast-and-ui.md) |
|
|
43
|
+
| `smartMatch` | Test a function, mongo-style filter, or truthy value against an object | layer | [forms.md](references/forms.md) |
|
|
44
|
+
| `unSet` | Set a nested path on an object, creating missing levels (mutates) | layer | — |
|
|
45
|
+
| `formatDate` / `parseDate` | Format and parse dates (`@formkit/tempo`) | layer | — |
|
|
46
|
+
| `isSlotFilled` | Check whether a slot has content | layer | — |
|
|
47
|
+
| `pathRelativeToBase` | Resolve a path against a file URL; also exported from the package for `nuxt.config` | layer | [layer-setup.md](references/layer-setup.md) |
|
|
48
|
+
| `makeConfetti` | Fire confetti: `template` picks a built-in effect (`parade`, `on-top` / `on-left` / `on-right` / `on-bottom`, `on-frame`, `split-on-top`, `on-curtain`), `amount` sets particles per burst, other args go to `canvas-confetti` | layer | — |
|
|
49
|
+
| `radXxx` | Any radashi function (`radGet`, `radPick`, …), in app and server | layer | [radashi.md](references/radashi.md) |
|
|
50
|
+
| `ufetch` | Make a one-off API request (submit, delete, click) | companion | [data-fetching.md](references/data-fetching.md) |
|
|
51
|
+
| `useUFetch` | Load reactive page data (`data`, `pending`, `refresh`) | companion | [data-fetching.md](references/data-fetching.md) |
|
|
52
|
+
| `parseSchema` | Compile a resource schema DSL into `{ schema, type, inferred }` | companion | [resources.md](references/resources.md) |
|
|
53
|
+
| `createUnifiedResourceController` / `UnifiedResourceController` | Create the typed Mongo controller (`dbo`) for a resource | companion | [resources.md](references/resources.md) |
|
|
54
|
+
| `app` / `UnifiedAppRegistry` | Global typed registry of resources (`app.users.dbo`) | companion | [resources.md](references/resources.md) |
|
|
55
|
+
| `handleResourceSchema`, `handleResourceList`, `handleResourceCreate`, `handleResourceCount`, `handleResourceRetrieve`, `handleResourceUpdate`, `handleResourceDelete` | Implement the standard REST routes of a resource | companion | [resources.md](references/resources.md) |
|
|
56
|
+
| `useResourceName` | Derive a resource's API path and display titles from its name | companion | [resources.md](references/resources.md) |
|
|
57
|
+
| `useResourceMeta` | Map a resource schema to form fields and table columns | companion | [resources.md](references/resources.md) |
|
|
58
|
+
| `<resource-manager>` | Full CRUD dashboard card for a resource; exposes `refreshResources()` | companion | [resources.md](references/resources.md) |
|
|
59
|
+
| `<resource-explorer-table>` | Filter bar + sortable headers + `un-table` for a resource | companion | [tables.md](references/tables.md) |
|
|
60
|
+
| `assertBody` | Validate a request body against a schema in a server route | companion | — |
|
|
61
|
+
| `assertRateLimit` | Rate-limit a server route | companion | — |
|
|
62
|
+
| `createUnauthenticatedError` | Throw a 401 from a server route | companion | — |
|
|
63
|
+
| `generateUuid` | Generate a UUID | companion | — |
|
|
64
|
+
| `useToken` | Read or set the auth token | companion | — |
|
|
65
|
+
| `is-authenticated` middleware; `dashboard` / `empty` layouts | Protect pages; dashboard and full-bleed page layouts | companion | [pages.md](references/pages.md) |
|
|
66
|
+
| `useJsonld` | Emit JSON-LD on public pages, only when `nuxt-jsonld` is installed | `nuxt-jsonld` | [pages.md](references/pages.md) |
|
|
67
|
+
|
|
68
|
+
## File structure
|
|
69
|
+
|
|
70
|
+
The main agent decides where a file lives and which one job it has, and does it while implementing. Apply subagents only report misplaced files; they never move files or update callers.
|
|
71
|
+
|
|
72
|
+
Each `.vue`, `.js`, and `.ts` file has one responsibility. When a file would have two independent jobs, create two files.
|
|
73
|
+
|
|
74
|
+
Nuxt auto-imports `app/components/` and `app/utils/` across every layer. `app/composables/` is public in the same way. A file that must stay inside one layer does not go in those directories.
|
|
75
|
+
|
|
76
|
+
| Role | Directory | Visibility |
|
|
77
|
+
|---|---|---|
|
|
78
|
+
| Private Vue component | `app/atoms/` | This layer only |
|
|
79
|
+
| Private function, composable, or helper | `app/libs/` | This layer only |
|
|
80
|
+
| Public Vue component | `app/components/` | Whole app, auto-imported |
|
|
81
|
+
| Public util | `app/utils/` | Whole app, auto-imported |
|
|
82
|
+
|
|
83
|
+
Generate private first. New components start in `app/atoms/`. New functions and similar helpers start in `app/libs/`. Promote a file to `app/components/` or `app/utils/` only when another layer needs it. After a promote, update every caller and remove the relative import; public modules are auto-imported.
|
|
84
|
+
|
|
85
|
+
Import `atoms` and `libs` with relative paths only (`../atoms/foo.vue`, `../libs/bar`). Never use `~/`, `@/`, `#layers/`, or another alias. Never import another layer's `atoms` or `libs`; promote that file first, then use the public auto-import.
|
|
86
|
+
|
|
87
|
+
Do not register `atoms` or `libs` with Nuxt `components` or `imports` config.
|
|
88
|
+
|
|
89
|
+
## Before writing
|
|
90
|
+
|
|
91
|
+
Read the reference that matches the task before creating or editing files. The details stay in that reference.
|
|
92
|
+
|
|
93
|
+
| Task | Read first |
|
|
94
|
+
|---|---|
|
|
95
|
+
| Layer installation and required CSS | [references/layer-setup.md](references/layer-setup.md) |
|
|
96
|
+
| Forms, field schema, built-in and custom elements | [references/forms.md](references/forms.md) |
|
|
97
|
+
| Dialogs | [references/dialogs.md](references/dialogs.md) |
|
|
98
|
+
| Toasts, `un-*` UI, button / badge / icon conventions | [references/toast-and-ui.md](references/toast-and-ui.md) |
|
|
99
|
+
| Tables | [references/tables.md](references/tables.md) |
|
|
100
|
+
| Pages and routing | [references/pages.md](references/pages.md) |
|
|
101
|
+
| `ufetch` / `useUFetch` | [references/data-fetching.md](references/data-fetching.md) |
|
|
102
|
+
| Unified resources | [references/resources.md](references/resources.md) |
|
|
103
|
+
| Radashi `radXxx` exports | [references/radashi.md](references/radashi.md) |
|
|
104
|
+
|
|
105
|
+
## Decisions the main agent owns
|
|
106
|
+
|
|
107
|
+
Make these choices while implementing. The apply pipeline checks them again afterward.
|
|
108
|
+
|
|
109
|
+
- Prefer the APIs above over hand-rolled equivalents (raw `$fetch`, hand-built `u-modal` flows, direct `radashi` imports).
|
|
110
|
+
- A new resource includes its server plugin, the full REST route set, and a dashboard nav entry or a custom `<resource-manager>` page.
|
|
111
|
+
- Use `ufetch` for a one-off request. Use `useUFetch` for reactive page data.
|
|
112
|
+
- Every page has an explicit `definePageMeta.name` and sets SEO with `useHead` (title) and `useSeoMeta` (description).
|
|
113
|
+
- Buttons, badges, and icons follow the component conventions in [references/toast-and-ui.md](references/toast-and-ui.md#component-conventions). Read them before writing any button.
|
|
114
|
+
- When splitting or promoting a file, update its callers in the same task.
|
|
115
|
+
- Installing the layer includes the required host `assets/css/main.css` and the `pathRelativeToBase` CSS entry in `nuxt.config`.
|
|
116
|
+
|
|
117
|
+
## i18n
|
|
118
|
+
|
|
119
|
+
- Every user-facing string goes through `$t`, in templates and in script. `$t` is available in both without calling `useI18n()`.
|
|
120
|
+
- Add each new key to every locale file the project has (the layer ships `en.json` and `de.json` in `i18n/locales/`).
|
|
121
|
+
- `un.*` keys belong to this layer. `common.*` holds shared labels such as submit and cancel. App keys go under a feature namespace (`patients.single.title`).
|
|
122
|
+
- Examples in the references often use English literals for brevity. In real code those strings are `$t('...')` keys.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# `/nuxt-unified-ui apply`
|
|
2
|
+
|
|
3
|
+
The one pipeline that brings code in line with this skill. One subagent per file applies the skill's logical, structural, and code-style rules; the main agent picks the files, launches the subagents, and carries out the cross-file follow-ups they report.
|
|
4
|
+
|
|
5
|
+
It runs:
|
|
6
|
+
|
|
7
|
+
- **After implementation** — whenever the main agent finishes implementing work that added or edited a `.vue`, `.js`, or `.ts` file, before its final reply.
|
|
8
|
+
- **On request** — when the skill is invoked with the argument `apply` (`/nuxt-unified-ui apply`), or the user asks to apply nuxt-unified-ui across the project or branch.
|
|
9
|
+
|
|
10
|
+
Both run the same steps on the same file selection.
|
|
11
|
+
|
|
12
|
+
## Main agent
|
|
13
|
+
|
|
14
|
+
Do not edit files while subagents are running.
|
|
15
|
+
|
|
16
|
+
### 1. Pick the files
|
|
17
|
+
|
|
18
|
+
Run from the repository root.
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
branch=$(git branch --show-current)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
If `branch` is empty (detached HEAD), stop and ask the user which files to process.
|
|
25
|
+
|
|
26
|
+
**On `dev`, `main`, or `master`** — every tracked or new, non-ignored file:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
git ls-files --cached --others --exclude-standard -- '*.vue' '*.js' '*.ts' ':!*.d.ts'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**On any other branch** — files the branch added or changed relative to its base branch, including uncommitted and untracked work.
|
|
33
|
+
|
|
34
|
+
Find the base: the closest of `dev`, `main`, `master` (local first, then `origin/`), measured by commits since the merge base. Ties go to the earlier name in that order.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
for candidate in dev main master; do
|
|
38
|
+
for ref in "$candidate" "origin/$candidate"; do
|
|
39
|
+
git rev-parse --verify --quiet "$ref^{commit}" >/dev/null || continue
|
|
40
|
+
base=$(git merge-base HEAD "$ref") || continue
|
|
41
|
+
echo "$(git rev-list --count "$base"..HEAD) $ref $base"
|
|
42
|
+
break
|
|
43
|
+
done
|
|
44
|
+
done | sort -s -n -k1,1
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The first line is the base: `<commits> <ref> <merge-base sha>`. If there is no output, stop and ask the user for the base branch. Then list the files with the merge-base sha:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
{
|
|
51
|
+
git diff --name-only --diff-filter=AMR "$base" -- '*.vue' '*.js' '*.ts' ':!*.d.ts'
|
|
52
|
+
git ls-files --others --exclude-standard -- '*.vue' '*.js' '*.ts' ':!*.d.ts'
|
|
53
|
+
} | sort -u
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Deleted files are excluded. Tell the user the branch, the base (when there is one), and how many files were selected. If none were selected, stop.
|
|
57
|
+
|
|
58
|
+
### 2. Launch one subagent per file
|
|
59
|
+
|
|
60
|
+
Launch exactly one subagent per selected file — never several files in one subagent. Run them in parallel batches. Each subagent edits only its own file, so parallel runs do not conflict.
|
|
61
|
+
|
|
62
|
+
Use this prompt:
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
Apply nuxt-unified-ui to this file only:
|
|
66
|
+
<absolute target path>
|
|
67
|
+
|
|
68
|
+
Read and follow, in full:
|
|
69
|
+
<absolute skill path>/references/apply.md (section "Per-file subagent")
|
|
70
|
+
|
|
71
|
+
Return the report described there.
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 3. Carry out the follow-ups
|
|
75
|
+
|
|
76
|
+
When every subagent has reported, collect their follow-ups, remove duplicates, and apply them **one at a time** in the main agent:
|
|
77
|
+
|
|
78
|
+
- **`i18n`** — add each key to every locale file the project has. Use the reported English text for English; translate for other locales when confident, otherwise use the English text and list those keys in the summary.
|
|
79
|
+
- **`split`** / **`move`** / **`promote`** — apply the file-structure rules from `SKILL.md`: create or move the files, then update every caller and import.
|
|
80
|
+
- **`other`** — apply cross-file changes that follow directly from the skill (for example a missing REST route of a resource). List anything that needs a product decision in the summary instead of guessing.
|
|
81
|
+
|
|
82
|
+
### 4. Second round for what step 3 touched
|
|
83
|
+
|
|
84
|
+
Launch the same per-file subagent (step 2) for every `.vue`, `.js`, or `.ts` file created or edited in step 3, then apply their `i18n` follow-ups. Do not start a third round: list any other follow-ups from this round in the summary.
|
|
85
|
+
|
|
86
|
+
### 5. Verify and summarize
|
|
87
|
+
|
|
88
|
+
Run the project's `lint` and `typecheck` scripts when `package.json` defines them, and fix failures caused by this run. Then report: files processed, files changed, follow-ups applied, follow-ups left for the user, and any subagent that failed.
|
|
89
|
+
|
|
90
|
+
## Per-file subagent
|
|
91
|
+
|
|
92
|
+
You bring one `.vue`, `.js`, or `.ts` file in line with the nuxt-unified-ui skill.
|
|
93
|
+
|
|
94
|
+
**Boundaries**
|
|
95
|
+
|
|
96
|
+
- Edit only the target file. Never create, move, rename, or delete files, and never edit locale files — report those needs as follow-ups.
|
|
97
|
+
- You may read and search the rest of the codebase to understand callers and context.
|
|
98
|
+
- Keep every feature of the file working. Changes required by the skill's conventions (button variants, `$t` keys, SEO, API swaps) are expected; other behavior changes are not.
|
|
99
|
+
- Do not change the file's public API (exports, props, emits, exposed members) unless the skill requires it; report callers that would need updating as `other` follow-ups.
|
|
100
|
+
- Leave generated, vendored, or third-party code unchanged and report `unchanged`.
|
|
101
|
+
|
|
102
|
+
**Steps**
|
|
103
|
+
|
|
104
|
+
1. Read `SKILL.md` (next to this `references/` folder) in full, then the whole target file.
|
|
105
|
+
2. Decide what the file is (page, component, dialog, form element, server route, plugin, util, config, …) and read the references the `SKILL.md` "Before writing" table lists for it.
|
|
106
|
+
3. **Logical pass** — fix in place:
|
|
107
|
+
- Replace hand-rolled code with the APIs in `SKILL.md`: raw `$fetch` / `useFetch` → `ufetch` / `useUFetch`; hand-built modals → dialog launchers; direct `radashi` imports → `radXxx`; and so on.
|
|
108
|
+
- Apply the decisions in `SKILL.md` and the rules of the references you read: page `definePageMeta.name` and SEO, dialog logic in `onClick`, named routes, `to` for navigation-only actions, a dumb `un-table`, reactive fetch gates, component conventions.
|
|
109
|
+
- Move user-facing literals to `$t('...')` keys. Record each new key as an `i18n` follow-up.
|
|
110
|
+
- Make `atoms` / `libs` imports relative.
|
|
111
|
+
4. **Structural pass** — decide, do not execute:
|
|
112
|
+
- Two or more independent responsibilities → `split` follow-up with each responsibility and its suggested path.
|
|
113
|
+
- Wrong directory for its visibility (`SKILL.md` file structure) → `move` or `promote` follow-up. Search for callers in other layers before proposing it.
|
|
114
|
+
- Anything else that needs another file changed → `other` follow-up.
|
|
115
|
+
5. **Style pass** — read [code-style.md](code-style.md) in full, then:
|
|
116
|
+
- Add or correct the `/* responsibility */` header. When the file needs a split, describe its current main job and keep the `split` follow-up.
|
|
117
|
+
- Apply every relevant rule in `code-style.md` to the whole file.
|
|
118
|
+
- Run every item of its "Checklist before finishing an edit" and correct what remains.
|
|
119
|
+
6. Re-read the whole result and confirm the file still does everything it did.
|
|
120
|
+
|
|
121
|
+
**Report**
|
|
122
|
+
|
|
123
|
+
```text
|
|
124
|
+
applied: <absolute path>
|
|
125
|
+
changes:
|
|
126
|
+
- <one line per change>
|
|
127
|
+
follow-ups:
|
|
128
|
+
- i18n: <key> = "<English text>"
|
|
129
|
+
- split: <responsibility> -> <suggested path>
|
|
130
|
+
- move: <current path> -> <suggested path> (<reason>)
|
|
131
|
+
- promote: <current path> -> <suggested path> (<layer that needs it>)
|
|
132
|
+
- other: <file> — <change needed and why>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Omit empty sections. If nothing needed changing, return `unchanged: <absolute path>`.
|