Skip to content

Commit 6196e9f

Browse files
committed
fix: edit CLI app agent instructions for generating a vue component. Recomend agent use afcl components and adminforth colors palette (lightPrimary, darkPrimary...)
AdminForth/1849/issue--if-this-was-prompt-ted-
1 parent 7545306 commit 6196e9f

1 file changed

Lines changed: 201 additions & 6 deletions

File tree

  • adminforth/commands/createApp/templates/.agents/skills/adminforth-custom-vue

adminforth/commands/createApp/templates/.agents/skills/adminforth-custom-vue/SKILL.md.hbs

Lines changed: 201 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
name: adminforth-custom-vue
3-
description: "Use when implementing AdminForth custom Vue UI: field components, page injections, login or global injections, meta-driven component declarations, and frontend packages inside custom/."
3+
description: "Use when implementing AdminForth custom Vue UI: AFCL components, theme colors and dark mode, field components, page injections, login or global injections, meta-driven component declarations, and frontend packages inside custom/."
44
user-invocable: true
55
---
66

@@ -13,6 +13,189 @@ user-invocable: true
1313
- Adding resource page injections, login injections, or global layout injections.
1414
- Passing `meta` into reusable Vue components.
1515
- Installing frontend packages used only by custom AdminForth Vue code.
16+
- Any task that produces visible UI in an AdminForth app, even when the task says nothing about how it should look.
17+
18+
## Non-Negotiable UI Defaults
19+
20+
Apply all of these to every piece of UI you write under `custom/`, including when the user gave no design
21+
instructions at all. These are the defaults, not options — do not ask whether the user wants them, and do
22+
not wait for a follow-up prompt about styling or dark mode.
23+
24+
1. **Build from AFCL first.** AFCL (AdminForth Components Library) is imported from `@/afcl` and is always
25+
available in `custom/` without installing anything. Reach for a raw HTML control only when no AFCL
26+
component covers the case.
27+
2. **Buttons come from AFCL with an explicit intent.** Primary/confirming action is the default filled
28+
accent `<Button>`. Secondary, cancel, and "back" actions are stroked `<Button variant="secondary">`.
29+
Destructive actions are `<Button variant="danger">`. Never hand-roll a `<button>` with your own
30+
background classes.
31+
3. **Form controls come from AFCL.** `Input`, `Textarea`, `Select`, `Checkbox`, `Toggle`, `DatePicker`,
32+
`Dropzone`. Never a bare `<input>`, `<select>`, or `<textarea>` styled by hand — that is the main way
33+
custom pages end up looking foreign.
34+
4. **Accents use `lightPrimary` / `darkPrimary`.** Anything that carries brand or "this is the important
35+
one" meaning — accent fills, highlighted values, active states, links, focus emphasis, the main chart
36+
series — should use `bg-lightPrimary dark:bg-darkPrimary`, `text-lightPrimary dark:text-darkPrimary`,
37+
`text-lightPrimaryContrast dark:text-darkPrimaryContrast` on top of an accent fill, or
38+
`bg-lightPrimaryOpacity dark:bg-darkPrimaryOpacity` for a subtle tint. Hardcoding an accent
39+
(`bg-blue-600`, `text-indigo-500`) breaks apps whose theme sets a different brand color.
40+
5. **Everything else may use Tailwind's stock palette.** `bg-white`, `bg-gray-50`, `text-gray-700`,
41+
`text-red-600`, `border-gray-200`, `bg-pink-500`, and friends are all fine for neutrals, surfaces,
42+
borders, and semantic colors. The theme tokens in the table below are still the better choice when a
43+
block sits directly next to built-in AdminForth chrome and should match it exactly — but they are a
44+
recommendation, not a restriction.
45+
6. **Dark theme is part of writing the class, not a later pass.** Every color utility must be written as a
46+
light/dark pair: `bg-white dark:bg-gray-900`, `text-gray-700 dark:text-gray-300`,
47+
`bg-lightForm dark:bg-darkForm`. This matters most with stock Tailwind colors, which have no built-in
48+
dark behavior — a `bg-gray-50` with no `dark:` counterpart is a defect, fix it before finishing.
49+
`light*`/`dark*` token pairs satisfy this by construction. Dark mode is class-based
50+
(`darkMode: 'class'`), so `dark:` variants work everywhere in `custom/`.
51+
7. **Non-color utilities are unrestricted.** Tailwind spacing, sizing, radius, flex/grid, and font-size
52+
utilities are fine and encouraged. Match AFCL's own rhythm so custom blocks sit naturally next to
53+
built-in ones: `rounded-lg`, `text-sm`, `p-4`, `gap-2`/`gap-4`.
54+
8. **Icons come from the prerendered Iconify packages** already present in the SPA:
55+
`@iconify-prerendered/vue-flowbite` (default), plus `-heroicons`, `-humbleicons`, and `-flag`.
56+
Do not add an icon dependency to `custom/package.json` for these.
57+
9. **Never build Tailwind class names dynamically.** `custom/` is copied into the SPA sources and scanned
58+
statically by Tailwind, so `` `text-${color}-600` `` produces no CSS. Write full class strings and pick
59+
between them.
60+
61+
## AFCL Component Inventory
62+
63+
All of these are imported from `@/afcl` and are already theme-aware and dark-mode-ready:
64+
65+
```ts
66+
import { Button, LinkButton, ButtonGroup, Link, Input, Textarea, Select, Checkbox, Toggle,
67+
DatePicker, Dropzone, Card, Table, Dialog, Modal, Tooltip, VerticalTabs,
68+
ProgressBar, Spinner, Skeleton, JsonViewer, CountryFlag,
69+
AreaChart, BarChart, PieChart, MixedChart, TreeMapChart } from '@/afcl';
70+
```
71+
72+
- Actions: `Button` (`variant`: `primary` | `secondary` | `danger`; also `loader`, `disabled`, `active`,
73+
`shadow`), `LinkButton` (same variants, navigates via `to`), `ButtonGroup`, `Link`.
74+
- Inputs: `Input` (requires `type`, supports `v-model`, `fullWidth`, `readonly`, `prefix`/`suffix` props
75+
or slots), `Textarea`, `Select` (`:options="[{ label, value }]"`, `multiple`, `placeholder`),
76+
`Checkbox`, `Toggle`, `DatePicker`, `Dropzone`.
77+
- Layout and data: `Card`, `Table` (client or server-side data, sorting, pagination), `VerticalTabs`,
78+
`Modal`, `Dialog`, `Tooltip`.
79+
- Feedback: `Spinner`, `Skeleton`, `ProgressBar`.
80+
- Charts: `AreaChart`, `BarChart`, `PieChart`, `MixedChart`, `TreeMapChart` — prefer these over pulling in
81+
a new charting library, they already follow theme colors.
82+
83+
Before writing a bespoke widget, check this list. Reusing an AFCL component is always the preferred
84+
answer to "make a button / input / table / modal / chart".
85+
86+
## Theme Color Tokens
87+
88+
These light/dark pairs follow the app's configured theme automatically. The accent rows are the ones you
89+
should actually reach for by default (rule 4); the rest are available when you want a custom block to
90+
match built-in AdminForth chrome pixel-for-pixel instead of approximating it with stock grays. Every
91+
`light*` token has a `dark*` twin.
92+
93+
| Need | Classes |
94+
| --- | --- |
95+
| **Accent (brand) text** | `text-lightPrimary dark:text-darkPrimary` |
96+
| **Accent fill** | `bg-lightPrimary dark:bg-darkPrimary` |
97+
| **Text on accent fill** | `text-lightPrimaryContrast dark:text-darkPrimaryContrast` |
98+
| **Subtle accent tint** | `bg-lightPrimaryOpacity dark:bg-darkPrimaryOpacity` |
99+
| Panel / form surface | `bg-lightForm dark:bg-darkForm` |
100+
| Panel border | `border-lightFormBorder dark:border-darkFormBorder` |
101+
| Section heading strip | `bg-lightFormHeading dark:bg-darkFormHeading` |
102+
| Card surface | `bg-lightCardBackground dark:bg-darkCardBackground` |
103+
| Card border | `border-lightCardBorder dark:border-darkCardBorder` |
104+
| Strong / title text | `text-lightCardTitle dark:text-darkCardTitle` |
105+
| Muted / secondary text | `text-lightCardDescription dark:text-darkCardDescription` |
106+
| Body and table text | `text-lightListTableText dark:text-darkListTableText` |
107+
| Table heading text | `text-lightListTableHeadingText dark:text-darkListTableHeadingText` |
108+
| Divider / separator | `border-lightListBorder dark:border-darkListBorder` |
109+
| Error / invalid text | `text-lightInputErrorColor dark:text-darkInputErrorColor` |
110+
| Required marker | `text-lightRequiredIconColor dark:text-darkRequiredIconColor` |
111+
| Focus ring | `focus:ring-lightFocusRing dark:focus:ring-darkFocusRing` |
112+
113+
The complete token list lives in `node_modules/adminforth/dist/modules/styles.js`. Look a name up there
114+
instead of inventing one — an unknown token silently produces no CSS.
115+
116+
## Default Panel Recipe
117+
118+
When a task asks for "a panel", "a summary block", "a small form", or any custom page area with no visual
119+
spec, start from this shape. It is theme-correct and dark-ready with no extra work:
120+
121+
```vue
122+
<template>
123+
<div class="rounded-lg border border-lightFormBorder dark:border-darkFormBorder
124+
bg-lightForm dark:bg-darkForm p-4">
125+
<h3 class="text-lg font-semibold text-lightCardTitle dark:text-darkCardTitle">
126+
\{{ meta?.title || 'Orders overview' }}
127+
</h3>
128+
<p class="mt-1 text-sm text-lightCardDescription dark:text-darkCardDescription">
129+
Totals for the current filter
130+
</p>
131+
132+
<div class="mt-4 grid gap-3 sm:grid-cols-2">
133+
<Input type="text" v-model="query" full-width placeholder="Search orders" />
134+
<Select v-model="period" :options="periodOptions" placeholder="Period" />
135+
</div>
136+
137+
<div class="mt-4 flex items-center gap-2">
138+
<Button :loader="loading" @click="apply">Apply</Button>
139+
<Button variant="secondary" @click="reset">Reset</Button>
140+
</div>
141+
142+
<p v-if="error" class="mt-2 text-sm text-lightInputErrorColor dark:text-darkInputErrorColor">
143+
\{{ error }}
144+
</p>
145+
</div>
146+
</template>
147+
148+
<script setup lang="ts">
149+
import { ref } from 'vue';
150+
import { Button, Input, Select } from '@/afcl';
151+
152+
defineProps<{ meta?: { title?: string } }>();
153+
154+
const query = ref('');
155+
const period = ref(null);
156+
const loading = ref(false);
157+
const error = ref('');
158+
const periodOptions = [
159+
{ label: 'Last 7 days', value: '7' },
160+
{ label: 'Last 30 days', value: '30' },
161+
];
162+
163+
function apply() { /* ... */ }
164+
function reset() { query.value = ''; period.value = null; }
165+
</script>
166+
```
167+
168+
## Dark Theme Self-Check
169+
170+
Run this over every file you touched before reporting the work as done:
171+
172+
- Search the file for `bg-`, `text-`, `border-`, `ring-`, `fill-`, `stroke-`, `divide-`, `placeholder-`,
173+
and `shadow-` color utilities.
174+
- Each one either has a `dark:` counterpart, comes from a `light*`/`dark*` token pair (which already is
175+
one), or belongs to an AFCL component that handles theming itself. This is the check that actually
176+
matters — a stock Tailwind color with no `dark:` twin is the single most common way custom UI breaks in
177+
dark mode.
178+
- Accents are `lightPrimary`/`darkPrimary`, not a hardcoded blue or indigo.
179+
- No raw `#hex` or `rgb()` in templates or `<style>` blocks.
180+
- Any raw `<button>`, `<input>`, `<select>`, or `<textarea>` has a justification; otherwise replace it with
181+
the AFCL equivalent.
182+
183+
```
184+
❌ <button class="bg-blue-600 text-white rounded px-4 py-2">Save</button>
185+
✅ <Button @click="save">Save</Button>
186+
187+
❌ <div class="bg-white border border-gray-200 text-gray-800">
188+
✅ <div class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700
189+
text-gray-800 dark:text-gray-200">
190+
✅ <div class="bg-lightForm dark:bg-darkForm border border-lightFormBorder
191+
dark:border-darkFormBorder text-lightListTableText dark:text-darkListTableText">
192+
193+
❌ <p class="text-red-600">\{{ error }}</p>
194+
✅ <p class="text-red-600 dark:text-red-400">\{{ error }}</p>
195+
196+
❌ <span class="font-semibold text-blue-600 dark:text-blue-400">\{{ total }}</span>
197+
✅ <span class="font-semibold text-lightPrimary dark:text-darkPrimary">\{{ total }}</span>
198+
```
16199
17200
## `custom/` Directory and `@@/`
18201
@@ -23,6 +206,10 @@ user-invocable: true
23206
24207
## Frontend Packages in `custom/`
25208
209+
- First check whether you need a package at all. These are already available to `custom/` components with
210+
no install step: `@/afcl` (AFCL components), `@/types/Common` (AdminForth types), `@/adminforth`
211+
(`useAdminforth`), `@/stores/core` (`useCoreStore`), `@/websocket`, Vue, Tailwind, and the
212+
`@iconify-prerendered/vue-*` icon sets. AFCL charts already wrap ApexCharts.
26213
- Install frontend-only dependencies inside `custom/`, not in the app root.
27214
28215
```bash
@@ -127,25 +314,27 @@ show: {
127314
<template>
128315
<div class="grid gap-2">
129316
<Input
317+
type="text"
318+
full-width
130319
:model-value="localValue"
131320
:readonly="readonly"
132321
:placeholder="meta?.placeholder || column.label"
133322
@update:model-value="onInput"
134323
/>
135324
136-
<p v-if="errorMessage" class="text-sm text-red-600">
325+
<p v-if="errorMessage" class="text-sm text-lightInputErrorColor dark:text-darkInputErrorColor">
137326
\{{ errorMessage }}
138327
</p>
139328
140-
<p v-else-if="isEmpty" class="text-sm text-amber-600">
329+
<p v-else-if="isEmpty" class="text-sm text-lightCardDescription dark:text-darkCardDescription">
141330
Value is currently empty
142331
</p>
143332
</div>
144333
</template>
145334
146335
<script setup lang="ts">
147336
import { computed, onMounted, ref } from 'vue';
148-
import Input from '@/afcl/Input.vue';
337+
import { Input } from '@/afcl';
149338
import type {
150339
AdminForthResourceColumnCommon,
151340
AdminForthResourceCommon,
@@ -225,7 +414,7 @@ function syncState() {
225414
226415
```vue
227416
<template>
228-
<div class="flex items-center gap-2">
417+
<div class="flex items-center gap-2 text-lightListTableText dark:text-darkListTableText">
229418
<span>
230419
\{{ meta?.filler?.repeat(record.number_of_rooms || 0) }}
231420
</span>
@@ -337,4 +526,10 @@ options: {
337526
- Prefer simple string declarations until you actually need `meta`.
338527
- Reuse one component with multiple full declarations instead of cloning similar files.
339528
- Keep page injections small unless the layout intentionally becomes page-scrolling.
340-
- Keep custom edit and create components explicit about validity and emptiness if the default input heuristics are not enough.
529+
- Keep custom edit and create components explicit about validity and emptiness if the default input heuristics are not enough.
530+
- Reach for an AFCL component before writing markup; use `lightPrimary`/`darkPrimary` for accents; write
531+
the `dark:` variant in the same edit as the light one. These are defaults for every UI task, not polish
532+
to be added when someone asks for it.
533+
- Stock Tailwind colors are fine for neutrals and semantic states — just never leave one without its
534+
`dark:` counterpart.
535+
- When you are done, re-read your diff against the Dark Theme Self-Check above before reporting completion.

0 commit comments

Comments
 (0)