diff --git a/components/admin/portfolio-project-form.tsx b/components/admin/portfolio-project-form.tsx
index 37a5f3e..98b0fd4 100644
--- a/components/admin/portfolio-project-form.tsx
+++ b/components/admin/portfolio-project-form.tsx
@@ -9,7 +9,6 @@ import {
CalendarDays,
CheckCircle2,
CircleAlert,
- Files,
FolderTree,
Grid2x2,
ImagePlus,
@@ -25,7 +24,12 @@ import { type ReactNode, useEffect, useRef, useState } from "react";
import { useFormStatus } from "react-dom";
import { MediaFieldPicker, type MediaFieldState } from "@/components/admin/media-field-picker";
-import { StatsCard } from "@/components/dashboard/stats-card";
+import {
+ Accordion,
+ AccordionContent,
+ AccordionItem,
+ AccordionTrigger,
+} from "@/components/ui/accordion";
import { AppCard } from "@/components/ui/app-card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
@@ -293,34 +297,32 @@ function LocaleInputs({
multiline?: boolean;
}) {
return (
-
-
+
+
{title}
+
{locales.map((locale) => (
-
- {locale.label}
+
+
+ {locale.label}
+
{multiline ? (
))}
@@ -347,6 +349,31 @@ function SectionHeader({
);
}
+function EmptyPanel({
+ icon: Icon,
+ title,
+ description,
+ action,
+}: {
+ icon: typeof Grid2x2;
+ title: string;
+ description: string;
+ action?: ReactNode;
+}) {
+ return (
+
+
+
+
+
+
{title}
+
{description}
+
+ {action}
+
+ );
+}
+
function SubmitButton({ onSelect }: { onSelect: () => void }) {
const { pending } = useFormStatus();
@@ -577,8 +604,8 @@ export function PortfolioProjectForm({
-
-
+
+
@@ -596,14 +623,14 @@ export function PortfolioProjectForm({
-
-
-
-
step.complete).length}/${progress.length}`}
- icon={CheckCircle2}
- />
+
+
+
+
Fortschritt
+
+ {progress.filter((step) => step.complete).length}/{progress.length} bereit
+
+
@@ -625,8 +652,8 @@ export function PortfolioProjectForm({
-
-
+
+
-
-
+
+
-
-
+
+
-
- {sections.map((section, index) => (
-
-
-
-
- {isPortfolioSectionReady({
- type: section.type,
- titleAr: section.titleAr,
- titleEn: section.titleEn,
- titleDe: section.titleDe,
- bodyAr: section.bodyAr,
- bodyEn: section.bodyEn,
- bodyDe: section.bodyDe,
- linkUrl: section.linkUrl,
- mediaAssetId: section.media.assetId,
- })
- ? "Ready"
- : "Open"}
-
-
{`Section ${index + 1}`}
-
+ {sections.length === 0 ? (
+
setSections((current) => [...current, createEmptySection(current.length)])}
+ >
+
+ Add Section
+
+ )}
+ />
+ ) : (
+
+ {sections.map((section, index) => {
+ const ready = isPortfolioSectionReady({
+ type: section.type,
+ titleAr: section.titleAr,
+ titleEn: section.titleEn,
+ titleDe: section.titleDe,
+ bodyAr: section.bodyAr,
+ bodyEn: section.bodyEn,
+ bodyDe: section.bodyDe,
+ linkUrl: section.linkUrl,
+ mediaAssetId: section.media.assetId,
+ });
-
-
-
-
-
-
+ return (
+
+
+
+ {ready ? "Ready" : "Open"}
+ {`Section ${index + 1}`}
+ {sectionTypeLabels[section.type]}
+
+
+
+
+
+
+
+
+
@@ -1020,190 +1059,174 @@ export function PortfolioProjectForm({
multiline
/>
) : null}
-
- ))}
-
+
+
+
+ );
+ })}
+
+ )}
-
-
-
-
-
-
+
+
+
-
+
-
- setAssets((current) => [...current, createEmptyAsset(current.length)])}
- >
-
- Add Asset
-
- )}
- />
+ setAssets((current) => [...current, createEmptyAsset(current.length)])}
+ >
+
+ Add Asset
+
+ )}
+ />
-
- {assets.map((asset, index) => (
-
setAssets((current) => [...current, createEmptyAsset(current.length)])}
>
-
-
-
- {isPortfolioAssetReady({
- mediaAssetId: asset.media.assetId,
- altAr: asset.altAr,
- altEn: asset.altEn,
- altDe: asset.altDe,
- })
- ? "Ready"
- : "Open"}
-
-
{`Asset ${index + 1}`}
-
+
+ Add Asset
+
+ )}
+ />
+ ) : (
+
+ {assets.map((asset, index) => {
+ const ready = isPortfolioAssetReady({
+ mediaAssetId: asset.media.assetId,
+ altAr: asset.altAr,
+ altEn: asset.altEn,
+ altDe: asset.altDe,
+ });
-
-
-
-
-
-
+ return (
+
+
+
+ {ready ? "Ready" : "Open"}
+ {`Asset ${index + 1}`}
+
+
+
+
+
+
+
+
+
-
- setAssets((current) =>
- current.map((item, currentIndex) =>
- currentIndex === index
- ? { ...item, media, filePath: media.url }
- : item,
- ),
- )
- }
- options={mediaOptions}
- hasInitialValue={Boolean(asset.media.assetId || asset.filePath)}
- inputName={`asset-media-${index}`}
- fileFieldName={asset.fileFieldName}
- allowClear
- clearLabel="Remove Asset"
- emptyValue={{ mode: "upload", assetId: "", url: "", label: "" }}
- />
+
+ setAssets((current) =>
+ current.map((item, currentIndex) =>
+ currentIndex === index
+ ? { ...item, media, filePath: media.url }
+ : item,
+ ),
+ )
+ }
+ options={mediaOptions}
+ hasInitialValue={Boolean(asset.media.assetId || asset.filePath)}
+ inputName={`asset-media-${index}`}
+ fileFieldName={asset.fileFieldName}
+ allowClear
+ clearLabel="Remove Asset"
+ emptyValue={{ mode: "upload", assetId: "", url: "", label: "" }}
+ />
-
- setAssets((current) =>
- current.map((item, currentIndex) =>
- currentIndex === index ? { ...item, [`alt${key}`]: value } : item,
- ),
- )
- }
- />
-
- ))}
-
-
-
-
-
-
-
-
-
-
-
-
- isPortfolioAssetReady({
- mediaAssetId: asset.media.assetId,
- altAr: asset.altAr,
- altEn: asset.altEn,
- altDe: asset.altDe,
- }),
- ).length,
- )}
- icon={CheckCircle2}
- />
-
-
-
- Start with the cover, then add gallery assets. Each asset needs media plus localized alt text.
-
-
-
-
-
+
+ setAssets((current) =>
+ current.map((item, currentIndex) =>
+ currentIndex === index ? { ...item, [`alt${key}`]: value } : item,
+ ),
+ )
+ }
+ />
+
+
+
+ );
+ })}
+
+ )}
+
-
+