@wallarm-org/claude-design 4.9.0 → 4.10.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.
Files changed (40) hide show
  1. package/README.md +6 -5
  2. package/dist/SETUP.md +35 -8
  3. package/dist/UPDATE.md +11 -9
  4. package/dist/project/README.md +49 -19
  5. package/dist/project/app-skeleton.dc.html +268 -0
  6. package/dist/project/components/AreaChart/README.md +0 -4
  7. package/dist/project/components/AreaChart/stories.js +1 -1
  8. package/dist/project/components/Badge/README.md +5 -31
  9. package/dist/project/components/BarList/README.md +0 -4
  10. package/dist/project/components/BarList/stories.js +1 -1
  11. package/dist/project/components/Chart/README.md +0 -4
  12. package/dist/project/components/Chart/stories.js +1 -1
  13. package/dist/project/components/CodeEditor/stories.js +4 -4
  14. package/dist/project/components/CodeEditor/stories.md +0 -4
  15. package/dist/project/components/CodeSnippet/README.md +0 -8
  16. package/dist/project/components/CodeSnippet/stories.js +2 -2
  17. package/dist/project/components/ColumnChart/README.md +0 -4
  18. package/dist/project/components/ColumnChart/stories.js +1 -1
  19. package/dist/project/components/HorizontalBarStack/README.md +0 -4
  20. package/dist/project/components/HorizontalBarStack/stories.js +1 -1
  21. package/dist/project/components/LineChart/README.md +0 -39
  22. package/dist/project/components/LineChart/stories.js +1 -1
  23. package/dist/project/components/List/README.md +1 -1
  24. package/dist/project/components/List/stories.js +1 -1
  25. package/dist/project/components/Metric/README.md +0 -9
  26. package/dist/project/components/Metric/stories.js +1 -1
  27. package/dist/project/components/Overview/README.md +0 -4
  28. package/dist/project/components/Overview/stories.js +1 -1
  29. package/dist/project/components/PieChart/README.md +0 -4
  30. package/dist/project/components/PieChart/stories.js +1 -1
  31. package/dist/project/components/UTILITIES.md +3 -3
  32. package/dist/project/components/bundle.css +15 -6
  33. package/dist/project/components/bundle.js +4 -4
  34. package/dist/project/components/index.d.ts +2 -2
  35. package/dist/project/design-system.json +4 -4
  36. package/dist/project/sampler.dc.html +5 -7
  37. package/dist/project/tokens.json +2 -2
  38. package/dist/wallarm-app.dc.html +269 -0
  39. package/dist/wallarm-sampler.dc.html +5 -7
  40. package/package.json +2 -2
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Wallarm Design System for Claude Design
2
2
 
