spotlight had list metrics, and it is not a list
It read as cramped because the first pass reused the app's own list sizing — a 7px tile, text-sm, py-2 — which is right for a row inside a panel competing with everything around it, and wrong for a modal you look at for two seconds with nothing else on screen. So the search input leads at text-base with a 5px glyph, rows are py-2.5 with a 9px tile, and the label is text-[15px] with the hint and the route kept deliberately subordinate rather than scaled with it. Two knock-on changes that are arithmetic rather than taste. The panel widened 560 → 640, because a row now carries a label, a hint and a route on one line and the route is the first thing squeezed out — it is also what disambiguates two rows with the same name. And the results box grew 52vh → 60vh, because taller rows in the same box show fewer results, which would have quietly undone removing the eight-item cap. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,20 @@ import { useSpotlightItems, type SpotlightItem } from './useSpotlightItems';
|
||||
// things to collide with, and this one moved twice already.
|
||||
//
|
||||
// Escape closes, arrows move, enter goes. The mouse works, but nothing here is designed around it.
|
||||
//
|
||||
// ── Sizing ──
|
||||
//
|
||||
// Loosened 2026-08-22: the first pass reused the app's list metrics (7px tile, text-sm, py-2) and read as
|
||||
// cramped, because this is not a list inside a panel — it is a modal you look at for two seconds with
|
||||
// nothing else competing for the eye. So the search input leads at `text-base`, rows are `py-2.5` with a
|
||||
// 9px tile, and the label is `text-[15px]` with the hint and path kept deliberately subordinate.
|
||||
//
|
||||
// The panel widened with them (560 → 640). Rows now carry a label, a hint and a route on one line, and the
|
||||
// route is the first thing to be squeezed out — it is also the thing that disambiguates two rows with the
|
||||
// same name.
|
||||
//
|
||||
// The results box grew 52vh → 60vh for the arithmetic reason: taller rows in the same box show fewer
|
||||
// results, and the cap on how many are listed was removed for a reason.
|
||||
|
||||
/*
|
||||
No cap, deliberately, and it used to be 8.
|
||||
@@ -94,7 +108,7 @@ const Row = ({
|
||||
ev.preventDefault();
|
||||
onPick();
|
||||
}}
|
||||
className={`flex w-full items-center gap-3 rounded-lg px-3 py-2 text-left transition-colors ${
|
||||
className={`flex w-full items-center gap-3.5 rounded-lg px-3.5 py-2.5 text-left transition-colors ${
|
||||
active ? 'bg-accent' : 'hover:bg-accent/50'
|
||||
}`}
|
||||
>
|
||||
@@ -112,7 +126,7 @@ const Row = ({
|
||||
it put a coloured pane behind Calendar, Contacts and every plugin logo.
|
||||
*/}
|
||||
<span
|
||||
className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md"
|
||||
className="flex h-9 w-9 shrink-0 items-center justify-center rounded-md"
|
||||
style={{
|
||||
background: item.tile === 'bare' ? 'transparent' : (item.color ?? 'transparent'),
|
||||
// No colour at all is a settings row: keep the muted glyph rather than inventing a swatch.
|
||||
@@ -126,18 +140,20 @@ const Row = ({
|
||||
className={item.tile === 'bare' ? 'h-full w-full object-contain' : 'h-5 w-5 object-contain'}
|
||||
/>
|
||||
) : Icon ? (
|
||||
<Icon className={`h-4 w-4 ${item.color ? '' : 'text-muted-foreground'}`} />
|
||||
<Icon className={`h-[18px] w-[18px] ${item.color ? '' : 'text-muted-foreground'}`} />
|
||||
) : (
|
||||
<Search className="h-4 w-4 text-muted-foreground" />
|
||||
<Search className="h-[18px] w-[18px] text-muted-foreground" />
|
||||
)}
|
||||
</span>
|
||||
<span className="min-w-0 flex-1">
|
||||
<span className="block truncate text-sm text-foreground">
|
||||
<span className="block truncate text-[15px] leading-snug text-foreground">
|
||||
<Highlighted label={item.label} hits={hits} />
|
||||
</span>
|
||||
{item.hint ? <span className="block truncate text-xs text-muted-foreground">{item.hint}</span> : null}
|
||||
{item.hint ? (
|
||||
<span className="block truncate text-[13px] leading-snug text-muted-foreground">{item.hint}</span>
|
||||
) : null}
|
||||
</span>
|
||||
<span className="shrink-0 font-mono text-[10px] text-muted-foreground/60">{item.to}</span>
|
||||
<span className="shrink-0 font-mono text-[11px] text-muted-foreground/60">{item.to}</span>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
@@ -205,12 +221,12 @@ export const Spotlight = () => {
|
||||
onMouseDown={close}
|
||||
>
|
||||
<div
|
||||
className="w-[min(92vw,560px)] overflow-hidden rounded-2xl border border-border bg-background/95 shadow-2xl"
|
||||
className="w-[min(92vw,640px)] overflow-hidden rounded-2xl border border-border bg-background/95 shadow-2xl"
|
||||
// The backdrop closes on mousedown; this stops a click INSIDE the panel counting as one.
|
||||
onMouseDown={(ev) => ev.stopPropagation()}
|
||||
>
|
||||
<div className="flex items-center gap-2 border-b border-border px-4">
|
||||
<Search className="h-4 w-4 shrink-0 text-muted-foreground" />
|
||||
<Search className="h-5 w-5 shrink-0 text-muted-foreground" />
|
||||
<input
|
||||
ref={inputRef}
|
||||
value={query}
|
||||
@@ -228,11 +244,11 @@ export const Spotlight = () => {
|
||||
}
|
||||
}}
|
||||
placeholder="Go to…"
|
||||
className="w-full bg-transparent py-3.5 text-sm text-foreground outline-none placeholder:text-muted-foreground"
|
||||
className="w-full bg-transparent py-4 text-base text-foreground outline-none placeholder:text-muted-foreground"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="max-h-[52vh] overflow-y-auto p-2">
|
||||
<div className="max-h-[60vh] overflow-y-auto p-2">
|
||||
{results.length === 0 ? (
|
||||
<p className="px-3 py-6 text-center text-sm text-muted-foreground">Nothing matches “{query}”.</p>
|
||||
) : (
|
||||
|
||||
Reference in New Issue
Block a user