refactor(sidebar): simplify folder header styling and fix arrow pixel alignment
- Drop the expanded-state background and border on folder headers; keep the unified hover background - Swap the arrow to a ChevronRight/ChevronDown toggle and remove the rotation animation to avoid subpixel rendering drift - Size the arrow icon at 11px so its vertical center lands on an integer pixel - Round the sticky overlay's top offset so it stays pixel-aligned with the virtual list items
This commit is contained in:
@@ -14,6 +14,7 @@ import { useTranslations } from "next-intl"
|
|||||||
import { toast } from "sonner"
|
import { toast } from "sonner"
|
||||||
import { Virtualizer, type VirtualizerHandle } from "virtua"
|
import { Virtualizer, type VirtualizerHandle } from "virtua"
|
||||||
import {
|
import {
|
||||||
|
ChevronDown,
|
||||||
ChevronRight,
|
ChevronRight,
|
||||||
Download,
|
Download,
|
||||||
FolderOpen,
|
FolderOpen,
|
||||||
@@ -149,11 +150,9 @@ const FolderHeader = memo(function FolderHeader({
|
|||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-[1.9375rem] w-full items-center",
|
"flex h-[1.9375rem] w-full items-center",
|
||||||
"rounded-[0.4375rem] border",
|
"rounded-[0.4375rem]",
|
||||||
"transition-[background-color,color,border-color] duration-150",
|
"transition-colors duration-150",
|
||||||
expanded
|
"hover:bg-[color-mix(in_oklab,var(--sidebar-accent),var(--sidebar-foreground)_2%)]"
|
||||||
? "bg-sidebar-primary/15 border-sidebar-primary/25"
|
|
||||||
: "border-transparent hover:bg-[color-mix(in_oklab,var(--sidebar-accent),var(--sidebar-foreground)_2%)]"
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
@@ -166,12 +165,14 @@ const FolderHeader = memo(function FolderHeader({
|
|||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-[0.75rem] w-[0.75rem] shrink-0 items-center justify-center text-muted-foreground/75",
|
"flex h-[0.75rem] w-[0.75rem] shrink-0 items-center justify-center text-muted-foreground/75"
|
||||||
"transition-transform duration-[180ms] [transition-timing-function:cubic-bezier(.3,.7,.3,1)]",
|
|
||||||
expanded ? "rotate-90" : "rotate-0"
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<ChevronRight className="h-[0.625rem] w-[0.625rem]" />
|
{expanded ? (
|
||||||
|
<ChevronDown className="h-[0.6875rem] w-[0.6875rem]" />
|
||||||
|
) : (
|
||||||
|
<ChevronRight className="h-[0.6875rem] w-[0.6875rem]" />
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
<div className="flex min-w-0 flex-1 items-center gap-[0.375rem]">
|
<div className="flex min-w-0 flex-1 items-center gap-[0.375rem]">
|
||||||
<span
|
<span
|
||||||
@@ -404,10 +405,6 @@ export function SidebarConversationList({
|
|||||||
folder: Extract<FlatItem, { type: "folder_header" }> | null
|
folder: Extract<FlatItem, { type: "folder_header" }> | null
|
||||||
pushOffset: number
|
pushOffset: number
|
||||||
}>(() => {
|
}>(() => {
|
||||||
// All items are uniform height (cardHeightPx). Compute offsets from the
|
|
||||||
// index directly instead of querying virtua — querying it during render
|
|
||||||
// (when flatItems has grown but Virtualizer hasn't re-rendered yet) can
|
|
||||||
// poison its internal size cache and produce NaN for total scroll height.
|
|
||||||
if (flatItems.length === 0 || cardHeightPx <= 0) {
|
if (flatItems.length === 0 || cardHeightPx <= 0) {
|
||||||
return { folder: null, pushOffset: 0 }
|
return { folder: null, pushOffset: 0 }
|
||||||
}
|
}
|
||||||
@@ -753,10 +750,8 @@ export function SidebarConversationList({
|
|||||||
<div className="flex-1 min-h-0 relative">
|
<div className="flex-1 min-h-0 relative">
|
||||||
{stickyFolderItem && (
|
{stickyFolderItem && (
|
||||||
<div
|
<div
|
||||||
className="absolute top-0 left-0 right-0 z-10"
|
className="absolute left-0 right-0 z-10"
|
||||||
style={{
|
style={{ top: `${Math.round(stickyState.pushOffset)}px` }}
|
||||||
transform: `translateY(${stickyState.pushOffset}px)`,
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
aria-hidden
|
aria-hidden
|
||||||
|
|||||||
Reference in New Issue
Block a user