matched design
Hee Sung Son committed
Nov 25, 2025 at 09:33 UTC
9f5ae5df9d0187cf3a43c6d2ea1e950d6e086686
2 files changed
+16
-12
cmd/relay-server/frontend/src/components/TagCombobox.tsx
+9
-9
@@ -33,9 +33,7 @@ export function TagCombobox({
33
const query = inputValue.trim().toLowerCase();
34
const pool = availableTags.filter((tag) => !selectedTags.includes(tag));
35
if (!query) return pool.slice(0, 8);
36
- return pool
37
- .filter((tag) => tag.toLowerCase().includes(query))
38
- .slice(0, 8);
36
+ return pool.filter((tag) => tag.toLowerCase().includes(query)).slice(0, 8);
37
}, [availableTags, selectedTags, inputValue]);
38
39
useEffect(() => {
@@ -106,18 +104,18 @@ export function TagCombobox({
104
className="flex w-full sm:w-auto sm:min-w-[320px] flex-1 items-center gap-2 overflow-visible"
105
>
106
<div className="flex min-w-0 flex-1 items-center gap-2 rounded-lg border border-border bg-background px-2 py-1.5 min-h-10">
109
- <div className="flex flex-wrap items-center gap-2 overflow-hidden">
107
+ <div className="flex flex-1 flex-wrap items-center gap-2 overflow-hidden">
108
{selectedTags.map((tag) => (
109
<Button
110
key={tag}
111
variant="secondary"
112
size="sm"
115
- className="h-7 rounded-full px-3 text-xs"
113
+ className="h-7 rounded px-3 bg-secondary text-primary text-xs"
114
onClick={() => onRemove(tag)}
115
aria-label={`Remove tag ${tag}`}
116
>
117
{tag}
120
- <span className="ml-2 text-foreground/70">×</span>
118
+ <span className="ml-2 bg-secondary text-primary">×</span>
119
</Button>
120
))}
121
<input
@@ -140,7 +138,7 @@ export function TagCombobox({
138
</div>
139
</div>
140
143
- <div className="flex items-center rounded-md bg-border text-xs font-semibold text-foreground/80 overflow-hidden h-10 flex-shrink-0">
141
+ <div className="flex items-center rounded-md bg-border text-xs font-semibold text-foreground/80 overflow-hidden h-10 shrink-0">
142
<button
143
type="button"
144
className={cn(
@@ -165,11 +163,13 @@ export function TagCombobox({
163
</button>
164
</div>
165
168
- {open && filtered.length > 0 && panelStyle &&
166
+ {open &&
167
+ filtered.length > 0 &&
168
+ panelStyle &&
169
createPortal(
170
<div
171
style={panelStyle}
172
- className="rounded-lg border border-border bg-background shadow-lg"
172
+ className="rounded-lg border border-border bg-background shadow-lg overflow-hidden"
173
>
174
<ul
175
id={listId}
cmd/relay-server/frontend/src/pages/ServerList.tsx
+7
-3
@@ -98,7 +98,9 @@ export function ServerList() {
98
counts.set(tag, (counts.get(tag) || 0) + 1);
99
});
100
});
101
- return Array.from(counts.entries()).sort((a, b) => b[1] - a[1]).map(([tag]) => tag);
101
+ return Array.from(counts.entries())
102
+ .sort((a, b) => b[1] - a[1])
103
+ .map(([tag]) => tag);
104
}, [servers]);
105
106
// Filter and sort servers
@@ -109,7 +111,9 @@ export function ServerList() {
111
if (selectedTags.length === 0) return true;
112
const tagsLower = server.tags.map((t) => t.toLowerCase());
113
if (tagMode === "AND") {
112
- return selectedTags.every((tag) => tagsLower.includes(tag.toLowerCase()));
114
+ return selectedTags.every((tag) =>
115
+ tagsLower.includes(tag.toLowerCase())
116
+ );
117
}
118
return selectedTags.some((tag) => tagsLower.includes(tag.toLowerCase()));
119
};
@@ -254,7 +258,7 @@ export function ServerList() {
258
online={server.online}
259
dns={server.dns}
260
serverUrl={server.link}
257
- navigationPath={`/server/${server.id}`}
261
+ navigationPath={server.link}
262
navigationState={{
263
id: server.id,
264
name: server.name,