@mohammadhprp/system-prompt 0.12.2 → 0.12.4
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/framework/commands/README.md +1 -1
- package/framework/commands/review.md +1 -1
- package/framework/mcps/README.md +0 -1
- package/framework/plugins/ponytail/README.md +0 -1
- package/framework/plugins/ponytail/capabilities.md +1 -1
- package/framework/references/standards/api.md +0 -1
- package/framework/references/standards/architecture.md +0 -1
- package/framework/references/standards/database.md +0 -1
- package/framework/references/standards/debugging.md +0 -1
- package/framework/references/standards/documentation.md +0 -1
- package/framework/references/standards/logging.md +0 -1
- package/framework/references/standards/naming.md +0 -1
- package/framework/references/standards/observability.md +0 -1
- package/framework/references/standards/performance.md +0 -1
- package/framework/references/standards/pull-requests.md +0 -1
- package/framework/references/standards/security.md +0 -1
- package/framework/references/standards/testing.md +0 -1
- package/framework/skills/README.md +16 -12
- package/framework/skills/architect/SKILL.md +83 -0
- package/framework/skills/architect/examples.md +5 -0
- package/framework/skills/architect/references/design-red-flags.md +33 -0
- package/framework/skills/architect/references/rationale-template.md +35 -0
- package/framework/skills/architect/references/runner-prompt.md +20 -0
- package/framework/skills/arena/SKILL.md +71 -0
- package/framework/skills/arena/examples.md +5 -0
- package/framework/skills/bro/SKILL.md +7 -0
- package/framework/skills/bro/examples.md +5 -0
- package/framework/skills/changelog/SKILL.md +41 -0
- package/framework/skills/changelog/examples.md +5 -0
- package/framework/skills/commit/SKILL.md +28 -0
- package/framework/skills/commit/examples.md +5 -0
- package/framework/skills/how/SKILL.md +135 -0
- package/framework/skills/how/examples.md +5 -0
- package/framework/skills/how/references/critic-prompt.md +59 -0
- package/framework/skills/how/references/critique-rubric.md +58 -0
- package/framework/skills/how/references/explainer-prompt.md +55 -0
- package/framework/skills/how/references/explorer-prompt.md +52 -0
- package/framework/skills/improve/SKILL.md +1 -3
- package/framework/skills/improve/examples.md +1 -1
- package/framework/skills/laravel-best-practices/SKILL.md +56 -216
- package/framework/skills/laravel-best-practices/references/architecture.md +1 -1
- package/framework/skills/laravel-best-practices/references/checklist.md +139 -0
- package/framework/skills/laravel-best-practices/references/eloquent.md +4 -2
- package/framework/skills/laravel-best-practices/references/infer-conventions.md +97 -0
- package/framework/skills/laravel-best-practices/references/pest-testing.md +47 -18
- package/framework/skills/laravel-best-practices/references/security.md +1 -1
- package/framework/skills/laravel-best-practices/references/style.md +1 -1
- package/framework/skills/laravel-best-practices/references/tailwindcss.md +0 -1
- package/framework/skills/merge-request/SKILL.md +40 -0
- package/framework/skills/merge-request/examples.md +5 -0
- package/framework/skills/pull-request/SKILL.md +31 -0
- package/framework/skills/pull-request/examples.md +5 -0
- package/framework/skills/release/SKILL.md +30 -0
- package/framework/skills/release/examples.md +5 -0
- package/framework/skills/review/SKILL.md +18 -0
- package/framework/skills/review/examples.md +5 -0
- package/framework/skills/tdd/SKILL.md +44 -0
- package/framework/skills/tdd/examples.md +5 -0
- package/framework/skills/unslop/SKILL.md +81 -0
- package/framework/skills/unslop/examples.md +5 -0
- package/framework/skills/why/SKILL.md +230 -0
- package/framework/skills/why/examples.md +5 -0
- package/framework/skills/why/references/epistemics.md +144 -0
- package/framework/skills/why/references/investigator-prompt.md +103 -0
- package/framework/skills/why/references/source-playbook.md +17 -0
- package/framework/skills/why/references/sources/code-archaeology.md +88 -0
- package/framework/skills/why/references/sources/databricks.md +70 -0
- package/framework/skills/why/references/sources/datadog.md +99 -0
- package/framework/skills/why/references/sources/incident-postmortem.md +15 -0
- package/framework/skills/why/references/sources/linear.md +48 -0
- package/framework/skills/why/references/sources/notion.md +55 -0
- package/framework/skills/why/references/sources/sentry.md +100 -0
- package/framework/skills/why/references/sources/slack.md +54 -0
- package/framework/skills/why/references/synthesizer-prompt.md +135 -0
- package/package.json +1 -1
- package/src/catalog.js +13 -12
- package/framework/mcps/notion-mcp/README.md +0 -57
- package/framework/mcps/notion-mcp/capabilities.md +0 -118
- package/framework/mcps/notion-mcp/configs/opencode.json +0 -9
- package/framework/mcps/notion-mcp/install.md +0 -70
- package/framework/mcps/notion-mcp/troubleshooting.md +0 -95
- package/framework/skills/brainstorming/SKILL.md +0 -159
- package/framework/skills/brainstorming/examples.md +0 -49
- package/framework/skills/brainstorming/scripts/frame-template.html +0 -213
- package/framework/skills/brainstorming/scripts/helper.js +0 -167
- package/framework/skills/brainstorming/scripts/server.cjs +0 -723
- package/framework/skills/brainstorming/scripts/start-server.sh +0 -209
- package/framework/skills/brainstorming/scripts/stop-server.sh +0 -120
- package/framework/skills/brainstorming/visual-companion.md +0 -291
- package/framework/skills/code-review/SKILL.md +0 -72
- package/framework/skills/code-review/examples.md +0 -31
- package/framework/skills/codenavi/SKILL.md +0 -306
- package/framework/skills/codenavi/examples.md +0 -33
- package/framework/skills/codenavi/references/coding-principles.md +0 -143
- package/framework/skills/codenavi/references/notebook-spec.md +0 -171
- package/framework/skills/create-adr/SKILL.md +0 -429
- package/framework/skills/create-adr/examples.md +0 -35
- package/framework/skills/design/SKILL.md +0 -399
- package/framework/skills/design/examples.md +0 -34
- package/framework/skills/great-interface/SKILL.md +0 -43
- package/framework/skills/great-interface/references/animations.md +0 -205
- package/framework/skills/great-interface/references/better-accessibility.md +0 -106
- package/framework/skills/great-interface/references/better-colors.md +0 -100
- package/framework/skills/great-interface/references/better-interface.md +0 -132
- package/framework/skills/great-interface/references/better-layout.md +0 -76
- package/framework/skills/great-interface/references/better-typography.md +0 -157
- package/framework/skills/great-interface/references/better-ui.md +0 -107
- package/framework/skills/great-interface/references/better-writing.md +0 -109
- package/framework/skills/great-interface/references/choosing-fonts.md +0 -64
- package/framework/skills/great-interface/references/color-formats.md +0 -90
- package/framework/skills/great-interface/references/color-usage.md +0 -118
- package/framework/skills/great-interface/references/contrast.md +0 -79
- package/framework/skills/great-interface/references/css-cheat-sheet.md +0 -65
- package/framework/skills/great-interface/references/details-and-accessibility.md +0 -119
- package/framework/skills/great-interface/references/enter-exit.md +0 -147
- package/framework/skills/great-interface/references/explain-interface.md +0 -126
- package/framework/skills/great-interface/references/find-the-effect.md +0 -94
- package/framework/skills/great-interface/references/focus-and-keyboard.md +0 -131
- package/framework/skills/great-interface/references/forms.md +0 -84
- package/framework/skills/great-interface/references/from-an-image.md +0 -55
- package/framework/skills/great-interface/references/grouping-and-alignment.md +0 -123
- package/framework/skills/great-interface/references/hit-areas.md +0 -94
- package/framework/skills/great-interface/references/icon-transitions.md +0 -102
- package/framework/skills/great-interface/references/icons.md +0 -110
- package/framework/skills/great-interface/references/interface-review.md +0 -148
- package/framework/skills/great-interface/references/motion-and-zoom.md +0 -79
- package/framework/skills/great-interface/references/no-browser.md +0 -73
- package/framework/skills/great-interface/references/palette-generation.md +0 -104
- package/framework/skills/great-interface/references/palette-structure.md +0 -76
- package/framework/skills/great-interface/references/performance.md +0 -88
- package/framework/skills/great-interface/references/picker.md +0 -76
- package/framework/skills/great-interface/references/read-the-system.md +0 -178
- package/framework/skills/great-interface/references/removed-signals.md +0 -38
- package/framework/skills/great-interface/references/review-format.md +0 -46
- package/framework/skills/great-interface/references/scope-resolution.md +0 -88
- package/framework/skills/great-interface/references/screen-readers.md +0 -101
- package/framework/skills/great-interface/references/semantics-and-aria.md +0 -84
- package/framework/skills/great-interface/references/spacing-and-adaptivity.md +0 -159
- package/framework/skills/great-interface/references/spacing-and-sizing.md +0 -121
- package/framework/skills/great-interface/references/surfaces.md +0 -219
- package/framework/skills/great-interface/references/token-naming.md +0 -97
- package/framework/skills/great-interface/references/variable-fonts-and-opentype.md +0 -105
- package/framework/skills/great-interface/references/variant.md +0 -104
- package/framework/skills/great-interface/references/wrapping-and-punctuation.md +0 -55
- package/framework/skills/learning-opportunities/SKILL.md +0 -140
- package/framework/skills/learning-opportunities/examples.md +0 -34
- package/framework/skills/learning-opportunities/references/PRINCIPLES.md +0 -42
- package/framework/skills/notion-mcp/SKILL.md +0 -57
- package/framework/skills/notion-mcp/examples.md +0 -31
- package/framework/skills/notion-mcp/references/comments.md +0 -112
- package/framework/skills/notion-mcp/references/databases.md +0 -193
- package/framework/skills/notion-mcp/references/pages.md +0 -235
- package/framework/skills/spec-driven-eval/SKILL.md +0 -341
- package/framework/skills/spec-driven-eval/examples.md +0 -35
- package/framework/skills/spec-driven-eval/references/quickstart.md +0 -118
- package/framework/skills/spec-driven-eval/references/reference.md +0 -295
- package/framework/skills/technical-design-doc-creator/README.md +0 -411
- package/framework/skills/technical-design-doc-creator/SKILL.md +0 -1484
- package/framework/skills/technical-design-doc-creator/examples.md +0 -35
- package/framework/skills/web-design-guidelines/SKILL.md +0 -65
- package/framework/skills/web-design-guidelines/examples.md +0 -32
- package/framework/skills/web-design-guidelines/references/guideline.md +0 -174
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
# Forms
|
|
2
|
-
|
|
3
|
-
Labels, autocomplete, error messaging, input types and submit behavior.
|
|
4
|
-
|
|
5
|
-
## Labels
|
|
6
|
-
|
|
7
|
-
Every control needs a programmatic label: `<label for>` pointing at the input's `id`, or a wrapping `<label>`. A placeholder is never a label. It disappears the moment the user types and usually fails contrast.
|
|
8
|
-
|
|
9
|
-
```html
|
|
10
|
-
<!-- Good: explicit association -->
|
|
11
|
-
<label for="email">Email</label>
|
|
12
|
-
<input id="email" type="email" autocomplete="email" />
|
|
13
|
-
|
|
14
|
-
<!-- Good: wrapping label, so label and control share one hit target -->
|
|
15
|
-
<label>
|
|
16
|
-
<input type="checkbox" /> Send me updates
|
|
17
|
-
</label>
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
Label and control share one hit target, so clicking "Send me updates" toggles the checkbox with no dead zone between them. Mark required fields with native `required` plus a visible indicator explained once per form ("* required").
|
|
21
|
-
|
|
22
|
-
A placeholder used *in addition to* a label shows an example of the expected format: `placeholder="name@company.com"`.
|
|
23
|
-
|
|
24
|
-
## Error messaging
|
|
25
|
-
|
|
26
|
-
The complete pattern:
|
|
27
|
-
|
|
28
|
-
```html
|
|
29
|
-
<label for="email">Email</label>
|
|
30
|
-
<input
|
|
31
|
-
id="email"
|
|
32
|
-
type="email"
|
|
33
|
-
autocomplete="email"
|
|
34
|
-
aria-invalid="true"
|
|
35
|
-
aria-describedby="email-error"
|
|
36
|
-
/>
|
|
37
|
-
<p id="email-error">Enter a valid email address.</p>
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
- `aria-invalid="true"` on the failing field, removed once fixed.
|
|
41
|
-
- `aria-describedby` links the field to its inline error so screen readers announce it with the field.
|
|
42
|
-
- Errors render inline beside their fields, with an icon or text. Never a red border alone, which is a color-only cue.
|
|
43
|
-
- On submit, focus the first invalid field.
|
|
44
|
-
- Allow incomplete submission so validation can surface. Never disable submit until valid (see below).
|
|
45
|
-
- Accept free text and validate after. Never block typing or filter characters as the user types. Trim values before validating, because autocomplete and text expansion add trailing spaces.
|
|
46
|
-
|
|
47
|
-
## Autocomplete and input types
|
|
48
|
-
|
|
49
|
-
`autocomplete` with a meaningful `name` fills forms in one tap and is a WCAG requirement (1.3.5) for fields about the user. The common tokens:
|
|
50
|
-
|
|
51
|
-
| Field | `autocomplete` |
|
|
52
|
-
| --- | --- |
|
|
53
|
-
| Name | `name` (or `given-name` / `family-name`) |
|
|
54
|
-
| Email | `email` |
|
|
55
|
-
| Phone | `tel` |
|
|
56
|
-
| Address | `street-address`, `address-line1`, `postal-code`, `country` |
|
|
57
|
-
| Card | `cc-number`, `cc-exp`, `cc-csc`, `cc-name` |
|
|
58
|
-
| Login | `username`, `current-password` |
|
|
59
|
-
| Signup / reset | `new-password` |
|
|
60
|
-
| 2FA code | `one-time-code` |
|
|
61
|
-
|
|
62
|
-
Prefix with a section where relevant: `autocomplete="shipping street-address"`.
|
|
63
|
-
|
|
64
|
-
Correct `type` and `inputmode` pick the right mobile keyboard:
|
|
65
|
-
|
|
66
|
-
| Input | Use |
|
|
67
|
-
| --- | --- |
|
|
68
|
-
| Email, URL, phone | `type="email"`, `type="url"`, `type="tel"` |
|
|
69
|
-
| OTP / PIN / card number | `type="text" inputmode="numeric"` (keeps text semantics, no spinner) |
|
|
70
|
-
| Money, decimals | `type="text" inputmode="decimal"` |
|
|
71
|
-
| True numeric quantity | `type="number"` |
|
|
72
|
-
|
|
73
|
-
Disable spellcheck on emails, codes and usernames: `spellcheck="false"`.
|
|
74
|
-
|
|
75
|
-
## Never fight the user's tools
|
|
76
|
-
|
|
77
|
-
- Stay compatible with password managers and 2FA autofill: real `<form>`, correct `autocomplete`, no fake inputs.
|
|
78
|
-
|
|
79
|
-
## Submit behavior
|
|
80
|
-
|
|
81
|
-
- Keep submit enabled until the request starts, then disable it and show a spinner *beside the original label*. "Save" with a spinner, not a bare spinner. The label is what tells assistive tech which button is busy.
|
|
82
|
-
- Announce results. Success goes through a polite live region. On failure, focus the first invalid field, which is itself the announcement. Reserve `role="alert"` for form-level errors not tied to a field ([screen-readers.md](screen-readers.md)).
|
|
83
|
-
- Warn on unsaved changes before navigation, and never lose typed input to a re-render. Hydration must preserve focus and value.
|
|
84
|
-
- Enter submits from any focused input; in `<textarea>`, ⌘/Ctrl+Enter submits.
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# Reading a screenshot
|
|
2
|
-
|
|
3
|
-
The method for a screenshot, where the answer is a reconstruction rather than a reading. Which property lands in which bucket:
|
|
4
|
-
|
|
5
|
-
| Exact from pixels | Ratios only | Unavailable |
|
|
6
|
-
| --- | --- | --- |
|
|
7
|
-
| Color values | Type sizes | Tokens and their names |
|
|
8
|
-
| Contrast between any two sampled colors | Spacing values | The stack and styling system |
|
|
9
|
-
| Relative proportion of anything measurable | Radii | Breakpoints |
|
|
10
|
-
| Which colors repeat and where | Stroke and border weights | Motion, easing, duration |
|
|
11
|
-
| | | Every state but the captured one |
|
|
12
|
-
|
|
13
|
-
You do not know the capture's scale. A screenshot may be at 1×, 2×, or browser zoom, so a measured 30px could be 15pt of type or 30. Never report a `px` size or spacing from an image alone.
|
|
14
|
-
|
|
15
|
-
One exception. Where the image contains text you can identify as body copy, assume `16px` and express everything as a multiple of it. Say you did, since the assumption may be wrong.
|
|
16
|
-
|
|
17
|
-
## Colors, which are the reliable part
|
|
18
|
-
|
|
19
|
-
Sample the actual pixels rather than describing what you see. Then hand the values to `better-colors`:
|
|
20
|
-
|
|
21
|
-
- Convert each to OKLCH, so lightness is comparable across hues.
|
|
22
|
-
- Sort by lightness to see whether the samples form a ramp and whether steps sit denser at the light end.
|
|
23
|
-
- Check hue constancy across the ramp. A drifting hue means someone picked the ramp by eye.
|
|
24
|
-
- Measure contrast on every foreground and background pair you can isolate. It is exact and the most valuable single number an image gives you.
|
|
25
|
-
- Watch for a tinted neutral. A gray carrying a few percent of the accent hue is a deliberate choice worth naming.
|
|
26
|
-
|
|
27
|
-
## Type, by category not by name
|
|
28
|
-
|
|
29
|
-
You cannot identify a typeface from a screenshot with confidence, so never claim one. You can read its category and features, which is what transfers:
|
|
30
|
-
|
|
31
|
-
- **Category:** geometric sans, grotesque, humanist, transitional serif, slab. Say which and why.
|
|
32
|
-
- **Tells worth naming:** single or double-storey `a` and `g`, terminal angle, aperture, x-height against cap height. Also whether the digits are lining or old-style and whether the figures look tabular.
|
|
33
|
-
- **Scale:** count the distinct sizes. Express them as multiples of the body size and derive the ratio.
|
|
34
|
-
- **Weight contrast:** how many weights and how far apart. Two weights three steps apart reads deliberate, four weights one step apart accidental.
|
|
35
|
-
- **Measure:** count characters on a full line of body copy and compare against `better-typography`'s 60 to 75 range.
|
|
36
|
-
|
|
37
|
-
Where the actual face matters, name the category and suggest identifying it from the live page.
|
|
38
|
-
|
|
39
|
-
## Spacing, as a rhythm
|
|
40
|
-
|
|
41
|
-
Measure in the image, then divide everything by the smallest repeated gap. That quotient set is the rhythm, and it survives not knowing the scale.
|
|
42
|
-
|
|
43
|
-
Then check the ratio `better-layout` owns, the gap between groups against the gap within one. At or above 2, space is carrying the grouping. Below that, something else is, usually a border or a background shape.
|
|
44
|
-
|
|
45
|
-
## Say what the image hid
|
|
46
|
-
|
|
47
|
-
Close by naming what a screenshot could not show, since that is where the reader would otherwise assume you looked:
|
|
48
|
-
|
|
49
|
-
- Hover, focus, active, disabled, loading, empty and error states.
|
|
50
|
-
- Whether anything animates and how.
|
|
51
|
-
- Behavior at any other width.
|
|
52
|
-
- Whether it is keyboard reachable and whether focus is visible.
|
|
53
|
-
- The other appearance, light or dark.
|
|
54
|
-
|
|
55
|
-
Where any of these matter to the reader's question, say that a live URL would answer it and this image cannot.
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
# Grouping and alignment
|
|
2
|
-
|
|
3
|
-
How spacing, shapes, shared edges and ordering communicate what belongs together and what matters most.
|
|
4
|
-
|
|
5
|
-
## Group with space, not lines
|
|
6
|
-
|
|
7
|
-
Three tools create grouping, in order of preference:
|
|
8
|
-
|
|
9
|
-
1. **Negative space**, the default. Related items sit close, unrelated ones far apart.
|
|
10
|
-
2. **Background shapes**, a card or filled container, where a group must read as one unit such as a selectable row or a draggable card.
|
|
11
|
-
3. **Separator lines**, a last resort for dense data where space costs too much, such as tables and long settings lists.
|
|
12
|
-
|
|
13
|
-
The structural rule is that the gap between groups is at least 2× the gap within one. At `8px` inside a group, groups need `16px`+ between them, or the eye can't tell where one ends.
|
|
14
|
-
|
|
15
|
-
```css
|
|
16
|
-
/* Good: spacing alone communicates the grouping */
|
|
17
|
-
.field-group { display: flex; flex-direction: column; gap: 8px; }
|
|
18
|
-
.form { display: flex; flex-direction: column; gap: 24px; }
|
|
19
|
-
|
|
20
|
-
/* Bad: uniform spacing plus lines to compensate */
|
|
21
|
-
.form > * { margin-bottom: 12px; border-bottom: 1px solid var(--separator); }
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
```html
|
|
25
|
-
<!-- Good: Tailwind -->
|
|
26
|
-
<div class="space-y-6">
|
|
27
|
-
<div class="space-y-2">…field group…</div>
|
|
28
|
-
<div class="space-y-2">…field group…</div>
|
|
29
|
-
</div>
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
Where a separator is genuinely needed, keep it quiet: hairline width, low contrast, never combined with a large gap that already did the job.
|
|
33
|
-
|
|
34
|
-
## Keep controls distinct from content
|
|
35
|
-
|
|
36
|
-
Interactive elements need a visual signal: a background, a border, an underline, or placement in a consistent control zone such as a toolbar or footer row. A control styled identically to static text is invisible.
|
|
37
|
-
|
|
38
|
-
```html
|
|
39
|
-
<!-- Bad: action looks exactly like the description text next to it -->
|
|
40
|
-
<p class="text-zinc-600">Your trial ends soon. Upgrade now</p>
|
|
41
|
-
|
|
42
|
-
<!-- Good: the action reads as an action -->
|
|
43
|
-
<p class="text-zinc-600">Your trial ends soon.</p>
|
|
44
|
-
<button class="font-medium text-blue-600">Upgrade now</button>
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
The inverse holds too. A non-clickable badge shaped exactly like the buttons beside it collects dead clicks.
|
|
48
|
-
|
|
49
|
-
## Align to shared edges
|
|
50
|
-
|
|
51
|
-
Pick a small set of alignment edges and put everything on them, because the eye tracks straight edges to scan content.
|
|
52
|
-
|
|
53
|
-
- Every stray edge reads as noise even when nobody can name it: an icon 2px off the text edge, a card padded unlike its neighbor.
|
|
54
|
-
- Use one project spacing step to express hierarchy. `16px` is a useful default where no scale exists, and deeper nesting repeats the same step.
|
|
55
|
-
- Numbers in tables align to the trailing edge, text to the leading edge. Tabular figures are `better-typography`'s.
|
|
56
|
-
|
|
57
|
-
```css
|
|
58
|
-
/* Good: one shared leading edge, one indent step */
|
|
59
|
-
.section { padding-inline: 24px; }
|
|
60
|
-
.section .child { margin-inline-start: 16px; }
|
|
61
|
-
|
|
62
|
-
/* Bad: three unrelated leading edges in one column */
|
|
63
|
-
.header { padding-inline-start: 20px; }
|
|
64
|
-
.list-item { padding-inline-start: 14px; }
|
|
65
|
-
.footer { padding-inline-start: 24px; }
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## Logical properties, not physical
|
|
69
|
-
|
|
70
|
-
Express direction-dependent horizontal position as leading/trailing so the layout mirrors automatically under `dir="rtl"`:
|
|
71
|
-
|
|
72
|
-
| Physical (avoid) | Logical (use) |
|
|
73
|
-
| --- | --- |
|
|
74
|
-
| `margin-left` | `margin-inline-start` |
|
|
75
|
-
| `padding-right` | `padding-inline-end` |
|
|
76
|
-
| `left: 0` | `inset-inline-start: 0` |
|
|
77
|
-
| `text-align: left` | `text-align: start` |
|
|
78
|
-
| `border-right` | `border-inline-end` |
|
|
79
|
-
|
|
80
|
-
```html
|
|
81
|
-
<!-- Good: Tailwind logical utilities -->
|
|
82
|
-
<div class="ms-4 pe-6 text-start">…</div>
|
|
83
|
-
|
|
84
|
-
<!-- Bad: breaks in RTL -->
|
|
85
|
-
<div class="ml-4 pr-6 text-left">…</div>
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
Reserve physical properties for things that refer to physical screen sides whatever the language, such as positioning against a device notch or matching a gesture direction.
|
|
89
|
-
|
|
90
|
-
Where arrangement encodes progression, as in star ratings, step indicators and progress bars, the sequence mirrors in RTL and stars fill from the trailing side. Flexbox and grid with logical properties mirror automatically; hand-positioned elements do not. Digit order inside numbers never reverses, which with other bidi rules belongs to `better-typography`.
|
|
91
|
-
|
|
92
|
-
## Order by importance
|
|
93
|
-
|
|
94
|
-
Readers scan top-to-bottom and leading-to-trailing. Place content accordingly:
|
|
95
|
-
|
|
96
|
-
- The most important information sits near the top and the leading edge. The further down and trailing something sits, the less attention it gets.
|
|
97
|
-
- Give essential information room. Never bury the one number the user came for under rows of secondary detail. Push that into collapsed sections, tabs, or detail views.
|
|
98
|
-
- Within a row, identifying content leads and metadata and actions trail.
|
|
99
|
-
|
|
100
|
-
```html
|
|
101
|
-
<!-- Good: primary fact first, detail demoted -->
|
|
102
|
-
<div>
|
|
103
|
-
<p class="text-2xl font-semibold">$4,320.00</p>
|
|
104
|
-
<p class="text-sm text-zinc-500">Available balance</p>
|
|
105
|
-
</div>
|
|
106
|
-
|
|
107
|
-
<!-- Bad: the key fact is buried below the fold of the card -->
|
|
108
|
-
<div>
|
|
109
|
-
<p class="text-sm">Account 4402 · Opened 2019 · Standard tier</p>
|
|
110
|
-
<p class="text-sm">Last statement: June 30</p>
|
|
111
|
-
<p class="text-sm">Balance: $4,320.00</p>
|
|
112
|
-
</div>
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
With logical properties, the same hierarchy mirrors correctly in RTL locales.
|
|
116
|
-
|
|
117
|
-
## Don't overload the entry point
|
|
118
|
-
|
|
119
|
-
The first screenful is a table of contents, not the whole book. If everything is prominent, nothing is:
|
|
120
|
-
|
|
121
|
-
- One primary action per view. `better-colors` owns how color enforces it.
|
|
122
|
-
- Group secondary actions behind a menu once they exceed two or three.
|
|
123
|
-
- Prefer a short view that links deeper over a long view that shows everything at level one.
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
# Hit areas
|
|
2
|
-
|
|
3
|
-
Target sizes, expanding hit areas without changing visual size and collision rules.
|
|
4
|
-
|
|
5
|
-
## Target sizes
|
|
6
|
-
|
|
7
|
-
Separate the conformance baseline from larger usability targets:
|
|
8
|
-
|
|
9
|
-
| Standard | Minimum |
|
|
10
|
-
| --- | --- |
|
|
11
|
-
| WCAG 2.5.8 (AA) | 24×24px, the hard floor |
|
|
12
|
-
| WCAG 2.5.5 (AAA) | 44×44px |
|
|
13
|
-
| Apple HIG | 44×44pt |
|
|
14
|
-
| Material Design | 48×48dp |
|
|
15
|
-
|
|
16
|
-
WCAG 2.5.8 Level AA requires a 24×24 CSS-pixel target or one of its exceptions. Treat 44px as the recommended touch target for primary controls and 40px as a useful desktop target where density permits. Smaller controls are not automatic failures. Check the spacing, equivalent-control, inline, user-agent and essential exceptions before reporting one.
|
|
17
|
-
|
|
18
|
-
Under the spacing exception, an undersized target passes when a 24px circle centered on its bounding box intersects no other target and no other undersized target's circle. In the simple case, 20px targets need a 4px gap.
|
|
19
|
-
|
|
20
|
-
The visible element can stay small; the hit area is what must be big. Anything that looks clickable must be clickable across its whole visual extent, with no dead zones. A checkbox and its label share one hit target.
|
|
21
|
-
|
|
22
|
-
## Expanding the hit area
|
|
23
|
-
|
|
24
|
-
Where the visible element is smaller, say a 20×20 checkbox, extend the hit area with a pseudo-element. Put it on the wrapping `<label>` or `<button>`, never on the `<input>`, because replaced elements don't render `::before`/`::after` reliably.
|
|
25
|
-
|
|
26
|
-
### CSS example
|
|
27
|
-
|
|
28
|
-
```css
|
|
29
|
-
/* Small checkbox with expanded 44px hit area, on the wrapping label */
|
|
30
|
-
.checkbox-label {
|
|
31
|
-
position: relative;
|
|
32
|
-
width: 20px;
|
|
33
|
-
height: 20px;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
.checkbox-label::after {
|
|
37
|
-
content: "";
|
|
38
|
-
position: absolute;
|
|
39
|
-
top: 50%;
|
|
40
|
-
left: 50%; /* physical centering: direction-independent */
|
|
41
|
-
transform: translate(-50%, -50%);
|
|
42
|
-
width: 44px;
|
|
43
|
-
height: 44px;
|
|
44
|
-
}
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### Tailwind example
|
|
48
|
-
|
|
49
|
-
```tsx
|
|
50
|
-
<button className="relative size-5 after:absolute after:top-1/2 after:left-1/2 after:size-11 after:-translate-1/2">
|
|
51
|
-
<CheckIcon />
|
|
52
|
-
</button>
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### Layout alternative
|
|
56
|
-
|
|
57
|
-
Where the element can afford real box size, skip the pseudo-element and let the box be the target. That hands the browser real geometry for scrolling and gestures:
|
|
58
|
-
|
|
59
|
-
```css
|
|
60
|
-
.icon-button {
|
|
61
|
-
min-width: 44px;
|
|
62
|
-
min-height: 44px;
|
|
63
|
-
display: inline-grid;
|
|
64
|
-
place-items: center;
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## Collision rule
|
|
69
|
-
|
|
70
|
-
Where the extended hit area overlaps another interactive element, shrink the pseudo-element to the largest size that does not collide. Two interactive elements never have overlapping hit areas.
|
|
71
|
-
|
|
72
|
-
## Decorative layers
|
|
73
|
-
|
|
74
|
-
A decorative layer painted over interactive content absorbs every pointer event its box covers: a gradient scrim, a glow, a blurred sheen, a full-bleed `::after`. The control underneath looks live and does nothing, and no hit-area sizing fixes it.
|
|
75
|
-
|
|
76
|
-
Give each one `pointer-events: none` (Tailwind `pointer-events-none`) so events reach the control below, plus `aria-hidden="true"` to keep it out of the accessibility tree:
|
|
77
|
-
|
|
78
|
-
```css
|
|
79
|
-
.card-glow {
|
|
80
|
-
position: absolute;
|
|
81
|
-
inset: 0;
|
|
82
|
-
pointer-events: none;
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
Keep pointer events on any layer the user is meant to hit: a modal scrim that dismisses on click is a control, not decoration.
|
|
87
|
-
|
|
88
|
-
## Touch behavior
|
|
89
|
-
|
|
90
|
-
- Add `touch-action: manipulation` to interactive elements to remove the double-tap-to-zoom delay on mobile.
|
|
91
|
-
- Set `touch-action: none` on a surface implementing its own pan, zoom, or drag gestures, so the browser stops claiming them for scrolling and pinch-zoom. Scope it to that surface; at page level it removes scrolling.
|
|
92
|
-
- Set `-webkit-tap-highlight-color` to match the design instead of the default gray flash.
|
|
93
|
-
- Put hover-only styling behind `@media (hover: hover)`. On touch, `:hover` latches after a tap and holds until the user taps elsewhere, so it reads as a stuck selected state. Tailwind 4's `hover:` variant already compiles under this query.
|
|
94
|
-
- Prefer generous targets and clear affordances over finicky interactions such as tiny drag handles and precise hover zones.
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
# Icon transitions
|
|
2
|
-
|
|
3
|
-
Cross-fading an icon when it changes contextually or by state, with and without a motion library. Icon weight, color and direction live in [icons.md](icons.md).
|
|
4
|
-
|
|
5
|
-
## Contextual icon animations
|
|
6
|
-
|
|
7
|
-
When icons appear or disappear contextually, on hover or a state change, animate them with `opacity`, `scale` and `blur` rather than toggling visibility.
|
|
8
|
-
|
|
9
|
-
### Motion example
|
|
10
|
-
|
|
11
|
-
This uses the `motion` package. Where the project has `framer-motion`, import the same APIs from `"framer-motion"`. Never mix an installed package with the other's import path.
|
|
12
|
-
|
|
13
|
-
```tsx
|
|
14
|
-
import { AnimatePresence, motion } from "motion/react";
|
|
15
|
-
|
|
16
|
-
function IconButton({ isActive, icon: Icon }) {
|
|
17
|
-
return (
|
|
18
|
-
<button>
|
|
19
|
-
<AnimatePresence mode="popLayout">
|
|
20
|
-
<motion.span
|
|
21
|
-
key={isActive ? "active" : "inactive"}
|
|
22
|
-
initial={{ opacity: 0, scale: 0.25, filter: "blur(4px)" }}
|
|
23
|
-
animate={{ opacity: 1, scale: 1, filter: "blur(0px)" }}
|
|
24
|
-
exit={{ opacity: 0, scale: 0.25, filter: "blur(4px)" }}
|
|
25
|
-
transition={{ type: "spring", duration: 0.3, bounce: 0 }}
|
|
26
|
-
>
|
|
27
|
-
<Icon />
|
|
28
|
-
</motion.span>
|
|
29
|
-
</AnimatePresence>
|
|
30
|
-
</button>
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
### CSS transition approach (no Motion)
|
|
36
|
-
|
|
37
|
-
Without Motion or Framer Motion, keep both icons in the DOM and cross-fade with CSS transitions. Neither unmounts, so enter and exit both animate smoothly.
|
|
38
|
-
|
|
39
|
-
One icon is absolutely positioned on top of the other. Toggling state cross-fades them, the entering icon scaling up from `0.25` while the exiting one scales down to `0.25`, both with opacity and blur.
|
|
40
|
-
|
|
41
|
-
```tsx
|
|
42
|
-
function IconButton({ isActive, ActiveIcon, InactiveIcon }) {
|
|
43
|
-
return (
|
|
44
|
-
<button>
|
|
45
|
-
<div className="relative">
|
|
46
|
-
<div
|
|
47
|
-
className={cn(
|
|
48
|
-
"absolute inset-0 flex items-center justify-center",
|
|
49
|
-
"transition-[opacity,filter,scale] duration-300",
|
|
50
|
-
"ease-[cubic-bezier(0.2,0,0,1)]",
|
|
51
|
-
isActive
|
|
52
|
-
? "scale-100 opacity-100 blur-0"
|
|
53
|
-
: "scale-[0.25] opacity-0 blur-[4px]"
|
|
54
|
-
)}
|
|
55
|
-
>
|
|
56
|
-
<ActiveIcon />
|
|
57
|
-
</div>
|
|
58
|
-
<div
|
|
59
|
-
className={cn(
|
|
60
|
-
"transition-[opacity,filter,scale] duration-300",
|
|
61
|
-
"ease-[cubic-bezier(0.2,0,0,1)]",
|
|
62
|
-
isActive
|
|
63
|
-
? "scale-[0.25] opacity-0 blur-[4px]"
|
|
64
|
-
: "scale-100 opacity-100 blur-0"
|
|
65
|
-
)}
|
|
66
|
-
>
|
|
67
|
-
<InactiveIcon />
|
|
68
|
-
</div>
|
|
69
|
-
</div>
|
|
70
|
-
</button>
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
The non-absolute icon, `InactiveIcon`, defines the layout size. The absolute one, `ActiveIcon`, overlays it without affecting flow.
|
|
76
|
-
|
|
77
|
-
### Choosing between Motion and CSS
|
|
78
|
-
|
|
79
|
-
| | Motion (Framer Motion) | CSS transitions (both icons in DOM) |
|
|
80
|
-
| --- | --- | --- |
|
|
81
|
-
| **Enter animation** | Yes | Yes |
|
|
82
|
-
| **Exit animation** | Yes (via `AnimatePresence`) | Yes (cross-fade, icon never unmounts) |
|
|
83
|
-
| **Spring physics** | Yes | No, use `cubic-bezier(0.2, 0, 0, 1)` as approximation |
|
|
84
|
-
| **When to use** | Project already uses `motion` or `framer-motion` | No motion dependency, or keeping bundle small |
|
|
85
|
-
|
|
86
|
-
Check the project's `package.json`. Import from `"motion/react"` when `motion` is installed, or `"framer-motion"` when that is. Where both exist, follow the imports the component or its nearest peers already use. Where neither is present, use the CSS cross-fade and never add a dependency just for icon transitions.
|
|
87
|
-
|
|
88
|
-
### When to animate icons
|
|
89
|
-
|
|
90
|
-
| Animate | Don't animate |
|
|
91
|
-
| --- | --- |
|
|
92
|
-
| Icons that appear on hover (action buttons) | Static navigation icons |
|
|
93
|
-
| State change icons (play → pause, like → liked) | Decorative icons |
|
|
94
|
-
| Icons in contextual toolbars | Icons that are always visible |
|
|
95
|
-
| Loading/success state indicators | Icon labels (text next to icon) |
|
|
96
|
-
|
|
97
|
-
Use exactly these values for contextual icon animations. Do not deviate:
|
|
98
|
-
- `scale`: `0.25` → `1` (never use `0.5` or `0.6`)
|
|
99
|
-
- `opacity`: `0` → `1`
|
|
100
|
-
- `filter`: `"blur(4px)"` → `"blur(0px)"`
|
|
101
|
-
- `transition`: `{ type: "spring", duration: 0.3, bounce: 0 }`; **bounce must always be `0`**, never `0.1` or any other value
|
|
102
|
-
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
# Icons
|
|
2
|
-
|
|
3
|
-
Icon weight, states, sizing and direction, the details that make icons sit naturally in an interface.
|
|
4
|
-
|
|
5
|
-
## Match icon stroke to text weight
|
|
6
|
-
|
|
7
|
-
A hairline icon beside semibold text reads as broken; a heavy icon beside regular text shouts.
|
|
8
|
-
|
|
9
|
-
| Adjacent text | Icon stroke width (24px grid) |
|
|
10
|
-
| --- | --- |
|
|
11
|
-
| Regular (400), 14–16px | `1.5px` |
|
|
12
|
-
| Medium/Semibold (500–600) | `2px` |
|
|
13
|
-
| Bold (700), or emphasized standalone | `2.5px` |
|
|
14
|
-
|
|
15
|
-
```html
|
|
16
|
-
<!-- Good: stroke tuned to the label weight -->
|
|
17
|
-
<button class="flex items-center gap-2 font-semibold">
|
|
18
|
-
<PlusIcon stroke-width="2" class="size-4" />
|
|
19
|
-
New project
|
|
20
|
-
</button>
|
|
21
|
-
|
|
22
|
-
<!-- Bad: default 1.5px stroke against a bold label -->
|
|
23
|
-
<button class="flex items-center gap-2 font-bold">
|
|
24
|
-
<PlusIcon stroke-width="1.5" class="size-4" />
|
|
25
|
-
New project
|
|
26
|
-
</button>
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
Two related consistency rules:
|
|
30
|
-
|
|
31
|
-
- **One optical strategy per surface.** Never mix icon libraries with incompatible stroke conventions on one toolbar. Where the library supports stroke variants, match them to adjacent text as above; otherwise keep the set's native stroke and use size or color for emphasis.
|
|
32
|
-
- **Size icons relative to the text's cap height**, typically `1em`–`1.25em` when inline with text, so the pair scales together.
|
|
33
|
-
|
|
34
|
-
## One SVG, recolored per state
|
|
35
|
-
|
|
36
|
-
Never ship separate assets for default, hover, selected and disabled states. Use one SVG drawn with `currentColor` and let CSS state drive the color:
|
|
37
|
-
|
|
38
|
-
```html
|
|
39
|
-
<!-- Good: one asset, states are CSS -->
|
|
40
|
-
<svg fill="none" stroke="currentColor" stroke-width="2">…</svg>
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
```css
|
|
44
|
-
.icon-button { color: oklch(0.552 0.016 285.938); }
|
|
45
|
-
.icon-button:hover { color: oklch(0.21 0.006 285.885); }
|
|
46
|
-
.icon-button[aria-pressed="true"] { color: oklch(0.623 0.188 259.815); }
|
|
47
|
-
.icon-button:disabled { opacity: 0.4; }
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
```html
|
|
51
|
-
<!-- Tailwind -->
|
|
52
|
-
<button class="text-zinc-500 hover:text-zinc-900 aria-pressed:text-blue-600 disabled:opacity-40">
|
|
53
|
-
<BookmarkIcon />
|
|
54
|
-
</button>
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Hardcoded fills inside the SVG, such as `fill="#666"`, break this. Strip them to `currentColor` when importing icons.
|
|
58
|
-
|
|
59
|
-
## Outline default, fill active
|
|
60
|
-
|
|
61
|
-
Where an icon set offers outline and filled variants, use them as a state pair, never interchangeably:
|
|
62
|
-
|
|
63
|
-
| Variant | Use for |
|
|
64
|
-
| --- | --- |
|
|
65
|
-
| Outline | Default state: toolbars, list rows, inline with text |
|
|
66
|
-
| Fill | Selected/active state: the active tab, a toggled bookmark, a liked heart |
|
|
67
|
-
|
|
68
|
-
```tsx
|
|
69
|
-
// Good: variant communicates state
|
|
70
|
-
<TabIcon variant={isActive ? "solid" : "outline"} />
|
|
71
|
-
|
|
72
|
-
// Bad: filled icons everywhere, so the active tab has no state signal
|
|
73
|
-
<TabIcon variant="solid" />
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
The swap between variants is a contextual icon animation. Use the exact cross-fade values in [icon-transitions.md](icon-transitions.md).
|
|
77
|
-
|
|
78
|
-
## Design at render size
|
|
79
|
-
|
|
80
|
-
An icon that looks great at 48px collapses into mush at 16px. Thin interior lines, tight counters and fine texture all blur or alias when small.
|
|
81
|
-
|
|
82
|
-
- Test every icon at the smallest size it will render, often `16px`. It must stay recognizable there.
|
|
83
|
-
- Prefer simplified glyphs for small contexts over scaling down detailed artwork.
|
|
84
|
-
- Keep icons on the pixel grid at their render size. A 16px icon drawn on a 24px grid with fractional scaling renders soft, so use the set's native grid sizes (`16`, `20`, `24`) rather than arbitrary scales.
|
|
85
|
-
- Always SVG, never raster, so the same asset stays crisp at every density.
|
|
86
|
-
|
|
87
|
-
## Icons in RTL
|
|
88
|
-
|
|
89
|
-
Under `dir="rtl"`, flip icons whose meaning is tied to reading direction, and leave the rest alone:
|
|
90
|
-
|
|
91
|
-
| Flip | Don't flip |
|
|
92
|
-
| --- | --- |
|
|
93
|
-
| Back/forward arrows, chevrons in navigation | Logos and brand marks |
|
|
94
|
-
| Text-block glyphs (alignment, lists, indent) | Checkmarks |
|
|
95
|
-
| Speaker/volume waves (emanate in reading direction) | Physical objects: clocks, cups, pencils |
|
|
96
|
-
| "Send" style directional glyphs | Media playback (play/rewind refer to tape direction, convention keeps them LTR) |
|
|
97
|
-
|
|
98
|
-
```css
|
|
99
|
-
/* Good: mirror only direction-dependent icons */
|
|
100
|
-
[dir="rtl"] .icon-directional {
|
|
101
|
-
scale: -1 1;
|
|
102
|
-
}
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
```html
|
|
106
|
-
<!-- Tailwind -->
|
|
107
|
-
<ChevronRightIcon class="icon-directional rtl:-scale-x-100" />
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
Analyze composite icons part by part. A badge or slash overlay may keep its position even when the base glyph flips. Accessible names for icon-only buttons belong to `better-accessibility`.
|