feat: plakat redesign phase 4 (chat window, contact, footer, cleanup)

- AI chat moves into a window/sheet, opened from a new speech-bubble card on
  the desk; it now respects the chatbot consent and asks before sending
  anything to n8n (previously it ignored the consent)
- Contact as red poster section with big mail address and the form on a paper
  card; validation errors are finally shown inline (aria-invalid, role=alert)
- Footer as ink strip with dk0 wordmark, legal links and a button to reopen
  the privacy settings
- "About me" in the header opens the about window on the home page
- Remove the old About section and its parts (BentoChat, ActivityFeed,
  CurrentlyReading, ReadBooks), the unused ChatWidget, Projects and BentoGrid,
  their tests, wrappers, loaders, types and texts
- scripts/directus-cleanup-redesign.mjs: dry run by default, --apply archives
  hobbies, tech stack categories and old content pages and deletes four
  unused message overrides after a full JSON backup; run only after the
  redesign is live on production

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
denshooter
2026-10-15 19:05:24 +02:00
parent 0fa10315b2
commit 6c2da49bfa
33 changed files with 534 additions and 2572 deletions
+3 -1
View File
@@ -155,7 +155,9 @@ function BoardItem({ obj, labels, spot, z, tableRef, onFront, register }: BoardI
const openWindow = useOpenWindow();
const elRef = useRef<HTMLDivElement | null>(null);
const openIt = () => openWindow?.(windowFor(obj), elRef.current);
const radius = { sticker: "rounded-full", photo: "rounded-md", book: "rounded-[6px_14px_14px_6px]" }[obj.kind as string] ?? "rounded-2xl";
const radius =
{ sticker: "rounded-full", photo: "rounded-md", book: "rounded-[6px_14px_14px_6px]", chat: "rounded-[22px_22px_22px_6px]" }[obj.kind as string] ??
"rounded-2xl";
return (
<motion.div
+9
View File
@@ -85,6 +85,15 @@ export default function ObjectFace({ obj, labels }: ObjectFaceProps) {
</div>
);
case "chat":
return (
<div className="flex h-full w-full flex-col justify-between rounded-[22px_22px_22px_6px] border-2 border-ink bg-ink p-4 text-paper">
<span className="font-mono text-xs uppercase tracking-wide text-signal">KI · n8n</span>
<span className="font-display text-[1.7rem] font-extrabold leading-[0.95] tracking-[-0.03em]">{labels.chatCard}</span>
<span className="font-mono text-xs opacity-70">{labels.chatCardHint} ↗</span>
</div>
);
case "sticker":
return (
<div className="grid h-full w-full place-items-center rounded-full border-2 border-ink bg-signal p-6 text-center font-display text-xl font-extrabold leading-[0.98] tracking-[-0.02em] text-ink">
+3
View File
@@ -45,6 +45,8 @@ export default async function TischSection({ locale }: TischSectionProps) {
bookLabel: t("bookLabel"),
bookFallback: t("bookFallback"),
photoCaption: t("photoCaption"),
chatCard: t("chatCard"),
chatCardHint: t("chatCardHint"),
sticker: t("sticker"),
};
@@ -73,6 +75,7 @@ export default async function TischSection({ locale }: TischSectionProps) {
{ kind: "server", id: "server" },
{ kind: "book", id: "book", href: `/${locale}/books` },
{ kind: "photo", id: "photo" },
{ kind: "chat", id: "chat" },
{ kind: "sticker", id: "sticker" },
];
// Im Stapel wäre der runde Sticker eine Ellipse und wiederholt nur den Claim
+10 -1
View File
@@ -37,12 +37,17 @@ export interface TischPhoto {
id: "photo";
}
export interface TischChat {
kind: "chat";
id: "chat";
}
export interface TischSticker {
kind: "sticker";
id: "sticker";
}
export type TischObject = TischProject | TischTicket | TischServer | TischBook | TischPhoto | TischSticker;
export type TischObject = TischProject | TischTicket | TischServer | TischBook | TischPhoto | TischChat | TischSticker;
export interface TischLabels {
hintBoard: string;
@@ -63,6 +68,8 @@ export interface TischLabels {
bookLabel: string;
bookFallback: string;
photoCaption: string;
chatCard: string;
chatCardHint: string;
sticker: string;
}
@@ -73,6 +80,7 @@ export const BOARD_SIZE: Record<TischObject["kind"], { w: number; h: number }> =
server: { w: 270, h: 290 },
book: { w: 176, h: 262 },
photo: { w: 210, h: 250 },
chat: { w: 250, h: 170 },
sticker: { w: 180, h: 180 },
};
@@ -89,6 +97,7 @@ export const BOARD_SPOTS: { x: number; y: number; r: number }[] = [
{ x: 0.76, y: 450, r: -7 },
{ x: 0.42, y: 800, r: 7 },
{ x: 0.12, y: 800, r: -4 },
{ x: 0.66, y: 790, r: 4 },
];
// Farbfelder für Projektkarten, abwechselnd hell und dunkel
+4
View File
@@ -15,6 +15,8 @@ export function windowFor(obj: TischObject): WindowRequest {
return { kind: "read" };
case "photo":
return { kind: "about" };
case "chat":
return { kind: "chat" };
}
}
@@ -31,6 +33,8 @@ export function labelFor(obj: TischObject, labels: TischLabels): string {
return labels.bookLabel;
case "photo":
return labels.photoCaption;
case "chat":
return labels.chatCard;
case "sticker":
return labels.sticker;
}