spotlight showed eight items, so every plugin was unreachable

MAX_RESULTS was 8. Core items alone fill eight slots, so on a populated server the empty-query list stopped
at Browser and none of the fourteen plugin tiles below it could be reached — unless you already knew the
name well enough to type it, which is not a thing a launcher gets to require. The owner caught it on alpha
with the dock and the launcher side by side; on this machine, which has few plugins, it looked complete.

The items were there the whole time. This was not a missing source — it was a silent truncation, with
nothing on screen saying "and 20 more", which is exactly how a cap reads as an absent feature.

There was never a layout reason for it either: the results container has scrolled since it was written.
Removed, and the active row now scrolls itself into view with `block: 'nearest'` so arrowing past the fold
works and arrowing through the visible middle does not jump the list.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-21 22:24:01 +00:00
co-authored by Claude Opus 5
parent f023ab5da0
commit 3cab16ca5b
@@ -25,7 +25,18 @@ import { useSpotlightItems, type SpotlightItem } from './useSpotlightItems';
//
// Escape closes, arrows move, enter goes. The mouse works, but nothing here is designed around it.
const MAX_RESULTS = 8;
/*
No cap, deliberately, and it used to be 8.
Eight was fine on the machine it was written on, which has few plugins. On a populated server the dock
carries fourteen plugin tiles and the core items alone fill all eight slots — so with an empty query the
list stopped at Browser and every plugin was unreachable unless you already knew its name well enough to
type it. A launcher you can only use for things you can already name is not doing the job.
The container has scrolled since it was written (`max-h-[52vh] overflow-y-auto`), so there was never a
layout reason for the limit, and the truncation was silent — nothing said "and 20 more", which is how a
cap becomes indistinguishable from a missing feature.
*/
/**
* Is the user typing into something?
@@ -71,8 +82,15 @@ const Row = ({
onPick: () => void;
}) => {
const Icon = item.icon;
// Keyboard navigation has to survive a list taller than the box. `block: 'nearest'` scrolls only when the
// row is actually out of sight, so arrowing through the visible middle of the list does not jump it.
const ref = useRef<HTMLButtonElement | null>(null);
useEffect(() => {
if (active) ref.current?.scrollIntoView({ block: 'nearest' });
}, [active]);
return (
<button
ref={ref}
type="button"
// `onMouseDown`, not `onClick`: the input holds focus and a click would blur it first, closing the
// overlay on the blur handler before the navigation ever ran.
@@ -136,7 +154,7 @@ export const Spotlight = () => {
const navigate = useNavigate();
const items = useSpotlightItems();
const results = useMemo(() => rank(items, query).slice(0, MAX_RESULTS), [items, query]);
const results = useMemo(() => rank(items, query), [items, query]);
const close = useCallback(() => {
setOpen(false);