Skip to content

Commit da568db

Browse files
committed
feat: add search on server when click in stack, fix package URL generation, improve style
1 parent b9df4ae commit da568db

File tree

3 files changed

+227
-223
lines changed

3 files changed

+227
-223
lines changed

src/App.tsx

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,17 @@ export default function App() {
9595
// Initialize apiUrl with default value
9696
const [apiUrl, setApiUrl] = useState('https://registry.modelcontextprotocol.io/v0/servers');
9797

98-
// Initialize stack with empty array
99-
const [stack, setStack] = useState<StackItem[]>([]);
98+
// Initialize stack from localStorage (client-side only) to avoid race
99+
// where the "save" effect would run on mount and overwrite a loaded value.
100+
const [stack, setStack] = useState<StackItem[]>(() => {
101+
try {
102+
if (typeof window === 'undefined') return [];
103+
const saved = localStorage.getItem('mcp-registry-stack');
104+
return saved ? (JSON.parse(saved) as StackItem[]) : [];
105+
} catch {
106+
return [];
107+
}
108+
});
100109

101110
useEffect(() => {
102111
// Load from localStorage after component mounts (client-side only)
@@ -109,14 +118,6 @@ export default function App() {
109118
setResultsPerPage(parsed);
110119
}
111120
}
112-
const savedStack = localStorage.getItem('mcp-registry-stack');
113-
if (savedStack) {
114-
try {
115-
setStack(JSON.parse(savedStack));
116-
} catch (err) {
117-
console.error('Failed to parse saved stack:', err);
118-
}
119-
}
120121
// Listen to back/forward navigation and sync `search` with the URL
121122
if (typeof window === 'undefined') return;
122123
const onPop = () => {
@@ -253,12 +254,6 @@ export default function App() {
253254
setNextCursor(null);
254255
setCurrentPage(1);
255256
fetchServers(search, null, filterDate);
256-
// // Update URL parameter
257-
// if (search) {
258-
// setSearchParams({ search });
259-
// } else {
260-
// setSearchParams({});
261-
// }
262257
}, [search, apiUrl, filterDate, resultsPerPage, fetchServers]);
263258

264259
const handleNext = () => {
@@ -280,11 +275,10 @@ export default function App() {
280275
}
281276
};
282277

283-
// NOTE: For cursor-based pagination, we can't jump to arbitrary pages
284-
// We can only navigate sequentially
278+
// NOTE: For cursor-based pagination, we can't jump to arbitrary pages, we can only navigate sequentially
285279
const handleGoToPage = (page: number) => {
286280
if (page === 1) {
287-
// Go to first page
281+
// Only support first page for now
288282
setCurrentCursor(null);
289283
setPreviousCursors([]);
290284
setCurrentPage(1);
@@ -300,8 +294,14 @@ export default function App() {
300294
{/* Header */}
301295
<header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
302296
<div className="container flex flex-col sm:flex-row sm:h-16 items-start sm:items-center justify-between gap-3 sm:gap-0 px-4 py-3 sm:py-0 mx-auto max-w-7xl">
303-
<div className="flex items-center gap-2 flex-shrink-0">
304-
<img src={McpLogo} alt="Cursor" className="h-5 w-5 [filter:invert(0)] dark:[filter:invert(1)]" />
297+
<div
298+
role="button"
299+
tabIndex={0}
300+
aria-label="Clear search"
301+
onClick={() => setSearch('')}
302+
className="flex items-center gap-2 flex-shrink-0 cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-ring rounded"
303+
>
304+
<img src={McpLogo} alt="MCP logo" className="h-5 w-5 [filter:invert(0)] dark:[filter:invert(1)]" />
305305
<h1 className="text-lg">MCP Registry</h1>
306306
</div>
307307
<div className="flex items-center gap-4 flex-1 w-full sm:w-auto justify-end max-w-2xl">
@@ -353,8 +353,9 @@ export default function App() {
353353
// List servers in the stack, with remove button
354354
<DropdownMenuItem
355355
key={idx}
356-
className="flex items-center justify-between gap-2 p-3"
356+
className="flex items-center justify-between gap-2 p-3 cursor-pointer"
357357
onSelect={(e) => e.preventDefault()}
358+
onClick={() => setSearch(item.serverName)}
358359
>
359360
<div className="flex-1 min-w-0">
360361
<div className="font-medium text-xs truncate">{item.serverName}</div>
@@ -365,7 +366,11 @@ export default function App() {
365366
</div>
366367
</div>
367368
<button
368-
onClick={() => removeFromStack(item.serverName, item.type, item.index)}
369+
onClick={(e) => {
370+
e.stopPropagation();
371+
e.preventDefault();
372+
removeFromStack(item.serverName, item.type, item.index);
373+
}}
369374
className="p-1 hover:bg-destructive/10 rounded transition-colors"
370375
>
371376
<Trash2 className="h-4 w-4 text-destructive" />
@@ -497,7 +502,7 @@ export default function App() {
497502

498503
{/* Loading/Error States */}
499504
{loading && (
500-
<p className="flex items-center justify-center text-center text-muted-foreground gap-2">
505+
<p className="flex mt-4 items-center justify-center text-center text-muted-foreground gap-2">
501506
<Spinner />
502507
<span>Loading servers...</span>
503508
</p>

0 commit comments

Comments
 (0)