Files
admin/docs/core/web-manager/admin.md
T

5.2 KiB

Web Manager — Admin (Web Studio)

Admin side of Web Manager. Source: apps/admin/src/core/WebStudio/.

Routes

/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; 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.