mcpField
N
nuxt-unified-ui

nuxt-unified-ui

github.com/yooneskhDevelopment043 installsUpdated 2d ago
Repository

About nuxt-unified-ui

nuxt-unified-ui is a skill that guides agents building Nuxt applications with shared UI, form, data, and resource APIs. Its apply workflow checks changed files individually and handles cross-file follow-ups.

Key features

  1. 01Schema-driven forms and custom elements
  2. 02Dialogs, toasts, tables, and UI components
  3. 03Typed resource and singleton controllers
  4. 04File placement and layer visibility rules
  5. 05Per-file apply checks and follow-ups

Use cases

  1. 01Building forms, tables, or dialogs in a Nuxt app
  2. 02Adding standard resource routes and dashboards
  3. 03Applying project structure and code-style rules to changed files

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/yooneskh/nuxt-unified-ui --skill nuxt-unified-ui

After installing, type/nuxt-unified-uiin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

references/
apply.md
code-style.md
data-fetching.md
dialogs.md
forms.md
layer-setup.md
pages.md
radashi.md
resources.md
tables.md
toast-and-ui.md

Details

From the project README

nuxt-unified-ui

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.

Finishing work: /nuxt-unified-ui apply

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. 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.

On dev, main, or master it processes uncommitted .vue, .js, and .ts files; when that branch is clean, or the project is not a Git worktree, it processes every eligible file. On any other branch, it processes only the files that branch added or changed relative to its base branch. One subagent per file, launched using a cheap fast model, applies the logical, structural, and code-style rules, then the main agent carries out the cross-file follow-ups.

APIs

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.

APIUse it toFromReference
un-form / useFormRender a schema-driven form; useForm returns { form, formTag }layerforms.md
registerFormExtraElementAdd a custom form element identifier (call from a Nuxt plugin)layerforms.md
useFormExtraElementsRead the registered custom elements (add them with registerFormExtraElement)layerforms.md
un-cardCard with icon / title / subtitle header, body, and action rowslayertoast-and-ui.md
un-typographyIcon + title + subtitle + text blocklayertoast-and-ui.md
un-spinnerShow a loading spinnerlayertoast-and-ui.md
un-tableShow one page of rows with row actions and a pagination footerlayertables.md
launchFormPickerDialogAsk for form input in a modal; submit logic goes in submitButton.onClicklayerdialogs.md
launchChoicePickerDialogConfirm or choose in a modal; logic goes in each button's onClicklayerdialogs.md
launchDialogOpen any dialog component; resolves with its close payloadlayerdialogs.md
toast, toastSuccess, toastError, toastWarning, toastInfoShow a toast (typed helpers set icon and color)layertoast-and-ui.md
smartMatchTest a function, mongo-style filter, or truthy value against an objectlayerforms.md
unSetSet a nested path on an object, creating missing levels (mutates)layer—
formatDate / parseDateFormat and parse dates (@formkit/tempo); defaults come from app.config dateFormatlayerlayer-setup.md
isSlotFilledCheck whether a slot has contentlayer—
pathRelativeToBaseResolve a path against a file URL; also exported from the package for nuxt.configlayerlayer-setup.md
makeConfettiFire 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-confettilayer—
radXxxAny radashi function (radGet, radPick, …), in app and serverlayerradashi.md
ufetchMake a one-off API request (submit, delete, click)companiondata-fetching.md
useUFetchLoad reactive page data (data, pending, refresh)companiondata-fetching.md
parseSchemaCompile a resource schema DSL into { schema, type, inferred }companionresources.md
createUnifiedResourceController / UnifiedResourceControllerCreate the typed Mongo controller (dbo) for a resourcecompanionresources.md
createUnifiedSingletonController / UnifiedSingletonControllerCreate the typed controller for one fixed singleton row (schema, retrieve, update)companionresources.md
app / UnifiedAppRegistryGlobal typed registry of resources (app.users.dbo)companionresources.md
handleResourceSchema, handleResourceList, handleResourceCreate, handleResourceCount, handleResourceRetrieve, handleResourceUpdate, handleResourceDeleteImplement the standard REST routes of a resourcecompanionresources.md
handleSingletonSchema, handleSingletonRetrieve, handleSingletonUpdateImplement the singleton routes: schema, retrieve, and update of the one rowcompanionresources.md
useResourceNameDerive a resource's API path and display titles from its namecompanionresources.md
useResourceMetaMap a resource schema to form fields and table columnscompanionresources.md
<resource-manager>Full CRUD dashboard card for a resource; exposes refreshResources()companionresources.md
<singleton-manager>Form card for one singleton row; exposes refreshSingleton()companionresources.md
<resource-explorer-table>Filter bar + sortable headers + un-table for a resourcecompaniontables.md
assertBodyValidate a request body against a schema in a server routecompanion—
assertRateLimitRate-limit a server routecompanion—
createUnauthenticatedErrorThrow a 401 from a server routecompanion—
generateUuidGenerate a UUIDcompanion—
useTokenRead or set the auth tokencompanion—
is-authenticated middleware; dashboard / empty layoutsProtect pages; dashboard and full-bleed page layoutscompanionpages.md
useJsonldEmit JSON-LD on public pages, only when nuxt-jsonld is installednuxt-jsonldpages.md

