@montytools/cli 0.5.4 → 0.5.6
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/bin/monty.mjs +606 -677
- package/lib/compile.mjs +3 -3
- package/lib/schemaCodegen.mjs +7 -3
- package/lib/schemaPull.mjs +36 -50
- package/lib/styleLint.mjs +175 -0
- package/lib/tokens-manifest.mjs +90 -0
- package/lib/views.mjs +19 -0
- package/package.json +3 -3
- package/skills/monty-build/SKILL.md +92 -105
- package/skills/monty-design/SKILL.md +104 -55
- package/template/AGENTS.md +53 -33
- package/template/index.html +5 -5
- package/template/package.json +2 -2
- package/template/src/components/ui/badge.tsx +1 -1
- package/template/src/components/ui/button.tsx +7 -7
- package/template/src/components/ui/card.tsx +3 -3
- package/template/src/components/ui/empty.tsx +3 -3
- package/template/src/components/ui/field.tsx +5 -5
- package/template/src/components/ui/input.tsx +1 -1
- package/template/src/components/ui/label.tsx +1 -1
- package/template/src/components/ui/select.tsx +4 -4
- package/template/src/components/ui/table.tsx +3 -3
- package/template/src/index.css +7 -118
- package/template/src/main.tsx +1 -1
- package/template/src/monty.gen.ts +16 -0
- package/template/src/routes/index.tsx +1 -1
- package/template/tsconfig.json +1 -1
- package/template/monty.config.ts +0 -21
|
@@ -1,126 +1,113 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: monty-build
|
|
3
|
-
description: Build, run, and save Monty workspace apps. Use whenever the task involves a Monty app, monty.
|
|
3
|
+
description: Build, run, and save Monty workspace apps. Use whenever the task involves a Monty app, its schema (monty schema / src/monty.gen.ts), the monty CLI (create/connect/dev/logs/save), the @montytools/sdk, or a prompt mentioning usemonty.dev. Covers folder discipline, the build loop, data/auth rules, and error handling.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Building Monty apps
|
|
7
7
|
|
|
8
|
-
Monty is a work OS
|
|
9
|
-
product logic only
|
|
10
|
-
platform's job. The
|
|
11
|
-
(nearest
|
|
12
|
-
the territory.
|
|
8
|
+
Monty is a work OS. Teams get internal apps built by coding agents. You write
|
|
9
|
+
product logic only. Data, auth, tenancy, deployment, and embedding are the
|
|
10
|
+
platform's job. The full contract is in the app's own `AGENTS.md`
|
|
11
|
+
(nearest file wins). Read it before writing code.
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
the
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
Every app has ONE copy: **Live**, the cloud copy the team uses. `monty save`
|
|
14
|
+
updates it. While a dev **session** runs (often already started for you by
|
|
15
|
+
the Monty desktop), workspace admins see the session's version automatically.
|
|
16
|
+
There is no publish step. "dev" and "prod" name platform environments, never
|
|
17
|
+
app states.
|
|
19
18
|
|
|
20
19
|
## Rules
|
|
21
20
|
|
|
22
|
-
1. **
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
`
|
|
26
|
-
|
|
27
|
-
`monty
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
`monty
|
|
37
|
-
|
|
38
|
-
`
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
is running it starts the shell (start it in the background and move on).
|
|
43
|
-
Then iterate: edit code → vite hot-reloads → `monty logs -n 50` shows
|
|
44
|
-
whether it compiled and any browser errors. Re-running `monty dev` is
|
|
45
|
-
always safe — it attaches, prints status, and exits. Never try to run a
|
|
46
|
-
second dev *server* for the same app (attach handles this for you) and
|
|
47
|
-
never kill a dev shell you didn't start; `monty dev --takeover` is the
|
|
48
|
-
only sanctioned restart when a session is wedged. **You are not done
|
|
49
|
-
until you've saved: once the work is verified in the session, run
|
|
50
|
-
`monty save "<what changed>"`** — it builds, typechecks, and pushes the
|
|
51
|
-
working copy to the cloud copy, like `git push main`. Save after every
|
|
52
|
-
meaningful change, not just at the end; unsaved work exists only on this
|
|
21
|
+
1. **Respect the folder.** `monty create` scaffolds new apps;
|
|
22
|
+
`monty connect <slug> [dir]` puts a copy of an existing app in any
|
|
23
|
+
folder you choose. Never mkdir an app folder by hand and never edit
|
|
24
|
+
`.monty/app.json` (the identity stamp). `monty current` says which app folder
|
|
25
|
+
you are in. Every file in the folder rides the source snapshot on
|
|
26
|
+
`monty save`, so keep scratch files out. Use the OS temp dir, or pipe
|
|
27
|
+
(`monty schema | <edit> | monty schema set -` needs no file), and delete
|
|
28
|
+
anything temporary before saving.
|
|
29
|
+
2. **The loop.** `monty create <slug> --name "Name" --icon <tabler-icon>`
|
|
30
|
+
(pass `--build <id>` when the prompt includes one), then `monty install`.
|
|
31
|
+
Shape the schema with `monty schema` and `monty schema set`; edit
|
|
32
|
+
`src/routes/`. Run `monty dev` once. If a shell is already running it
|
|
33
|
+
prints status and exits; otherwise start it in the background. Then
|
|
34
|
+
iterate: edit, vite hot-reloads, `monty logs -n 50` shows compile and
|
|
35
|
+
browser errors. Re-running `monty dev` is always safe. Never start a
|
|
36
|
+
second dev server for the same app and never kill a shell you didn't
|
|
37
|
+
start; `monty dev --takeover` is the one sanctioned restart.
|
|
38
|
+
**You are not done until you've saved.** `monty save "<what changed>"`
|
|
39
|
+
builds, typechecks, and pushes to the cloud copy, like `git push main`.
|
|
40
|
+
Save after every meaningful change. Unsaved work exists only on this
|
|
53
41
|
machine.
|
|
54
42
|
3. **Everything through the CLI.** `monty install`, `monty build`,
|
|
55
|
-
`monty typecheck`, `monty dev`, `monty save
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
the
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
a `valueDescriptions` map saying
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
reserved.
|
|
77
|
-
6. **Prefer a saved view for filtered tables.**
|
|
78
|
-
|
|
79
|
-
|
|
43
|
+
`monty typecheck`, `monty dev`, `monty save`. Never run vite, tsc, pnpm,
|
|
44
|
+
or npm scripts directly. `monty logs` (add `-f` to follow) is where vite
|
|
45
|
+
errors, browser errors, and save results land.
|
|
46
|
+
4. **Import only the SDK.** `@montytools/sdk` (`defineApp`, zod) and
|
|
47
|
+
`@montytools/sdk/react` (hooks: `useList`, `useInsert`, ...). Never
|
|
48
|
+
import Clerk or Convex; never fetch external APIs from app code, the CSP
|
|
49
|
+
blocks them. Open external pages with `openExternal(url)` from the SDK,
|
|
50
|
+
called synchronously from the click handler. `window.open` and
|
|
51
|
+
`target="_blank"` are blocked in the app iframe.
|
|
52
|
+
5. **The schema lives in the workspace, not in code.** Read it with
|
|
53
|
+
`monty schema` (JSON on stdout), change it with
|
|
54
|
+
`monty schema set '<json>'` — the whole config as one JSON argument, or
|
|
55
|
+
piped: `monty schema | <edit> | monty schema set -` (validated
|
|
56
|
+
server-side, additive by default). `src/monty.gen.ts` is the GENERATED
|
|
57
|
+
mirror of that config — import `{ app }` from it for typed hooks, never
|
|
58
|
+
edit it (it regenerates within a heartbeat of any change while
|
|
59
|
+
`monty dev` runs). Give every field a
|
|
60
|
+
`description` and every enum a `valueDescriptions` map saying when each
|
|
61
|
+
option applies; record-writing agents follow that guidance later.
|
|
62
|
+
Declare a page before shipping its route (`monty page add <name>` does
|
|
63
|
+
both); a save with an undeclared route refuses. Field names `_*`,
|
|
64
|
+
`updatedAt`, `createdBy` are reserved.
|
|
65
|
+
6. **Prefer a saved view for filtered tables.** One table with different
|
|
66
|
+
filters, sorting, or hidden columns is `monty views set <table> <name>`.
|
|
67
|
+
An evaluation queue:
|
|
80
68
|
`monty views set leads "Evaluate" --filter '{"pipelineId":null}'`.
|
|
81
|
-
|
|
82
|
-
`monty views
|
|
83
|
-
|
|
84
|
-
`@montytools/sdk/react`
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
`monty
|
|
90
|
-
|
|
91
|
-
the `monty-design` skill; read it before styling any page.
|
|
69
|
+
A board: `--kanban <select-field>` lanes records by that field
|
|
70
|
+
(`monty views set deals "Pipeline" --kanban stage`). Update later with
|
|
71
|
+
`monty views update`; omitted properties stay unchanged. If the table
|
|
72
|
+
needs actions, compose `RecordPage` from `@montytools/sdk/react` with
|
|
73
|
+
controls from `@montytools/sdk/ui`. Write a whole custom page only when
|
|
74
|
+
the shared components no longer fit.
|
|
75
|
+
7. **UI is stock shadcn** (preset already wired). Install curated components
|
|
76
|
+
with `monty components add <name>`; `monty components [query]` lists the
|
|
77
|
+
catalog, `monty components docs <name>` prints one's source. How pages
|
|
78
|
+
should look is the `monty-design` skill; read it before styling.
|
|
92
79
|
8. **Errors are instructions.** Every failure prints
|
|
93
|
-
`[MontyError CODE] Fix:
|
|
94
|
-
|
|
80
|
+
`[MontyError CODE] Fix: ...`. Do what the Fix says. Typecheck failures
|
|
81
|
+
block the save by design.
|
|
95
82
|
9. **Edits are real.** The dev shell reads and writes the app's LIVE
|
|
96
|
-
records
|
|
97
|
-
app
|
|
98
|
-
create; never seed junk into a team's working tables.
|
|
83
|
+
records, and every write journals into the app's Activity. Exercise the
|
|
84
|
+
app for real, clean up test rows, never seed junk into a team's tables.
|
|
99
85
|
10. **Report platform failures when sharing is enabled.** `monty support
|
|
100
|
-
status` shows whether
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
consent yourself. Do not file reports for ordinary app-code bugs or send
|
|
108
|
-
duplicates for the same incident.
|
|
86
|
+
status` shows whether an admin allowed agent reports. If enabled, submit
|
|
87
|
+
one report when a platform error still blocks you after following its
|
|
88
|
+
Fix, or when the task needs a missing platform feature. State the
|
|
89
|
+
problem, expected behavior, attempted fixes, and exact error. Don't
|
|
90
|
+
paste the conversation. If sharing is off, ask the user before running
|
|
91
|
+
`monty support enable --yes`. No reports for ordinary app-code bugs, no
|
|
92
|
+
duplicates.
|
|
109
93
|
|
|
110
94
|
## CLI reference
|
|
111
95
|
|
|
112
96
|
| command | purpose |
|
|
113
97
|
|---|---|
|
|
114
|
-
| `monty login` | browser sign-in
|
|
115
|
-
| `monty
|
|
116
|
-
| `monty
|
|
117
|
-
| `monty
|
|
118
|
-
| `monty
|
|
119
|
-
| `monty
|
|
120
|
-
| `monty
|
|
121
|
-
| `monty
|
|
122
|
-
| `monty
|
|
123
|
-
| `monty
|
|
124
|
-
| `monty
|
|
125
|
-
| `monty
|
|
126
|
-
| `monty
|
|
98
|
+
| `monty login` | browser sign-in, once per machine |
|
|
99
|
+
| `monty connect <slug> [dir]` | pull an existing app into any folder, ready for `monty dev` |
|
|
100
|
+
| `monty create <slug>` | register a new app and scaffold it (needs login) |
|
|
101
|
+
| `monty current` / `select` / `apps` | where am I / jump to app / list local copies |
|
|
102
|
+
| `monty install` / `build` / `typecheck` | lifecycle, no raw pnpm/vite/tsc |
|
|
103
|
+
| `monty dev` | run the app's session, or attach to a running one |
|
|
104
|
+
| `monty logs [-n N] [-f]` | read/follow the session log |
|
|
105
|
+
| `monty save ["what changed"]` | push the working copy to the cloud copy (build + typecheck gate it) |
|
|
106
|
+
| `monty history [slug]` | saved-version history, one row per save |
|
|
107
|
+
| `monty schema [slug]` | print the app's config (stored in the workspace) as JSON |
|
|
108
|
+
| `monty schema set '<json>'` (or `set -` piped) | write the edited config back (validated, CAS) |
|
|
109
|
+
| `monty views <list\|set\|update\|remove> <table>` | manage shared saved views |
|
|
110
|
+
| `monty page add <name>` | declare + scaffold a custom page |
|
|
111
|
+
| `monty components add <name...>` | install curated shadcn components |
|
|
112
|
+
| `monty support <status\|enable\|disable\|submit>` | consent + platform reports |
|
|
113
|
+
| `monty skills` | (re)install this skill |
|
|
@@ -1,45 +1,92 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: monty-design
|
|
3
|
-
description: Design Monty app pages — Lyra shadcn styling (
|
|
3
|
+
description: Design Monty app pages — the Monty design tokens (type ladder, radius policy, elevation), Lyra shadcn styling (sharp surfaces, stock components only), dark-only theming, and the Monty chart language (square marks on real axes). Use whenever building or restyling UI in a Monty app; pages, dashboards, charts, stat tiles, KPI rows, tables, or any prompt about how a Monty app should look.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Designing Monty pages
|
|
7
7
|
|
|
8
8
|
Monty is a B2B work OS. Apps render inside the platform shell, so a page is
|
|
9
|
-
"designed" when it
|
|
10
|
-
The design system is already installed —
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
`
|
|
24
|
-
- Sanctioned overrides are content-level only:
|
|
25
|
-
on a
|
|
9
|
+
"designed" when it is indistinguishable from the shell around it: quiet,
|
|
10
|
+
rectilinear, data-forward. The design system is already installed — the shell
|
|
11
|
+
and every app share ONE token sheet (`@montytools/sdk/tokens.css`, imported
|
|
12
|
+
by `src/index.css`) and one component surface. Your job is to NOT fight it.
|
|
13
|
+
|
|
14
|
+
## The one law: tokens and stock components, nothing invented
|
|
15
|
+
|
|
16
|
+
- Use components as they come: `Card`/`CardHeader`/`CardTitle`/
|
|
17
|
+
`CardDescription`/`CardContent`, `Table`, `Badge`, `Button`, … Never
|
|
18
|
+
rebuild a surface as a styled `div` — a hand-rolled `rounded-xl border`
|
|
19
|
+
card is the canonical mistake.
|
|
20
|
+
- Never write a raw value the tokens already name: no hex/oklch colors, no
|
|
21
|
+
`text-[13px]`, no `rounded-[10px]`, no hand-written `shadow-[…]`.
|
|
22
|
+
Semantic utilities only (`bg-background`, `text-muted-foreground`,
|
|
23
|
+
`var(--chart-2)`, `shadow-control`, …).
|
|
24
|
+
- Sanctioned overrides are content-level only: `tabular-nums` on values, a
|
|
25
|
+
width on a label column, `capitalize` on an enum. If an override styles a
|
|
26
26
|
SURFACE, you are off the system.
|
|
27
27
|
|
|
28
|
+
## The type ladder — six styles, and fewer is better
|
|
29
|
+
|
|
30
|
+
One class per role; each carries its size, line-height, weight, and
|
|
31
|
+
tracking. **Hierarchy comes from weight and ink, never from inventing
|
|
32
|
+
sizes.**
|
|
33
|
+
|
|
34
|
+
| Class | Size | Use |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| `text-tick` | 10/12 | chart axis ticks ONLY |
|
|
37
|
+
| `text-meta` | 12/16 | column headers, chips, captions, timestamps, secondary values |
|
|
38
|
+
| `text-body` | 13/20 | THE DEFAULT — content, controls, table cells (already on `body`) |
|
|
39
|
+
| `text-title` | 14/20 · 500 | card titles, page-header titles, nav rows |
|
|
40
|
+
| `text-heading` | 18/24 · 600 | page-level headings (rare — `PageHeader` owns page tops) |
|
|
41
|
+
| `text-stat` | 24/32 · 600 | stat-tile values, always with `tabular-nums` |
|
|
42
|
+
|
|
43
|
+
A typical page uses three: `text-body` (inherited — write nothing),
|
|
44
|
+
`text-meta` for secondary lines, `text-stat` on tile values. Reach for the
|
|
45
|
+
others only when the role in the table matches. Weights: default 400,
|
|
46
|
+
`font-medium` for titled/interactive text; 600 arrives only via
|
|
47
|
+
`text-heading`/`text-stat`. Never `font-bold`, never `text-xs/sm/lg/2xl` —
|
|
48
|
+
those sizes exist for legacy chrome, not for pages.
|
|
49
|
+
|
|
50
|
+
## Radius policy — sharp, everywhere
|
|
51
|
+
|
|
52
|
+
Lyra is rectilinear: surfaces, controls, and overlays are ALL square-
|
|
53
|
+
cornered. Cards/tables/tiles/chips are `rounded-none` with `bg-card ring-1
|
|
54
|
+
ring-foreground/10` hairlines, never borders; buttons, inputs, dialogs, and
|
|
55
|
+
popovers come sharp from the stock components. Elevation and hierarchy come
|
|
56
|
+
from hairlines and the three shadows, never from softened corners.
|
|
57
|
+
`rounded-full` (avatars, status dots) is the ONE exception — write no other
|
|
58
|
+
`rounded-*` class yourself; the semantic names the chrome uses
|
|
59
|
+
(`rounded-control`, `rounded-overlay`) resolve to 0 by policy.
|
|
60
|
+
|
|
61
|
+
## Color and status
|
|
62
|
+
|
|
63
|
+
The palette is the platform's; you never pick colors. Ground `bg-background`,
|
|
64
|
+
surface `bg-card`, ink `text-foreground`/`text-muted-foreground`, quiet fill
|
|
65
|
+
`bg-accent`, the one accent `bg-primary`, links `text-link`. Status is a
|
|
66
|
+
**dot + muted text**, never a colored pill: `text-success`, `text-warning`,
|
|
67
|
+
`text-destructive` for the dot/figure, label in `text-muted-foreground`.
|
|
68
|
+
Elevation: `shadow-control` on rest-state controls, `shadow-btn-primary` on
|
|
69
|
+
the one primary action, `shadow-menu` on overlays — never `shadow-md/lg/xl`.
|
|
70
|
+
|
|
71
|
+
## Spacing — the 4px grid, three names
|
|
72
|
+
|
|
73
|
+
Page bodies are `p-page` (24px); cards pad themselves; card grids are
|
|
74
|
+
`gap-3` (12px); control rows `gap-2`. Stay on the default Tailwind steps
|
|
75
|
+
(`p-1`…`p-6`); if you're typing an arbitrary value like `p-[18px]`, the
|
|
76
|
+
layout is wrong, not the scale.
|
|
77
|
+
|
|
28
78
|
## Dark-only, in the shell's palette
|
|
29
79
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
the template ships dark by default: `class="dark"` on `<html>` in
|
|
35
|
-
`index.html`, and any boot-splash background set to the dark `--background`
|
|
36
|
-
value. Verify your page against the shell, not in isolation.
|
|
80
|
+
Monty is dark-only; the tokens ship the shell palette (#101112 ground) and
|
|
81
|
+
`index.html` carries `class="dark"` plus the dark boot splash. Never
|
|
82
|
+
retheme, never hand-pick a dark color, and verify your page against the
|
|
83
|
+
shell (`/apps/<slug>/…`), not the bare dev port.
|
|
37
84
|
|
|
38
85
|
## Page anatomy
|
|
39
86
|
|
|
40
87
|
Every page opens with the platform chrome from `@montytools/sdk/ui` — the
|
|
41
|
-
SAME components the shell renders system table views with
|
|
42
|
-
|
|
88
|
+
SAME components the shell renders system table views with. Never hand-roll
|
|
89
|
+
the header bar.
|
|
43
90
|
|
|
44
91
|
```tsx
|
|
45
92
|
import { PageHeader, PageHeaderButton } from "@montytools/sdk/ui";
|
|
@@ -50,7 +97,7 @@ import { PageHeader, PageHeaderButton } from "@montytools/sdk/ui";
|
|
|
50
97
|
<PageHeaderButton primary onClick={main}><Plus className="size-3.5" /> New</PageHeaderButton>
|
|
51
98
|
</PageHeader>
|
|
52
99
|
<div className="min-h-0 flex-1 overflow-auto">
|
|
53
|
-
<div className="flex flex-col gap-3 p-
|
|
100
|
+
<div className="flex flex-col gap-3 p-page pt-4">
|
|
54
101
|
{/* KPI row */}
|
|
55
102
|
<div className="grid grid-cols-[repeat(auto-fill,minmax(14rem,1fr))] gap-3">…</div>
|
|
56
103
|
{/* section cards */}
|
|
@@ -72,36 +119,35 @@ A stat tile is a stock Card, nothing more:
|
|
|
72
119
|
<Card size="sm">
|
|
73
120
|
<CardHeader>
|
|
74
121
|
<CardDescription>Leads added</CardDescription>
|
|
75
|
-
<CardTitle className="text-
|
|
76
|
-
<div className="text-
|
|
122
|
+
<CardTitle className="text-stat tabular-nums">{value}</CardTitle>
|
|
123
|
+
<div className="text-meta text-muted-foreground">{delta or context}</div>
|
|
77
124
|
</CardHeader>
|
|
78
125
|
</Card>
|
|
79
126
|
```
|
|
80
127
|
|
|
81
128
|
## Charts: sharp marks on real axes
|
|
82
129
|
|
|
83
|
-
Chart marks are **sharp rectangles — no rounded corners, ever
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
130
|
+
Chart marks are **sharp rectangles — no rounded corners, ever**. The three
|
|
131
|
+
failure modes to avoid: pill "track+fill" bars (read as progress bars),
|
|
132
|
+
rounded caps (misstate where a value ends), and floating bars with no axis
|
|
133
|
+
(nothing anchors the eye).
|
|
87
134
|
|
|
88
135
|
- **Horizontal bars**: grow from a left hairline baseline
|
|
89
136
|
(`border-l border-foreground/25`) over quarter gridlines
|
|
90
137
|
(`absolute left-1/4|1/2|3/4 border-l border-foreground/10` —
|
|
91
138
|
foreground-alpha so hairlines read on any surface), bar `h-4`,
|
|
92
|
-
fill `var(--chart-2)`. Label left in `text-muted-foreground`
|
|
93
|
-
(fixed-width, truncate); count right in `font-medium
|
|
94
|
-
zero values muted with no fill.
|
|
139
|
+
fill `var(--chart-2)`. Label left in `text-body text-muted-foreground`
|
|
140
|
+
(fixed-width, truncate); count right in `text-body font-medium
|
|
141
|
+
tabular-nums`, zero values muted with no fill.
|
|
95
142
|
- **Columns**: a value axis with a baseline (`border-foreground/25`) plus
|
|
96
|
-
hairline gridlines (`border-foreground/10`) and
|
|
97
|
-
right-aligned in a left gutter). Round the axis top to a
|
|
98
|
-
(≤4 exact; else the next multiple of 5/10/50) so ticks
|
|
99
|
-
Direct value labels above non-zero columns.
|
|
100
|
-
- **Color**: one accent ramp
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
never wears the data color.
|
|
143
|
+
hairline gridlines (`border-foreground/10`) and `text-tick` tabular tick
|
|
144
|
+
labels (muted, right-aligned in a left gutter). Round the axis top to a
|
|
145
|
+
"nice" integer (≤4 exact; else the next multiple of 5/10/50) so ticks
|
|
146
|
+
stay honest. Direct `text-tick` value labels above non-zero columns.
|
|
147
|
+
- **Color**: one accent ramp — `var(--chart-2)` for the emphasized series
|
|
148
|
+
(today, the selection), `var(--chart-5)` for context. Never restate the
|
|
149
|
+
values as hex, never a hue per category, and text never wears the data
|
|
150
|
+
color.
|
|
105
151
|
- **Numbers**: `tabular-nums` everywhere values align; money via
|
|
106
152
|
`toLocaleString(undefined, { style: "currency", currency: "USD" })`
|
|
107
153
|
(compact notation on tiles, full in tables).
|
|
@@ -109,15 +155,18 @@ and floating bars with no axis (nothing anchors the eye).
|
|
|
109
155
|
muted line ("No activity logged on this day.") — structure stays, zeros
|
|
110
156
|
carry meaning.
|
|
111
157
|
|
|
112
|
-
Reference implementations: `
|
|
113
|
-
|
|
114
|
-
`demos/crm-v2/src/routes/
|
|
158
|
+
Reference implementations: `demos/crm-v2/src/routes/stats.tsx` (KPI tiles,
|
|
159
|
+
day-selector columns, status bars, top-deals table) and
|
|
160
|
+
`demos/crm-v2/src/routes/reports.tsx` (stat tiles over live records).
|
|
115
161
|
|
|
116
162
|
## Checklist before you call a page done
|
|
117
163
|
|
|
118
|
-
1. No `border`/`rounded-*`
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
164
|
+
1. No `border`/`rounded-*` anywhere you authored (`rounded-full` on dots
|
|
165
|
+
and avatars is the one exception) — surfaces and controls are stock
|
|
166
|
+
components, sharp by policy.
|
|
167
|
+
2. No text class outside the six ladder styles; no arbitrary values
|
|
168
|
+
(`text-[…]`, `bg-[#…]`, `rounded-[…]`, `shadow-[…]`).
|
|
169
|
+
3. No rounded corners on any chart mark; every bar/column sits on an axis.
|
|
170
|
+
4. Dark: the page blends into the shell with no light seams.
|
|
171
|
+
5. Values in tabular figures; status as dot + muted text, never a pill.
|
|
172
|
+
6. Screenshot it inside the shell (`/apps/<slug>/…`), not just the dev port.
|