feat(panel): tooltip sweep — tasks, kanban, task assistant, git, work sessions (58 tips, 22 files)

Full import-graph walk per page: filter-chip and plan-section icon
buttons gain their first accessible names, per-state description maps
for git/docs/finding/priority badges, truncation-gated full-value tips,
disabled buttons explain their gate. Stateful Radix triggers use the
task-tabs data-state re-assertion pattern.
This commit is contained in:
Renn F
2026-07-15 16:30:26 +02:00
parent 14ee9b3b49
commit d1b02e3747
30 changed files with 1079 additions and 543 deletions
+31 -12
View File
@@ -10,6 +10,7 @@ import { ScrollArea } from "@/components/ui/scroll-area";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { cn } from "@/lib/utils";
import { FileCode, FileDiff, WrapText } from "lucide-react";
import { HelpTip } from "@/components/ui/help-tip";
interface GitDiffViewerProps {
stagedDiff: GitDiffResponse | undefined;
@@ -124,21 +125,39 @@ export function GitDiffViewer({
<Tabs defaultValue="unstaged">
<div className="px-4 border-b">
<TabsList className="h-9">
{/* HelpTip wraps an inner span, never the TabsTrigger itself —
TooltipTrigger's asChild would clobber the trigger's own
data-state and break the active-tab highlight (see
task-tabs.tsx for the fuller writeup of this bug class). */}
<TabsTrigger value="unstaged" className="text-xs gap-1">
Working Directory
{unstagedCount > 0 && (
<Badge variant="secondary" className="h-4 px-1 text-[10px]">
{unstagedCount}
</Badge>
)}
<HelpTip label="Files changed on disk that haven't been staged for the next commit yet">
<span className="inline-flex items-center gap-1">
Working Directory
{unstagedCount > 0 && (
<Badge
variant="secondary"
className="h-4 px-1 text-[10px]"
>
{unstagedCount}
</Badge>
)}
</span>
</HelpTip>
</TabsTrigger>
<TabsTrigger value="staged" className="text-xs gap-1">
Staged
{stagedCount > 0 && (
<Badge variant="secondary" className="h-4 px-1 text-[10px]">
{stagedCount}
</Badge>
)}
<HelpTip label="Files staged and ready to be included in the next commit">
<span className="inline-flex items-center gap-1">
Staged
{stagedCount > 0 && (
<Badge
variant="secondary"
className="h-4 px-1 text-[10px]"
>
{stagedCount}
</Badge>
)}
</span>
</HelpTip>
</TabsTrigger>
</TabsList>
</div>
+37 -17
View File
@@ -14,12 +14,22 @@ import {
ArrowDown,
CheckCircle,
} from "lucide-react";
import { HelpTip } from "@/components/ui/help-tip";
interface GitStatusPanelProps {
status: GitStatusResponse | undefined;
isLoading: boolean;
}
// Plain-language explanation per file bucket, mirroring the task-status-badge
// per-state description map so non-git-fluent readers (CEO, PM) know what
// each section means without having to already know git jargon.
const FILE_SECTION_DESCRIPTIONS = {
staged: "Changes staged and ready to be included in the next commit.",
unstaged: "Tracked files with changes not yet staged for commit.",
untracked: "New files git isn't tracking yet.",
} as const;
export function GitStatusPanel({ status, isLoading }: GitStatusPanelProps) {
if (isLoading) {
return (
@@ -77,16 +87,20 @@ export function GitStatusPanel({ status, isLoading }: GitStatusPanelProps) {
{(status.ahead > 0 || status.behind > 0) && (
<div className="flex items-center gap-2">
{status.ahead > 0 && (
<Badge variant="secondary" className="text-xs">
<ArrowUp className="h-3 w-3 mr-1" />
{status.ahead} ahead
</Badge>
<HelpTip label="Local commits not yet pushed to the remote.">
<Badge variant="secondary" className="text-xs">
<ArrowUp className="h-3 w-3 mr-1" />
{status.ahead} ahead
</Badge>
</HelpTip>
)}
{status.behind > 0 && (
<Badge variant="secondary" className="text-xs">
<ArrowDown className="h-3 w-3 mr-1" />
{status.behind} behind
</Badge>
<HelpTip label="Remote commits not yet merged into your local branch.">
<Badge variant="secondary" className="text-xs">
<ArrowDown className="h-3 w-3 mr-1" />
{status.behind} behind
</Badge>
</HelpTip>
)}
</div>
)}
@@ -99,9 +113,11 @@ export function GitStatusPanel({ status, isLoading }: GitStatusPanelProps) {
{/* Staged Files */}
{status.staged_files.length > 0 && (
<div>
<h4 className="text-xs font-semibold text-green-600 uppercase tracking-wider mb-1">
Staged ({status.staged_files.length})
</h4>
<HelpTip label={FILE_SECTION_DESCRIPTIONS.staged}>
<h4 className="text-xs font-semibold text-green-600 uppercase tracking-wider mb-1 w-fit">
Staged ({status.staged_files.length})
</h4>
</HelpTip>
<div className="space-y-0.5">
{status.staged_files.map((file) => (
<div
@@ -121,9 +137,11 @@ export function GitStatusPanel({ status, isLoading }: GitStatusPanelProps) {
{/* Unstaged Files */}
{status.unstaged_files.length > 0 && (
<div>
<h4 className="text-xs font-semibold text-orange-600 uppercase tracking-wider mb-1">
Modified ({status.unstaged_files.length})
</h4>
<HelpTip label={FILE_SECTION_DESCRIPTIONS.unstaged}>
<h4 className="text-xs font-semibold text-orange-600 uppercase tracking-wider mb-1 w-fit">
Modified ({status.unstaged_files.length})
</h4>
</HelpTip>
<div className="space-y-0.5">
{status.unstaged_files.map((file) => (
<div
@@ -143,9 +161,11 @@ export function GitStatusPanel({ status, isLoading }: GitStatusPanelProps) {
{/* Untracked Files */}
{status.untracked_files.length > 0 && (
<div>
<h4 className="text-xs font-semibold text-blue-600 uppercase tracking-wider mb-1">
Untracked ({status.untracked_files.length})
</h4>
<HelpTip label={FILE_SECTION_DESCRIPTIONS.untracked}>
<h4 className="text-xs font-semibold text-blue-600 uppercase tracking-wider mb-1 w-fit">
Untracked ({status.untracked_files.length})
</h4>
</HelpTip>
<div className="space-y-0.5">
{status.untracked_files.map((file) => (
<div