From d672610b460a8ac56f2c5092393404bbe006707c Mon Sep 17 00:00:00 2001 From: lashman Date: Sun, 15 Feb 2026 21:41:16 +0200 Subject: [PATCH] redesign card detail modal as 2-column dashboard grid --- .../card-detail/CardDetailModal.tsx | 152 ++++++++++++------ .../card-detail/ChecklistSection.tsx | 28 ++-- src/components/card-detail/MarkdownEditor.tsx | 4 +- 3 files changed, 125 insertions(+), 59 deletions(-) diff --git a/src/components/card-detail/CardDetailModal.tsx b/src/components/card-detail/CardDetailModal.tsx index 35b0324..77d914b 100644 --- a/src/components/card-detail/CardDetailModal.tsx +++ b/src/components/card-detail/CardDetailModal.tsx @@ -1,6 +1,6 @@ import { useState, useEffect, useRef } from "react"; import { AnimatePresence, motion } from "framer-motion"; -import { Separator } from "@/components/ui/separator"; +import { X } from "lucide-react"; import { useBoardStore } from "@/stores/board-store"; import { MarkdownEditor } from "@/components/card-detail/MarkdownEditor"; import { ChecklistSection } from "@/components/card-detail/ChecklistSection"; @@ -38,74 +38,112 @@ export function CardDetailModal({ cardId, onClose }: CardDetailModalProps) { /> {/* Modal */} -
+
e.stopPropagation()} > - {/* Close on Escape */} - - {/* Hidden accessible description */} Card detail editor + {/* Header: cover color background + title + close */} +
+ + +
+ + {/* Dashboard grid body */} - {/* Left panel: Title + Markdown (60%) */} + {/* Row 1: Labels + Due Date */} -
- -
- - -
- - {/* Vertical separator */} - - - {/* Right sidebar (40%) */} - - - - - + - - + + - - + {/* Row 2: Checklist + Description */} + + - + + + + {/* Row 3: Cover + Attachments */} + + + + + void; + hasColor: boolean; } -function InlineTitle({ cardId, title, updateCard }: InlineTitleProps) { +function InlineTitle({ cardId, title, updateCard, hasColor }: InlineTitleProps) { const [editing, setEditing] = useState(false); const [draft, setDraft] = useState(title); const inputRef = useRef(null); @@ -177,6 +216,9 @@ function InlineTitle({ cardId, title, updateCard }: InlineTitleProps) { } } + const textColor = hasColor ? "text-white" : "text-pylon-text"; + const hoverColor = hasColor ? "hover:text-white/80" : "hover:text-pylon-accent"; + if (editing) { return ( setDraft(e.target.value)} onBlur={handleSave} onKeyDown={handleKeyDown} - className="font-heading text-xl text-pylon-text bg-transparent outline-none border-b border-pylon-accent pb-0.5" + className={`flex-1 font-heading text-xl bg-transparent outline-none border-b pb-0.5 ${ + hasColor ? "text-white border-white/50" : "text-pylon-text border-pylon-accent" + }`} /> ); } @@ -193,7 +237,7 @@ function InlineTitle({ cardId, title, updateCard }: InlineTitleProps) { return (

setEditing(true)} - className="cursor-pointer font-heading text-xl text-pylon-text transition-colors hover:text-pylon-accent" + className={`flex-1 cursor-pointer font-heading text-xl transition-colors ${textColor} ${hoverColor}`} > {title}

@@ -202,14 +246,25 @@ function InlineTitle({ cardId, title, updateCard }: InlineTitleProps) { /* ---------- Cover color picker ---------- */ -function CoverColorPicker({ cardId, coverColor }: { cardId: string; coverColor: string | null }) { +function CoverColorPicker({ + cardId, + coverColor, +}: { + cardId: string; + coverColor: string | null; +}) { const updateCard = useBoardStore((s) => s.updateCard); const presets = [ - { hue: "160", label: "Teal" }, { hue: "240", label: "Blue" }, - { hue: "300", label: "Purple" }, { hue: "350", label: "Pink" }, - { hue: "25", label: "Red" }, { hue: "55", label: "Orange" }, - { hue: "85", label: "Yellow" }, { hue: "130", label: "Lime" }, - { hue: "200", label: "Cyan" }, { hue: "0", label: "Slate" }, + { hue: "160", label: "Teal" }, + { hue: "240", label: "Blue" }, + { hue: "300", label: "Purple" }, + { hue: "350", label: "Pink" }, + { hue: "25", label: "Red" }, + { hue: "55", label: "Orange" }, + { hue: "85", label: "Yellow" }, + { hue: "130", label: "Lime" }, + { hue: "200", label: "Cyan" }, + { hue: "0", label: "Slate" }, ]; return ( @@ -232,7 +287,8 @@ function CoverColorPicker({ cardId, coverColor }: { cardId: string; coverColor: className="size-6 rounded-full transition-transform hover:scale-110" style={{ backgroundColor: `oklch(55% 0.12 ${hue})`, - outline: coverColor === hue ? "2px solid currentColor" : "none", + outline: + coverColor === hue ? "2px solid currentColor" : "none", outlineOffset: "1px", }} title={label} diff --git a/src/components/card-detail/ChecklistSection.tsx b/src/components/card-detail/ChecklistSection.tsx index 5c59d33..d03265f 100644 --- a/src/components/card-detail/ChecklistSection.tsx +++ b/src/components/card-detail/ChecklistSection.tsx @@ -37,20 +37,30 @@ export function ChecklistSection({ cardId, checklist }: ChecklistSectionProps) { return (
- {/* Header */} -
-

- Checklist -

+ {/* Header + progress */} +
+
+

+ Checklist +

+ {checklist.length > 0 && ( + + {checked}/{checklist.length} + + )} +
{checklist.length > 0 && ( - - {checked}/{checklist.length} - +
+
+
)}
{/* Items */} -
+
{checklist.map((item) => ( ) : (
setMode("edit")} > {draft ? (