From d4de363227d3d7d5dcdc7d21e5fb830691445fdb Mon Sep 17 00:00:00 2001 From: teernisse Date: Fri, 30 Jan 2026 23:04:38 -0500 Subject: [PATCH] Polish UI: SearchBar sizing, SessionList layout, Tooltip offset, and progress CSS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SearchBar: - Switch from fixed w-80/sm:w-96 to fluid min-w-80 max-w-md w-full - Adjust left padding for better visual alignment with search icon SessionList: - Memoize project grouping computation with useMemo - Move horizontal padding from per-item margin (mx-2 + width calc hack) to container padding (px-2) for cleaner layout and full-width buttons - Remove inline width override that was compensating for the old margins Tooltip: - Increase offset from 8px to 12px for better visual separation CSS: - Add prose-message-progress variant with compact 11px mono typography for progress event content (code blocks, tables, links, blockquotes) - Reduce search minimap marker height from 4px to 3px - Normalize prose-message line-height: paragraphs 1.625→1.6, list items 1.5→1.6 for consistent rhythm - Switch custom checkbox checkmark sizing from fixed px to percentages for better scaling across different zoom levels Co-Authored-By: Claude Opus 4.5 --- src/client/components/SearchBar.tsx | 4 +- src/client/components/SessionList.tsx | 30 ++++--- src/client/components/Tooltip.tsx | 2 +- src/client/styles/main.css | 124 ++++++++++++++++++++++++-- 4 files changed, 136 insertions(+), 24 deletions(-) diff --git a/src/client/components/SearchBar.tsx b/src/client/components/SearchBar.tsx index 779fbba..6e5d9d1 100644 --- a/src/client/components/SearchBar.tsx +++ b/src/client/components/SearchBar.tsx @@ -107,7 +107,7 @@ export function SearchBar({ const showControls = !!localQuery || !!query; return ( -
+
{/* Unified search container */}
setIsFocused(true)} onBlur={() => setIsFocused(false)} placeholder="Search messages..." - className="flex-1 min-w-0 bg-transparent px-2.5 py-2 text-body text-foreground + className="flex-1 min-w-0 bg-transparent pl-3 pr-2.5 py-2 text-body text-foreground placeholder:text-foreground-muted focus:outline-none" /> diff --git a/src/client/components/SessionList.tsx b/src/client/components/SessionList.tsx index 0de3bf9..375cd05 100644 --- a/src/client/components/SessionList.tsx +++ b/src/client/components/SessionList.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect, useMemo } from "react"; import type { SessionEntry } from "../lib/types"; interface Props { @@ -11,13 +11,16 @@ interface Props { export function SessionList({ sessions, loading, selectedId, onSelect }: Props) { const [selectedProject, setSelectedProject] = useState(null); - // Group by project - const grouped = new Map(); - for (const session of sessions) { - const group = grouped.get(session.project) || []; - group.push(session); - grouped.set(session.project, group); - } + // Group by project (memoized to avoid recomputing on unrelated rerenders) + const grouped = useMemo(() => { + const map = new Map(); + for (const session of sessions) { + const group = map.get(session.project) || []; + group.push(session); + map.set(session.project, group); + } + return map; + }, [sessions]); // Auto-select project when selectedId changes useEffect(() => { @@ -73,7 +76,7 @@ export function SessionList({ sessions, loading, selectedId, onSelect }: Props)
{formatProjectName(selectedProject)}
-
+
{projectSessions.map((session, idx) => { const isSelected = selectedId === session.id; return ( @@ -81,13 +84,13 @@ export function SessionList({ sessions, loading, selectedId, onSelect }: Props) key={session.id} onClick={() => onSelect(session.id)} className={` - w-full text-left mx-2 my-0.5 px-3 py-2.5 rounded-lg transition-all duration-200 + w-full text-left my-0.5 px-3 py-2.5 rounded-lg transition-all duration-200 ${isSelected ? "bg-accent-light shadow-glow-accent ring-1 ring-accent/25" : "hover:bg-surface-overlay" } `} - style={{ width: "calc(100% - 1rem)", animationDelay: `${idx * 30}ms` }} + style={{ animationDelay: `${idx * 30}ms` }} >
{session.summary || session.firstPrompt || "Untitled Session"} @@ -113,7 +116,7 @@ export function SessionList({ sessions, loading, selectedId, onSelect }: Props) // Project list return ( -
+
{[...grouped.entries()].map(([project, projectSessions]) => { const latest = projectSessions.reduce((a, b) => (a.modified || a.created) > (b.modified || b.created) ? a : b @@ -123,8 +126,7 @@ export function SessionList({ sessions, loading, selectedId, onSelect }: Props)