Files

80 lines
5.2 KiB
Markdown

# Web Manager — Admin (Web Studio)
Admin side of [Web Manager](./Readme.md). Source: `apps/admin/src/core/WebStudio/`.
## Routes
```txt
/web-studio/pages/listing list, search, filters, row actions
/web-studio/pages/-/create new draft
/web-studio/pages/-/:id editor (page or draft clone)
/web-studio/settings/:section header | footer | legal
```
The list shows title with full path, locale, slug, group key, page type, status, draft marker and
updated time; search is debounced and filters, pagination and locale live in the query string
(`useWebStudioQueryParams`), so links and the back arrow keep the editor's context. Row actions are
Edit, Preview, Open in web app, Publish, Unpublish, Discard and Delete — Edit opens the draft clone
when `draftId` is present, so an editor always lands on the working copy.
## Editor
The editor is a flat two-column layout: a sticky ~320px Page details column, and Hero / Blocks / SEO
as line tabs beside it. One React Hook Form instance (`PAGE_EDITOR_FORM_ID`) owns everything;
the header's Save button submits it by form id, and submitting disables the whole fieldset.
Actions sit in a split button: Save draft, then Preview / Publish / Unpublish / Discard / Delete in
the dropdown, each behind its own control component in `view/controls/` and its own permission.
Publish is offered whenever the page is not already live, so it doubles as republish.
Blocks are added from a sheet filtered to the page type's `allowedBlockTypes`, reordered by drag
(`view/components/SortableList.tsx`), and duplicated or removed from their own header. Nested
collections — content columns, CTAs, FAQ items, navigation links — behave the same way one level
down.
## Key Files
| Concern | File |
| ------------------- | ------------------------------------------------------------------------------------------------------ |
| Module registration | `config/module.ts`, `config/routing.tsx`, `config/menu.ts` |
| Languages | `config/languages.ts` — code, labels, direction, public prefix |
| Page types | `config/pages.ts` — allowed blocks and default path per type |
| Block catalogue | `config/blocks.ts` — label, description, preview image, factory |
| Settings shape | `config/siteSettings.ts` |
| HTTP + multipart | `data/api/WebStudioAPI.ts`, `data/api/PagePayloadSerializer.ts` |
| Domain types | `entities/` — `PageType`, `PageStatus`, `BlockType`, `HeroType`, block and field shapes |
| Form ↔ DTO | `pages/PageEditPage/helpers/toEditorValues.ts`, `view/forms/PageEditorForm/helpers/toCreatePayload.ts` |
Page types decide what an editor can build:
| Type | Layout | Blocks offered | Default path |
| ----------- | ---------- | --------------------------------------------------- | ------------ |
| `landing` | Standard | all six | `/` |
| `blog` | Blog index | none — the listing is rendered from published posts | `/blog` |
| `blog-item` | Editorial | all except `articles` | `/` |
## UI Conventions
The module is a content tool, not a dashboard of cards. Flat surfaces, few separators, one primary
action per screen.
| Element | Treatment |
| ------------------- | -------------------------------------------------------- |
| Screen heading | `text-mono text-xl font-semibold` |
| Supporting copy | `text-muted-foreground text-sm` |
| Editor settings | `bg-muted/40 space-y-5 p-5` |
| Top-level block | `bg-muted/35`, compact header, one `border-b` while open |
| Nested field group | `border-l-2 pl-4` (`view/components/FieldCard.tsx`) |
| Inline actions | small ghost icon buttons |
| Destructive trigger | ghost button, destructive text, confirmation dialog |
| Empty collection | `bg-muted/35`, generous padding, short copy |
`view/components/BlockCard.tsx` is named for compatibility but is a flat section, not a card — no
shadow, no hover lift, no bordered container nested inside every block. The block picker stays a
sheet with a divided list, because picking is a temporary task. Shared visual principles live in the
[Admin UI Style Guide](../../../apps/admin/ui-style-guide.md); style Web Studio from Web Studio and do
not edit `apps/admin/src/shared` for a module-only visual change.
A visual change must not alter routes, `locale` / `group_key` query behavior, list filtering or DTO
mapping, draft-clone semantics, form values or validation, block factory output, settings payload
shape, or the toast / error / loading states. Anything that does is a feature change.