3
3
  Install [Wallarm Design System](https://github.com/wallarm/design-system) in Claude Design from
4
- one prompt. Paste the prompt from the [Claude Design guide](https://wallarm.github.io/design-system/ai/claude-design)
4
+ one prompt. Paste the prompt from the [Claude Design guide](https://wallarm.github.io/design-system/ai/claude-design#your-own-copy)
5
5
  into a Claude Design chat; Claude runs:
6
6
 
7
7
  ```bash
@@ -14,9 +14,10 @@ The command writes `wallarm-design-system/` and never prompts:
14
14
  | --- | --- |
15
15
  | `project/` | The system to publish as a Design System artifact: runtime bundle, tokens, CSS, fonts, component guides and previews. Its index lists no asset groups until `index` adds them |
16
16
  | `assets/`, `assets.json` | The icon and logo SVGs for the system's galleries, uploaded as assets (not files), and their manifest (group, name, path, sha256, size, type, in gallery order) |
17
- | `SETUP.md` | Claude's steps: publish the system, install it on a canvas, add and check the sampler |
17
+ | `SETUP.md` | Claude's steps: publish the system, install it on a canvas, add and check the sampler and the app skeleton |
18
18
  | `UPDATE.md` | Claude's steps to update an installed system to this release (also written alone by `update`) |
19
19
  | `wallarm-sampler.dc.html` | The sampler artboard, linked to the canvas's `ds/wallarm-design-system/` copy |
20
+ | `wallarm-app.dc.html` | The app skeleton (the system's `app-skeleton.dc.html`), linked the same way; Claude edits only its `APP` object |
20
21
  | `files.json` | Each written file with its sha256 |
21
22
  | `removed.json` | With `--existing`: the paths an update drops |
22
23
 
@@ -63,7 +64,7 @@ and `dist/` from `../design-system` (`DESIGN_SYSTEM_DIR` in `src/config.ts`); th
63
64
  `@wallarm-org/design-system` package is not affected. Each stable release publishes this package
64
65
  from `deploy-site.yml` (job `claude-design`): it runs `export`, sets the version to the tag and
65
66
  runs `pnpm publish`, whose `prepack` (`src/pack.ts`) packs `.claude-design/` into `dist/` with
66
- the rendered `content/SETUP.md` and `content/UPDATE.md` and the canvas sampler. Wallarm's own artifact is synced by hand
67
+ the rendered `content/SETUP.md` and `content/UPDATE.md` and the canvas sampler and skeleton. Wallarm's own artifact is synced by hand
67
68
  with the [`claude-design-sync`](../../.claude/skills/claude-design-sync/SKILL.md) skill; the
68
69
  designer guide is `apps/website/docs/ai/claude-design.mdx`. What Storybook does not show, and
69
70
  so Claude Design cannot learn: [CLAUDE_DESIGN_GAP.md](./CLAUDE_DESIGN_GAP.md).
@@ -79,11 +80,11 @@ All under `src/`. Outside it: `bin/claude-design.js` (the npm CLI, plain Node ES
79
80
  | `tokens/` | Design tokens |
80
81
  | `docs/` | Component guides, prop types and the project README (embeds `design-system/src/guidelines/rules.md`) |
81
82
  | `previews/` | Story previews |
82
- | `sampler/` | The canonical screen `sampler.dc.html`, checked against the built CSS, tokens and exports, and shipped at the project root |
83
+ | `sampler/` | The canonical screen `sampler.dc.html` and the app skeleton `app-skeleton.dc.html` (the README's "Start here"), checked against the built CSS, tokens and exports, and shipped at the project root |
83
84
  | `assets/` | Icons, fonts and the cover |
84
85
  | `harness/` | React 18 tests that mount the built bundle and previews |
85
86
  | `config.ts` | Artifact identity, namespace, budgets |
86
- | `pack.ts` | `prepack`: `.claude-design/` → `dist/` for npm (SVGs moved to `dist/assets/` with `assets.json`, rendered `SETUP.md` and `UPDATE.md`, canvas sampler) |
87
+ | `pack.ts` | `prepack`: `.claude-design/` → `dist/` for npm (SVGs moved to `dist/assets/` with `assets.json`, rendered `SETUP.md` and `UPDATE.md`, canvas sampler and skeleton) |
87
88
  | `build.ts`, `verify.ts` | Builder and repeatability check |
88
89
 
89
90
  ### Commands
package/dist/SETUP.md CHANGED
@@ -1,17 +1,18 @@
1
- # Install Wallarm Design System 4.9.0 in Claude Design
1
+ # Install Wallarm Design System 4.10.0 in Claude Design
2
2
 
3
- This guide ships with Wallarm Design System 4.9.0. Work through the steps in order and run each check before moving on.
3
+ This guide ships with Wallarm Design System 4.10.0. Work through the steps in order and run each check before moving on.
4
4
 
5
5
  The export wrote `wallarm-design-system/`:
6
6
 
7
7
  | Path | Contents | Publish it |
8
8
  | --- | --- | --- |
9
- | `project/` | The design system: 373 files | Yes: every file, unchanged |
9
+ | `project/` | The design system: 374 files | Yes: every file, unchanged |
10
10
  | `assets/` | The icon and logo galleries: 583 SVG files in Logos (1), Icons (582) | As assets, in step 1 |
11
11
  | `assets.json` | Each SVG's group, name, path and sha256 | No |
12
12
  | `SETUP.md` | This guide | No |
13
13
  | `UPDATE.md` | The update guide, for a later release | No |
14
14
  | `wallarm-sampler.dc.html` | The sampler artboard, for step 4 | To the canvas, in step 4 |
15
+ | `wallarm-app.dc.html` | The app skeleton, for step 6 | To the canvas, in step 6 |
15
16
  | `files.json` | Every file the export wrote, with its sha256 | No |
16
17
  | `removed.json` | Paths an update drops. Written only with `--existing` | No |
17
18
  | `blobs.json` | You write it in step 1: each SVG's path and the url its upload returned. The `index` command rewrites it keyed by sha256. The `update` command deletes it | No |
@@ -26,7 +27,7 @@ Create a new **Design System** artifact titled `Wallarm Design System`, with the
26
27
  - Send `project/components/index.d.ts` with the content type `text/plain`; the artifact refuses it otherwise. Every other file's type follows its extension.
27
28
  - A publish takes at most 255 files, so send the files in batches of up to 200.
28
29
  2. **Icons and logos.** The galleries are asset uploads, not files: never publish anything from `wallarm-design-system/assets/` as a file under `project/`.
29
- 1. Run `npx -y @wallarm-org/claude-design@4.9.0 index --blobs wallarm-design-system/blobs.json`. It exits 3 and lists in `wallarm-design-system/upload.json` the local paths of the SVGs to upload (identical SVGs share one upload).
30
+ 1. Run `npx -y @wallarm-org/claude-design@4.10.0 index --blobs wallarm-design-system/blobs.json`. It exits 3 and lists in `wallarm-design-system/upload.json` the local paths of the SVGs to upload (identical SVGs share one upload).
30
31
  2. Upload them in the order listed: the Artifact tool's publish with the system's `url`, `asset: true` and `file_paths` set to the next 25 paths from `upload.json`, copied as they are. With `upload_asset`, if that is the tool you have, send at most 10 per call. The first install takes about 24 calls. If an upload is refused, show the person the error and stop.
31
32
  3. After each call, add one entry per uploaded file to `wallarm-design-system/blobs.json`, a JSON object: the path as `upload.json` lists it, mapped to the `url` the result gives for that file, for example `{"wallarm-design-system/assets/Icons/activity.svg": "https://…/_blob/<id>"}`. Copy the url, not the asset's `id`. If the result has no url but gives each file's sha256 and id (as `upload_asset` does), key the entry by that sha256 instead.
32
33
  4. Run the `index` command again. It rewrites `blobs.json` keyed by sha256; keep its entries and add new ones after them. Exit 3: upload the paths it lists now and run it again. Exit 0: it wrote the asset groups into `project/design-system.json`.
@@ -34,7 +35,7 @@ Create a new **Design System** artifact titled `Wallarm Design System`, with the
34
35
 
35
36
  In artboards, icons are still `WallarmDS.Icons.<Name>` and the logo `WallarmDS.Logo`, from `components/bundle.js`; the galleries show them on the system's page.
36
37
 
37
- Check: every `project/` path in `wallarm-design-system/files.json` (373 files) is in the artifact, its title is `Wallarm Design System`, and `project/design-system.json` has a `lastChange.note` that starts with `v4.9.0:`. The Artifact tool's `list` with the system's `url` and `scope: "assets"` shows at least 580 assets. The system's page shows the asset groups Logos (1), Icons (582), with every icon drawn (no broken image). The page may add `project/manifest.json` and files under `project/api/`; they don't count. Give the person the artifact's link: they need it to install the system on other canvases and to update it.
38
+ Check: every `project/` path in `wallarm-design-system/files.json` (374 files) is in the artifact, its title is `Wallarm Design System`, and `project/design-system.json` has a `lastChange.note` that starts with `v4.10.0:`. The Artifact tool's `list` with the system's `url` and `scope: "assets"` shows at least 580 assets. The system's page shows the asset groups Logos (1), Icons (582), with every icon drawn (no broken image). The page may add `project/manifest.json` and files under `project/api/`; they don't count. Give the person the artifact's link: they need it to install the system on other canvases and to update it.
38
39
 
39
40
  If a publish is refused for a reason this step doesn't cover, show the person the error and stop. Don't edit or rename files to get past it.
40
41
 
@@ -103,7 +104,31 @@ If you can't see the canvas or its console, ask the person to check each item an
103
104
 
104
105
  The sampler is light only. For a dark artboard, set `theme="dark"` on its `WallarmDS.Root`, as the README says.
105
106
 
106
- When every check passes, tell the person the Wallarm Design System is ready, give them the system link, and wait for their design request.
107
+ ## 6. Build the app skeleton
108
+
109
+ `wallarm-design-system/wallarm-app.dc.html` is the person's application frame: the console header, the product rail, a product menu and an empty page. They design their screens inside it. It is the same file as the system's `project/app-skeleton.dc.html`, with canvas link lines.
110
+
111
+ 1. Publish it to the canvas at `project/wallarm-app.dc.html` exactly as step 4 publishes the sampler, with the same folder rule for its three link lines.
112
+ 2. Merge this key into `boards` in `project/canvas.json` and append `"wallarm-app.dc.html"` to `order`, as in step 4. It sits right of the sampler; if the canvas has other boards, the step 4 placement rule applies.
113
+
114
+ ```json
115
+ {"wallarm-app.dc.html":{"x":1520,"y":0,"w":1440,"h":900,"title":"Wallarm app","expand":"fill"}}
116
+ ```
117
+
118
+ 3. If the person's message names their product, its menu items or its pages (for example "My product: API Security. Menu: Overview, API Discovery; group Detect & Respond: Attacks, Incidents"), edit the board's `APP` object, the block that starts with `var APP = {` at the top of its script, and change nothing else in the file:
119
+ - `nav.productLabel` is the product's name and `nav.productPath` is `/` plus its kebab-case id. Make the matching `rail` entry carry the same `label` and `path`; keep or replace the other rail products as they ask.
120
+ - `nav.items` follows the menu they gave, in their order: a page is `{ type: 'link', id, label, path }`; a named group of pages is `{ type: 'group', id, label, defaultExpanded: true, children: [links] }`; a label over a run of entries is `{ type: 'section-header', id, label }`. Use `type: 'drill'` only if they ask for an entity picker. `id` and `path` are the label in kebab-case with punctuation dropped (`API Discovery` → `api-discovery`, `Detect & Respond` → `detect-respond`), each path one segment and unique. Give every top-level link and group an `icon` (a `WallarmDS.Icons` name as a string), or give none: mixed icons misalign the menu.
121
+ - `start` is the first link's `path`. A link may take `action`, the label of its page's primary button, and `dividerAfter`, only when they name them; drop the sample's otherwise.
122
+
123
+ If the message names none of these, keep the sample product as it is.
124
+
125
+ Check, as in step 5 (ask the person if you can't see the canvas):
126
+
127
+ - A board titled `Wallarm app` shows the header (logo, search, tenant, assistant, notification bell with 2 unread, help), the rail (Home, the products, and Settings and the account at the bottom), the product menu, the breadcrumb and a page titled after the first menu item with the `Ask Claude to design this screen` empty state.
128
+ - The console has no `[WallarmDS]` warning and no error. `[WallarmDS] icon "…" is not in WallarmDS.Icons` means an `icon` in `APP` is misspelled: fix the name there.
129
+ - Click another menu item: the menu highlights it, and the breadcrumb and the page title follow.
130
+
131
+ When every check passes, tell the person the Wallarm Design System is ready, give them the system link, and say the canvas has two boards: the sampler, a reference screen, and their app skeleton. Ask for the screens they want and design each one inside the skeleton's `Page`, as the README's "Start here" step 3 says: title and action through `APP` (add a menu link for a screen that has none), `PageDescription` and a `PageToolbar` around a new `PageContent` as the pattern guide says, `fixed-height` on a list page, the screen's data in `renderVals()`, and the shell kept. Then wait for their design request.
107
132
 
108
133
  ## Update to a new release
109
134
 
@@ -116,8 +141,10 @@ To update a system the person already has, run `npx -y @wallarm-org/claude-desig
116
141
  | The publish is refused for `index.d.ts` | Send `project/components/index.d.ts` as `text/plain`. |
117
142
  | The publish is refused for too many files | Send smaller batches, as step 1 says. |
118
143
  | The `index` command exits 3 | Upload the paths in `upload.json`, add their urls to `blobs.json` and run it again. An entry it names as invalid has a key that matches no SVG or a value that isn't a 32-character blob id or `/_blob/<id>` url: copy it again from `upload.json` and the upload result. |
119
- | Publishing `project/design-system.json` is refused as stale | The system's page saved a newer index. Save the version the refusal hands back as `current-index.json` (copy it; don't retype it), run `npx -y @wallarm-org/claude-design@4.9.0 index --blobs wallarm-design-system/blobs.json --index current-index.json`, and publish the index again. Nothing needs uploading again. |
144
+ | Publishing `project/design-system.json` is refused as stale | The system's page saved a newer index. Save the version the refusal hands back as `current-index.json` (copy it; don't retype it), run `npx -y @wallarm-org/claude-design@4.10.0 index --blobs wallarm-design-system/blobs.json --index current-index.json`, and publish the index again. Nothing needs uploading again. |
120
145
  | The gallery is empty or shows broken images | `project/design-system.json` was published before the `index` command exited 0, or with a wrong url. Fix `blobs.json`, run `index` again and publish the index again. |
146
+ | The skeleton shows no menu, or a click doesn't move the highlight | `APP.nav` is broken: every node needs `type`, `id` and `label`, every link a one-segment `path`, and `start` must be one of those paths. Fix the object; change nothing else. |
147
+ | The rail's products, the page title or the tenant are empty | The canvas runtime ignores `children="{{…}}"` holes. Tell the person and report it with the version (4.10.0). |
121
148
  | No sampler board shows | The file isn't at `project/wallarm-sampler.dc.html`, or `project/canvas.json` has no `"wallarm-sampler.dc.html"` in `boards` or `order`. |
122
149
  | Components render unstyled | The link lines don't reach `project/ds/wallarm-design-system/`. The artboard must sit directly in `project/`, and the folder name must match step 2. |
123
150
  | `WallarmDS is not defined` | `components/bundle.js` isn't loaded: same cause as above. |
@@ -127,4 +154,4 @@ To update a system the person already has, run `npx -y @wallarm-org/claude-desig
127
154
  | Text shows in the system font | The fonts in `project/fonts/` weren't published or installed. Check step 1's file check and step 2. |
128
155
  | The export command fails or can't reach npm | Show the person its output and stop. |
129
156
 
130
- Never edit a file in the system artifact or under `project/ds/wallarm-design-system/` on a canvas to make a check pass. If a check still fails, tell the person which check, what you saw and the version (4.9.0). Problems go to https://github.com/wallarm/design-system/issues.
157
+ Never edit a file in the system artifact or under `project/ds/wallarm-design-system/` on a canvas to make a check pass. If a check still fails, tell the person which check, what you saw and the version (4.10.0). Problems go to https://github.com/wallarm/design-system/issues.
package/dist/UPDATE.md CHANGED
@@ -1,6 +1,6 @@
1
- # Update Wallarm Design System to 4.9.0 in Claude Design
1
+ # Update Wallarm Design System to 4.10.0 in Claude Design
2
2
 
3
- This guide updates a Wallarm Design System artifact the person installed in Claude Design to 4.9.0. Work through the steps in order and run each check before moving on.
3
+ This guide updates a Wallarm Design System artifact the person installed in Claude Design to 4.10.0. Work through the steps in order and run each check before moving on.
4
4
 
5
5
  ## 0. Find the system
6
6
 
@@ -18,15 +18,15 @@ Check: `current-files.json` is a JSON array that has `project/design-system.json
18
18
 
19
19
  ## 2. Export the release
20
20
 
21
- Run this command; it pins 4.9.0, the release of this guide:
21
+ Run this command; it pins 4.10.0, the release of this guide:
22
22
 
23
23
  ```bash
24
- npx -y @wallarm-org/claude-design@4.9.0 export --overwrite --existing current-files.json
24
+ npx -y @wallarm-org/claude-design@4.10.0 export --overwrite --existing current-files.json
25
25
  ```
26
26
 
27
27
  Exit 0 or 3 are both done; on 3 the output names the manual step, which is removing the paths in `wallarm-design-system/removed.json` (steps 3 and 6). Any other exit: show the person the output and stop.
28
28
 
29
- Check: `wallarm-design-system/files.json` and `wallarm-design-system/SETUP.md` exist, and `wallarm-design-system/SETUP.md` is for 4.9.0. The steps below point into it.
29
+ Check: `wallarm-design-system/files.json` and `wallarm-design-system/SETUP.md` exist, and `wallarm-design-system/SETUP.md` is for 4.10.0. The steps below point into it.
30
30
 
31
31
  ## 3. Confirm removals
32
32
 
@@ -42,14 +42,14 @@ Publish `wallarm-design-system/project/` to the same artifact link: every file e
42
42
  2. Run this exact command, and use it unchanged on every run below:
43
43
 
44
44
  ```bash
45
- npx -y @wallarm-org/claude-design@4.9.0 index --blobs wallarm-design-system/blobs.json --index current-index.json
45
+ npx -y @wallarm-org/claude-design@4.10.0 index --blobs wallarm-design-system/blobs.json --index current-index.json
46
46
  ```
47
47
 
48
48
  It reuses the blob id of every SVG whose sha256 the current index already has, so `upload.json` lists only the new and changed SVGs. Exit 3: upload them and add their urls to `blobs.json` as SETUP.md step 1's "Icons and logos" says (items 2 and 3), then run the command again. Exit 0: nothing (more) needs uploading.
49
49
  3. Right before publishing, read `project/design-system.json` again into `current-index.json` as in item 1 (the system's page may have saved it meanwhile), and run the command again: it exits 0 and merges this release into the index just read.
50
50
  4. Publish `project/design-system.json` at once, last and alone.
51
51
 
52
- Check: every `project/` path in `wallarm-design-system/files.json` (373 files) is in the artifact, `project/design-system.json` has a `lastChange.note` that starts with `v4.9.0:`, and the page shows Logos (1), Icons (582) with no broken image. `project/manifest.json` and files under `project/api/` are written by the system's page: they don't count and stay.
52
+ Check: every `project/` path in `wallarm-design-system/files.json` (374 files) is in the artifact, `project/design-system.json` has a `lastChange.note` that starts with `v4.10.0:`, and the page shows Logos (1), Icons (582) with no broken image. `project/manifest.json` and files under `project/api/` are written by the system's page: they don't count and stay.
53
53
 
54
54
  ## 6. Remove dropped files
55
55
 
@@ -69,7 +69,9 @@ On one canvas you reinstalled in step 7:
69
69
  2. Publish the new sampler to `project/wallarm-sampler.dc.html` as SETUP.md step 4 says. Read `project/canvas.json` right before merging into it (the canvas writes it when boards move), keep its board's `x` and `y` and its place in `order`.
70
70
  3. Run the checks in SETUP.md step 5.
71
71
 
72
- When every check passes, tell the person the system is on 4.9.0, give them the system link, and wait for their request.
72
+ Never replace or edit `project/wallarm-app.dc.html` on an update: the app skeleton is the person's own work (their product, menu and screens). Only the sampler is refreshed. Tell the person so; if they want the new release's skeleton too, add it as a new board as SETUP.md step 6 says, under another file name such as `wallarm-app-new.dc.html`.
73
+
74
+ When every check passes, tell the person the system is on 4.10.0, give them the system link, and wait for their request.
73
75
 
74
76
  ## When something looks wrong
75
77
 
@@ -81,4 +83,4 @@ When every check passes, tell the person the system is on 4.9.0, give them the s
81
83
  | The gallery is empty or shows broken images | `project/design-system.json` was published before the `index` command exited 0, or with a wrong url. Fix `blobs.json`, run `index` again and publish the index again. |
82
84
  | A canvas shows an older version | Install the system again on that canvas. |
83
85
 
84
- Anything else: see "When something looks wrong" in `wallarm-design-system/SETUP.md`. Never edit a file in the system artifact or under a canvas's `project/ds/` folder to make a check pass. If a check still fails, tell the person which check, what you saw and the version (4.9.0). Problems go to https://github.com/wallarm/design-system/issues.
86
+ Anything else: see "When something looks wrong" in `wallarm-design-system/SETUP.md`. Never edit a file in the system artifact or under a canvas's `project/ds/` folder to make a check pass. If a check still fails, tell the person which check, what you saw and the version (4.10.0). Problems go to https://github.com/wallarm/design-system/issues.
@@ -4,9 +4,28 @@ Generated from wallarm/design-system — change it in code and run /claude-desig
4
4
 
5
5
  Wallarm's product UI system uses the real library components, semantic tokens and Geist fonts. Build with components first, style with semantic tokens second, and reach for primitives last. The generated canvas bundle uses the page's React 18 runtime.
6
6
 
7
+ ## Start here
8
+
9
+ On a Design canvas, every screen lives inside the app skeleton: [`app-skeleton.dc.html`](app-skeleton.dc.html), the console frame with the header, the product rail, a product menu (`RemoteShell` from a `NavConfig`) and an empty `Page`. Set it up before the first screen:
10
+
11
+ 1. If the canvas has `project/wallarm-app.dc.html`, that is the person's skeleton: use it and never replace it. Otherwise copy this system's `app-skeleton.dc.html` to `project/wallarm-app.dc.html`. On a canvas this system is installed in `project/ds/<folder>/`, the folder this README is in; boards sit directly in `project/`. If that folder has no `app-skeleton.dc.html`, read `project/app-skeleton.dc.html` from the design system artifact the canvas was installed from. In the copy, replace the three link lines in `<head>` with these four, `<folder>` being that folder's name, and change nothing else:
12
+
13
+ ```html
14
+ <script src="./support.js"></script>
15
+ <link rel="stylesheet" href="ds/<folder>/tokens.css">
16
+ <link rel="stylesheet" href="ds/<folder>/components/bundle.css">
17
+ <script src="ds/<folder>/components/bundle.js"></script>
18
+ ```
19
+
20
+ Add it as the first board: merge `"wallarm-app.dc.html": {"x": 0, "y": 0, "w": 1440, "h": 900, "title": "Wallarm app", "expand": "fill"}` into `boards` in `project/canvas.json` (right of the other boards if there are any: `x` is their largest `x + w` plus 80) and append `"wallarm-app.dc.html"` to `order`.
21
+ 2. Set up the shell only through its `APP` object, the block that starts with `var APP = {` at the top of its script, from the person's request: the product's name and path, its menu (`link`, `group` and `section-header` nodes; `drill` only if asked; ids and paths in kebab-case with punctuation dropped, `Detect & Respond` → `detect-respond`), the rail's products and `start`, the first link's path. Give every top-level link and group an `icon` (a `WallarmDS.Icons` name), or give none. When you rebuild the menu, drop the sample's `action` and `dividerAfter` unless the person names them. The comment above the object describes each field. With no product named, keep the sample. Leave the header, rails and product menu markup as it is.
22
+ 3. Design each requested screen inside the skeleton's `Page`, following its pattern guide. Set `start` to the path of the screen's menu link; if the screen has no link, add one to `APP.nav.items`, in kebab-case like the others, and set `start` to it. The link's label is the page title and its `action` the primary button. Keep `PageHeader`; add `PageDescription` in its `PageHeaderGroup` and a `PageToolbar` (search, tabs, filters) between `PageHeader` and `PageContent`; on a page that lists rows, set `fixed-height="{{yes}}"` on `Page`. Replace the `EmptyState` in `PageContent` with the screen. The screen's own data (table rows, counts) goes in `renderVals()`, outside `APP`. For several screens, make one board per screen: a copy of the skeleton under a new file name, with its own `start`.
23
+
24
+ Skip the skeleton only when the person asks for a standalone component or a screen without the app frame. The console must show no `[WallarmDS]` warning, and clicking a menu item moves the highlight, the breadcrumb and the page title.
25
+
7
26
  ## Rules
8
27
 
9
- These are the design system's own rules (`src/guidelines/rules.md`), embedded at build time. On the canvas, read `get_guideline` as "the pattern guide": they ship in the npm package under `dist/guidelines/` (`rules.md`, `foundations/`, `patterns/`) and through the MCP server's `get_guideline` tool.
28
+ These are the design system's own rules (`src/guidelines/rules.md`), embedded at build time. On the canvas, read `get_guideline` as "the pattern guide": they ship in the npm package under `dist/guidelines/` (`rules.md`, `foundations/`, `patterns/`, `templates/`) and through the MCP server's `get_guideline` tool.
10
29
 
11
30
  Every numeric utility is in px, not 4px steps: p-16 is 16px, p-4 is 4px. Translate Tailwind habits (p-4 → p-16, gap-6 → gap-24, w-64 → w-256).
12
31
 
@@ -14,29 +33,30 @@ Before composing a screen, call get_guideline for the pattern (app shell, list p
14
33
 
15
34
  - p-5, gap-3, p-10 → stay on the scale: 1, 2, 4, 6, 8, 12, 16, 20, 24, 28, 32, 40, 48, 64…
16
35
  - space-y-4, margins per child → <VStack gap={16}>, <HStack gap={8}>
17
- - Padded page wrapper → Page > PageHeader / PageToolbar / PageContent own the 24px gutter
36
+ - Padded page wrapper → PageHeader / PageToolbar / PageContent own the 24px gutter
18
37
  - p-* on Card, DrawerBody, DialogBody, PageToolbar, Table → none; they own their padding
19
38
  - className on Text, Heading, Field, Drawer/Dialog Header/Body/Footer → wrap in your own element
20
39
  - Raw <h1>, <p>, <label> → <Heading as="h2" size="lg">, <Text size="sm">, Field
21
- - <Text> default (16px) for body → size="sm" (md is only an alias of sm)
22
- - leading-none (0px), leading-5 (5px) → leading-sm or leading-20
40
+ - <Text> default (16px) for body → size="sm"
41
+ - leading-none (0px), leading-5 (5px) → leading-sm, leading-20
23
42
  - weight="semibold" → weight is light|regular|medium|bold (medium = 450)
24
- - bg-primary, text-muted, bg-card, bg-white, text-gray-500 → bg-bg-primary, text-text-secondary, bg-bg-surface-1
43
+ - bg-primary, text-muted, bg-card, bg-white → bg-bg-primary, text-text-secondary, bg-bg-surface-1
25
44
  - text-error, bg-red-500 → danger tokens; categorical color → Badge color
26
45
  - dark: variant, setting data-theme → semantic tokens, useTheme().setTheme()
27
46
  - rounded-lg, rounded, rounded-[15px] → rounded-8 (controls), rounded-12 (panels)
28
47
  - shadow-* on DS components, z-* on overlays → never; they own both
29
48
  - focus:ring → focus-visible:ring-3 ring-focus-primary outline-none
30
- - size, DIALOG_SIZES, DRAWER_SIZES → width: Dialog 400 confirm, 560 default, 960 picker; Drawer 640 default, 700 Timeline form
49
+ - size, DIALOG/DRAWER_SIZES → width: Dialog 400 confirm, 560 default, 960 picker; Drawer 640 default, 700 Timeline form
31
50
  - Dialog, useToast from the root → @wallarm-org/design-system/Dialog, /Toast
32
51
  - Field invalid → error on the control + FieldError
52
+ - Table actions column → meta.renderMenuAction on the master column
33
53
  - Hand-built side menu → RemoteShell config={NavConfig}
34
54
  - ConfirmDialog, FilterBar, Combobox → compose Dialog parts, PageToolbar + FilterDropdown, Select + useSelectSearch
35
55
  - data-slot in tests → data-testid
36
56
 
37
57
  ## Screen sampler
38
58
 
39
- [`sampler.dc.html`](sampler.dc.html) is one canonical 1440-wide screen built only from this system through `x-import`: `AppShell`, a resource list `Page` with `PageHeader` and its create action, a `PageToolbar` with search and status tabs, an entity `Table` with a status `Badge` column and an always-visible actions column, a no-results `EmptyState`, and a detail `Drawer` opened by `open` with an empty nested table. It follows the `resource-list-page`, `entity-table` and `detail-drawer` pattern guides. Start a screen from it rather than from raw `div`s; the export checks that every class it uses exists in `components/bundle.css`.
59
+ [`sampler.dc.html`](sampler.dc.html) is one canonical 1440-wide screen built only from this system through `x-import`: `AppShell`, a resource list `Page` with `PageHeader` and its create action, a `PageToolbar` with search and status tabs, an entity `Table` with a status `Badge` column and the row menu in the master cell (`meta.renderMenuAction`), a no-results `EmptyState`, and a detail `Drawer` opened by `open` with an empty nested table. It follows the `resource-list-page`, `entity-table` and `detail-drawer` pattern guides. Start a screen from it rather than from raw `div`s; the export checks that every class it uses exists in `components/bundle.css`.
40
60
 
41
61
  ## Content
42
62
 
@@ -83,7 +103,7 @@ Before composing a screen, call get_guideline for the pattern (app shell, list p
83
103
 
84
104
  ## Layout on a canvas
85
105
 
86
- - Start from the [screen sampler](#screen-sampler). `AppShell` is the frame; `Card` → `CardHeader` / `CardContent` / `CardFooter` groups content.
106
+ - Start inside the [app skeleton](#start-here); the [screen sampler](#screen-sampler) shows a finished screen. `AppShell` is the frame; `Card` → `CardHeader` / `CardContent` / `CardFooter` groups content.
87
107
  - A number prop such as `gap` is a `{{hole}}` from `renderVals()`: `gap="{{rowGap}}"` with `rowGap: 6`.
88
108
  - When a raw grid is unavoidable, use the layout kit: `grid grid-cols-4 gap-16`, `md:grid-cols-2`, `col-span-2`, `w-1/3`, `max-w-7xl`, `divide-y divide-border-primary-light`, `first:`/`last:` padding and border resets. Give flex and grid children `min-w-0` so they can shrink.
89
109
  - Responsive variants (`sm:`, `md:`, `lg:`, `xl:`) follow the viewport, not the artboard.
@@ -247,17 +267,27 @@ This is the separate Claude Design build; the npm package still targets React 19
247
267
  - color-data-viz-1: source placeholder omitted.
248
268
  - color-transparent: unsupported color value "transparent" (light); retained in bundle.css.
249
269
  - drawer-level-ratio: unsupported component value; retained in bundle.css.
250
- - src/guidelines/patterns/app-layout.stories.tsx: pattern story, not a component; the screen sampler covers the patterns on a canvas.
251
- - src/guidelines/patterns/auth-page.stories.tsx: pattern story, not a component; the screen sampler covers the patterns on a canvas.
252
- - src/guidelines/patterns/confirmation-dialogs.stories.tsx: pattern story, not a component; the screen sampler covers the patterns on a canvas.
253
- - src/guidelines/patterns/create-edit-forms.stories.tsx: pattern story, not a component; the screen sampler covers the patterns on a canvas.
254
- - src/guidelines/patterns/detail-drawer.stories.tsx: pattern story, not a component; the screen sampler covers the patterns on a canvas.
255
- - src/guidelines/patterns/empty-states.stories.tsx: pattern story, not a component; the screen sampler covers the patterns on a canvas.
256
- - src/guidelines/patterns/entity-table.stories.tsx: pattern story, not a component; the screen sampler covers the patterns on a canvas.
257
- - src/guidelines/patterns/feedback-toasts.stories.tsx: pattern story, not a component; the screen sampler covers the patterns on a canvas.
258
- - src/guidelines/patterns/filtering.stories.tsx: pattern story, not a component; the screen sampler covers the patterns on a canvas.
259
- - src/guidelines/patterns/resource-list-page.stories.tsx: pattern story, not a component; the screen sampler covers the patterns on a canvas.
260
- - src/guidelines/patterns/settings-page.stories.tsx: pattern story, not a component; the screen sampler covers the patterns on a canvas.
270
+ - src/guidelines/patterns/app-layout.stories.tsx: pattern or template story, not a component; the screen sampler covers the patterns on a canvas.
271
+ - src/guidelines/patterns/auth-page.stories.tsx: pattern or template story, not a component; the screen sampler covers the patterns on a canvas.
272
+ - src/guidelines/patterns/complex-drawer.stories.tsx: pattern or template story, not a component; the screen sampler covers the patterns on a canvas.
273
+ - src/guidelines/patterns/confirmation-dialogs.stories.tsx: pattern or template story, not a component; the screen sampler covers the patterns on a canvas.
274
+ - src/guidelines/patterns/create-edit-forms.stories.tsx: pattern or template story, not a component; the screen sampler covers the patterns on a canvas.
275
+ - src/guidelines/patterns/detail-drawer.stories.tsx: pattern or template story, not a component; the screen sampler covers the patterns on a canvas.
276
+ - src/guidelines/patterns/empty-states.stories.tsx: pattern or template story, not a component; the screen sampler covers the patterns on a canvas.
277
+ - src/guidelines/patterns/entity-table.stories.tsx: pattern or template story, not a component; the screen sampler covers the patterns on a canvas.
278
+ - src/guidelines/patterns/error-states.stories.tsx: pattern or template story, not a component; the screen sampler covers the patterns on a canvas.
279
+ - src/guidelines/patterns/feedback-toasts.stories.tsx: pattern or template story, not a component; the screen sampler covers the patterns on a canvas.
280
+ - src/guidelines/patterns/filtering.stories.tsx: pattern or template story, not a component; the screen sampler covers the patterns on a canvas.
281
+ - src/guidelines/patterns/resource-list-page.stories.tsx: pattern or template story, not a component; the screen sampler covers the patterns on a canvas.
282
+ - src/guidelines/patterns/settings-page.stories.tsx: pattern or template story, not a component; the screen sampler covers the patterns on a canvas.
283
+ - src/guidelines/templates/ai-assistant.stories.tsx: pattern or template story, not a component; the screen sampler covers the patterns on a canvas.
284
+ - src/guidelines/templates/api-inventory.stories.tsx: pattern or template story, not a component; the screen sampler covers the patterns on a canvas.
285
+ - src/guidelines/templates/attack-events.stories.tsx: pattern or template story, not a component; the screen sampler covers the patterns on a canvas.
286
+ - src/guidelines/templates/incident-detail.stories.tsx: pattern or template story, not a component; the screen sampler covers the patterns on a canvas.
287
+ - src/guidelines/templates/integrations-settings.stories.tsx: pattern or template story, not a component; the screen sampler covers the patterns on a canvas.
288
+ - src/guidelines/templates/page-states.stories.tsx: pattern or template story, not a component; the screen sampler covers the patterns on a canvas.
289
+ - src/guidelines/templates/rule-editor.stories.tsx: pattern or template story, not a component; the screen sampler covers the patterns on a canvas.
290
+ - src/guidelines/templates/security-dashboard.stories.tsx: pattern or template story, not a component; the screen sampler covers the patterns on a canvas.
261
291
  - src/icons/module/Icons.stories.tsx: icon gallery story, not a component; use `WallarmDS.Icons.<Name>`.
262
292
  - src/theme/Pixel.stories.tsx: theme gallery story, not a component; see tokens.css.
263
293
  - temp-token: source placeholder omitted.
@@ -0,0 +1,268 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Wallarm app</title>
6
+ <link rel="stylesheet" href="tokens.css">
7
+ <link rel="stylesheet" href="components/bundle.css">
8
+ <script src="components/bundle.js"></script>
9
+ </head>
10
+ <body>
11
+ <!-- App skeleton: the console frame (AppShell) with a product's RemoteShell. Customize it by
12
+ editing only the APP object at the top of the script; design screens inside its Page. -->
13
+ <x-dc>
14
+ <x-import component-from-global-scope="WallarmDS.Root" theme="light">
15
+ <x-import component-from-global-scope="WallarmDS.AppShell">
16
+ <x-import component-from-global-scope="WallarmDS.AppShellHeader">
17
+ <x-import component-from-global-scope="WallarmDS.TopHeader">
18
+ <x-import component-from-global-scope="WallarmDS.TopHeaderLogo" href="/" on-click="{{onRailClick}}">
19
+ <x-import component-from-global-scope="WallarmDS.Logo" size="md"></x-import>
20
+ </x-import>
21
+ <!-- Header actions, in this order: search, separator, tenant, assistant, notifications, help. -->
22
+ <x-import component-from-global-scope="WallarmDS.TopHeaderActions">
23
+ <x-import component-from-global-scope="WallarmDS.Button" variant="ghost" color="neutral" size="small" aria-label="Search">
24
+ <x-import component-from-global-scope="WallarmDS.Icons.Search"></x-import>
25
+ </x-import>
26
+ <x-import component-from-global-scope="WallarmDS.TopHeaderSeparator"></x-import>
27
+ <x-import component-from-global-scope="WallarmDS.Button" variant="ghost" color="neutral" size="small" children="{{tenantLabel}}"></x-import>
28
+ <x-import component-from-global-scope="WallarmDS.ChatTrigger"></x-import>
29
+ <x-import component-from-global-scope="WallarmDS.NotificationCenter" data-testid="notifications">
30
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterTrigger" count="{{unreadCount}}"></x-import>
31
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterContent">
32
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterHeader">
33
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterTitle"></x-import>
34
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterHeaderActions">
35
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterHeaderAction">Mark all as read</x-import>
36
+ </x-import>
37
+ </x-import>
38
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterTabs" default-value="new">
39
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterTabsList">
40
+ <x-import component-from-global-scope="WallarmDS.TabsTrigger" value="new">New <x-import component-from-global-scope="WallarmDS.NumericBadge" size="small">2</x-import></x-import>
41
+ <x-import component-from-global-scope="WallarmDS.TabsTrigger" value="read">Read</x-import>
42
+ </x-import>
43
+ <x-import component-from-global-scope="WallarmDS.TabsContent" value="new">
44
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterBody">
45
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterList">
46
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterItem" unread="{{yes}}">
47
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterItemTitle">New attack detected on api.example.com</x-import>
48
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterItemTime" value="{{sentAt1}}"></x-import>
49
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterItemDescription">214 SQL injection attempts from 12 IPs in the last 10 minutes.</x-import>
50
+ </x-import>
51
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterItem" unread="{{yes}}">
52
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterItemTitle">Node wallarm-node-3 is offline</x-import>
53
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterItemTime" value="{{sentAt2}}"></x-import>
54
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterItemDescription">No heartbeat for 15 minutes. Traffic fails over to wallarm-node-1.</x-import>
55
+ </x-import>
56
+ </x-import>
57
+ </x-import>
58
+ </x-import>
59
+ <x-import component-from-global-scope="WallarmDS.TabsContent" value="read">
60
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterBody">
61
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterList">
62
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterItem">
63
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterItemTitle">Weekly API discovery report is ready</x-import>
64
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterItemTime" value="{{sentAt3}}"></x-import>
65
+ <x-import component-from-global-scope="WallarmDS.NotificationCenterItemDescription">38 new endpoints this week, 5 of them handling sensitive data.</x-import>
66
+ </x-import>
67
+ </x-import>
68
+ </x-import>
69
+ </x-import>
70
+ </x-import>
71
+ </x-import>
72
+ </x-import>
73
+ <x-import component-from-global-scope="WallarmDS.Button" variant="ghost" color="neutral" size="small" aria-label="Help">
74
+ <x-import component-from-global-scope="WallarmDS.Icons.CircleHelp"></x-import>
75
+ </x-import>
76
+ </x-import>
77
+ </x-import>
78
+ </x-import>
79
+ <x-import component-from-global-scope="WallarmDS.AppShellRail">
80
+ <x-import component-from-global-scope="WallarmDS.NavRail" data-testid="nav-rail">
81
+ <!-- Home, then the products from APP.rail; the one at APP.nav.productPath is active. -->
82
+ <x-import component-from-global-scope="WallarmDS.NavRailBody" children="{{railItems}}"></x-import>
83
+ <!-- Settings and the account menu always live in the rail footer. -->
84
+ <x-import component-from-global-scope="WallarmDS.NavRailFooter">
85
+ <x-import component-from-global-scope="WallarmDS.NavRailItem" href="/settings" icon="{{settingsIcon}}" label="Settings" on-click="{{onRailClick}}"></x-import>
86
+ <x-import component-from-global-scope="WallarmDS.DropdownMenu" positioning="{{accountMenuPositioning}}">
87
+ <x-import component-from-global-scope="WallarmDS.DropdownMenuTrigger">
88
+ <x-import component-from-global-scope="WallarmDS.NavRailItem" icon="{{userIcon}}" label="{{userName}}" avatar="{{yes}}"></x-import>
89
+ </x-import>
90
+ <x-import component-from-global-scope="WallarmDS.DropdownMenuContent" class-name="w-200">
91
+ <x-import component-from-global-scope="WallarmDS.DropdownMenuItem">
92
+ <x-import component-from-global-scope="WallarmDS.DropdownMenuItemIcon">
93
+ <x-import component-from-global-scope="WallarmDS.Icons.Settings"></x-import>
94
+ </x-import>
95
+ <x-import component-from-global-scope="WallarmDS.DropdownMenuItemText">Profile settings</x-import>
96
+ </x-import>
97
+ <x-import component-from-global-scope="WallarmDS.DropdownMenuSeparator"></x-import>
98
+ <x-import component-from-global-scope="WallarmDS.DropdownMenuItem">
99
+ <x-import component-from-global-scope="WallarmDS.DropdownMenuItemIcon">
100
+ <x-import component-from-global-scope="WallarmDS.Icons.LogOut"></x-import>
101
+ </x-import>
102
+ <x-import component-from-global-scope="WallarmDS.DropdownMenuItemText">Sign out</x-import>
103
+ </x-import>
104
+ </x-import>
105
+ </x-import>
106
+ </x-import>
107
+ </x-import>
108
+ </x-import>
109
+ <x-import component-from-global-scope="WallarmDS.AppShellRemote">
110
+ <!-- The product: RemoteShell builds the panel and the trail from APP.nav; the URL is its only state. -->
111
+ <x-import component-from-global-scope="WallarmDS.RemoteShell" config="{{navConfig}}" base-path="{{productPath}}" pathname="{{pathname}}" on-navigate="{{onNavigate}}" data-testid="product-shell">
112
+ <x-import component-from-global-scope="WallarmDS.RemoteShellPanel"></x-import>
113
+ <x-import component-from-global-scope="WallarmDS.RemoteShellBreadcrumb"></x-import>
114
+ <x-import component-from-global-scope="WallarmDS.RemoteShellContent">
115
+ <!-- Design the requested screen here: keep PageHeader, add PageDescription and a PageToolbar before PageContent, fixed-height on a list, and replace PageContent's EmptyState. -->
116
+ <x-import component-from-global-scope="WallarmDS.Page" name="{{pageName}}" full-size="{{yes}}" data-testid="page">
117
+ <x-import component-from-global-scope="WallarmDS.PageHeader">
118
+ <x-import component-from-global-scope="WallarmDS.PageHeaderGroup">
119
+ <x-import component-from-global-scope="WallarmDS.PageTitle" children="{{pageTitle}}"></x-import>
120
+ </x-import>
121
+ <x-import component-from-global-scope="WallarmDS.PageActions" children="{{pageActions}}"></x-import>
122
+ </x-import>
123
+ <x-import component-from-global-scope="WallarmDS.PageContent">
124
+ <x-import component-from-global-scope="WallarmDS.EmptyState" type="collection-empty">
125
+ <x-import component-from-global-scope="WallarmDS.EmptyStateIllustration">
126
+ <x-import component-from-global-scope="WallarmDS.Icons.PenTool"></x-import>
127
+ </x-import>
128
+ <x-import component-from-global-scope="WallarmDS.EmptyStateMessage">
129
+ <x-import component-from-global-scope="WallarmDS.EmptyStateTitle">Ask Claude to design this screen</x-import>
130
+ <x-import component-from-global-scope="WallarmDS.EmptyStateDescription">Describe what this page shows and Claude builds it here, inside the app frame.</x-import>
131
+ </x-import>
132
+ </x-import>
133
+ </x-import>
134
+ </x-import>
135
+ </x-import>
136
+ </x-import>
137
+ </x-import>
138
+ </x-import>
139
+ </x-import>
140
+ </x-dc>
141
+ <script type="text/x-dc" data-dc-script data-props="{&quot;$preview&quot;:{&quot;width&quot;:1440,&quot;height&quot;:900}}">
142
+ /* ===== APP: the person's product. Change the shell only here; everything below reads from it.
143
+ A screen's own data (rows, counts) goes in renderVals(), not here. =====
144
+ rail: the Wallarm products in the 1st rail (label, path, icon). The one whose path is
145
+ nav.productPath is active; Home and Settings are always there.
146
+ nav: the product's RemoteShell NavConfig. Node types: 'link' (id, label, path, icon?),
147
+ 'group' (id, label, icon?, defaultExpanded?, children), 'section-header' (id, label),
148
+ 'drill' only when asked. ids and paths are kebab-case; a path is one segment.
149
+ Icons are WallarmDS.Icons names as strings. A link may have `action`: the label of
150
+ its page's primary button.
151
+ start: the path of the link the board opens on: the first link, or the screen this board designs.
152
+ tenant, user: the header's tenant switcher and the account menu's name. */
153
+ var APP = {
154
+ tenant: 'Acme Bank',
155
+ user: 'Maria Lopez',
156
+ rail: [
157
+ { label: 'API Security', path: '/api-security', icon: 'ShieldCheck' },
158
+ { label: 'Edge', path: '/edge', icon: 'Cloud' },
159
+ { label: 'Security Testing', path: '/security-testing', icon: 'FlaskConical' },
160
+ { label: 'AI Hypervisor', path: '/ai-hypervisor', icon: 'Bot' }
161
+ ],
162
+ nav: {
163
+ productLabel: 'API Security',
164
+ productPath: '/api-security',
165
+ items: [
166
+ { type: 'link', id: 'overview', label: 'Overview', path: 'overview', icon: 'Activity' },
167
+ { type: 'link', id: 'api-discovery', label: 'API Discovery', path: 'api-discovery', icon: 'Search' },
168
+ { type: 'link', id: 'api-specifications', label: 'API Specifications', path: 'api-specifications', icon: 'Layers', action: 'Upload specification', dividerAfter: true },
169
+ { type: 'section-header', id: 'detect', label: 'Detect & Respond' },
170
+ { type: 'group', id: 'events', label: 'Events', icon: 'Zap', defaultExpanded: true, children: [
171
+ { type: 'link', id: 'attacks', label: 'Attacks', path: 'attacks' },
172
+ { type: 'link', id: 'incidents', label: 'Incidents', path: 'incidents' },
173
+ { type: 'link', id: 'sessions', label: 'Sessions', path: 'sessions' }
174
+ ] }
175
+ ]
176
+ },
177
+ start: 'overview'
178
+ };
179
+ /* ===== End of APP. ===== */
180
+
181
+ var minutesAgo = function (minutes) { return new Date(Date.now() - minutes * 60000); };
182
+ var warned = {};
183
+
184
+ class Component extends DCLogic {
185
+ constructor(props) {
186
+ super(props);
187
+ this.state = { pathname: APP.nav.productPath + '/' + (APP.start || firstLink(APP.nav.items).path) };
188
+ }
189
+ renderVals() {
190
+ var h = React.createElement;
191
+ var DS = WallarmDS;
192
+ var self = this;
193
+ var icon = function (name) {
194
+ if (!name) return undefined;
195
+ if (!DS.Icons[name] && !warned[name]) {
196
+ warned[name] = true;
197
+ console.warn('[WallarmDS] icon "' + name + '" is not in WallarmDS.Icons; fix it in APP.');
198
+ }
199
+ return DS.Icons[name];
200
+ };
201
+ // NavConfig with icon names resolved; `action` stays out of the config.
202
+ var toNode = function (node) {
203
+ var out = {};
204
+ for (var key in node) if (key !== 'action') out[key] = node[key];
205
+ if (node.icon) out.icon = icon(node.icon);
206
+ if (node.children) out.children = node.children.map(toNode);
207
+ return out;
208
+ };
209
+ var segments = this.state.pathname.split('/').filter(Boolean);
210
+ var page = findLink(APP.nav.items, segments[segments.length - 1]) || firstLink(APP.nav.items);
211
+ var onRailClick = function (event) { event.preventDefault(); };
212
+ var railItems = [
213
+ h(DS.NavRailItem, { key: 'home', href: '/', icon: DS.Icons.Home, label: 'Home', onClick: onRailClick }),
214
+ h(DS.NavRailSeparator, { key: 'separator' })
215
+ ].concat(APP.rail.map(function (product) {
216
+ return h(DS.NavRailItem, {
217
+ key: product.path,
218
+ href: product.path,
219
+ icon: icon(product.icon) || DS.Icons.Layers,
220
+ label: product.label,
221
+ active: product.path === APP.nav.productPath,
222
+ onClick: onRailClick
223
+ });
224
+ }));
225
+ return {
226
+ yes: true,
227
+ tenantLabel: [APP.tenant, h(DS.Icons.ChevronUpDown, { key: 'chevron' })],
228
+ unreadCount: 2,
229
+ sentAt1: minutesAgo(3),
230
+ sentAt2: minutesAgo(22),
231
+ sentAt3: minutesAgo(60 * 24),
232
+ railItems: railItems,
233
+ onRailClick: onRailClick,
234
+ settingsIcon: DS.Icons.Settings,
235
+ userIcon: DS.Icons.UserRound,
236
+ userName: APP.user,
237
+ accountMenuPositioning: { placement: 'right-end', gutter: 6, offset: { crossAxis: 12 } },
238
+ navConfig: { productLabel: APP.nav.productLabel, productPath: APP.nav.productPath, items: APP.nav.items.map(toNode) },
239
+ productPath: APP.nav.productPath,
240
+ pathname: this.state.pathname,
241
+ onNavigate: function (to) { self.setState({ pathname: to }); },
242
+ pageName: page.id,
243
+ pageTitle: page.label,
244
+ pageActions: page.action ? h(DS.Button, { size: 'medium' }, page.action) : null
245
+ };
246
+ }
247
+ }
248
+
249
+ // The first link in menu order, and the link whose path is `path`, through groups and drills.
250
+ function firstLink(items) {
251
+ for (var i = 0; i < items.length; i++) {
252
+ if (items[i].type === 'link') return items[i];
253
+ var inner = items[i].children && firstLink(items[i].children);
254
+ if (inner) return inner;
255
+ }
256
+ return null;
257
+ }
258
+ function findLink(items, path) {
259
+ for (var i = 0; i < items.length; i++) {
260
+ if (items[i].type === 'link' && items[i].path === path) return items[i];
261
+ var inner = items[i].children && findLink(items[i].children, path);
262
+ if (inner) return inner;
263
+ }
264
+ return null;
265
+ }
266
+ </script>
267
+ </body>
268
+ </html>
@@ -130,10 +130,6 @@ const meta = {
130
130
  },
131
131
  parameters: {
132
132
  layout: 'centered',
133
- design: {
134
- type: 'figma',
135
- url: 'https://www.figma.com/design/VKb5gW46uSGw0rqrhZsbXT/WADS-Components?node-id=11973-4142&m=dev',
136
- },
137
133
  docs: { description: { component: DESCRIPTION } },
138
134
  },
139
135
  tags: ['autodocs'],