Skip to content

Commit 290497e

Browse files
authored
Merge pull request #283 from zigzagdev/refactor/search-form-ui
Search form UX changed
2 parents 907096a + 9717973 commit 290497e

2 files changed

Lines changed: 80 additions & 94 deletions

File tree

client/src/app/features/top/components/HeritageSubHeader.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export type Props = {
88

99
export function HeritageSubHeader({ value, onSubmit, onChange }: Props) {
1010
return (
11-
<div className="sticky top-0 z-30 border-zinc-200/70 bg-white/95 backdrop-blur">
11+
<div className="z-30 border-zinc-200/70 bg-white/95 backdrop-blur">
1212
<div className="mx-auto w-full max-w-6xl px-4 py-3">
1313
<div className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
1414
<div className="w-full md:w-[1000px]">

client/src/app/features/top/components/heritage-detail/HeritageSubHeader.tsx

Lines changed: 79 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,10 @@ type Props = {
1111
onSubmit?: (query: Partial<SearchValues>) => void;
1212
};
1313

14-
function Divider() {
15-
return <div className="hidden h-8 w-px bg-zinc-200 md:block" aria-hidden="true" />;
16-
}
14+
const isStudyRegion = (value: string): value is StudyRegion =>
15+
STUDY_REGIONS.includes(value as StudyRegion);
1716

18-
function FieldLabel({ title, subtitle }: { title: string; subtitle: string }) {
19-
return (
20-
<div className="min-w-[84px] leading-tight">
21-
<div className="text-[11px] font-semibold text-zinc-600">{title}</div>
22-
<div className="text-[11px] text-zinc-400">{subtitle}</div>
23-
</div>
24-
);
25-
}
26-
27-
const isStudyRegion = (value: string): value is StudyRegion => {
28-
return STUDY_REGIONS.includes(value as StudyRegion);
29-
};
30-
31-
const isCategory = (value: string): value is Category => {
32-
return CATEGORIES.includes(value as Category);
33-
};
17+
const isCategory = (value: string): value is Category => CATEGORIES.includes(value as Category);
3418

3519
export function HeritageSubHeader({ value, onChange, onSubmit }: Props): React.JSX.Element {
3620
const regionOptions = useMemo(() => ["", ...STUDY_REGIONS] as const, []);
@@ -63,85 +47,87 @@ export function HeritageSubHeader({ value, onChange, onSubmit }: Props): React.J
6347
};
6448

6549
return (
66-
<div className="sticky top-0 z-30 border-zinc-200/70 bg-white/95 backdrop-blur">
50+
<div className="border-b border-zinc-200/70 bg-white">
6751
<div className="mx-auto w-full max-w-6xl px-4 py-3">
68-
<div className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
69-
<div className="w-full md:w-[1000px]">
70-
<form
71-
onSubmit={(e) => {
72-
e.preventDefault();
73-
submit();
74-
}}
75-
className="rounded-2xl border border-zinc-200 bg-white px-4 py-3 shadow-sm"
76-
>
77-
<div className="flex flex-col gap-3 md:flex-row md:items-center md:gap-4">
78-
<div className="flex items-center gap-3 md:w-[180px]">
79-
<FieldLabel title="Region" subtitle="Area" />
80-
<select
81-
value={current.region}
82-
onChange={(e) => {
83-
const v = e.target.value;
84-
set({ region: v === "" || isStudyRegion(v) ? v : "" });
85-
}}
86-
className="h-10 w-full rounded-xl bg-transparent px-2 text-sm font-semibold text-zinc-900 hover:bg-zinc-50 focus:outline-none"
87-
aria-label="Region"
88-
>
89-
{regionOptions.map((opt, i) => (
90-
<option key={`${opt || "all"}-${i}`} value={opt}>
91-
{opt || "All"}
92-
</option>
93-
))}
94-
</select>
95-
</div>
96-
97-
<Divider />
98-
99-
<div className="flex items-center gap-3 md:w-[220px]">
100-
<FieldLabel title="Category" subtitle="Type" />
101-
<select
102-
value={current.category}
103-
onChange={(e) => {
104-
const v = e.target.value;
105-
set({ category: v === "" || isCategory(v) ? v : "" });
106-
}}
107-
className="h-10 w-full rounded-xl bg-transparent px-2 text-sm font-semibold text-zinc-900 hover:bg-zinc-50 focus:outline-none"
108-
aria-label="Category"
109-
>
110-
{categoryOptions.map((opt, i) => (
111-
<option key={`${opt || "all"}-${i}`} value={opt}>
112-
{opt || "All"}
113-
</option>
114-
))}
115-
</select>
116-
</div>
52+
<form
53+
onSubmit={(e) => {
54+
e.preventDefault();
55+
submit();
56+
}}
57+
className="rounded-2xl border border-zinc-200 bg-white shadow-sm overflow-hidden"
58+
>
59+
<div className="divide-y divide-zinc-100 md:divide-y-0 md:flex md:items-stretch">
60+
{/* Region */}
61+
<div className="flex items-center gap-3 px-4 py-3 md:border-r md:border-zinc-100 md:w-[160px]">
62+
<div className="leading-tight shrink-0">
63+
<div className="text-[11px] font-semibold text-zinc-500">Region</div>
64+
<div className="text-[10px] text-zinc-400">Area</div>
65+
</div>
66+
<select
67+
value={current.region}
68+
onChange={(e) => {
69+
const v = e.target.value;
70+
set({ region: v === "" || isStudyRegion(v) ? v : "" });
71+
}}
72+
className="flex-1 bg-transparent text-sm font-semibold text-zinc-900 focus:outline-none"
73+
aria-label="Region"
74+
>
75+
{regionOptions.map((opt, i) => (
76+
<option key={`${opt || "all"}-${i}`} value={opt}>
77+
{opt || "All"}
78+
</option>
79+
))}
80+
</select>
81+
</div>
11782

118-
<Divider />
83+
{/* Category */}
84+
<div className="flex items-center gap-3 px-4 py-3 md:border-r md:border-zinc-100 md:w-[160px]">
85+
<div className="leading-tight shrink-0">
86+
<div className="text-[11px] font-semibold text-zinc-500">Category</div>
87+
<div className="text-[10px] text-zinc-400">Type</div>
88+
</div>
89+
<select
90+
value={current.category}
91+
onChange={(e) => {
92+
const v = e.target.value;
93+
set({ category: v === "" || isCategory(v) ? v : "" });
94+
}}
95+
className="flex-1 bg-transparent text-sm font-semibold text-zinc-900 focus:outline-none"
96+
aria-label="Category"
97+
>
98+
{categoryOptions.map((opt, i) => (
99+
<option key={`${opt || "all"}-${i}`} value={opt}>
100+
{opt || "All"}
101+
</option>
102+
))}
103+
</select>
104+
</div>
119105

120-
<div className="flex items-center gap-3 md:flex-1">
121-
<FieldLabel title="Keyword" subtitle="Name / Country" />
122-
<input
123-
value={current.keyword}
124-
onChange={(e) => set({ keyword: e.target.value })}
125-
placeholder="Search the List"
126-
className="h-10 w-full rounded-xl bg-transparent px-2 text-sm text-zinc-900 placeholder:text-zinc-400 hover:bg-zinc-50 focus:outline-none"
127-
aria-label="Keyword"
128-
/>
129-
<Button
130-
type="submit"
131-
size="sm"
132-
className="h-10 w-10 shrink-0 rounded-full p-0 !bg-rose-600 !text-white hover:!bg-rose-700
133-
focus:outline-none focus-visible:ring-2 focus-visible:ring-rose-400
134-
focus-visible:ring-offset-2 focus-visible:ring-offset-white"
135-
aria-label="Search"
136-
title="Search"
137-
>
138-
<SearchIcon fontSize="small" />
139-
</Button>
140-
</div>
106+
{/* Keyword + Submit */}
107+
<div className="flex flex-1 items-center gap-3 px-4 py-3">
108+
<div className="flex-1 min-w-0">
109+
<div className="text-[11px] font-semibold text-zinc-500">Keyword</div>
110+
<input
111+
value={current.keyword}
112+
onChange={(e) => set({ keyword: e.target.value })}
113+
placeholder="Name / Country"
114+
className="w-full bg-transparent text-sm font-semibold text-zinc-900 placeholder:text-zinc-400 placeholder:font-normal focus:outline-none"
115+
aria-label="Keyword"
116+
/>
141117
</div>
142-
</form>
118+
<Button
119+
type="submit"
120+
size="sm"
121+
className="shrink-0 h-9 w-9 rounded-full p-0 !bg-rose-600 !text-white hover:!bg-rose-700
122+
focus:outline-none focus-visible:ring-2 focus-visible:ring-rose-400"
123+
aria-label="Search"
124+
title="Search"
125+
>
126+
<SearchIcon fontSize="small" />
127+
</Button>
128+
</div>
143129
</div>
144-
</div>
130+
</form>
145131
</div>
146132
</div>
147133
);

0 commit comments

Comments
 (0)