80 lines
5.2 KiB
Markdown
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.
|