feat(web): kategori ağacına kılavuz çizgileri + yumuşak aç/kapa animasyonu

- Girinti satır-bazlı paddingLeft yerine açılan çocuk grubunda border-l ile;
  her seviyenin çizgisi parent satırın chevron merkeziyle hizalanır
- Aç/kapa CSS grid-rows 0fr↔1fr geçişiyle animasyonlu (motion-reduce saygılı)
- Lazy fetch, şema prefetch/preview, leaf→Link ve a11y korundu

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-26 00:43:54 +03:00
parent ac437eaadb
commit 6499c98ae9

View File

@@ -40,7 +40,6 @@ export function CategoryTree({
key={cat.id}
category={cat}
vehicleId={vehicleId}
level={0}
parentPrefetching={false}
catalogMode={catalogMode}
brandName={brandName}
@@ -54,7 +53,6 @@ export function CategoryTree({
function CategoryNode({
category,
vehicleId,
level,
parentPrefetching,
catalogMode,
brandName,
@@ -62,7 +60,6 @@ function CategoryNode({
}: {
category: Category;
vehicleId: string;
level: number;
parentPrefetching: boolean;
catalogMode?: boolean;
brandName?: string;
@@ -167,8 +164,6 @@ function CategoryNode({
category.unavailable && "pointer-events-none opacity-40",
);
const indentStyle = { paddingLeft: `${level * 16 + 12}px` };
const rowInner = (
<>
<span aria-hidden className="flex h-5 w-5 shrink-0 items-center justify-center">
@@ -214,35 +209,38 @@ function CategoryNode({
}
search={catalogMode && variantSearch ? variantSearch : undefined}
className={cn(rowClass, "no-underline")}
style={indentStyle}
>
{rowInner}
</Link>
) : (
<button
type="button"
onClick={handleExpand}
aria-expanded={expanded}
className={rowClass}
style={indentStyle}
>
<button type="button" onClick={handleExpand} aria-expanded={expanded} className={rowClass}>
{rowInner}
</button>
)}
{hasChildren && expanded && (
<div>
{children.map((child) => (
<CategoryNode
key={child.id}
category={child}
vehicleId={vehicleId}
level={level + 1}
parentPrefetching={prefetching}
catalogMode={catalogMode}
brandName={brandName}
variantSearch={variantSearch}
/>
))}
{hasChildren && (
// Yumuşak aç/kapa: grid-rows 0fr↔1fr (içerik yüksekliği bilmeye gerek yok, JS animasyon yok)
<div
className={cn(
"grid transition-[grid-template-rows] duration-200 ease-out motion-reduce:transition-none",
expanded ? "grid-rows-[1fr]" : "grid-rows-[0fr]",
)}
>
<div className="overflow-hidden">
{/* Girinti + kılavuz çizgisi: çizgi parent satırın chevron merkezine (≈22px) hizalanır */}
<div className="ml-[22px] border-l border-border">
{children.map((child) => (
<CategoryNode
key={child.id}
category={child}
vehicleId={vehicleId}
parentPrefetching={prefetching}
catalogMode={catalogMode}
brandName={brandName}
variantSearch={variantSearch}
/>
))}
</div>
</div>
</div>
)}
</div>