fix(issues): polish sub-issues section design to match Linear (#503)

- Add chevron collapse indicator in header
- Show completion progress (done/total) with tabular-nums
- Use left border indentation for child items (tree view)
- Increase icon size, row padding, and spacing
- Larger + button with better hover state
- Only show section when child issues exist
This commit is contained in:
Bohan Jiang 2026-04-08 16:47:07 +08:00 committed by GitHub
parent 0c45864ef0
commit 180c6966db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -694,35 +694,38 @@ export function IssueDetail({ issueId, onDelete, defaultSidebarOpen = true, layo
</div> </div>
{/* Sub-issues — below description, like Linear */} {/* Sub-issues — below description, like Linear */}
{(childIssues.length > 0 || parentIssue) && ( {childIssues.length > 0 && (
<div className="mt-6"> <div className="mt-8">
<div className="flex items-center gap-2 mb-2"> {/* Header */}
<span className="text-sm font-medium">Sub-issues</span> <div className="flex items-center gap-3 mb-1">
{childIssues.length > 0 && ( <div className="flex items-center gap-2">
<span className="text-xs text-muted-foreground">{childIssues.length}/{childIssues.length}</span> <ChevronDown className="h-3.5 w-3.5 text-muted-foreground" />
)} <span className="text-sm font-medium">Sub-issues</span>
</div>
<span className="text-xs text-muted-foreground tabular-nums">{childIssues.filter((c) => c.status === "done").length}/{childIssues.length}</span>
<button <button
type="button" type="button"
className="ml-auto p-1 rounded hover:bg-accent/60 transition-colors text-muted-foreground hover:text-foreground" className="ml-auto p-1.5 rounded-md hover:bg-accent/60 transition-colors text-muted-foreground hover:text-foreground"
onClick={() => useModalStore.getState().open("create-issue", { onClick={() => useModalStore.getState().open("create-issue", {
parent_issue_id: issue.id, parent_issue_id: issue.id,
parent_issue_identifier: issue.identifier, parent_issue_identifier: issue.identifier,
})} })}
> >
<Plus className="h-3.5 w-3.5" /> <Plus className="h-4 w-4" />
</button> </button>
</div> </div>
<div className="space-y-0.5"> {/* List */}
<div className="ml-[7px] border-l border-border">
{childIssues.map((child) => ( {childIssues.map((child) => (
<Link <Link
key={child.id} key={child.id}
href={`/issues/${child.id}`} href={`/issues/${child.id}`}
className="flex items-center gap-2 rounded-md px-2 py-1.5 -mx-2 text-sm hover:bg-accent/50 transition-colors group" className="flex items-center gap-3 pl-5 pr-2 py-2.5 hover:bg-accent/40 transition-colors group"
> >
<StatusIcon status={child.status} className="h-4 w-4 shrink-0" /> <StatusIcon status={child.status} className="h-[18px] w-[18px] shrink-0" />
<span className="truncate group-hover:text-foreground">{child.title}</span> <span className="text-sm truncate group-hover:text-foreground">{child.title}</span>
{child.assignee_type && child.assignee_id && ( {child.assignee_type && child.assignee_id && (
<ActorAvatar actorType={child.assignee_type} actorId={child.assignee_id} size={20} className="ml-auto shrink-0" /> <ActorAvatar actorType={child.assignee_type} actorId={child.assignee_id} size={24} className="ml-auto shrink-0" />
)} )}
</Link> </Link>
))} ))}