@jskit-ai/agent-docs 0.1.278 → 0.1.280
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/guide/agent/app-extras/assistant.md +123 -0
- package/guide/agent/app-setup/authentication.md +46 -4
- package/guide/agent/app-setup/database-layer.md +35 -6
- package/guide/agent/app-setup/material-3-migration.md +53 -10
- package/guide/agent/app-setup/multi-homing.md +8 -2
- package/guide/agent/app-setup/upgrading-jskit.md +30 -0
- package/guide/agent/app-setup/users.md +9 -1
- package/guide/agent/framework/material-3.md +153 -71
- package/guide/agent/framework/sanity-checks.md +180 -0
- package/guide/agent/framework/translation.md +4 -0
- package/guide/agent/framework/typed-features.md +158 -105
- package/guide/agent/framework/ui-operations.md +3 -1
- package/guide/agent/index.md +3 -0
- package/package.json +2 -2
- package/patterns/feature-package/example/booking-engine/package.json +1 -1
- package/patterns/minimal-foundation/PATTERN.md +6 -2
- package/patterns/minimal-foundation/example/AGENTS.md +10 -0
- package/patterns/minimal-foundation/example/package.json +6 -6
- package/patterns/minimal-foundation/example/playwright.config.mjs +3 -0
- package/patterns/minimal-foundation/example/src/main.js +3 -2
- package/patterns/minimal-foundation/example/vite.config.mjs +3 -1
- package/patterns/shell-foundation/PATTERN.md +4 -1
- package/patterns/shell-foundation/example/AGENTS.md +10 -0
- package/patterns/shell-foundation/example/package.json +7 -7
- package/patterns/shell-foundation/example/packages/main/package.json +1 -1
- package/patterns/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +3 -0
- package/patterns/shell-foundation/example/playwright.config.mjs +3 -0
- package/patterns/shell-foundation/example/src/components/menus/SectionTabLinkItem.vue +42 -0
- package/patterns/shell-foundation/example/src/main.js +3 -2
- package/patterns/shell-foundation/example/src/pages/home.vue +1 -1
- package/patterns/shell-foundation/example/src/views/NotFound.vue +1 -1
- package/patterns/shell-foundation/example/vite.config.mjs +3 -1
- package/reference/autogen/PATTERN_INDEX.md +37 -37
- package/reference/autogen/packages/agent-docs.md +4 -0
- package/reference/autogen/packages/assistant-runtime.md +27 -2
- package/reference/autogen/packages/auth-provider-local-core.md +1 -1
- package/reference/autogen/packages/auth-web.md +10 -0
- package/reference/autogen/packages/crud-core.md +3 -0
- package/reference/autogen/packages/http-web.md +0 -6
- package/reference/autogen/packages/json-rest-api-core.md +17 -4
- package/reference/autogen/packages/kernel.md +10 -1
- package/reference/autogen/packages/material-web.md +2 -1
- package/reference/autogen/packages/shell-web.md +95 -4
- package/reference/autogen/packages/users-web.md +9 -2
- package/reference/autogen/packages/workspaces-core.md +2 -0
- package/reference/autogen/tooling/jskit-catalog.md +55 -6
- package/reference/autogen/tooling/testUtils.md +15 -1
- package/skills/jskit/SKILL.md +15 -5
- package/skills/jskit/references/heuristics/INDEX.md +3 -1
- package/skills/jskit/references/heuristics/row-policies.md +3 -3
- package/skills/jskit/references/heuristics/typed-features.md +7 -7
- package/skills/jskit/references/heuristics/ui-testing.md +8 -7
- package/skills/jskit/references/material-3.md +153 -71
- package/skills/jskit/references/multi-homing.md +8 -2
- package/skills/jskit/references/pattern-index.md +37 -37
- package/skills/jskit/references/patterns/app/minimal-foundation/PATTERN.md +6 -2
- package/skills/jskit/references/patterns/app/minimal-foundation/example/AGENTS.md +10 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +6 -6
- package/skills/jskit/references/patterns/app/minimal-foundation/example/playwright.config.mjs +3 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/src/main.js +3 -2
- package/skills/jskit/references/patterns/app/minimal-foundation/example/vite.config.mjs +3 -1
- package/skills/jskit/references/patterns/app/shell-foundation/PATTERN.md +4 -1
- package/skills/jskit/references/patterns/app/shell-foundation/example/AGENTS.md +10 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +7 -7
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +1 -1
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +3 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/playwright.config.mjs +3 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/components/menus/SectionTabLinkItem.vue +42 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/main.js +3 -2
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/pages/home.vue +1 -1
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/views/NotFound.vue +1 -1
- package/skills/jskit/references/patterns/app/shell-foundation/example/vite.config.mjs +3 -1
- package/skills/jskit/references/patterns/auth/accounts-hub/example/package.json +2 -2
- package/skills/jskit/references/patterns/auth/auth-surface/PATTERN.md +18 -5
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/components/AppBrand.vue +17 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/pages/auth/login.vue +2 -2
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/pages/auth/reset-password.vue +2 -2
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/pages/auth/signout.vue +2 -2
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/views/auth/LoginView.vue +6 -1
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/views/auth/ResetPasswordView.vue +6 -1
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/views/auth/SignOutView.vue +6 -1
- package/skills/jskit/references/patterns/auth/oidc-sign-in/example/package.json +2 -2
- package/skills/jskit/references/patterns/auth/supabase-auth/example/package.json +1 -1
- package/skills/jskit/references/patterns/connectors/aws-storage-queries/example/formats/package.json +1 -1
- package/skills/jskit/references/patterns/connectors/calendar-cli/example/package.json +4 -4
- package/skills/jskit/references/patterns/console/console-surface/example/src/pages/console.vue +1 -1
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/package.json +2 -2
- package/skills/jskit/references/patterns/database/mysql-application/example/package.json +1 -1
- package/skills/jskit/references/patterns/database/postgres-application/example/package.json +1 -1
- package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +2 -2
- package/skills/jskit/references/patterns/rewards/google-rewarded/example/googlePublisherTag.js +5 -2
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +1 -1
- package/skills/jskit/references/patterns/shell/application-shell/PATTERN.md +11 -6
- package/skills/jskit/references/patterns/shell/application-shell/example/src/components/menus/SectionTabLinkItem.vue +42 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/pages/home.vue +1 -1
- package/skills/jskit/references/patterns/shell/application-shell/example/src/views/NotFound.vue +1 -1
- package/skills/jskit/references/patterns/ui/page-and-placement/PATTERN.md +6 -0
- package/skills/jskit/references/patterns/ui/page-and-placement/example/src/pages/home/reports.vue +9 -4
- package/skills/jskit/references/patterns/ui/page-and-placement/example/src/placementTopology.js +5 -3
- package/skills/jskit/references/patterns/users/account-settings/PATTERN.md +28 -2
- package/skills/jskit/references/patterns/users/account-settings/example/src/components/account/settings/AccountSettingsNotificationsSection.vue +1 -1
- package/skills/jskit/references/patterns/users/account-settings/example/src/components/account/settings/AccountSettingsPreferencesSection.vue +2 -1
- package/skills/jskit/references/patterns/users/account-settings/example/src/components/account/settings/AccountSettingsProfileSection.vue +3 -2
- package/skills/jskit/references/patterns/users/account-settings/example/src/pages/account/[section].vue +23 -0
- package/skills/jskit/references/patterns/users/account-settings/example/src/pages/account.vue +23 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +2 -2
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +3 -3
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/packages/main/src/client/components/AccountPendingInvitesCue.vue +3 -3
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/surfaces/admin/root.vue +1 -1
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/surfaces/app/root.vue +1 -1
- package/skills/jskit/references/sanity-checks.md +180 -0
- package/skills/jskit/references/translation.md +4 -0
- package/skills/jskit/references/typed-features.md +158 -105
- package/skills/jskit/references/ui-operations.md +3 -1
|
@@ -42,7 +42,8 @@ app and never leaves it.
|
|
|
42
42
|
- **What the person sees:** one Up arrow on every inner page, also when opened
|
|
43
43
|
directly: icon only (`$arrowBack`), accessible name "Back" (localized), a
|
|
44
44
|
tooltip on pointer devices. None on top-level destinations, and no other
|
|
45
|
-
back control anywhere; the bar title says where the person is. A
|
|
45
|
+
back control anywhere; the bar title says where the person is. A new or edit
|
|
46
|
+
form shows a close (X) in the arrow's place, which cancels. A list-detail
|
|
46
47
|
layout showing the parent beside the page needs no arrow for that step;
|
|
47
48
|
collapsed to one pane, the record pane gets it back.
|
|
48
49
|
- **Where Up goes:** to the previous trail entry while it is valid, so inside
|
|
@@ -74,31 +75,49 @@ Exactly this, and nothing more:
|
|
|
74
75
|
</script>
|
|
75
76
|
```
|
|
76
77
|
|
|
77
|
-
The same key works in a `<route lang="json">` block.
|
|
78
|
-
list, an edit page its record, a sub-page its page. Tabs under a layout
|
|
78
|
+
The same key works in a `<route lang="json">` block. Tabs under a layout
|
|
79
79
|
(`settings.vue` rendering `<RouterView>` for `settings/`) declare nothing:
|
|
80
80
|
they inherit the nearest layout's declaration, and moving between them keeps
|
|
81
|
-
the trail.
|
|
81
|
+
the trail and the scroll. A folder without a layout (`bookings/` with no
|
|
82
|
+
`bookings.vue`) only groups routes: its pages are different pages, each
|
|
83
|
+
opening at the top. The parent is read from the page up to its surface root, the
|
|
84
|
+
record that declares `jskit.surface`, and stops there. So the surface goes
|
|
85
|
+
only on the surface's layout page (`account.vue`: `ShellLayout` around
|
|
86
|
+
`<RouterView />`) and the parent on the page it renders
|
|
87
|
+
(`account/index.vue`). A package route declares its parent in its
|
|
88
|
+
`package.json` `meta`; under no layout, its component draws `ShellLayout`.
|
|
82
89
|
2. **Each top-level destination is a main-navigation item** (a `kind: "link"`
|
|
83
90
|
placement with `target: "shell.primary-nav"` or `"shell.secondary-nav"`) and
|
|
84
91
|
declares no parent; nor do its tabs. A shell page with no parent is
|
|
85
|
-
top-level: no arrow, a fresh trail.
|
|
92
|
+
top-level: no arrow, a fresh trail. Placements are literal declarative data,
|
|
93
|
+
one `addPlacement({ ... })` per destination with plain string `surface`,
|
|
94
|
+
`scopedSuffix` and `unscopedSuffix`, never built by a helper, a spread or a
|
|
95
|
+
template, so a reader and `jskit check` can map every destination.
|
|
86
96
|
3. **Every in-app link and navigation goes through JSKIT navigation:**
|
|
87
97
|
`:to="paths.page('/suppliers')"` and `router.push(paths.page(...))` with
|
|
88
98
|
`usePaths()`, the CRUD runtime's `resolveViewUrl()`, `resolveEditUrl()` and
|
|
89
99
|
`resolveParams()`, and link placements (`surface` with `scopedSuffix` and
|
|
90
|
-
`unscopedSuffix`; `to` only for a global route
|
|
91
|
-
|
|
100
|
+
`unscopedSuffix`; `to` only for a global route). A global route
|
|
101
|
+
(`scope: "global"`, on no surface) is
|
|
102
|
+
`paths.page("/auth/login", { scope: "global" })`; `explicitTo` only passes
|
|
103
|
+
through a finished target that arrives as data, never a hand-written path.
|
|
104
|
+
The trail follows the router, so there is no special link component.
|
|
92
105
|
4. **A custom new or edit page finishes through the shell:**
|
|
93
106
|
`useShellNavigation()` (`@jskit-ai/shell-web/client/navigation/useShellNavigation`)
|
|
94
107
|
gives `finish(target)` for Save (the target replaces the form in the trail)
|
|
95
108
|
and `finish()` for Cancel (back to where the form was opened, else its
|
|
96
|
-
parent)
|
|
97
|
-
`
|
|
109
|
+
parent); `useShellPageClose({ label, close })`
|
|
110
|
+
(`@jskit-ai/shell-web/client/composables/useShellPageClose`) makes the
|
|
111
|
+
arrow its Cancel, never an X beside it. A page whose
|
|
112
|
+
record turns out deleted or forbidden calls `pageUnavailable()`. JSKIT's
|
|
113
|
+
CRUD screens already do all three.
|
|
98
114
|
5. **A full page load goes through the shell too:** `reloadAppPage(path)`
|
|
99
115
|
(after sign-in or a user switch, to rebuild client state) and
|
|
100
116
|
`leaveApp(url)` (an external site in the same tab, such as a payment page),
|
|
101
|
-
from `@jskit-ai/shell-web/client/navigation/documentNavigation`.
|
|
117
|
+
from `@jskit-ai/shell-web/client/navigation/documentNavigation`. `leaveApp`
|
|
118
|
+
opens the site with a push, so Back returns to the page; a hand-off page
|
|
119
|
+
that only forwards (to an OAuth consent screen) uses
|
|
120
|
+
`leaveApp(url, { replace: true })`, so Back from the site doesn't rerun it.
|
|
102
121
|
|
|
103
122
|
### Forbidden in app code
|
|
104
123
|
|
|
@@ -107,9 +126,12 @@ Exactly this, and nothing more:
|
|
|
107
126
|
| `nav/history` | `history.back()`, `history.go()`, `history.pushState()`/`replaceState()`, `router.back()`, `router.go()` |
|
|
108
127
|
| `nav/window-location` | `window.location` assignments, `.href =`, `location.assign()`, `location.replace()` |
|
|
109
128
|
| `nav/raw-link` | a hand-built in-app path in `to`, `href`, `router.push()`, `router.replace()` or a `to:`/`href:` object key outside a placement |
|
|
110
|
-
| `nav/back-control` | any back control but the shell's Up that navigates the app: "Back to X", "← Suppliers", back arrows and navigating chevrons, breadcrumbs, a custom app-bar back button, a back component, a `goBack()`-style handler |
|
|
111
|
-
| `nav/missing-parent` | an inner page of a shell surface without a declared parent |
|
|
129
|
+
| `nav/back-control` | any back control but the shell's Up that navigates the app: "Back to X", "← Suppliers", back arrows and navigating chevrons, breadcrumbs, a custom app-bar back button, a back component (`<ContextBackButton />` or `<page-back-link>`, and its import), a `goBack()`-style handler |
|
|
130
|
+
| `nav/missing-parent` | an inner page of a shell surface without a declared parent, when it always renders under the shell's top app bar (a layout that also renders its pages without `ShellLayout`, such as a shop device's sign-in in a `v-if`, leaves its pages unjudged) |
|
|
112
131
|
| `nav/top-level-parent` | a main-navigation destination that declares a parent |
|
|
132
|
+
| `nav/placement-data` | a main-navigation placement that isn't literal data (no page is judged for a missing parent until it is) |
|
|
133
|
+
| `nav/missing-shell-layout` | a page that declares a parent with no shell layout rendering it, so its title, Up and actions never show |
|
|
134
|
+
| `nav/surface-parent` | a parent declared beside `jskit.surface`, which the shell never reads |
|
|
113
135
|
| `nav/allow` | any `m3-check: allow nav/...` comment: nothing excuses a navigation rule |
|
|
114
136
|
|
|
115
137
|
### Each rule, right and wrong
|
|
@@ -167,29 +189,43 @@ Exactly this, and nothing more:
|
|
|
167
189
|
- **Type:** Vuetify 4 Material 3 roles (`text-headline-small`,
|
|
168
190
|
`text-title-large`, `text-body-medium`, `text-label-large`). Never the
|
|
169
191
|
Material 2 scale (`text-h5`, `text-body-2`) or a page-local type system.
|
|
170
|
-
Roboto Flex
|
|
192
|
+
Material 3 has two typefaces, both Roboto Flex unless the app names its own
|
|
193
|
+
in `src/theme/index.js`:
|
|
194
|
+
`typography: { brand: '"Fraunces", serif', plain: '"Inter", sans-serif' }`.
|
|
195
|
+
`brand` sets display, headline and title-large, `plain` the rest (title-medium
|
|
196
|
+
and -small, body, label); each is a CSS font-family value, and the app loads
|
|
197
|
+
the font. Never set `font-family` or `--v-font-body` in app CSS.
|
|
171
198
|
- **Icons:** Material Symbols Rounded through Vuetify `$` aliases: Vuetify's
|
|
172
199
|
standard ones (`$close`, `$menu`, `$delete`, `$prev`, `$next`) and JSKIT's
|
|
173
200
|
camelCase names (`$add`, `$edit`, `$search`, `$moreVert`, `$filterList`,
|
|
174
201
|
`$arrowBack`); `$homeFilled`-style `Filled` variants mark active navigation.
|
|
175
202
|
An app adds an icon under `theme.icons` in `src/theme/index.js` as
|
|
176
203
|
`{ name: "<24x24 path data>" }` from Material Symbols Rounded, then uses
|
|
177
|
-
`$name`. No `mdi-*` strings and no `@mdi/js` imports in app code.
|
|
204
|
+
`$name`. No `mdi-*` strings and no `@mdi/js` imports in app code. Material
|
|
205
|
+
Symbols has no brand marks (Google, GitHub, a payment network): a brand's
|
|
206
|
+
logo is the brand's own artwork, a content image or SVG used as its owner
|
|
207
|
+
publishes it, not an icon alias.
|
|
178
208
|
|
|
179
209
|
## Exact sizes
|
|
180
210
|
|
|
181
|
-
JSKIT ships these exact sizes; an app never re-implements or overrides them
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
211
|
+
JSKIT ships these exact sizes; an app never re-implements or overrides them:
|
|
212
|
+
|
|
213
|
+
- 40dp buttons with a 48dp touch target, icon buttons included; a smaller
|
|
214
|
+
button is `size="small"` or `size="x-small"`, which keeps its smaller look
|
|
215
|
+
and the 48dp target. No icon button is under 32dp, and a target stops at
|
|
216
|
+
the edge of a button beside it, so each of a row's touching icon buttons
|
|
217
|
+
answers its own press;
|
|
218
|
+
- one-line button labels, ending in an ellipsis: keep labels short, and give
|
|
219
|
+
one that can run long, such as a name, its full label as `title`;
|
|
220
|
+
- 12dp cards: flat (the default) and tonal at level 0, `variant="elevated"`
|
|
221
|
+
at level 1; flat expansion panels;
|
|
187
222
|
- 28dp dialogs and bottom-sheet top corners, square full-screen dialogs;
|
|
188
|
-
- 8dp chips and
|
|
223
|
+
- 8dp chips, and FABs of 56dp (small 40dp, large 96dp; extended 56dp tall)
|
|
224
|
+
with 16dp corners;
|
|
189
225
|
- emphasized easing, with reduced motion honoured.
|
|
190
226
|
|
|
191
227
|
So never set `height` or `min-height` on a button, or a radius on a card,
|
|
192
|
-
dialog, chip or FAB.
|
|
228
|
+
dialog, chip or FAB.
|
|
193
229
|
|
|
194
230
|
## The top app bar carries the page
|
|
195
231
|
|
|
@@ -197,29 +233,46 @@ dialog, chip or FAB. A missing size is a JSKIT defect.
|
|
|
197
233
|
`useShellPageTitle(title)` (`@jskit-ai/shell-web/client/composables/useShellPageTitle`)
|
|
198
234
|
for a runtime title such as the record's name. The shell renders it as the
|
|
199
235
|
app bar's only `h1`; pages add no `h1`, page header, title block or
|
|
200
|
-
standalone heading.
|
|
201
|
-
|
|
202
|
-
it
|
|
236
|
+
standalone heading. Route pages own the title: a section or a nested
|
|
237
|
+
component uses a title role (a component's claim gives the title back when
|
|
238
|
+
it goes). A page with no top app bar (a hero front page, an intro, an invite
|
|
239
|
+
or hand-off page) has its own one `h1`.
|
|
240
|
+
- **Up** leads the bar on every inner page; on phones it replaces the menu
|
|
241
|
+
icon.
|
|
203
242
|
- **A layout that draws its own top app bar** (a workspace bar with the
|
|
204
243
|
app's own controls, instead of `ShellLayout`) builds it from `ShellLayout`'s
|
|
205
244
|
own pieces, from `@jskit-ai/shell-web/client`. It calls `useShellAppBar()`
|
|
206
245
|
once, so its pages enter the trail and their `ShellPageActions` show in its
|
|
207
246
|
bar, and renders `ShellUpButton` first, then `ShellPageTitle` (the page's one
|
|
208
|
-
`h1
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
247
|
+
`h1`) and `ShellPageActionsTarget`. A title that is also a switcher, such as a
|
|
248
|
+
project menu, goes in `ShellPageTitle`'s default slot (given `{ title }`) as
|
|
249
|
+
the menu's activator, so it stays the one `h1`. `jskit check` counts it as a
|
|
250
|
+
shell layout, so its inner pages need parents.
|
|
212
251
|
- **Actions:** a screen's actions go in the bar inside `ShellPageActions`
|
|
213
252
|
(`@jskit-ai/shell-web/client/components/ShellPageActions`), each a
|
|
214
253
|
`ShellPageAction` with `icon`, `label` (also its accessible name and compact
|
|
215
|
-
tooltip), and `primary`, `to`, `replace`, `
|
|
216
|
-
|
|
217
|
-
`
|
|
254
|
+
tooltip), and `primary`, `to`, `replace`, `href` (with `download` for a
|
|
255
|
+
file, such as a CSV export), `disabled`, `loading` or `color` (`error` for a
|
|
256
|
+
destructive one); attributes such as `target` reach its button. On compact
|
|
257
|
+
widths the bar keeps one trailing item after the title: the single
|
|
258
|
+
`primary` action when the page has one (a form's Save), otherwise its own
|
|
259
|
+
item nearest the corner (a top-right placement such as the account avatar).
|
|
260
|
+
Every other action and the bar's other items (a notification bell, tools)
|
|
261
|
+
go to its "More actions" menu, where `overflow` actions always are. Medium
|
|
262
|
+
and wider bars show them all.
|
|
218
263
|
- **Window size classes:** compact under 600 (navigation bar), medium 600–839
|
|
219
|
-
(navigation rail), expanded 840–1199 and large from 1200 (drawer)
|
|
220
|
-
|
|
264
|
+
(navigation rail), expanded 840–1199 and large from 1200 (drawer), read from
|
|
265
|
+
`useShellWindowSizeClass()`
|
|
221
266
|
(`@jskit-ai/shell-web/client/composables/useShellWindowSizeClass`), never from
|
|
222
|
-
copied breakpoint numbers.
|
|
267
|
+
copied breakpoint numbers. A surface with fewer than two navigation
|
|
268
|
+
destinations (none, as on an account surface, or Home alone) draws no
|
|
269
|
+
navigation bar, rail or drawer; its pages keep the app bar.
|
|
270
|
+
- **Section tabs:** a page's own sections (`page.section-nav`) are Material 3
|
|
271
|
+
primary tabs: the topology names `ShellSectionTabLinkItem`'s token (the
|
|
272
|
+
starter registers it as `local.main.ui.section-tab-link-item`), and the page
|
|
273
|
+
draws one tab row, `display: flex; overflow-x: auto` over a 1dp
|
|
274
|
+
`outline-variant` bottom border. `ShellTabLinkItem` is the navigation bar's
|
|
275
|
+
destination; placed in a page it draws a section tab.
|
|
223
276
|
|
|
224
277
|
## Colour
|
|
225
278
|
|
|
@@ -242,35 +295,41 @@ dialog, chip or FAB. A missing size is a JSKIT defect.
|
|
|
242
295
|
control; never a permanent panel of outlined fields. A card opens its record
|
|
243
296
|
when tapped (a stretched title link); a table row opens on click. Row actions
|
|
244
297
|
are trailing icon buttons (edit, a `$moreVert` overflow menu, a chevron to
|
|
245
|
-
open), never "View" or "Edit" text buttons on every row. "New" is
|
|
246
|
-
|
|
247
|
-
and
|
|
298
|
+
open), never "View" or "Edit" text buttons on every row. "New" is
|
|
299
|
+
`ShellPrimaryAction` (`label`, and `to` or a click handler): an extended FAB
|
|
300
|
+
on compact and medium widths, a filled bar button on expanded. On/off filters
|
|
301
|
+
are `aria-pressed` chips, or chips in a `v-chip-group`; JSKIT draws them as
|
|
302
|
+
filter chips. Empty and error states carry an icon.
|
|
248
303
|
- **A list never scrolls sideways, at any width.** The list's own width (a
|
|
249
304
|
container query, not the window) chooses cards or table. Cards flow into a
|
|
250
305
|
grid; tables use a fixed layout with an ellipsis on long values, and fold
|
|
251
306
|
low-priority columns into a stronger column's second line. Lists show figures
|
|
252
307
|
("120 kg", tabular and right-aligned) and names, never ids.
|
|
253
308
|
- **Record:** a header (avatar, title, status chips) and value-first detail
|
|
254
|
-
lists, never a grid of label/value text. Edit sits in the bar
|
|
309
|
+
lists, never a grid of label/value text. Edit sits in the bar, its secondary
|
|
310
|
+
actions in the bar's overflow menu, never in the content; the record's
|
|
255
311
|
next workflow step is the one filled button, shown in context rather than a
|
|
256
312
|
row of mostly disabled actions.
|
|
257
|
-
- **Form:**
|
|
258
|
-
Nothing moves under a finger: a multi-select chip
|
|
259
|
-
when it loses focus. A pick-one-of-N choice is a
|
|
260
|
-
|
|
313
|
+
- **Form:** the bar's close (X) cancels and Save is its filled action. Fields
|
|
314
|
+
use `hideDetails: "auto"`. Nothing moves under a finger: a multi-select chip
|
|
315
|
+
field keeps its input width when it loses focus. A pick-one-of-N choice is a
|
|
316
|
+
segmented button (`v-btn-toggle`, drawn by JSKIT, with 12dp segment sides as
|
|
317
|
+
in any `v-btn-group`) with `role="radiogroup"` and
|
|
318
|
+
`role="radio"`/`aria-checked` buttons.
|
|
261
319
|
- **Dialogs:** plain `v-dialog` and `v-bottom-sheet`; JSKIT gives them their
|
|
262
320
|
Material 3 shapes. A full-screen dialog (compact and medium) puts close, title
|
|
263
321
|
and its confirm action in a top bar, never at the bottom where a snackbar
|
|
264
322
|
covers them.
|
|
265
323
|
- **Menus and badges:** a menu's list has `role="menu"` and its items
|
|
266
324
|
`role="menuitem"`, with `aria-disabled` on unavailable ones; a badge has a
|
|
267
|
-
`label` such as "3 batches".
|
|
325
|
+
`label` such as "3 batches". JSKIT draws a menu's list and a dialog's card;
|
|
326
|
+
an app sets no `VMenu` or `VDialog` defaults, under which
|
|
327
|
+
Vuetify 4.2.1 to 4.3.2 loses a `v-select`'s typeahead match, or a dialog's
|
|
328
|
+
virtual list, when an ancestor re-renders.
|
|
268
329
|
|
|
269
330
|
## Components, state, and feedback
|
|
270
331
|
|
|
271
|
-
- Choose components by purpose
|
|
272
|
-
tables, sheets, dialogs, menus, navigation, progress, alerts, snackbars, and
|
|
273
|
-
tooltips over custom imitations.
|
|
332
|
+
- Choose standard components by purpose over custom imitations.
|
|
274
333
|
- Give one primary action emphasis. Distinguish destructive, secondary, and
|
|
275
334
|
icon-only actions without relying on color; give icon controls accessible
|
|
276
335
|
names and fields meaningful labels, errors, and autocomplete behavior.
|
|
@@ -287,6 +346,11 @@ dialog, chip or FAB. A missing size is a JSKIT defect.
|
|
|
287
346
|
field. A user-triggered command uses JSKIT's shared action
|
|
288
347
|
feedback/snackbar path. Never insert a transient command-error alert above
|
|
289
348
|
page content where it shifts the working layout.
|
|
349
|
+
- A snackbar never covers the FAB or the actions it reports on. `ShellErrorHost`
|
|
350
|
+
centres it above the navigation bar on compact windows and starts it at the
|
|
351
|
+
content's start edge, at most half its width, on wider ones. A FAB takes
|
|
352
|
+
layout room (`<v-fab app layout>`, as `ShellPrimaryAction`'s does), so the
|
|
353
|
+
snackbar shows above it.
|
|
290
354
|
|
|
291
355
|
## Adaptive layout
|
|
292
356
|
|
|
@@ -308,16 +372,15 @@ npx jskit check m3 src/pages/home/books # a section
|
|
|
308
372
|
npx jskit check m3 $(git diff --name-only --diff-filter=d main) # changed files
|
|
309
373
|
```
|
|
310
374
|
|
|
311
|
-
Plain `jskit check` fails on the [navigation rules](#forbidden-in-app-code)
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
and so every app's verify, fail on them too:
|
|
375
|
+
Plain `jskit check` fails on the [navigation rules](#forbidden-in-app-code).
|
|
376
|
+
`jskit check m3` lists those and the visual rules below. The visual rules are a
|
|
377
|
+
report until every JSKIT app has been converted to them; the JSKIT release after
|
|
378
|
+
that makes plain `jskit check`, and so every app's verify, fail on them too:
|
|
316
379
|
|
|
317
380
|
| Rule | Finds |
|
|
318
381
|
|---|---|
|
|
319
|
-
| `m3/duplicate-h1` | a second `h1
|
|
320
|
-
| `m3/raw-hex` | a hex colour outside `src/theme/` |
|
|
382
|
+
| `m3/duplicate-h1` | a second `h1` that can show beside the first (one per `v-if` branch is one), or an in-page `h1` under a layout that always shows the shell's page title |
|
|
383
|
+
| `m3/raw-hex` | a hex colour, or one written as channels (`rgba(0, 0, 0, 0.15)`, as in a hand-made shadow), outside `src/theme/` (`palettes.js` holds content colours); `rgba(var(--v-theme-shadow), 0.2)` reads a role and passes |
|
|
321
384
|
| `m3/dark-scheme` | no dark scheme, or the theme pinned to light |
|
|
322
385
|
| `m3/outlined-card` | `variant="outlined"` or `border` on a card or sheet |
|
|
323
386
|
| `m3/mdi-icon` | `mdi-*` icon strings and `@mdi/js` imports |
|
|
@@ -338,19 +401,41 @@ Take the approved route first; none needs an exception:
|
|
|
338
401
|
`<v-chip color="partner">`. A hex string is harmonized toward the seed; a
|
|
339
402
|
colour that must keep its hue is `{ value: "#F5C518", blend: false }`
|
|
340
403
|
(Material Theme Builder's Blend switched off), with the same four roles.
|
|
341
|
-
- **
|
|
342
|
-
|
|
404
|
+
- **Content colours**, colours that are content rather than UI, keep one
|
|
405
|
+
value in both schemes: an identity palette a person picks and the server
|
|
406
|
+
stores, avatar and illustration artwork, brand marks (a language's
|
|
407
|
+
file-type tint), fixed chart series, QR codes, colours written into
|
|
408
|
+
exported files. They are named exports of plain hex values in
|
|
409
|
+
`src/theme/palettes.js`, used as they are, never for UI chrome (a theme
|
|
410
|
+
colour is toned per scheme, so it can't keep an identity the same).
|
|
411
|
+
Components read them through bindings:
|
|
412
|
+
|
|
413
|
+
```vue
|
|
414
|
+
<script setup>
|
|
415
|
+
// src/theme/palettes.js: export const botColours = ["#6750A4", "#B3261E"];
|
|
416
|
+
import { botColours } from "@/theme/palettes.js";
|
|
417
|
+
const props = defineProps({ bot: Object });
|
|
418
|
+
const ring = botColours[props.bot.colour];
|
|
419
|
+
</script>
|
|
420
|
+
<template>
|
|
421
|
+
<v-avatar :style="{ backgroundColor: ring }"><svg><path :fill="ring" /></svg></v-avatar>
|
|
422
|
+
</template>
|
|
423
|
+
<style scoped>.v-avatar { outline: 2px solid v-bind(ring); }</style>
|
|
424
|
+
```
|
|
425
|
+
- **Chart and data colours** that follow the scheme come from the theme:
|
|
426
|
+
`const theme = useTheme()`, then
|
|
427
|
+
`["primary", "tertiary"].map((role) => theme.current.value.colors[role])`.
|
|
343
428
|
- **A third-party widget** lives in one wrapper component, such as
|
|
344
429
|
`src/components/RouteMap.vue`, that hands it theme colours; pages use only
|
|
345
430
|
the wrapper.
|
|
346
431
|
|
|
347
|
-
What is left
|
|
348
|
-
before: `<!-- m3-check: allow m3/raw-hex - the partner's contractual logo colour -->`
|
|
432
|
+
What is left, such as a colour inside static SVG markup that can't import,
|
|
433
|
+
may be excused one line at a time, on its line or the line before: `<!-- m3-check: allow m3/raw-hex - the partner's contractual logo colour -->`
|
|
349
434
|
(`// m3-check: ...` in scripts, `/* ... */` in CSS). **Never add one on your
|
|
350
435
|
own:** ask the person first, naming the rule and the reason. A comment with no
|
|
351
|
-
reason (`m3/allow-reason`) or an unknown rule (`m3/allow-rule`)
|
|
352
|
-
|
|
353
|
-
|
|
436
|
+
reason (`m3/allow-reason`) or an unknown rule (`m3/allow-rule`) is itself a
|
|
437
|
+
finding, as any `nav/allow` is; nothing turns the check off for a file, a
|
|
438
|
+
folder or the app. `jskit check m3` lists every
|
|
354
439
|
exception with its file, line and reason, and their total.
|
|
355
440
|
|
|
356
441
|
## Material 3 audit
|
|
@@ -359,19 +444,16 @@ Run this behavior-preserving audit over every affected screen:
|
|
|
359
444
|
|
|
360
445
|
1. Identify the owning JSKIT surface, shared screen, shell, placement, theme,
|
|
361
446
|
and Vuetify components before judging local markup.
|
|
362
|
-
2. Check navigation and Up first, as must-fix: plain `jskit check` passes
|
|
363
|
-
every
|
|
364
|
-
destinations have none; no inner link is hand-built; nothing writes back
|
|
365
|
-
logic.
|
|
447
|
+
2. Check navigation and Up first, as must-fix: plain `jskit check` passes and
|
|
448
|
+
every rule in Navigation and Up holds.
|
|
366
449
|
3. Find parallel components, duplicated state chrome, page-local themes, raw
|
|
367
450
|
visual constants, CSS against Vuetify internals, nested generic cards,
|
|
368
|
-
borders instead of tones, Material 2 typography, and desktop-only layout
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
5. Correct issues at the narrowest established owner. Consolidate only truly
|
|
451
|
+
borders instead of tones, Material 2 typography, and desktop-only layout;
|
|
452
|
+
check states, focus, labels, targets, contrast and reduced motion against
|
|
453
|
+
the rules above.
|
|
454
|
+
4. Correct issues at the narrowest established owner. Consolidate only truly
|
|
373
455
|
repeated policy; avoid pass-through wrappers and speculative abstractions.
|
|
374
|
-
|
|
456
|
+
5. Run `jskit check` and `jskit check m3` on the affected files, then focused
|
|
375
457
|
tests and Playwright at compact, medium, and expanded widths in light and
|
|
376
458
|
dark (`shellBackButton(page)` and `pressShellBack(page)` from
|
|
377
459
|
`@jskit-ai/shell-web/test/shellNavigation` drive Up).
|
|
@@ -174,6 +174,12 @@ capability provides:
|
|
|
174
174
|
| `workspaces.repositories.workspaces`, `.workspaceMemberships`, `.workspaceSettings`, `.workspaceInvites` | Repository access inside the application's own transactions |
|
|
175
175
|
| `workspaces.tenancyProfile` | The resolved tenancy mode and workspace policy |
|
|
176
176
|
|
|
177
|
+
To check one person's membership, for example a notification recipient, call
|
|
178
|
+
`workspaces.services.members.getMember(workspace, userId, options)`. It answers
|
|
179
|
+
that member's `listMembers` entry, or `null` for a removed or unknown member,
|
|
180
|
+
and reads only that membership. Do not list every member to find one: the list
|
|
181
|
+
grows with the workspace, and a lookup per row multiplies it.
|
|
182
|
+
|
|
177
183
|
### Invitation email
|
|
178
184
|
|
|
179
185
|
To send invitation email, provide the optional `workspaces.invite-mailer`
|
|
@@ -452,9 +458,9 @@ Use only a verified empty disposable database named
|
|
|
452
458
|
reports its engine version, applies package migrations and drops fixture tables.
|
|
453
459
|
|
|
454
460
|
```sh
|
|
455
|
-
|
|
461
|
+
npx jskit test packages/workspaces-core/test/*.test.js
|
|
456
462
|
# Set JSKIT_REPOSITORY_TEST_DATABASE_URL to the verified empty disposable target.
|
|
457
|
-
|
|
463
|
+
npx jskit test packages/workspaces-core/test/repositories.integration.test.js
|
|
458
464
|
npm run verify
|
|
459
465
|
```
|
|
460
466
|
|