Skip to content

Commit eb26906

Browse files
Yuihamshhdgit
andauthored
feat(search): migrate to unified index and add category chip (#677)
* feat(search): migrate to unified index and add category chip (cherry picked from commit 8159d1d) * chore: update chip variant (cherry picked from commit 51b689b) --------- Co-authored-by: Suhaha <jklopsdfw@gmail.com>
1 parent 3469581 commit eb26906

File tree

4 files changed

+227
-269
lines changed

4 files changed

+227
-269
lines changed

src/components/Search/Results.tsx

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ import Typography from "@mui/material/Typography";
66
import Skeleton from "@mui/material/Skeleton";
77
import clsx from "clsx";
88
import TablePagination from "@mui/material/TablePagination";
9-
10-
import LinkComponent from "components/Link";
9+
import Chip from "@mui/material/Chip";
10+
import {
11+
getSearchCategoryLabelKey,
12+
resolveSearchCategory,
13+
} from "shared/utils/searchCategory";
1114

1215
export default function SearchResults(props: {
1316
loading: boolean;
@@ -176,28 +179,61 @@ function SearchItemSkeleton() {
176179

177180
function SearchItem(props: { data: any }) {
178181
const { data } = props;
182+
const { t } = useI18next();
183+
const category = React.useMemo(
184+
() => resolveSearchCategory(data.url),
185+
[data.url]
186+
);
187+
const categoryLabel = category ? t(getSearchCategoryLabelKey(category)) : "";
188+
179189
return (
180190
<Stack spacing={1}>
181-
<Typography
182-
variant="h5"
183-
component="a"
184-
href={data.url}
191+
<Box
185192
sx={{
186-
textDecoration: "none",
187-
width: "fit-content",
188-
"& >div": {
189-
width: "fit-content",
190-
},
193+
display: "flex",
194+
alignItems: "flex-start",
195+
flexWrap: "wrap",
196+
gap: "0.5rem",
191197
}}
192198
>
193-
{!!data._highlightResult?.hierarchy?.lvl0 && (
194-
<div
195-
dangerouslySetInnerHTML={{
196-
__html: data._highlightResult.hierarchy.lvl0?.value,
199+
<Typography
200+
variant="h5"
201+
component="a"
202+
href={data.url}
203+
sx={{
204+
textDecoration: "none",
205+
minWidth: 0,
206+
flex: "1 1 16rem",
207+
overflowWrap: "anywhere",
208+
"& >div": {
209+
width: "100%",
210+
maxWidth: "100%",
211+
},
212+
}}
213+
>
214+
{!!data._highlightResult?.hierarchy?.lvl0 && (
215+
<div
216+
dangerouslySetInnerHTML={{
217+
__html: data._highlightResult.hierarchy.lvl0?.value,
218+
}}
219+
/>
220+
)}
221+
</Typography>
222+
{!!category && !!categoryLabel && (
223+
<Chip
224+
size="small"
225+
variant="outlined"
226+
label={categoryLabel}
227+
sx={{
228+
height: "20px",
229+
fontSize: "12px",
230+
borderRadius: "10px",
231+
backgroundColor: "carbon.100",
232+
color: "carbon.800",
197233
}}
198234
/>
199235
)}
200-
</Typography>
236+
</Box>
201237
{data?._highlightResult?.url ? (
202238
<Typography
203239
variant="body1"

src/components/Search/index.tsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,16 +76,11 @@ export default function Search(props: {
7676

7777
if (searchType === SearchType.Onsite) {
7878
gtmTrack(GTMEvent.UseOnsiteSearch);
79-
navigate(
80-
`/search/?type=${docInfo.type}&version=${docInfo.version}&q=${q}`,
81-
{
82-
state: {
83-
type: docInfo.type,
84-
version: docInfo.version,
85-
query: query,
86-
},
87-
}
88-
);
79+
navigate(`/search/?q=${q}`, {
80+
state: {
81+
query: query,
82+
},
83+
});
8984
onSubmit?.(query);
9085
return;
9186
}

src/shared/utils/searchCategory.ts

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
export const SEARCH_CATEGORIES = {
2+
Releases: "releases",
3+
TiDBCloud: "tidb-cloud",
4+
TiDBInKubernetes: "tidb-in-kubernetes",
5+
TiDB: "tidb",
6+
TiDBForAI: "tidb-for-ai",
7+
Developer: "developer",
8+
BestPractices: "best-practices",
9+
API: "api",
10+
} as const;
11+
12+
export type SearchCategory =
13+
(typeof SEARCH_CATEGORIES)[keyof typeof SEARCH_CATEGORIES];
14+
15+
const LANGUAGE_PREFIXES = new Set(["en", "zh", "ja"]);
16+
17+
export const getSearchCategoryLabelKey = (
18+
category: SearchCategory
19+
): string => {
20+
switch (category) {
21+
case SEARCH_CATEGORIES.TiDBCloud:
22+
return "navbar.cloud";
23+
case SEARCH_CATEGORIES.TiDBInKubernetes:
24+
return "navbar.tidbOnKubernetes";
25+
case SEARCH_CATEGORIES.TiDB:
26+
return "navbar.tidbShortTerm";
27+
case SEARCH_CATEGORIES.TiDBForAI:
28+
return "navbar.tidbForAI";
29+
case SEARCH_CATEGORIES.Developer:
30+
return "navbar.developer";
31+
case SEARCH_CATEGORIES.BestPractices:
32+
return "navbar.bestPractices";
33+
case SEARCH_CATEGORIES.API:
34+
return "navbar.api";
35+
case SEARCH_CATEGORIES.Releases:
36+
return "navbar.releases";
37+
default:
38+
return "";
39+
}
40+
};
41+
42+
export const normalizeSearchResultPath = (url: string): string => {
43+
if (!url) {
44+
return "";
45+
}
46+
47+
const fallbackPath = url
48+
.split("?")[0]
49+
.split("#")[0]
50+
.replace(/^https?:\/\/[^/]+\//i, "")
51+
.replace(/^\/+/, "")
52+
.toLowerCase();
53+
54+
const normalizedPathname = (() => {
55+
try {
56+
const parsedUrl = new URL(url);
57+
return parsedUrl.pathname.replace(/^\/+/, "").toLowerCase();
58+
} catch (_) {
59+
return fallbackPath;
60+
}
61+
})();
62+
63+
if (!normalizedPathname) {
64+
return "";
65+
}
66+
67+
const segments = normalizedPathname.split("/").filter(Boolean);
68+
if (segments.length === 0) {
69+
return "";
70+
}
71+
72+
if (LANGUAGE_PREFIXES.has(segments[0])) {
73+
segments.shift();
74+
}
75+
76+
return segments.join("/");
77+
};
78+
79+
export const resolveSearchCategory = (url: string): SearchCategory | null => {
80+
const normalizedPath = normalizeSearchResultPath(url);
81+
if (!normalizedPath) {
82+
return null;
83+
}
84+
85+
if (normalizedPath === "releases" || normalizedPath.startsWith("releases/")) {
86+
return SEARCH_CATEGORIES.Releases;
87+
}
88+
89+
if (normalizedPath.startsWith("tidbcloud/")) {
90+
return SEARCH_CATEGORIES.TiDBCloud;
91+
}
92+
93+
if (normalizedPath.startsWith("tidb-in-kubernetes/")) {
94+
return SEARCH_CATEGORIES.TiDBInKubernetes;
95+
}
96+
97+
if (normalizedPath.startsWith("tidb/")) {
98+
return SEARCH_CATEGORIES.TiDB;
99+
}
100+
101+
if (normalizedPath.startsWith("ai/")) {
102+
return SEARCH_CATEGORIES.TiDBForAI;
103+
}
104+
105+
if (normalizedPath.startsWith("developer/")) {
106+
return SEARCH_CATEGORIES.Developer;
107+
}
108+
109+
if (normalizedPath.startsWith("best-practices/")) {
110+
return SEARCH_CATEGORIES.BestPractices;
111+
}
112+
113+
if (normalizedPath.startsWith("api/")) {
114+
return SEARCH_CATEGORIES.API;
115+
}
116+
117+
return null;
118+
};

0 commit comments

Comments
 (0)