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>
67 lines
2.0 KiB
TypeScript
67 lines
2.0 KiB
TypeScript
/** 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>
|
|
)
|
|
}
|