Style group session dialog with the group's accent color

- Replace generic card/gray styling with the group's own tint, derived
  via color-mix so the dialog reads as a "window" version of the card
- Add 3px colored border, tinted header/footer panels, and softened
  border rules on todo rows to tie the whole dialog to one hue
- Give the Save button a solid accent background with theme-appropriate
  text color (white on light, dark on neon) for clear affordance
This commit is contained in:
Brian Fertig 2026-09-29 07:47:11 -06:00
parent b6d72fff95
commit f204f41b68
1 changed files with 49 additions and 8 deletions

View File

@ -102,6 +102,14 @@ export function GroupSessionDialog({
const color = useGroupColor(group.color); const color = useGroupColor(group.color);
const accentColor = isDark ? color.dark : color.light; const accentColor = isDark ? color.dark : color.light;
const todoTextColor = getBrighterColor(accentColor, isDark ? "dark" : "light"); const todoTextColor = getBrighterColor(accentColor, isDark ? "dark" : "light");
// The group's card treatment, scaled to a window: the same hand-picked
// tint fill the card uses (blended into the theme's card surface), plus a
// softer version of the group's stroke for the header/footer rules so
// they read as the same hue without competing with the 3px border.
const dialogBackground = `color-mix(in srgb, ${isDark ? color.softDark : color.soft} 85%, var(--card))`;
const panelBackground = `color-mix(in srgb, ${isDark ? color.softDark : color.soft} 100%, var(--card))`;
const ruleColor = `color-mix(in srgb, ${accentColor} 40%, transparent)`;
const subtleRuleColor = `color-mix(in srgb, ${accentColor} 25%, transparent)`;
const [noteDraft, setNoteDraft] = useState(group.noteContent); const [noteDraft, setNoteDraft] = useState(group.noteContent);
const [todoDrafts, setTodoDrafts] = useState<TodoDraft[]>(() => toDrafts(group.todos)); const [todoDrafts, setTodoDrafts] = useState<TodoDraft[]>(() => toDrafts(group.todos));
@ -215,10 +223,16 @@ export function GroupSessionDialog({
<DialogContent <DialogContent
data-color-mode={colorMode} data-color-mode={colorMode}
showCloseButton={false} showCloseButton={false}
className="fixed top-[2vh] left-1/2 h-[96vh] max-h-[96vh] w-[calc(100%-1rem)] max-w-[calc(100%-1rem)] sm:max-w-5xl -translate-x-1/2 translate-y-0 flex flex-col gap-0 overflow-hidden p-0" className="fixed top-[2vh] left-1/2 h-[96vh] max-h-[96vh] w-[calc(100%-1rem)] max-w-[calc(100%-1rem)] sm:max-w-5xl -translate-x-1/2 translate-y-0 flex flex-col gap-0 overflow-hidden rounded-2xl border-[3px] p-0 ring-0"
style={{ borderColor: accentColor, backgroundColor: dialogBackground }}
> >
<div className="flex shrink-0 items-center justify-between gap-2 border-b p-4"> <div
<DialogTitle className="min-w-0 truncate">{group.title}</DialogTitle> className="flex shrink-0 items-center justify-between gap-2 border-b p-4"
style={{ borderColor: ruleColor, backgroundColor: panelBackground }}
>
<DialogTitle className="min-w-0 truncate" style={{ color: todoTextColor }}>
{group.title}
</DialogTitle>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span className="text-xs text-muted-foreground"> <span className="text-xs text-muted-foreground">
{savingAll || noteAutosave.isSaving ? "Saving…" : "Saved"} {savingAll || noteAutosave.isSaving ? "Saving…" : "Saved"}
@ -273,7 +287,10 @@ export function GroupSessionDialog({
</div> </div>
{completedTodoDrafts.length > 0 && ( {completedTodoDrafts.length > 0 && (
<div className="space-y-2 rounded-md border"> <div
className="space-y-2 rounded-md border"
style={{ borderColor: ruleColor }}
>
<button <button
type="button" type="button"
onClick={() => setCompletedOpen((v) => !v)} onClick={() => setCompletedOpen((v) => !v)}
@ -328,7 +345,10 @@ export function GroupSessionDialog({
</div> </div>
</div> </div>
<div className="flex shrink-0 flex-wrap items-center justify-between gap-2 border-t bg-muted/50 p-4"> <div
className="flex shrink-0 flex-wrap items-center justify-between gap-2 border-t p-4"
style={{ borderColor: ruleColor, backgroundColor: panelBackground }}
>
<div className="flex flex-wrap items-center gap-2"> <div className="flex flex-wrap items-center gap-2">
<Button variant="outline" className="gap-2" onClick={addEmptyTodoDraft}> <Button variant="outline" className="gap-2" onClick={addEmptyTodoDraft}>
<Plus className="size-4" /> <Plus className="size-4" />
@ -343,7 +363,19 @@ export function GroupSessionDialog({
Ask AI Ask AI
</Button> </Button>
</div> </div>
<Button onClick={handleSaveAll} disabled={savingAll}> <Button
onClick={handleSaveAll}
disabled={savingAll}
className="hover:brightness-110"
style={{
backgroundColor: accentColor,
borderColor: accentColor,
// The stroke is a darker ink on light themes (white type
// clears it) and a brighter neon on dark themes (dark type
// clears it) -- the same pairing the to-do text uses.
color: isDark ? "#18181b" : "#ffffff",
}}
>
{savingAll ? "Saving…" : "Save"} {savingAll ? "Saving…" : "Save"}
</Button> </Button>
</div> </div>
@ -482,7 +514,13 @@ function SessionTodoRow({
); );
return ( return (
<div className="space-y-2 rounded-md border p-3"> <div
className="space-y-2 rounded-md border p-3"
// A whisper of this group's own stroke on the row frame (see
// subtleRuleColor in GroupSessionDialog) so the rows tie into the
// card's color instead of generic gray rules.
style={{ borderColor: `color-mix(in srgb, ${accentColor} 25%, transparent)` }}
>
<div className="flex items-start gap-2"> <div className="flex items-start gap-2">
{draft.isNew ? ( {draft.isNew ? (
<Tooltip> <Tooltip>
@ -545,7 +583,10 @@ function SessionTodoRow({
preview="edit" preview="edit"
/> />
) : draft.details ? ( ) : draft.details ? (
<div className="max-h-40 overflow-y-auto rounded-md border p-2"> <div
className="max-h-40 overflow-y-auto rounded-md border p-2"
style={{ borderColor: `color-mix(in srgb, ${accentColor} 25%, transparent)` }}
>
<MarkdownPreview source={draft.details} /> <MarkdownPreview source={draft.details} />
</div> </div>
) : null} ) : null}