File structure

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.

Each .vue, .js, and .ts file has one responsibility. When a file would have two independent jobs, create two files.

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.

RoleDirectoryVisibility
Private Vue componentapp/atoms/This layer only
Private function, composable, or helperapp/libs/This layer only
Public Vue componentapp/components/Whole app, auto-imported
Public utilapp/utils/Whole app, auto-imported

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.

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.

Do not register atoms or libs with Nuxt components or imports config.

Before writing

Read the reference that matches the task before creating or editing files. The details stay in that reference.

TaskRead first
Layer installation and required CSSreferences/layer-setup.md
Forms, field schema, built-in and custom elementsreferences/forms.md
Dialogsreferences/dialogs.md
Toasts, un-* UI, button / badge / icon conventionsreferences/toast-and-ui.md
Tablesreferences/tables.md
Pages and routingreferences/pages.md
ufetch / useUFetchreferences/data-fetching.md
Unified resourcesreferences/resources.md
Radashi radXxx exportsreferences/radashi.md

Decisions the main agent owns

Make these choices while implementing. The apply pipeline checks them again afterward.

  • Prefer the APIs above over hand-rolled equivalents (raw $fetch, hand-built u-modal flows, direct radashi imports).
  • A new resource includes its server plugin, the full REST route set, and a dashboard nav entry or a custom <resource-manager> page.
  • Use ufetch for a one-off request. Use useUFetch for reactive page data.
  • Every page has an explicit definePageMeta.name and sets SEO with useHead (title) and useSeoMeta (description).
  • Buttons, badges, and icons follow the component conventions in references/toast-and-ui.md. Read them before writing any button.
  • When splitting or promoting a file, update its callers in the same task.
  • Installing the layer includes the required host assets/css/main.css and the pathRelativeToBase CSS entry in nuxt.config.

i18n

i18n is optional. Conform to the project's current state.

  • If the project does not translate its own strings (literal text, no $t, no locale files of its own), keep writing literal strings. Do not introduce $t, locale files, or i18n config unless the user decides to integrate i18n.
  • If the project already uses i18n in another layout, follow that layout.
  • The rules below apply once the project has decided to integrate i18n, or already follows them. This layer's own $t usage does not count as a decision for the project.
  • Examples in the references often use English literals for brevity. In an i18n project those strings are $t('...') keys.

When i18n is integrated

  • Every user-facing string goes through $t, in templates and in script. $t is available in both without calling useI18n().
  • Global i18n settings — strategy, defaultLocale, and the full locales list (codes, names, languages) — go in the nuxt.config.ts of the aarde layer: the project's base app layer that extends nuxt-unified-ui (for example layers/100-aarde/). If the project has no aarde layer, use the layer that extends nuxt-unified-ui.
  • Every other layer (feature) keeps its own locale files in its own i18n/locales/<code>.json. In its own nuxt.config.ts it declares only those files — i18n: { locales: [{ code, file }] } — and no other i18n settings. @nuxtjs/i18n loads a layer's locale files only when that layer lists them, then merges the same locale from every layer into one message tree.
  • The layer that owns a file is the nearest directory above it with a nuxt.config. Its strings go in that layer's locale files only — never in another layer's or the host's.
  • Each layer's locale file has exactly one top-level key: the layer's namespace, such as patients or billing. Every key nests under it ($t('patients.single.title')), so merged trees never clash.
  • Add every new key to each locale that layer declares.
  • This layer owns two top-level keys: un for its components and common for shared labels (common.submit, common.cancel, common.close, …). Reuse common.* instead of duplicating those labels, but never add keys to un or common from another layer.

Aarde layer nuxt.config.ts (fragment):

i18n: {
  strategy: 'no_prefix',
  defaultLocale: 'en',
  locales: [
    {
      code: 'en',
      name: 'English',
      file: 'en.json',
    },
    {
      code: 'de',
      name: 'Deutsch',
      file: 'de.json',
    },
  ],
},

Feature layer nuxt.config.ts (fragment) and its i18n/locales/en.json:

i18n: {
  locales: [
    {
      code: 'en',
      file: 'en.json',
    },
    {
      code: 'de',
      file: 'de.json',
    },
  ],
},
{
  "patients": {
    "single": {
      "title": "Patient"
    }
  }
}

Comments

Markdown supported