@uidu/skills 0.4.0 → 0.5.0

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 CHANGED
@@ -14,9 +14,10 @@ Replace `claude-code` with your agent of choice (`cursor`, `copilot`, `windsurf`
14
14
 
15
15
  ## Available skills
16
16
 
17
- | Skill | Description |
18
- |---|---|
19
- | `uidu` | Comprehensive guide to the uidu SDK — package map, env setup, fetch patterns for CMS pages, events, stories, donations, help center, and forms, plus RichText rendering and scaffolding via `create-uidu-app`. |
17
+ | Skill | Description |
18
+ | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
19
+ | `uidu` | Comprehensive guide to the uidu SDK — package map, env setup, fetch patterns for CMS pages, events, stories, donations, help center, and forms, plus RichText rendering and scaffolding via `create-uidu-app`. |
20
+ | `uidu-design` | How an app framed inside uidu (a custom app) should look: uidu's tokens and components, layout inside the iframe, states, icons. Ships inside the `custom-app` template, so the app builder's agent has it too. |
20
21
 
21
22
  More skills will be split out from `uidu` as individual areas grow.
22
23
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uidu/skills",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Agent skills for the uidu SDK — installable via the open agent skills ecosystem (skills.sh).",
5
5
  "license": "MIT",
6
6
  "author": "uidu",
@@ -164,7 +164,7 @@ export function Bookings() {
164
164
  }
165
165
  ```
166
166
 
167
- `app.context` carries `user`, `space`, `workspaceApp`, `locale` and `theme`. Outside React: `connect()` from
167
+ `app.context` carries `user`, `space`, `workspaceApp`, `locale`, `theme` and `accent` (the page's colour, to set as `--primary`). Outside React: `connect()` from
168
168
  `@uidu/app-bridge`, then `createClient(fromBridge(bridge))` from `@uidu/client`. Start a new
169
169
  one with `npm create uidu-app@latest my-app -- -t custom-app`: it declares its Models in
170
170
  `public/uidu.app.json` and sets `frame-ancestors` so only uidu can frame it.
@@ -0,0 +1,136 @@
1
+ ---
2
+ name: uidu-design
3
+ description: Use when building or restyling the UI of an app that runs inside uidu (a custom app framed in a Space or workspace, including one made in the uidu app builder) — layout, components, colours, typography, empty and loading states. Makes the app look like the uidu page around it instead of a patch sewn on.
4
+ license: MIT
5
+ metadata:
6
+ author: uidu
7
+ version: '0.1.0'
8
+ ---
9
+
10
+ # Looking like uidu
11
+
12
+ A custom app is an iframe in the middle of a uidu page. Above it sits uidu's header, with
13
+ the app's name and its buttons; around it, uidu's sidebar. Whatever the app draws has those
14
+ on every side, so the only good outcome is an app that reads as one more uidu page.
15
+
16
+ That is mostly already done for you. The template ships **uidu's own tokens**
17
+ (`src/app/globals.css`) and **uidu's own components** (`src/components/ui/`), generated from
18
+ uidu's source. The rules below are about not undoing it.
19
+
20
+ ## 1. Use the kit, don't restyle it
21
+
22
+ - Build from `src/components/ui/*`: `Button`, `Input`, `Field`, `Select`, `Checkbox`,
23
+ `Switch`, `Textarea`, `Table`, `Tabs`, `Dialog`, `Sheet`, `DropdownMenu`, `Popover`,
24
+ `Tooltip`, `Badge`, `Alert`, `Empty`, `Skeleton`, `Spinner`, `Item`, `Card`, `Calendar`,
25
+ `Toaster` (`toast()` from `sonner`)…
26
+ - A `<button>`, `<input>`, `<table>` or `<select>` written by hand is almost always a
27
+ component you didn't import. A `<div className="rounded-lg border p-4">` is a `Card`, a
28
+ coloured pill is a `Badge`, a status line is an `Alert`.
29
+ - Don't edit the files in `src/components/ui/`: they are regenerated from uidu. Compose them,
30
+ and pass `className` for layout (margins, width, flex), not for colour or size.
31
+ - Need one that isn't there? `npx shadcn add @uidu/<name>` works where the network allows it
32
+ (not in the builder's sandbox). Otherwise build it from the ones you have.
33
+
34
+ ## 2. Colours are tokens, never a palette
35
+
36
+ Only the semantic classes, which flip with uidu's light/dark theme:
37
+
38
+ | For | Use |
39
+ | -------------------------------------------------- | ------------------------------------------------------------- |
40
+ | page, text | `bg-background`, `text-foreground` |
41
+ | secondary text, captions, labels | `text-muted-foreground` |
42
+ | panels, popovers | `bg-card`, `bg-popover` (usually via `Card`, `Popover`) |
43
+ | hover, selected row | `bg-accent`, `hover:bg-accent` |
44
+ | subtle fill (a weekend, a disabled row) | `bg-muted` |
45
+ | the app's accent (main button, active item, links) | `bg-primary`, `text-primary` |
46
+ | error, destructive action | `text-destructive`, `bg-destructive/10` |
47
+ | done / needs attention / neutral info | `text-success`, `text-warning`, `text-info` (and `/10` fills) |
48
+ | lines | `border` (already the right colour), `divide-y` |
49
+ | charts | `bg-chart-1` … `bg-chart-5`, `var(--chart-1)` |
50
+
51
+ Never `text-gray-*`, `bg-white`, `text-black`, `bg-blue-500`, `text-red-600`, a hex value or
52
+ an inline `style={{ color }}`: they don't follow the theme, and in dark mode they break.
53
+ `--primary` is the page's accent: uidu sends it (`context.accent`, set by
54
+ `app-provider.tsx`), so it changes with the workspace and the app. Don't set it yourself,
55
+ and don't add a brand colour of your own — `bg-primary` already is one.
56
+
57
+ ## 3. Typography: uidu's density
58
+
59
+ - Body text is `text-sm` (14px): paragraphs, table cells, list items, form fields.
60
+ - `text-base` only for emphasis: the figure a card is about, a record's name.
61
+ - `text-xs` is rare: counters, hints.
62
+ - Headings inside the app are `text-sm font-semibold` (a section) or `text-base
63
+ font-semibold` at most. No `text-2xl` hero titles: this is a tool, not a landing page.
64
+ - A label never outweighs its value: label `text-sm text-muted-foreground`, value
65
+ `font-medium`.
66
+ - The font is Inter, set in `layout.tsx`. Don't load another one.
67
+
68
+ ## 4. Layout: fill the frame, don't frame it again
69
+
70
+ - **No title that repeats the app's name.** uidu's header already shows it. If the page needs
71
+ a bar, make it a toolbar: `flex h-14 shrink-0 items-center justify-between gap-2 border-b
72
+ px-4` with context (a count, a filter, a period) on the left and actions on the right.
73
+ - **No second navigation shell**: no sidebar, no top nav, no footer, no logo. For a few views
74
+ use `Tabs` in the toolbar; for a detail, a `Sheet` or a `Dialog`.
75
+ - **Edge to edge.** The page fills the iframe (`flex min-h-screen flex-col`): no centred
76
+ `max-w-2xl` column with a card floating in it, no outer margin. Content is inset `px-4`
77
+ (16px), the same as uidu's header above, so their left edges line up.
78
+ - Sections are separated by `border-b`, not by stacking cards with gaps. Use `Card` for a
79
+ real sub-surface (one card per related thing), never a card inside a card.
80
+ - **No dead space.** When the data is short, the empty area is filled by an `Empty` state
81
+ (it grows with `flex-1`) or the page ends where the data ends. Never leave the bottom
82
+ third of the frame blank.
83
+ - Spacing on Tailwind's scale (`gap-2`, `gap-3`, `p-4`, `px-4`); no `px-[13px]`.
84
+
85
+ ## 5. Data
86
+
87
+ - Rows of things are a `Table` (`TableHeader`/`TableHead`/`TableBody`/`TableRow`/`TableCell`),
88
+ with `pl-4` on the first column and `pr-4` on the last, to align with the toolbar.
89
+ - A table that scrolls keeps its header visible: bound the table's own container with
90
+ `containerClassName="h-full overflow-y-auto"` and make the `TableHead`s `sticky top-0
91
+ bg-background`. Wrapping the table in your own scroller does not work.
92
+ - Dates and numbers through `Intl` with `context.locale` (`toLocaleString(locale)`,
93
+ `Intl.NumberFormat(locale, …)`), never hand-formatted.
94
+ - A thing that spans several days or columns is **one** element across them, not one per cell.
95
+
96
+ ## 6. States
97
+
98
+ Every screen has four, and each has a shape:
99
+
100
+ | State | Shape |
101
+ | -------------------- | ----------------------------------------------------------------------------------------------------------- |
102
+ | connecting / loading | `Skeleton`s shaped like the content (rows, a card) — not a centred spinner, not "Loading…" text alone |
103
+ | empty | `Empty` with an icon (`EmptyMedia variant="icon"`), a title, one sentence and, if there is one, the action |
104
+ | error | `Alert variant="destructive"` near what failed, with what to do; a failed write keeps what the person typed |
105
+ | saving | the button stays, disabled, with a `Spinner` inside; `toast()` for a result that lands elsewhere |
106
+
107
+ ## 7. Icons
108
+
109
+ - `lucide-react` only, imported by name: `import { Plus } from 'lucide-react'`.
110
+ - Inside a component (`Button`, `DropdownMenuItem`, `Badge`, `Alert`, `EmptyMedia`…) write
111
+ `<Plus />` with **no** `size-*` class: the component sizes it. Elsewhere `size-4`.
112
+ - Never change `strokeWidth`. Colour with `text-*` tokens.
113
+ - An icon-only button is `variant="ghost" size="icon"` with an `aria-label`, and the icon
114
+ `aria-hidden="true"`.
115
+
116
+ ## 8. Accessible by default
117
+
118
+ - Every field has a label (`Field` + `FieldLabel htmlFor`), every icon-only button an
119
+ `aria-label`.
120
+ - Actions are buttons, navigation is links; nothing clickable is a `<div onClick>`.
121
+ - Messages that appear after an action (`Alert`, a saved state) are announced: `role="alert"`
122
+ for errors, `aria-live="polite"` for the rest.
123
+ - Motion stays small (the components' own); spatial animations get `motion-safe:`.
124
+
125
+ ## 9. Words
126
+
127
+ - Short, plain, in the person's language (`context.locale`); sentence case ("New booking",
128
+ not "New Booking").
129
+ - Say what happened and what to do next, not an error code.
130
+
131
+ ## Before you finish
132
+
133
+ Run `npm run check`: it type-checks and flags raw palette colours, hex values, hand-written
134
+ `<button>`/`<input>`/`<table>`, other icon sets and `strokeWidth`. Fix what it reports.
135
+ Then look at the page in dark mode too: if something is invisible or glaring there, it is
136
+ using a colour instead of a token.
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "uidu-design",
3
+ "version": "0.1.0",
4
+ "author": "uidu",
5
+ "license": "MIT",
6
+ "homepage": "https://developers.uidu.org",
7
+ "repository": "https://github.com/uidu-org/api.js/tree/main/packages/skills/skills/uidu-design"
8
+ }