WEB-0b: CMS-Verwaltung der öffentlichen Webseite (Hand-Editier-UI)
Neuer Bereich /webseite im Manager (Nav: "Mehr"-Blatt) zur Pflege der 6
Webseiten-Seiten gegen Pams WEB-0-Backend (LAN-only, keine Auth):
- Übersicht: alle Seiten mit Status (Entwurf/Veröffentlicht).
- Seiten-Editor: Titel + SEO-Beschreibung + Status speichern.
- Geordneter Block-Editor: Blöcke hinzufügen (Überschrift, Textabschnitt/
Markdown, Bild, Galerie, Kontaktangaben), bearbeiten, nach oben/unten
verschieben (PUT .../blocks/order), löschen. Die dynamische AbgabetiereList
ist nicht manuell anlegbar; nur ihr Einleitungstext ist editierbar.
Vertraege: GET /pages, GET /pages/{slug}, PUT /pages/{id},
POST /pages/{pageId}/blocks, PUT /blocks/{id}, DELETE /blocks/{id},
PUT /pages/{pageId}/blocks/order. Enums als Strings (Draft/Published, Heading...).
Deutsch via de.ts (LF beibehalten), mobile-first. e2e-Mock um die CMS-Routen
erweitert (zustandsbehaftet) + Smoke (Block anlegen/bearbeiten/verschieben,
bleibt erhalten). Gate gruen: build, eslint, vitest 69, e2e 68.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
66
gerbil-manager-web/src/pages/WebseitePage.tsx
Normal file
66
gerbil-manager-web/src/pages/WebseitePage.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
/** WEB-0b: Übersicht der Webseiten-Seiten mit Status (Entwurf/Veröffentlicht). */
|
||||
import { Link } from 'react-router-dom'
|
||||
import { de } from '../strings/de'
|
||||
import { listPages, type PageStatus } from '../api/pages'
|
||||
import { useApi } from '../hooks/useApi'
|
||||
import './webseite.css'
|
||||
|
||||
function StatusBadge({ status }: { status: PageStatus }) {
|
||||
const t = de.pages.webseite
|
||||
const published = status === 'Published'
|
||||
return (
|
||||
<span className={published ? 'status-badge status-badge--published' : 'status-badge status-badge--draft'}>
|
||||
{published ? t.statusPublished : t.statusDraft}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
export default function WebseitePage() {
|
||||
const t = de.pages.webseite
|
||||
const pages = useApi(() => listPages(), [])
|
||||
|
||||
if (pages.loading) return <p className="muted">{de.common.loading}</p>
|
||||
if (pages.error || !pages.data) {
|
||||
return (
|
||||
<section className="page">
|
||||
<h2>{t.title}</h2>
|
||||
<div className="alert alert--error">
|
||||
<span>{pages.error}</span>
|
||||
<button type="button" className="btn" onClick={pages.reload}>
|
||||
{de.common.retry}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="page">
|
||||
<header className="page-head">
|
||||
<div>
|
||||
<h2>{t.title}</h2>
|
||||
<p className="muted">{t.intro}</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{pages.data.length === 0 ? (
|
||||
<p className="muted">{t.empty}</p>
|
||||
) : (
|
||||
<ul className="card-list">
|
||||
{pages.data.map((p) => (
|
||||
<li key={p.id} className="gerbil-card webseite-card">
|
||||
<span className="gerbil-card__name">{p.title}</span>
|
||||
<span className="gerbil-card__meta">/{p.slug}</span>
|
||||
<span className="webseite-card__actions">
|
||||
<StatusBadge status={p.status} />
|
||||
<Link to={`/webseite/${p.slug}`} className="btn btn--primary">
|
||||
{t.edit}
|
||||
</Link>
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user