STYLED - Two-column project form, drop the redundant header card

- Remove the project summary/header card (project name, badges, progress);
  it added no value while creating a project. Move the on-submit validation
  alert down to the action bar.
- Lay the whole form out in two columns: Basic Information + Localized
  Content, then Sections + Cover/Assets. Basic Information fields cap at two
  columns and the Cover/Assets card stacks inside its column.

All 375 tests pass; tsc and eslint clean.
This commit is contained in:
moh
2026-09-20 17:40:45 +02:00
parent 077e1c5836
commit 19e8fa8f19
+18 -59
View File
@@ -7,7 +7,6 @@ import {
BookOpenText,
BriefcaseBusiness,
CalendarDays,
CheckCircle2,
CircleAlert,
FolderTree,
Grid2x2,
@@ -533,14 +532,6 @@ export function PortfolioProjectForm({
})),
});
const firstIncompleteStep = getFirstIncompleteWizardStep(progress);
const selectedCategory =
availableCategories.find((category) => category.id === projectState.categoryId) ?? null;
const projectLabel =
projectState.titleDe.trim() ||
projectState.titleEn.trim() ||
projectState.titleAr.trim() ||
projectState.slug.trim() ||
"Untitled Project";
useEffect(() => {
sectionsInputRef.current?.dispatchEvent(new Event("input", { bubbles: true }));
@@ -603,53 +594,7 @@ export function PortfolioProjectForm({
<input ref={assetsInputRef} type="hidden" name="assets" value={assetsPayload} />
<input ref={intentRef} type="hidden" name="intent" defaultValue="save" />
<AppCard level={3} padding="md" contentClassName="space-y-5">
<div className="flex flex-col gap-5">
<div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
<div className="space-y-3">
<div className="flex flex-wrap items-center gap-2">
<Badge variant={projectState.isPublished ? "success" : "warning"}>
{projectState.isPublished ? "Published" : "Draft"}
</Badge>
{projectState.isFeatured ? <Badge variant="outline">Featured</Badge> : null}
{!selectedCategory?.isActive ? <Badge variant="warning">Inactive Category</Badge> : null}
</div>
<div>
<h2 className="text-2xl font-semibold text-foreground">{projectLabel}</h2>
<p className="mt-1 text-sm text-muted-foreground">
{selectedCategory ? `${selectedCategory.name.de || selectedCategory.name.en || selectedCategory.name.ar}` : "No category selected"}
</p>
</div>
</div>
<div className="flex items-center gap-3 rounded-nested border border-border/70 bg-surface-2 px-4 py-2.5">
<CheckCircle2 className="h-5 w-5 shrink-0 text-brand-primary" />
<div className="min-w-0">
<p className="text-[11px] uppercase tracking-[0.14em] text-muted-foreground">Fortschritt</p>
<p className="text-sm font-semibold text-foreground">
{progress.filter((step) => step.complete).length}/{progress.length} bereit
</p>
</div>
</div>
</div>
{showValidation && firstIncompleteStep ? (
<div className="rounded-nested border border-status-warning/30 bg-status-warning-soft px-4 py-3">
<div className="flex items-start gap-3">
<CircleAlert className="mt-0.5 h-4 w-4 text-status-warning" />
<div className="space-y-1">
<p className="text-sm font-medium text-foreground">Some required fields are still missing.</p>
<p className="text-sm text-muted-foreground">
Fill the Basics and Localized Content fields below, then save.
</p>
</div>
</div>
</div>
) : null}
</div>
</AppCard>
<div className="space-y-6">
<div className="grid gap-6 xl:grid-cols-2 xl:items-start">
<div>
<AppCard level={3} padding="md">
<section className="space-y-5">
@@ -658,7 +603,7 @@ export function PortfolioProjectForm({
description="Choose the category and the stable project metadata first."
/>
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
<div className="grid gap-4 sm:grid-cols-2">
<div className="space-y-2">
<Label htmlFor="categoryId" className="sr-only">Category</Label>
<div className="relative">
@@ -1071,7 +1016,7 @@ export function PortfolioProjectForm({
<div>
<AppCard level={3} padding="md">
<div className="grid gap-6 lg:grid-cols-2">
<div className="space-y-6">
<section className="space-y-4">
<SectionHeader
title="Cover Media"
@@ -1227,7 +1172,21 @@ export function PortfolioProjectForm({
</div>
</div>
<AppCard level={3} padding="md">
<AppCard level={3} padding="md" contentClassName="space-y-4">
{showValidation && firstIncompleteStep ? (
<div className="rounded-nested border border-status-warning/30 bg-status-warning-soft px-4 py-3">
<div className="flex items-start gap-3">
<CircleAlert className="mt-0.5 h-4 w-4 text-status-warning" />
<div className="space-y-1">
<p className="text-sm font-medium text-foreground">Some required fields are still missing.</p>
<p className="text-sm text-muted-foreground">
Fill the Basics and Localized Content fields, then save.
</p>
</div>
</div>
</div>
) : null}
<div className="flex flex-col gap-4 md:flex-row md:items-center md:justify-end">
<div className="flex flex-wrap items-center gap-3">
{firstIncompleteStep ? (