@tamsensedev/runner 0.0.0-stage → 0.1.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/LICENSE +5 -0
- package/README.md +45 -2
- package/dist/cli.js +2234 -0
- package/dist/cli.js.map +1 -0
- package/library/.claude-plugin/plugin.json +5 -0
- package/library/THIRD_PARTY_NOTICES.md +123 -0
- package/library/agents/code-architect.md +67 -0
- package/library/agents/code-explorer.md +61 -0
- package/library/agents/code-reviewer.md +73 -0
- package/library/agents/code-simplifier.md +62 -0
- package/library/agents/design-critic.md +52 -0
- package/library/agents/second-opinion.md +64 -0
- package/library/agents/security-auditor.md +86 -0
- package/library/agents/silent-failure-hunter.md +70 -0
- package/library/agents/test-coverage-analyzer.md +78 -0
- package/library/agents/test-runner.md +48 -0
- package/library/agents/ui-tester.md +47 -0
- package/library/licenses/Apache-2.0.txt +202 -0
- package/library/skills/accessibility/SKILL.md +144 -0
- package/library/skills/accessibility/references/wcag-checks.md +168 -0
- package/library/skills/addressing-review-feedback/SKILL.md +109 -0
- package/library/skills/app-screens/SKILL.md +96 -0
- package/library/skills/app-screens/references/shell-kpis-charts.md +108 -0
- package/library/skills/app-screens/references/states-density-phone.md +54 -0
- package/library/skills/app-screens/references/tables-forms-settings.md +104 -0
- package/library/skills/avoiding-generic-ai-design/SKILL.md +92 -0
- package/library/skills/avoiding-generic-ai-design/references/tells.md +112 -0
- package/library/skills/clean-commits/SKILL.md +85 -0
- package/library/skills/design-review/SKILL.md +107 -0
- package/library/skills/design-review/references/critique-passes.md +101 -0
- package/library/skills/design-review/references/screenshot-procedure.md +113 -0
- package/library/skills/differential-security-review/LICENSE +427 -0
- package/library/skills/differential-security-review/SKILL.md +105 -0
- package/library/skills/differential-security-review/references/adversarial.md +115 -0
- package/library/skills/differential-security-review/references/methodology.md +145 -0
- package/library/skills/differential-security-review/references/patterns.md +108 -0
- package/library/skills/false-positive-check/LICENSE +427 -0
- package/library/skills/false-positive-check/SKILL.md +95 -0
- package/library/skills/false-positive-check/references/bug-class-verification.md +128 -0
- package/library/skills/false-positive-check/references/deep-verification.md +113 -0
- package/library/skills/false-positive-check/references/evidence-templates.md +93 -0
- package/library/skills/false-positive-check/references/false-positive-patterns.md +122 -0
- package/library/skills/false-positive-check/references/gate-reviews.md +36 -0
- package/library/skills/false-positive-check/references/standard-verification.md +80 -0
- package/library/skills/focused-implementation/SKILL.md +104 -0
- package/library/skills/implementation-plan/SKILL.md +66 -0
- package/library/skills/interface-design/SKILL.md +144 -0
- package/library/skills/interface-design/references/craft-defaults.md +130 -0
- package/library/skills/interface-design/references/new-direction.md +62 -0
- package/library/skills/interface-design/references/writing.md +52 -0
- package/library/skills/interface-polish/SKILL.md +103 -0
- package/library/skills/interface-polish/references/detail-rules.md +154 -0
- package/library/skills/interface-polish/references/worst-case-data.md +158 -0
- package/library/skills/motion-design/SKILL.md +106 -0
- package/library/skills/motion-design/references/recipes.md +243 -0
- package/library/skills/postgres-performance/SKILL.md +97 -0
- package/library/skills/postgres-performance/references/rules.md +265 -0
- package/library/skills/project-orientation/SKILL.md +77 -0
- package/library/skills/reviewing-changes/SKILL.md +183 -0
- package/library/skills/safe-database-changes/SKILL.md +111 -0
- package/library/skills/safe-database-changes/references/backfills.md +75 -0
- package/library/skills/safe-database-changes/references/migration-tools.md +69 -0
- package/library/skills/safe-database-changes/references/postgres-ddl.md +199 -0
- package/library/skills/security-review/SKILL.md +132 -0
- package/library/skills/security-review/references/checks-by-area.md +107 -0
- package/library/skills/security-review/references/do-not-report.md +86 -0
- package/library/skills/spec-writing/SKILL.md +144 -0
- package/library/skills/systematic-debugging/SKILL.md +130 -0
- package/library/skills/systematic-debugging/references/flaky-tests.md +51 -0
- package/library/skills/systematic-debugging/references/root-cause-tracing.md +55 -0
- package/library/skills/task-interview/SKILL.md +84 -0
- package/library/skills/test-driven-development/SKILL.md +116 -0
- package/library/skills/test-driven-development/references/writing-good-tests.md +85 -0
- package/library/skills/ui-testing/SKILL.md +99 -0
- package/library/skills/ui-testing/references/headless-check.md +262 -0
- package/library/skills/ui-testing/references/playwright-patterns.md +134 -0
- package/library/skills/verification-before-completion/SKILL.md +113 -0
- package/library/skills/web-interface-guidelines/SKILL.md +202 -0
- package/package.json +44 -5
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# WCAG 2.2 checks, patterns and scripts
|
|
2
|
+
|
|
3
|
+
Read this when you need the exact criterion for a finding, a correct markup pattern for a fix, a contrast calculation, or the keyboard pass for the headless check.
|
|
4
|
+
|
|
5
|
+
## Level A and AA criteria that matter most for web apps
|
|
6
|
+
|
|
7
|
+
| Criterion | Level | What to check |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| 1.1.1 Non-text Content | A | Alt text on meaningful images, names on icon buttons, `alt=""` on decorative images |
|
|
10
|
+
| 1.2.2 Captions (Prerecorded) | A | Videos with speech have captions |
|
|
11
|
+
| 1.3.1 Info and Relationships | A | Headings, lists, tables, labels and groups exist in markup, not only in styling |
|
|
12
|
+
| 1.3.2 Meaningful Sequence | A | DOM order matches reading order (CSS `order` and grid placement can break it) |
|
|
13
|
+
| 1.3.5 Identify Input Purpose | AA | `autocomplete` on fields about the user |
|
|
14
|
+
| 1.4.1 Use of Color | A | Colour is not the only way information is shown |
|
|
15
|
+
| 1.4.3 Contrast (Minimum) | AA | 4.5:1 text, 3:1 large text (24 px, or 18.66 px bold) |
|
|
16
|
+
| 1.4.4 Resize Text | AA | Usable at 200% zoom |
|
|
17
|
+
| 1.4.10 Reflow | AA | No two-dimensional scrolling at 320 CSS px wide (except maps, tables, editors) |
|
|
18
|
+
| 1.4.11 Non-text Contrast | AA | 3:1 for control boundaries, focus indicators, meaningful icons and graphics |
|
|
19
|
+
| 1.4.12 Text Spacing | AA | No clipped text when line and letter spacing increase (avoid fixed heights on text boxes) |
|
|
20
|
+
| 1.4.13 Content on Hover or Focus | AA | Tooltips and popovers can be dismissed (Escape), hovered and stay until dismissed |
|
|
21
|
+
| 2.1.1 Keyboard | A | Every function works with the keyboard |
|
|
22
|
+
| 2.1.2 No Keyboard Trap | A | Focus can always move away |
|
|
23
|
+
| 2.1.4 Character Key Shortcuts | A | Single-key shortcuts can be turned off or only work when a component has focus |
|
|
24
|
+
| 2.2.1 Timing Adjustable | A | Time limits can be extended |
|
|
25
|
+
| 2.2.2 Pause, Stop, Hide | A | Moving or auto-updating content can be paused |
|
|
26
|
+
| 2.3.1 Three Flashes | A | Nothing flashes more than three times per second |
|
|
27
|
+
| 2.4.1 Bypass Blocks | A | Skip link or landmarks |
|
|
28
|
+
| 2.4.2 Page Titled | A | Descriptive, unique titles per route |
|
|
29
|
+
| 2.4.3 Focus Order | A | Order preserves meaning; dialogs and route changes manage focus |
|
|
30
|
+
| 2.4.4 Link Purpose (In Context) | A | Link text says where it goes |
|
|
31
|
+
| 2.4.6 Headings and Labels | AA | Headings and labels describe their content |
|
|
32
|
+
| 2.4.7 Focus Visible | AA | A visible focus indicator |
|
|
33
|
+
| 2.4.11 Focus Not Obscured (Minimum) | AA | Focused element not fully hidden by sticky or overlay content |
|
|
34
|
+
| 2.5.1 Pointer Gestures | A | Multi-finger or path gestures have a single-pointer alternative |
|
|
35
|
+
| 2.5.2 Pointer Cancellation | A | Actions fire on release, not on press |
|
|
36
|
+
| 2.5.3 Label in Name | A | Accessible name contains the visible label |
|
|
37
|
+
| 2.5.7 Dragging Movements | AA | Dragging has a single-pointer alternative |
|
|
38
|
+
| 2.5.8 Target Size (Minimum) | AA | 24 by 24 CSS px, or enough spacing |
|
|
39
|
+
| 3.1.1 Language of Page | A | `<html lang>` |
|
|
40
|
+
| 3.1.2 Language of Parts | AA | `lang` on passages in another language |
|
|
41
|
+
| 3.2.1 On Focus / 3.2.2 On Input | A | Focusing or changing a field does not navigate or submit unexpectedly |
|
|
42
|
+
| 3.2.3 Consistent Navigation | AA | Navigation in the same order across pages |
|
|
43
|
+
| 3.2.6 Consistent Help | A | Help links or contact options in the same place across pages |
|
|
44
|
+
| 3.3.1 Error Identification | A | Errors described in text and tied to the field |
|
|
45
|
+
| 3.3.2 Labels or Instructions | A | Labels and format hints |
|
|
46
|
+
| 3.3.3 Error Suggestion | AA | Say how to fix it when known |
|
|
47
|
+
| 3.3.4 Error Prevention (Legal, Financial, Data) | AA | Review, confirm or undo for important submissions |
|
|
48
|
+
| 3.3.7 Redundant Entry | A | Do not ask again for data entered earlier in the same process |
|
|
49
|
+
| 3.3.8 Accessible Authentication (Minimum) | AA | No memory or puzzle test without an alternative; allow paste and password managers |
|
|
50
|
+
| 4.1.2 Name, Role, Value | A | Custom controls expose name, role and state |
|
|
51
|
+
| 4.1.3 Status Messages | AA | Status updates announced without moving focus |
|
|
52
|
+
|
|
53
|
+
Criteria 2.4.12, 2.4.13 and 3.3.9 are AAA and new in 2.2; 4.1.1 Parsing was removed in 2.2, so do not report it.
|
|
54
|
+
|
|
55
|
+
## Patterns
|
|
56
|
+
|
|
57
|
+
**Visually hidden text** (for screen readers only):
|
|
58
|
+
|
|
59
|
+
```css
|
|
60
|
+
.visually-hidden {
|
|
61
|
+
position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
|
|
62
|
+
overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Use the project's existing utility if it has one (`sr-only`, `visually-hidden`, a component).
|
|
67
|
+
|
|
68
|
+
**Dialog:** prefer native `<dialog>` opened with `showModal()`, which makes the rest of the page inert and closes on Escape. Give it a name (`aria-labelledby` pointing at its heading), move focus inside on open, and return focus to the trigger on close. A custom dialog needs `role="dialog"`, `aria-modal="true"`, a focus trap, Escape handling and an inert or `aria-hidden` background.
|
|
69
|
+
|
|
70
|
+
**Skip link:**
|
|
71
|
+
|
|
72
|
+
```html
|
|
73
|
+
<a class="skip-link" href="#main">Skip to main content</a>
|
|
74
|
+
<main id="main" tabindex="-1">...</main>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
with CSS that keeps it off-screen until it receives focus.
|
|
78
|
+
|
|
79
|
+
**Error summary on submit:** a heading like "2 problems need fixing" with links to each invalid field, focused after a failed submit; each field keeps its own inline error with `aria-describedby`.
|
|
80
|
+
|
|
81
|
+
**Tabs:** `role="tablist"` containing `role="tab"` elements with `aria-selected` and `aria-controls`; panels with `role="tabpanel"` and `aria-labelledby`. Only the active tab has `tabindex="0"`; arrow keys move between tabs.
|
|
82
|
+
|
|
83
|
+
**Disclosure and menus:** a button with `aria-expanded` that toggles the controlled region. Do not use `role="menu"` for site navigation; it promises application-style keyboard behaviour.
|
|
84
|
+
|
|
85
|
+
**Live region:** render the container empty on page load, then change its text:
|
|
86
|
+
|
|
87
|
+
```html
|
|
88
|
+
<div role="status" class="visually-hidden" id="announcer"></div>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Clearing it before writing the same message again makes screen readers repeat it.
|
|
92
|
+
|
|
93
|
+
**Reduced motion:**
|
|
94
|
+
|
|
95
|
+
```css
|
|
96
|
+
@media (prefers-reduced-motion: reduce) {
|
|
97
|
+
*, *::before, *::after {
|
|
98
|
+
animation-duration: 0.01ms !important;
|
|
99
|
+
animation-iteration-count: 1 !important;
|
|
100
|
+
transition-duration: 0.01ms !important;
|
|
101
|
+
scroll-behavior: auto !important;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Or scope it to the animations the change adds, if the project handles motion per component.
|
|
107
|
+
|
|
108
|
+
## Contrast from design tokens
|
|
109
|
+
|
|
110
|
+
When colours come from tokens or CSS variables, compute the ratio instead of guessing. Run with `node -e` or in a temp file:
|
|
111
|
+
|
|
112
|
+
```js
|
|
113
|
+
function luminance(hex) {
|
|
114
|
+
const value = hex.replace('#', '')
|
|
115
|
+
const full = value.length === 3 ? value.split('').map(c => c + c).join('') : value
|
|
116
|
+
const [r, g, b] = [0, 2, 4].map(i => parseInt(full.slice(i, i + 2), 16) / 255)
|
|
117
|
+
.map(c => (c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4))
|
|
118
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b
|
|
119
|
+
}
|
|
120
|
+
function contrast(foreground, background) {
|
|
121
|
+
const [light, dark] = [luminance(foreground), luminance(background)].sort((a, b) => b - a)
|
|
122
|
+
return (light + 0.05) / (dark + 0.05)
|
|
123
|
+
}
|
|
124
|
+
console.log(contrast('#6b7280', '#ffffff').toFixed(2))
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Semi-transparent colours must be blended with their real background first. For dark mode, check both themes.
|
|
128
|
+
|
|
129
|
+
## Keyboard pass in a headless browser
|
|
130
|
+
|
|
131
|
+
Use as the `steps` function of the `ui-testing` headless check. It records the first stops of the Tab order, whether each one shows a focus style, and whether Escape closes an open dialog. The focus-style test is a heuristic (it looks for an outline or box shadow); confirm doubtful cases on a screenshot.
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
async function steps(page) {
|
|
135
|
+
const stops = []
|
|
136
|
+
for (let i = 0; i < 25; i++) {
|
|
137
|
+
await page.keyboard.press('Tab')
|
|
138
|
+
const stop = await page.evaluate(() => {
|
|
139
|
+
const el = document.activeElement
|
|
140
|
+
if (!el || el === document.body) return null
|
|
141
|
+
const style = getComputedStyle(el)
|
|
142
|
+
const hasOutline = style.outlineStyle !== 'none' && parseFloat(style.outlineWidth) > 0
|
|
143
|
+
const hasShadow = style.boxShadow && style.boxShadow !== 'none'
|
|
144
|
+
const label = el.getAttribute('aria-label') || el.innerText || el.getAttribute('title') || el.getAttribute('name') || ''
|
|
145
|
+
return {
|
|
146
|
+
element: el.tagName.toLowerCase() + (el.getAttribute('role') ? `[role=${el.getAttribute('role')}]` : ''),
|
|
147
|
+
name: label.trim().replace(/\s+/g, ' ').slice(0, 60),
|
|
148
|
+
visibleFocus: Boolean(hasOutline || hasShadow),
|
|
149
|
+
inViewport: (() => { const r = el.getBoundingClientRect(); return r.bottom > 0 && r.top < innerHeight })(),
|
|
150
|
+
}
|
|
151
|
+
})
|
|
152
|
+
if (!stop) break
|
|
153
|
+
stops.push(stop)
|
|
154
|
+
}
|
|
155
|
+
let escapeClosesDialog = null
|
|
156
|
+
const dialog = page.locator('dialog[open], [role="dialog"]').first()
|
|
157
|
+
if (await dialog.isVisible().catch(() => false)) {
|
|
158
|
+
await dialog.locator('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])').first().focus().catch(() => {})
|
|
159
|
+
await page.keyboard.press('Escape')
|
|
160
|
+
escapeClosesDialog = !(await dialog.isVisible().catch(() => false))
|
|
161
|
+
}
|
|
162
|
+
return { stops, escapeClosesDialog }
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Read the result: stops with an empty `name` are unnamed controls; `visibleFocus: false` needs a screenshot check; the order should follow the visual layout; stops that repeat in a loop inside one component suggest a trap. To test a dialog, open it in `steps` first (click its trigger), then run the same loop and check focus stays inside it and returns to the trigger after Escape.
|
|
167
|
+
|
|
168
|
+
Adapted from addyosmani/web-quality-skills `skills/accessibility/references/WCAG.md` and `A11Y-PATTERNS.md` (MIT, commit afa8da942115f2961fdbfa80807ea0b232ff6c00, Copyright (c) 2026 Addy Osmani). Changed: limited to A and AA criteria relevant to web apps with "what to check" notes, patterns condensed, contrast and keyboard-pass scripts added.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: addressing-review-feedback
|
|
3
|
+
description: Use when a code step is a rework with review comments to address: check each comment against the current code before acting, fix every valid one, explain with evidence any you do not apply, keep the reviewer's own commits, and report the outcome per comment.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Addressing review feedback
|
|
7
|
+
|
|
8
|
+
A rework run gets the reviewer's comments and a branch that already has the earlier work, and maybe commits from the reviewer. Nobody will answer questions, and you cannot reply on GitHub. Your answer to the reviewer is the code plus the report.
|
|
9
|
+
|
|
10
|
+
Review feedback is a set of technical claims to check, not orders to apply blindly and not opinions to argue with. Verify, then act.
|
|
11
|
+
|
|
12
|
+
## 1. Get the current state
|
|
13
|
+
|
|
14
|
+
In each repository:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
git log --oneline origin/<base>..HEAD
|
|
18
|
+
git diff --stat origin/<base>...HEAD
|
|
19
|
+
git status
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
- The current branch is the source of truth. Line numbers in the comments may refer to an older version; find the code by content, not by number.
|
|
23
|
+
- Identify commits that are not from the earlier agent run (different author, or messages like "review fixes"). These are the reviewer's own changes. Keep them: do not revert, rewrite or "clean up" them unless a comment explicitly asks for that.
|
|
24
|
+
- Never rewrite history: no rebase, amend, reset or force push. Add new commits on top.
|
|
25
|
+
|
|
26
|
+
## 2. List every comment
|
|
27
|
+
|
|
28
|
+
Read all comments before changing anything. Items can depend on each other, and a later comment can change how you read an earlier one.
|
|
29
|
+
|
|
30
|
+
Number them and restate each as a concrete technical requirement:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
C1 "this will blow up for guests" -> getCart() must handle a null user (src/cart.ts, getCart)
|
|
34
|
+
C2 "use the existing money helper" -> replace manual rounding with formatMoney() in Invoice.vue
|
|
35
|
+
C3 "add a test for the empty state" -> component test: no items shows the empty message
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
A comment that holds several requests becomes several items.
|
|
39
|
+
|
|
40
|
+
## 3. Verify each item against the code
|
|
41
|
+
|
|
42
|
+
For each item, before editing:
|
|
43
|
+
|
|
44
|
+
- Is the claim true in the current code? Reproduce it if it is a bug (a test, a quick run). It may already be fixed by a reviewer commit.
|
|
45
|
+
- Would the suggested change break something else? Search for other callers, run the related tests.
|
|
46
|
+
- Is there a reason the code is the way it is (a comment, a test, the spec, a platform constraint)?
|
|
47
|
+
- Does the suggestion fit this codebase and its conventions?
|
|
48
|
+
- For "do it properly" or "add X" requests, check whether X is used: search the code. Building an unused feature is not a fix.
|
|
49
|
+
|
|
50
|
+
If a comment is unclear, choose the reading that best matches the reviewer's evident intent, the spec and the code. Write the reading you chose in the report. Do not stop and do not skip it.
|
|
51
|
+
|
|
52
|
+
## 4. Decide and act
|
|
53
|
+
|
|
54
|
+
Each item ends in one of these states:
|
|
55
|
+
|
|
56
|
+
| State | When |
|
|
57
|
+
|---|---|
|
|
58
|
+
| Fixed | The comment is valid; you changed the code and checked it. |
|
|
59
|
+
| Already done | The current code already does it (say where, for example a reviewer commit). |
|
|
60
|
+
| Fixed differently | The concern is valid but the suggested change is wrong here; you solved the concern another way. |
|
|
61
|
+
| Not changed | The comment is wrong for this code, conflicts with the spec, or would break something. Give the evidence. |
|
|
62
|
+
| Partly done | You could do only part of it (needs credentials, out of scope of the task). Say what is left. |
|
|
63
|
+
|
|
64
|
+
Default to fixing. Use "Not changed" only with concrete evidence (file:line, test output, a spec quote), never because the change is inconvenient. When the reviewer and the spec disagree, follow the reviewer if the change is safe and within the task, and note the conflict.
|
|
65
|
+
|
|
66
|
+
Order of work:
|
|
67
|
+
1. Blocking items: broken behaviour, security, data loss.
|
|
68
|
+
2. Simple items: naming, imports, small corrections.
|
|
69
|
+
3. Larger items: logic changes, refactors.
|
|
70
|
+
|
|
71
|
+
Work one item at a time and run the related tests after each. Use `systematic-debugging` for bug reports and `test-driven-development` when a comment asks for new behaviour or reports a bug that a test could catch.
|
|
72
|
+
|
|
73
|
+
Stay within the comments and what they directly imply. A rework is not the time for unrelated improvements; list those under "Noticed, not changed".
|
|
74
|
+
|
|
75
|
+
## 5. Verify everything and commit
|
|
76
|
+
|
|
77
|
+
Run `verification-before-completion` across the whole branch, not only the lines you touched: a fix for one comment can break another part. Commit with `clean-commits`; one commit per comment or one commit for the whole round both work, as long as messages say what was addressed.
|
|
78
|
+
|
|
79
|
+
## 6. Report per comment
|
|
80
|
+
|
|
81
|
+
Plain technical statements. No thanks, no "great catch", no "you're absolutely right": the reader wants to know what changed.
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
Review comments
|
|
85
|
+
C1 Fixed: getCart() returns an empty cart for guests (src/cart.ts:31), test "guest gets empty cart" added, failed before.
|
|
86
|
+
C2 Fixed: Invoice.vue uses formatMoney() for totals and line prices.
|
|
87
|
+
C3 Fixed: test "shows the empty message when there are no items" in Invoice.test.ts.
|
|
88
|
+
C4 Not changed: the comment suggests removing the legacy date parser, but importInvoices() still calls it for CSV files (src/import/csv.ts:88); removing it breaks 4 tests in csv.test.ts.
|
|
89
|
+
C5 Already done: reviewer commit 3f2a1c0 renamed the prop.
|
|
90
|
+
C6 Unclear, read as "show the VAT column only for business customers" (matches spec rule 2): done in InvoiceTable.vue.
|
|
91
|
+
|
|
92
|
+
Checks
|
|
93
|
+
- pnpm test -- --run: 220 passed, 0 failed
|
|
94
|
+
- pnpm typecheck: exit 0
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Common mistakes
|
|
98
|
+
|
|
99
|
+
| Mistake | Instead |
|
|
100
|
+
|---|---|
|
|
101
|
+
| Applying every suggestion without checking it | Verify against the code first; reviewers can be wrong or work from an old version. |
|
|
102
|
+
| Skipping a comment silently | Every comment appears in the report with a state. |
|
|
103
|
+
| Arguing without evidence | Show the file:line, the test or the spec line. |
|
|
104
|
+
| Reverting or rewriting the reviewer's commits | Keep them; build on top. |
|
|
105
|
+
| Fixing items in a batch and testing once at the end | One item, then its tests. |
|
|
106
|
+
| Fixing only the commented lines | Look for the same problem elsewhere in your change and fix it there too. |
|
|
107
|
+
| Asking questions in the report and waiting | Decide, state the reading you chose, and finish. |
|
|
108
|
+
|
|
109
|
+
Sources: obra/superpowers (MIT, commit bb92a77) receiving-code-review. Changed: rewritten for unattended reworks, every question path removed.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: app-screens
|
|
3
|
+
description: Use when building or changing screens people work in: dashboards, admin and back office, analytics and reports, tables and lists with filters, inboxes and queues, forms, settings and billing, detail pages. Covers answering the screen's one question first, KPIs, charts, tables, forms, empty, loading and error states, and the phone layout.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# App screens
|
|
7
|
+
|
|
8
|
+
An app screen is worked in, not read once. The generated version is the average of every dashboard template: a tinted sidebar, "Welcome back" with a wave, four KPI cards with icons and green deltas, a gradient area chart, a zebra table. Nothing in it is wrong and none of it was decided. Good product screens are quieter and fuller at the same time: colour on data instead of chrome, numbers set as type instead of tiles, and the product's real objects answering a real question.
|
|
9
|
+
|
|
10
|
+
Follow `interface-design` for the general process. This skill adds what is specific to working screens. Defaults here come from measurements of real product screens; the project's own components, tokens and existing screens always win over them. If a sibling screen already has a table, filters or KPIs, reuse those patterns exactly.
|
|
11
|
+
|
|
12
|
+
## The run
|
|
13
|
+
|
|
14
|
+
Do these in order. The first three decide whether the screen is any good.
|
|
15
|
+
|
|
16
|
+
### 1. Inventory the data and the jobs
|
|
17
|
+
|
|
18
|
+
Write eight to twelve lines in your notes:
|
|
19
|
+
|
|
20
|
+
- **Objects** the screen shows (invoices, deployments, members) and their fields, with units.
|
|
21
|
+
- **Realistic magnitudes**: how many objects, typical and extreme values, and how small a new account really is.
|
|
22
|
+
- **People**: who opens it, how often (a glance a day or an eight-hour session), on what device.
|
|
23
|
+
- **Jobs**: what they do next from here (approve, reply, pay, redeploy), and which job is most frequent.
|
|
24
|
+
- **The product's own things**: its name, the workspace or account scope, its people and recognisable objects (product photos, avatars, cover art).
|
|
25
|
+
|
|
26
|
+
Use the real data source. When you need sample data (a new screen with no backend yet, a story, a test fixture), make it believable and consistent: totals computed from the rows, dates in order, a unit on every figure, small numbers for small accounts. Never "Acme", "John Doe", "User 1", lorem ipsum or vanity totals. List sample data in the report.
|
|
27
|
+
|
|
28
|
+
### 2. Name the screen's one question
|
|
29
|
+
|
|
30
|
+
Every screen answers one question first: "Did today's orders ship?", "Which deploy broke?", "Who is waiting for a reply?". Write it in one line. It decides:
|
|
31
|
+
|
|
32
|
+
- **What is biggest.** The largest block, and the largest figure, answer that question.
|
|
33
|
+
- **What comes first** in reading order.
|
|
34
|
+
- **What is left out.** A block that answers no question is deleted. A few numbers may need no chart at all.
|
|
35
|
+
|
|
36
|
+
Then name the screen's **one finding**: the fact in the current data that most needs attention ("3 invoices overdue, the oldest by 41 days"). Put it where it is read first (the line under the title, or the subline of the main figure), next to the action it drives.
|
|
37
|
+
|
|
38
|
+
List the remaining blocks as answers to the next questions, one line each. This replaces the stock order of KPI row, big chart, two small charts, table.
|
|
39
|
+
|
|
40
|
+
Three more checks:
|
|
41
|
+
|
|
42
|
+
- **Everything the task names shows on the first screen** at 1440 x 900: each block's header and first rows or figure. Cap overview lists at 4 to 6 rows with "View all".
|
|
43
|
+
- **The most frequent job is one click away**: a primary button in the title row, an action on the row that needs it, "View logs" on the failed item. A screen with no control for its main job reads as a report.
|
|
44
|
+
- **Show the evidence beside the answer.** "Error rate 0.28%, peaked at 3.9% after deploy a3f09c1" is trusted more than the number alone.
|
|
45
|
+
|
|
46
|
+
### 3. Build the shell, then the data, then the states
|
|
47
|
+
|
|
48
|
+
1. **Shell first, empty**: navigation, title row, canvas with gutters. Use the project's layout components. Check it at 1440 and 390 before data goes in. Do the grid arithmetic so cards land on the canvas edges.
|
|
49
|
+
2. **Data**: render every block from the data. Format every figure (separators, fixed decimals per metric, a sign on every change, units as a smaller muted suffix, tabular figures, numbers right-aligned in columns). Use the product's words for labels ("Waiting on customer", not "Status 2").
|
|
50
|
+
3. **States**: for every block, its loading, empty, zero and error state; for every row and control, hover, selected, focus and disabled. Look at each in the browser.
|
|
51
|
+
|
|
52
|
+
### 4. Check the screenshots
|
|
53
|
+
|
|
54
|
+
Take screenshots at 1440, 768 and 390 (procedure in `design-review`) and answer in writing:
|
|
55
|
+
|
|
56
|
+
1. Is the screen's question answered by the biggest thing on it, and is that read first?
|
|
57
|
+
2. Does every block share the screen's edges? Any dead strip, a card stopping short, an orphan cell, a card stretched with a blank band at its foot?
|
|
58
|
+
3. Is colour only on data, status and the one primary action?
|
|
59
|
+
4. Do the numbers add up and line up digit for digit? Does every fact shown twice agree? Does every relative figure name its baseline ("vs last week")?
|
|
60
|
+
5. Does every zero look like a zero and every missing value like a dash?
|
|
61
|
+
6. Does every legend swatch match its mark? Do any labels collide?
|
|
62
|
+
7. On the phone, is the navigation folded away, and does each block still answer its question?
|
|
63
|
+
|
|
64
|
+
Fix the worst three, look again. Three rounds at most.
|
|
65
|
+
|
|
66
|
+
## Defaults at a glance
|
|
67
|
+
|
|
68
|
+
Details and numbers: [references/shell-kpis-charts.md](references/shell-kpis-charts.md) (navigation, title row, KPIs, deltas, charts), [references/tables-forms-settings.md](references/tables-forms-settings.md) (tables, lists, forms, settings, buttons) and [references/states-density-phone.md](references/states-density-phone.md) (empty, zero, loading, error, density, phone and tablet).
|
|
69
|
+
|
|
70
|
+
- **Shell.** Labelled sidebar about 224 to 240px on the page background (not a dark or saturated block), active item as a neutral pill or brighter text. Product name and scope (workspace, project) at the top. A top bar only when it holds something real (search, switcher, object name).
|
|
71
|
+
- **Title.** One `h1` per screen, a noun ("Invoices", the project's name), 20 to 28px. An optional one-line muted sentence about the data. Actions on the right only when real. One filled primary button per screen.
|
|
72
|
+
- **KPIs.** Type, not tiles: one container split by 1px dividers, label over value, value 24 to 32px, no icons, no sparklines. Deltas optional, small, with the window in words; colour says good or bad (a rise in errors is bad), not up or down; zero change is grey.
|
|
73
|
+
- **Charts.** One question, one series, one hue. Straight 2px lines, 3 to 5 faint horizontal gridlines, no y-axis line, round ticks above the maximum, flat x labels. No legend for a single series. Annotate the event that matters.
|
|
74
|
+
- **Tables.** Sentence-case muted headers, no fill band, no zebra stripes, 1px row rules or none, numbers right-aligned in tabular figures, identity column widest, one status mark per row, row actions only where rows need them.
|
|
75
|
+
- **Forms.** Label above the field, no placeholder-as-label, 16px between fields, one control height per context, errors inline, disabled controls say why.
|
|
76
|
+
- **States.** Zero printed as zero, missing as a muted dash, empty blocks keep their frame and header with one sentence and an action, loading as a skeleton at final size, errors inside the failed block with a retry.
|
|
77
|
+
- **Phone.** Navigation folds to a top bar with a menu or a bottom bar; tables become two-line lists below about 640px; at most one row of controls above a chart; the page never scrolls sideways.
|
|
78
|
+
- **Motion.** Feedback only: press, hover, focus, a menu or sheet opening, a row arriving. Nothing performs an entrance on load.
|
|
79
|
+
|
|
80
|
+
## Common mistakes
|
|
81
|
+
|
|
82
|
+
- A grid chosen before the data: four KPI tiles in a three-column grid, a lone card beside 800px of nothing.
|
|
83
|
+
- Colour on chrome (tinted nav rows, coloured tab pills, brand fill on every button) and none on the data.
|
|
84
|
+
- The biggest number on the screen is not the answer to its question.
|
|
85
|
+
- A KPI and a table on the same screen that disagree, or totals that do not add up.
|
|
86
|
+
- A green "+100%" grown from zero; red on every negative number.
|
|
87
|
+
- A full-screen error banner when one block failed.
|
|
88
|
+
- Only the full-data state built.
|
|
89
|
+
|
|
90
|
+
## Done when
|
|
91
|
+
|
|
92
|
+
The one question and the one finding are written down and visible on the first screen; the main job is one click away; every block has its states; numbers reconcile; screenshots at three widths pass the seven questions. Report the screen's question, any sample data to replace, and anything not checked.
|
|
93
|
+
|
|
94
|
+
Related: `interface-design`, `avoiding-generic-ai-design`, `interface-polish`, `design-review`, `accessibility`.
|
|
95
|
+
|
|
96
|
+
Sources: adapted from Leonxlnx/taste-skill references/app-screens.md (MIT, changed: condensed; no direction library, scripts, chart helpers or house bans; project system takes precedence) and pbakaus/impeccable operate reference (Apache-2.0, changed: rewritten).
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Shell, title row, KPIs and charts
|
|
2
|
+
|
|
3
|
+
Read this when building navigation, a page header, headline numbers or a chart on an app screen. Numbers are measured from real product screens (desktop, 1440 to 1512px wide) and are defaults: the project's existing shell and components win.
|
|
4
|
+
|
|
5
|
+
## Shell
|
|
6
|
+
|
|
7
|
+
Five shapes cover almost every product:
|
|
8
|
+
|
|
9
|
+
| Shell | What it is | Suits |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| Open plane | Labelled sidebar on the page background, separated by nothing or one 1px line; no top bar | Most tools |
|
|
12
|
+
| Tinted frame, white sheet | Sidebar and top bar share one light tint (#f6f6f6 to #f9fbfc); the page sits on a white sheet inset about 8px, radius 10 to 16, a 1px edge, no shadow | B2B analytics, developer platforms |
|
|
13
|
+
| Ruled T-frame | 210 to 240px sidebar and 64px top bar on one background, divided by 1px rules | Dark products, monitoring |
|
|
14
|
+
| Icon rail | Unlabelled 48 to 56px rail, 16 to 18px icons, tooltip and accessible name on each | Five destinations or fewer, research views needing width |
|
|
15
|
+
| No sidebar | 46 to 48px top bar over a centred 1088 to 1208px column | Reports, viewers, few destinations |
|
|
16
|
+
|
|
17
|
+
**Sidebar**
|
|
18
|
+
|
|
19
|
+
- Width 224 to 256px. Rows: 32px hit area on a 34px pitch (roomy: 40px on 44). Icons 16px outline at about 1.5px stroke, label 14px regular, 8 to 10px after the icon.
|
|
20
|
+
- Active item: a neutral grey pill (radius about 8, inset 8px, fill about #ececec) with the label unchanged; on dark, the label brightens. A coloured left bar is rare in good products.
|
|
21
|
+
- Groups: sentence-case muted labels at 12 to 13px with 24px or more above, never uppercase by default; or hairlines between groups.
|
|
22
|
+
- Top: product mark and name, then the scope switcher (workspace, team, project). Bottom: settings, help, the user.
|
|
23
|
+
- Counts only on queues that need action, with a clear noun ("Requests 5").
|
|
24
|
+
- Nav items go to other screens, never to anchors in one long page.
|
|
25
|
+
|
|
26
|
+
**Top bar**: 48px on light chrome, 64px with a rule. It holds something real: search (about 32 to 36px tall, with a shortcut hint), the switcher, or the object's name. A top bar left mostly empty is wasted.
|
|
27
|
+
|
|
28
|
+
**Right rail**: a fixed column (about 320 to 384px, `1fr 384px` with a 24px gap) only for a stable secondary stream: details of the selected object, recent items.
|
|
29
|
+
|
|
30
|
+
**Floating buttons**: only for the screen's one primary action, and only when they cover nothing at any width.
|
|
31
|
+
|
|
32
|
+
## Canvas and title row
|
|
33
|
+
|
|
34
|
+
- Fluid canvas with 24 to 40px side padding, or a centred 1100 to 1250px column for data pages. Narrower than about 900px wastes the width.
|
|
35
|
+
- Title 20 to 36px from the canvas top on tools.
|
|
36
|
+
- **One gutter**: the same gap horizontally and vertically (16px default). Mixed 12/16/20/24 gaps on one screen look accidental.
|
|
37
|
+
- **One left edge, one right edge** from the header to the last row. Write the arithmetic down: 3 x 368 + 2 x 16 = 1136.
|
|
38
|
+
- **A grid that fits the data**: choose the column count from the number of items; a lone card spans; a table of five columns or fewer pairs with another block instead of stretching to 1300px.
|
|
39
|
+
- **Cards in a row share a bottom edge.** Balance by content (same number of rows in both lists); otherwise let a card keep its own height (`align-items: start`) rather than stretching with a blank band. Only an action or a total may be pinned to a stretched card's foot.
|
|
40
|
+
|
|
41
|
+
**Title**
|
|
42
|
+
|
|
43
|
+
- One `h1` per screen. A noun: "Analytics", "Invoices", the project or object name. A greeting only on personal homes, never with an emoji.
|
|
44
|
+
- 20 to 28px at 600 (24 default). In dense tools a breadcrumb whose last item is the `h1` at 16px is fine.
|
|
45
|
+
- Optional second line: one 14px muted sentence about the data (the period, the scope, the finding), never instructions about the interface.
|
|
46
|
+
- Right side: real actions only, or a freshness stamp ("Updated 09:14" with a refresh button).
|
|
47
|
+
- One filled primary button per screen; often near-black or the brand colour. Secondary: outlined; tertiary: text.
|
|
48
|
+
|
|
49
|
+
**Tabs, filters and date range**
|
|
50
|
+
|
|
51
|
+
- Date range at page level or per card, never both. A card's own period sits right-aligned in its header in a muted tone.
|
|
52
|
+
- Underline tabs on a full-width 1px rule, indicator 2px, as wide as the label.
|
|
53
|
+
- Segmented controls are as wide as their options; full width only below about 480px.
|
|
54
|
+
- Control height in title and filter rows 32 to 36px. Scope on the left (date, then filters), utilities on the right. About 24px from the filter row to the first card.
|
|
55
|
+
|
|
56
|
+
## KPIs
|
|
57
|
+
|
|
58
|
+
- **Type, not tiles.** Default: one container split by 1px dividers into equal columns, label above value. Or put each headline number in the card that explains it.
|
|
59
|
+
- Count matches the grid: four KPIs, four columns. One to six per row.
|
|
60
|
+
- Value 24 to 32px (median about 26), label 12 to 14px muted, sentence case. Value about 1.7 times the label. Weight 400 to 600; bold for money only.
|
|
61
|
+
- **The answer figure leads**: when one figure answers the screen's question (a balance, the month's revenue), it is 30 to 36px and at least 1.3 times its siblings. No other figure on the screen is larger.
|
|
62
|
+
- No icon in a coloured circle, no sparkline, no tinted tile. An info icon beside the label is fine. Units as a smaller muted suffix ("5 min", "24 / 30").
|
|
63
|
+
- One figure, one place: do not repeat a KPI in a legend beside it or as a panel title below.
|
|
64
|
+
- KPIs can double as tabs for a chart; then the selected one gets a 2px rule or the active fill, and the others keep their values in the text colour (a grey value reads as disabled).
|
|
65
|
+
|
|
66
|
+
**Deltas**
|
|
67
|
+
|
|
68
|
+
- Optional. 12 to 14px, never larger than the label; text, a small glyph, or a pale pill.
|
|
69
|
+
- The window in words: "vs previous 30 days".
|
|
70
|
+
- **Colour says good or bad, not up or down.** Latency, errors, cost and churn are better when they fall. A change in the bad direction gets the danger colour; a good change gets the success colour or stays muted.
|
|
71
|
+
- Zero or undefined change is grey. From a zero baseline write "+4 (new)", not "+100%" or ">999%". Nothing to compare: a muted dash.
|
|
72
|
+
|
|
73
|
+
## Charts
|
|
74
|
+
|
|
75
|
+
**Which chart for which question**
|
|
76
|
+
|
|
77
|
+
| Question | Form |
|
|
78
|
+
|---|---|
|
|
79
|
+
| Is it moving over time? | One line; an area only with a fill of 15% or less |
|
|
80
|
+
| How much per period? | Columns with square corners (at most a 4px top radius) |
|
|
81
|
+
| How is it distributed? | Histogram with equal bins |
|
|
82
|
+
| Who ranks? | Sorted horizontal bar list |
|
|
83
|
+
| What share? | A thin ring or a 100% stacked bar, five parts at most |
|
|
84
|
+
| How far to a target? | A progress bar with both ends labelled, fill at the true ratio |
|
|
85
|
+
| How much of a budget is used? | A track as long as the budget, spent part filled, committed part lighter, overrun in the danger colour |
|
|
86
|
+
| Has it drifted from target? | One row per part: current value as a bar with a 1px tick at the target |
|
|
87
|
+
| Where? | A map with a list beside it; the list carries the magnitudes |
|
|
88
|
+
|
|
89
|
+
A few numbers need no chart. Link to the analytics screen instead.
|
|
90
|
+
|
|
91
|
+
**Rules**
|
|
92
|
+
|
|
93
|
+
- One series per chart is normal; three at most. Switch metrics with a control rather than overlaying lines.
|
|
94
|
+
- Plot height 120 to 260px (about 200 default); aspect about 2:1 to 5:1. A series flat except for one event gets at most two-thirds of the width.
|
|
95
|
+
- Gridlines: 3 to 5, horizontal, 1px, faint (about #e5e5e5 on light, #2b2b2b on dark). No y-axis line; the baseline is the one stronger line. Dashed lines only in chart grids and reference lines.
|
|
96
|
+
- Y ticks: 4 to 7, round even steps, top tick above the maximum, integers for counts, zero as the baseline for bars. Never a chart without a scale.
|
|
97
|
+
- Axis text no larger than the data (11 to 12px muted). X labels: 4 to 8, flat, never rotated, on one regular step. Time goes on a time scale.
|
|
98
|
+
- Lines 2px straight segments, no point markers except on hover. Fill none or a flat 10 to 15% tint.
|
|
99
|
+
- **Colour**: one hue per chart, on the main data element (today, the current period, the bar that breaks). One subject keeps one hue across the screen. Four hues at most on a screen. Status colours only for status.
|
|
100
|
+
- **Legends**: none for a single series. Otherwise five items at most, in the card header, each swatch drawn like its mark.
|
|
101
|
+
- **Rings**: thin (3 to 8px stroke), no labels on slices, total in the centre or beside it, values in a table next to it.
|
|
102
|
+
- **Tooltips**: plain text or a plain box, label and value on one line.
|
|
103
|
+
- **Annotate the event that matters**: a spike or step more than about three times the usual change gets a 1px marker and a short label naming its cause. Reference lines (budget, SLO) are 1px dashed with the label at the end. Labels never collide with lines or each other.
|
|
104
|
+
- **Forecasts** are dashed after today, with the end value labelled.
|
|
105
|
+
- **Short and empty histories are drawn honestly**: the zero line, missing bars for empty periods, no padded range, no "No data" illustration.
|
|
106
|
+
- Use the project's chart library and set these options on it; never ship the library's defaults (gradients, rainbow palettes, smoothing, legends for one series) unchanged.
|
|
107
|
+
|
|
108
|
+
Sources: adapted from Leonxlnx/taste-skill references/app-screens.md sections 3 to 6 (MIT, changed: condensed, chart helper and inspector references removed, defaults placed under the project's system).
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# States, density and the phone
|
|
2
|
+
|
|
3
|
+
Read this when building the empty, zero, loading and error states of an app screen, deciding density, or laying the screen out for tablets and phones. Reuse the project's existing empty-state, skeleton and error components first.
|
|
4
|
+
|
|
5
|
+
## Empty, zero, loading and error
|
|
6
|
+
|
|
7
|
+
- **A real zero is printed** in the normal style: "0", "$0.00", "0%". It may be muted when the line beside it becomes the next step.
|
|
8
|
+
- **Missing or not applicable is a muted dash**, at text size. A dash at headline size reads as loading.
|
|
9
|
+
- **Counts follow the view.** Counts in tabs, KPIs and "12 open" are computed from the current filter and recomputed on every switch.
|
|
10
|
+
- **An empty block keeps its frame and header** and adds one sentence spanning the block (in a grid, `grid-column: 1 / -1`) with the next action: "No invoices match these filters. Clear filters." Distinguish first use, no results from filters, no permission, and failure: each has its own sentence.
|
|
11
|
+
- **First run** (the whole screen empty): keep the frame and title; put the first action where the data will appear; show setup progress at its true percentage if there are steps.
|
|
12
|
+
- **An empty chart is drawn**: the zero line and the axis, not an illustration.
|
|
13
|
+
- **An empty side card can show reference data** instead of a blank box (last week's values under "Nothing yet today").
|
|
14
|
+
- **Loading**: the final layout with each value replaced by a flat muted bar at its real size (a 24px figure gets a 24px bar, rows keep their pitch). Labels and headers appear at once. No layout shift when data lands. A refresh of data already on screen keeps the old values and updates the freshness stamp. Spinners only inside the control that triggered the work.
|
|
15
|
+
- **Error**: inside the block that failed, never a full-screen banner when one block failed. One sentence saying what failed and when data was last good ("Couldn't load deployments. Last updated 09:14."), and a Retry button. The danger colour on a small icon or a pale pill, not on the whole block.
|
|
16
|
+
- **Stale or static data**: a freshness stamp with a refresh button; a snapshot that cannot refresh says so in one quiet notice.
|
|
17
|
+
- **Limits and usage**: a bar at the true ratio with both ends labelled ("12.7k of 20k").
|
|
18
|
+
- **Permissions**: read-only and no-access states say why and who can change it; rows keep their layout when actions are hidden.
|
|
19
|
+
- **Red is a signal, not a texture**: one red mark per object at most, on the overdue or failing fact.
|
|
20
|
+
|
|
21
|
+
## Density
|
|
22
|
+
|
|
23
|
+
Choose by how the screen is used, then move three settings together: row height, padding and type size.
|
|
24
|
+
|
|
25
|
+
| Density | Typical screen | Body | Rows | Card padding |
|
|
26
|
+
|---|---|---|---|---|
|
|
27
|
+
| Sparse (6 to 25 data points) | Home, settings, one object | 14 to 16px | 56 to 72px | 20 to 24px |
|
|
28
|
+
| Medium (25 to 50) | Analytics overview, list screen | 14px | 44 to 56px | 16 to 24px |
|
|
29
|
+
| Dense (100 and more) | Monitoring, trading, research, long sessions | 13px | 32 to 42px | 16px, with generous gutters between bands |
|
|
30
|
+
|
|
31
|
+
- Placed space reads as calm; leftover space reads as unfinished. Emptiness from a fixed grid and repeated gaps looks deliberate; emptiness from a grid that does not fit the data looks broken.
|
|
32
|
+
- Design for the data a new account has as well as a busy one: size blocks to the question, not to hoped-for data.
|
|
33
|
+
|
|
34
|
+
## The phone
|
|
35
|
+
|
|
36
|
+
- **Navigation folds**: the sidebar becomes a 48 to 56px top bar with the screen name, a menu button opening a full-screen sheet (nav, switcher, account) and at most one action; or a bottom bar of four or five destinations with short labels. A sidebar that still takes more than about 30% of the width is broken.
|
|
37
|
+
- **Margins** 16 to 20px; touch targets at least 44px; data and labels 14px; sublines no smaller than 12px; inputs 16px.
|
|
38
|
+
- **The title stays** at 20 to 24px. Header actions move into a menu, except the one primary.
|
|
39
|
+
- **Filters** collapse into one row of chips or a Filters sheet; tabs scroll sideways inside their own row, never the page. The first list row starts in the top 60% of the screen.
|
|
40
|
+
- **KPIs** become a two-column grid (an even count, or let the last cell span) or a list with label left and value right. Never four squeezed columns.
|
|
41
|
+
- **At most one row of controls above a chart.** Charts go full width, 160 to 200px tall, 3 or 4 x labels, legend as dots above. Y ticks keep their own lane; a tick label never sits on the line.
|
|
42
|
+
- **Tables become two-line lists below about 640px**: identity and key number on line one, the other fields muted on line two, the one action on the right. Fields move to line two; they are never dropped. A table that must stay a table scrolls inside its own frame with the first column fixed.
|
|
43
|
+
- **Row actions** are text actions or one compact trailing button; one filled bulk action for the list.
|
|
44
|
+
- **When a strip collapses**, drop the item least relevant to the screen's main job, not the last in source order.
|
|
45
|
+
- **Blocks that carry an action move up**: a right rail with "Reorder" becomes a summary row above the list ("5 items low, Review").
|
|
46
|
+
- **Several panes** (list and detail, inbox): one at a time; choosing a row pushes the detail, back returns to the list at its scroll position.
|
|
47
|
+
- **Settings**: the label column stacks above its panel.
|
|
48
|
+
- **Builders and editors**: show the work read-only, with tools in a bottom sheet if editing stays.
|
|
49
|
+
|
|
50
|
+
## The tablet (about 641 to 1100px)
|
|
51
|
+
|
|
52
|
+
Its own band, not a stretched phone or a squeezed desktop: the sidebar folds to a top bar or rail, tables keep four or five columns with secondary fields as sublines, two panels stack once either would be under about 340px, and the identity column is never the one truncated.
|
|
53
|
+
|
|
54
|
+
Sources: adapted from Leonxlnx/taste-skill references/app-screens.md sections 10 to 12 (MIT, changed: condensed; inspector checks removed) and pbakaus/impeccable operate and harden references (Apache-2.0, changed: rewritten).
|