feat(chrome)!: v0.4.0 — AdminShell + headers as /chrome sub-export
New `./chrome` entrypoint exporting `<AdminShell>` and the header
components (Search, SearchHistory, SearchOptions, Messages, BrowseApps,
HeaderCustomers, HeaderContacts, LogoutButton). Refactored from the
Chronos-style AdminShell that gscCRM was vendoring byte-for-byte —
header/footer/sidebar are now a single shared surface across apps.
Explicit props contract (no site-informations.json, no internal data
sources): `menus`, `apps`, `user`, `brand` are required; `features.*`
flags gate every section (search/browseApps/messages/notifications/
subbar*/pageHeader*/activityPanel/chat/footer); `slots.*` lets apps
inject content; `labels` overrides the next-intl "chrome" namespace.
Locale-aware navigation: chrome calls useLocale() and prepends
/{locale} to internal menu URLs, leaving externals (http(s)://…) and
the "#" sentinel alone. Breadcrumbs and the path-derived page title
strip the leading locale segment so they read "Contacts" not
"En › Contacts". Necessary for `localePrefix: 'always'` consumers like
gscCRM.
Phosphor 2.x icons: `normalizeIconClass` prepends the base `ph` class
(compound selectors `.ph.ph-house:before` require both). All hardcoded
`<i className="ph-…">` sites switched to `ph ph-…`.
`next-intl` and `next-auth` moved to peerDependencies (with devDep
copies for the kit's own typecheck/build). Consumers must symlink their
installed copies into the kit's node_modules at build time — otherwise
useTranslations()/useSession() bind to a separate React context and
next-intl throws Error(void 0) on render.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
150
README.md
150
README.md
@@ -29,7 +29,10 @@ your app
|
||||
```ts
|
||||
import "@gsc/web-kit/css"; // CSS bundle (layout-3 + JetBrains Mono)
|
||||
|
||||
// Chrome
|
||||
// Chrome — unified header/footer/sidebar shell
|
||||
import { AdminShell } from "@gsc/web-kit/chrome";
|
||||
|
||||
// Lower-level layout primitives
|
||||
import { AppLayout } from "@gsc/web-kit/layout";
|
||||
import { useShell } from "@gsc/web-kit/shell";
|
||||
import { fetchShellConfig } from "@gsc/web-kit/shell/server";
|
||||
@@ -81,8 +84,149 @@ The `/api` sub-export is reserved for a future HTTP client helper; it currently
|
||||
| 2 | layout · auth · shell — usable end-to-end with shell-api | **done** |
|
||||
| 3 | data · forms — curated re-exports from limitless + validation | **done (v0.3.0)** |
|
||||
| 4 | feedback · navigation · utils — curated re-exports from limitless | **done (v0.3.0)** |
|
||||
| 4a | api · HTTP client helper (Bearer injection, 401 → signInRedirect) | planned |
|
||||
| 5 | Roll out to gscCRM / gscChronos / gscAdmin / gscPortal | planned |
|
||||
| 5 | chrome · AdminShell + headers + LogoutButton + nav migrations | **done (v0.4.0)** |
|
||||
| 5a | Roll out chrome to gscCRM / gscChronos / gscAdmin / gscPortal | in progress |
|
||||
| 6 | api · HTTP client helper (Bearer injection, 401 → signInRedirect) | planned |
|
||||
|
||||
---
|
||||
|
||||
## Chrome (`/chrome`) — v0.4.0
|
||||
|
||||
Unified `AdminShell` providing navbar, subbar, page-header, sidebar, footer,
|
||||
optional chat overlay and activity panel. Every app receives the same UI
|
||||
chrome and toggles features it doesn't use via `features` props.
|
||||
|
||||
### Adopting chrome in a new app
|
||||
|
||||
1. **Add the dep** (already a `file:` resolve to this kit) and import:
|
||||
|
||||
```tsx
|
||||
// app/[locale]/layout.tsx
|
||||
import { AdminShell } from "@gsc/web-kit/chrome";
|
||||
import "@gsc/web-kit/css";
|
||||
```
|
||||
|
||||
2. **Apply nav migrations** to your app's database:
|
||||
|
||||
```bash
|
||||
# In your app's migrations directory, copy the two kit-canonical files verbatim
|
||||
cp node_modules/@gsc/web-kit/migrations/nav-schema.up.sql apps/<your-app>/migrations/00X_nav_schema.up.sql
|
||||
cp node_modules/@gsc/web-kit/migrations/nav-apps-seed.up.sql apps/<your-app>/migrations/00Y_nav_apps_seed.up.sql
|
||||
# Then copy the menu-items template once and adapt to your app's menu
|
||||
cp node_modules/@gsc/web-kit/migrations/nav-menu-items-template.sql apps/<your-app>/migrations/00Z_nav_menu_items.up.sql
|
||||
# edit 00Z_… to replace example rows with your app's sidebar/topbar entries
|
||||
psql "$DATABASE_URL" -f apps/<your-app>/migrations/00X_nav_schema.up.sql
|
||||
psql "$DATABASE_URL" -f apps/<your-app>/migrations/00Y_nav_apps_seed.up.sql
|
||||
psql "$DATABASE_URL" -f apps/<your-app>/migrations/00Z_nav_menu_items.up.sql
|
||||
```
|
||||
|
||||
Re-copy `nav-schema` + `nav-apps-seed` on every kit upgrade. The
|
||||
menu-items file is yours after the first copy — the kit never touches it
|
||||
again.
|
||||
|
||||
3. **Add Prisma** to read the data:
|
||||
|
||||
```prisma
|
||||
// prisma/schema.prisma
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
schemas = ["nav"]
|
||||
}
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
previewFeatures = ["multiSchema"]
|
||||
}
|
||||
```
|
||||
|
||||
Add `"postinstall": "prisma generate"` to package.json. Copy `prisma/`
|
||||
into the Docker image *before* `npm install` so the generate step sees it.
|
||||
|
||||
4. **Wire the layout server component**:
|
||||
|
||||
```tsx
|
||||
const [sidebar, topbar, subbar, apps] = await Promise.all([
|
||||
getMenuItemsByType("sidebar"),
|
||||
getMenuItemsByType("topbar"),
|
||||
getMenuItemsByType("subbar"),
|
||||
getApps(),
|
||||
]);
|
||||
|
||||
return (
|
||||
<AdminShell
|
||||
menus={{ sidebar, topbar, subbar }}
|
||||
apps={apps}
|
||||
user={{ displayName, email, avatarUrl }}
|
||||
brand={{
|
||||
name: "MyApp",
|
||||
product: "GoSec MyApp",
|
||||
logoUrl: "https://assets.gosec.cloud/logos/logo.svg",
|
||||
websiteUrl: "https://gosec.cloud",
|
||||
supportUrl: "https://support.gosec.cloud/",
|
||||
docsUrl: "https://support.gosec.cloud/docs",
|
||||
copyrightStartYear: 2024,
|
||||
}}
|
||||
features={{ chat: false, activityPanel: false }}
|
||||
>
|
||||
{children}
|
||||
</AdminShell>
|
||||
);
|
||||
```
|
||||
|
||||
### Props reference
|
||||
|
||||
`<AdminShell>` is the kit's contract — see `src/chrome/types.ts` for the
|
||||
authoritative TypeScript definition. Summary:
|
||||
|
||||
- **Data**: `menus`, `apps`, `user`, `notificationCount?`, `activity?`
|
||||
- **Brand** (required): `name`, `product`, `logoUrl`, `websiteUrl`,
|
||||
`supportUrl`, `docsUrl`, `copyrightStartYear` (+ optional `logoSmallUrl`)
|
||||
- **`features`** (all optional booleans, sensible defaults):
|
||||
`search`, `searchHistory`, `searchOptions`, `browseApps`, `messages`,
|
||||
`notifications`, `subbar`, `subbarSupport`, `subbarSettings`,
|
||||
`pageHeader`, `pageHeaderCustomers`, `pageHeaderContacts`,
|
||||
`activityPanel`, `chat`, `footer`
|
||||
- **`slots`** (ReactNode overrides):
|
||||
`pageTitle`, `pageHeaderExtras`, `subbarExtras`, `activityPanel`,
|
||||
`navbarExtras`, `footerExtras`
|
||||
- **Behavior**: `onSignOut?` (default `next-auth signOut`),
|
||||
`labels?: Partial<ChromeLabels>` (override individual chrome strings)
|
||||
|
||||
### i18n
|
||||
|
||||
Chrome's own strings come from next-intl namespace `chrome` with English
|
||||
fallbacks. Add to your app's `common.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"chrome": {
|
||||
"navigation": "Navigation",
|
||||
"logout": "Logout",
|
||||
"support": "Support",
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Menu item labels (`menu.dashboard`, `menu.accounts`, …) live in your app's
|
||||
existing translation namespace.
|
||||
|
||||
### Semver
|
||||
|
||||
Public surface = `<AdminShell>` props + exported types + migration files +
|
||||
chrome CSS class names.
|
||||
|
||||
- **Major** — removed/renamed prop, changed prop shape, removed feature
|
||||
flag, renamed CSS class, changed migration DDL.
|
||||
- **Minor** — new optional prop, new feature flag (default off), new
|
||||
slot, new export, new migration file.
|
||||
- **Patch** — bugfix, internal refactor.
|
||||
|
||||
Deprecations land for one minor release with `console.warn` and a
|
||||
`CHANGELOG.md` note before removal in the next major. Pin
|
||||
`"@gsc/web-kit": "^X.Y.Z"` to receive minors automatically.
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user