From af1a06b0a340a31307655b2f409b98d3c3f33f7a Mon Sep 17 00:00:00 2001 From: openhands Date: Sun, 13 Sep 2026 12:36:20 +0200 Subject: [PATCH] feat(studio): polish search highlight, zebra rows, and transitions Highlight the active search term in names/classnames (grid + table), add zebra striping and a left accent bar on selected table rows, fade the results list when switching grid/table or on first load, and swap the broken-icon fallback for a cleaner placeholder. --- src/components/admin/studio/studio-client.tsx | 52 ++++++++++++++++--- .../admin/studio/studio-furni-icons.ts | 3 +- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/components/admin/studio/studio-client.tsx b/src/components/admin/studio/studio-client.tsx index 20236d83..460d4162 100644 --- a/src/components/admin/studio/studio-client.tsx +++ b/src/components/admin/studio/studio-client.tsx @@ -25,6 +25,7 @@ import { Trash2, X, } from "lucide-react"; +import { motion } from "motion/react"; import { lazy, Suspense, @@ -142,6 +143,23 @@ function writeLs(key: string, value: string) { } } +// Wraps the first case-insensitive match of `query` inside `text` in an accent +// mark so users can see where their search hit. +function Highlighted({ text, query }: { text: string; query: string }) { + if (!query) return text; + const index = text.toLowerCase().indexOf(query.toLowerCase()); + if (index === -1) return text; + return ( + <> + {text.slice(0, index)} + + {text.slice(index, index + query.length)} + + {text.slice(index + query.length)} + + ); +} + // Table layout: a shared grid template keeps the sticky header and each // virtualized row in perfect column alignment. const TABLE_COLS = @@ -1930,7 +1948,12 @@ export function StudioClient({

) : ( - <> + {viewMode === "grid" ? (

- {item.name} +

- {item.classname} +

{item.category || "—"} @@ -2164,7 +2193,10 @@ export function StudioClient({ aria-selected={isSel} className={cn( "absolute left-0 top-0 grid w-full min-w-[660px] text-sm transition-colors hover:bg-[var(--admin-accent)]/5", - isSel && "bg-[var(--admin-accent)]/10", + vi.index % 2 === 1 && + "bg-[var(--admin-text)]/[0.03]", + isSel && + "bg-[var(--admin-accent)]/10 shadow-[inset_2px_0_0_0_var(--admin-accent)]", )} style={{ display: "grid", @@ -2206,10 +2238,16 @@ export function StudioClient({ - {item.name} + - {item.classname} + {TYPE_LABELS[item.type] ?? item.type} @@ -2354,7 +2392,7 @@ export function StudioClient({ )}

- + )}
diff --git a/src/components/admin/studio/studio-furni-icons.ts b/src/components/admin/studio/studio-furni-icons.ts index 282e5cd7..8879aead 100644 --- a/src/components/admin/studio/studio-furni-icons.ts +++ b/src/components/admin/studio/studio-furni-icons.ts @@ -28,9 +28,8 @@ export function handleImgError( img.dataset.fallback = "2"; img.src = `/swf/dcr/hof_furni/icons/${encodeURIComponent(iconName)}_icon.png`; } else { - img.style.opacity = "0.3"; img.src = - 'data:image/svg+xml,'; + 'data:image/svg+xml,'; } }