Skip to content

Commit f9835ac

Browse files
committed
[Docs Site] Refactor ResourcesBySelector
1 parent da6a97e commit f9835ac

File tree

4 files changed

+153
-71
lines changed

4 files changed

+153
-71
lines changed

src/components/ReactSelect.tsx

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import Select, { type Props } from "react-select";
2+
import type { ActionMeta, StylesConfig } from "react-select";
3+
import { setSearchParams } from "~/util/url";
4+
5+
export type Option = {
6+
label: string;
7+
value: string;
8+
};
9+
10+
export default function ReactSelect(props: Props & { urlParam?: string }) {
11+
const selectStyles: StylesConfig = {
12+
control: (base, state) => ({
13+
...base,
14+
backgroundColor: "var(--sl-color-gray-6)",
15+
borderColor: state.isFocused
16+
? "var(--sl-color-gray-3)"
17+
: "var(--sl-color-gray-4)",
18+
"&:hover": {
19+
borderColor: "var(--sl-color-gray-3)",
20+
},
21+
boxShadow: state.isFocused ? "0 0 0 1px var(--sl-color-gray-3)" : "none",
22+
}),
23+
menu: (base) => ({
24+
...base,
25+
backgroundColor: "var(--sl-color-gray-6)",
26+
borderColor: "var(--sl-color-gray-4)",
27+
}),
28+
option: (base, state) => ({
29+
...base,
30+
backgroundColor: state.isFocused
31+
? "var(--sl-color-gray-5)"
32+
: "var(--sl-color-gray-6)",
33+
color: "var(--sl-color-gray-1)",
34+
"&:active": {
35+
backgroundColor: "var(--sl-color-gray-4)",
36+
},
37+
}),
38+
singleValue: (base) => ({
39+
...base,
40+
color: "var(--sl-color-gray-1)",
41+
}),
42+
input: (base) => ({
43+
...base,
44+
color: "var(--sl-color-gray-1)",
45+
}),
46+
groupHeading: (base) => ({
47+
...base,
48+
color: "var(--sl-color-gray-3)",
49+
}),
50+
};
51+
52+
const onChangeHandler = (
53+
option: Option | null,
54+
actionMeta: ActionMeta<Option>,
55+
) => {
56+
props.onChange?.(option, actionMeta);
57+
58+
const params = new URLSearchParams(window.location.search);
59+
60+
if (option) {
61+
params.set(props.urlParam || "filters", option.value);
62+
} else {
63+
params.delete(props.urlParam || "filters");
64+
}
65+
66+
setSearchParams(params);
67+
};
68+
69+
return (
70+
<Select
71+
{...props}
72+
styles={selectStyles}
73+
onChange={(val: unknown, meta: ActionMeta<unknown>) =>
74+
onChangeHandler(val as Option | null, meta as ActionMeta<Option>)
75+
}
76+
/>
77+
);
78+
}
Lines changed: 63 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,85 @@
11
---
22
import { z } from "astro:schema";
3-
import { getCollection } from "astro:content";
3+
import { getCollection, type CollectionEntry } from "astro:content";
4+
import ReactSelect from "./ReactSelect";
45
56
type Props = z.infer<typeof props>;
7+
type Frontmatter = keyof CollectionEntry<"docs">["data"];
68
79
const props = z.object({
810
tags: z.string().array().optional(),
911
types: z.string().array(),
1012
products: z.string().array().optional(),
13+
directory: z.string().optional(),
14+
filters: z.custom<Frontmatter>().array().optional(),
1115
});
1216
13-
const { tags, types, products } = props.parse(Astro.props);
17+
const { tags, types, products, directory, filters } = props.parse(Astro.props);
1418
15-
const resources = await getCollection("docs", ({ data }) => {
19+
const resources = await getCollection("docs", ({ id, data }) => {
1620
return (
1721
types.includes(data.pcx_content_type ?? "") &&
22+
(directory ? id.startsWith(directory) : true) &&
1823
(tags ? data.tags?.some((v: string) => tags.includes(v)) : true) &&
1924
(products ? data.products?.some((v: string) => products.includes(v)) : true)
2025
);
2126
});
27+
28+
const facets = resources.reduce(
29+
(acc, page) => {
30+
if (!filters) return acc;
31+
32+
for (const filter of filters) {
33+
const val = page.data[filter];
34+
if (val) {
35+
if (Array.isArray(val) && val.every((v) => typeof v === "string")) {
36+
acc[filter] = [...new Set([...(acc[filter] || []), ...val])];
37+
} else if (typeof val === "string") {
38+
acc[filter] = [...new Set([...(acc[filter] || []), val])];
39+
}
40+
}
41+
}
42+
43+
return acc;
44+
},
45+
{} as Record<string, string[]>,
46+
);
2247
---
2348

24-
<ul>
49+
{
50+
filters && (
51+
<div class="not-content">
52+
<ReactSelect
53+
id="resources-filters"
54+
className="mt-2"
55+
options={Object.entries(facets).map(([key, values]) => ({
56+
label: key,
57+
options: values.map((v) => ({
58+
value: v,
59+
label: v,
60+
})),
61+
}))}
62+
onChange={(opt) => console.log(opt)}
63+
client:idle
64+
/>
65+
</div>
66+
)
67+
}
68+
69+
<div class="grid grid-cols-2 gap-4">
2570
{
26-
resources.map((page) => {
27-
const description = page.data.description;
28-
return (
29-
<li>
30-
<!-- prettier-ignore -->
31-
<a href={`/${page.id}/`}>{page.data.title}</a>{description && `: ${description}`}
32-
</li>
33-
);
34-
})
71+
resources.map((page) => (
72+
<a
73+
href={`/${page.id}/`}
74+
class="flex flex-col gap-2 rounded-sm border border-solid border-gray-200 p-6 text-black no-underline hover:bg-gray-50 dark:border-gray-700 dark:hover:bg-gray-800"
75+
>
76+
<p class="decoration-accent underline decoration-2 underline-offset-4">
77+
{page.data.title}
78+
</p>
79+
<span class="line-clamp-3" title={page.data.description}>
80+
{page.data.description}
81+
</span>
82+
</a>
83+
))
3584
}
36-
</ul>
85+
</div>
Lines changed: 5 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
11
import type { CollectionEntry } from "astro:content";
2-
import type { StylesConfig } from "react-select";
3-
import Select from "react-select";
2+
import ReactSelect, { type Option } from "../ReactSelect";
43
import { useEffect, useState } from "react";
54

65
interface Props {
76
products: CollectionEntry<"products">[];
87
groups: string[];
98
}
109

11-
interface Option {
12-
label?: string;
13-
value: string;
14-
}
15-
1610
export default function ProductSelect({ products, groups }: Props) {
1711
const [selectedOption, setSelectedOption] = useState<Option>();
1812

@@ -42,47 +36,6 @@ export default function ProductSelect({ products, groups }: Props) {
4236
},
4337
];
4438

45-
const selectStyles: StylesConfig<Option, false> = {
46-
control: (base, state) => ({
47-
...base,
48-
backgroundColor: "var(--sl-color-gray-6)",
49-
borderColor: state.isFocused
50-
? "var(--sl-color-gray-3)"
51-
: "var(--sl-color-gray-4)",
52-
"&:hover": {
53-
borderColor: "var(--sl-color-gray-3)",
54-
},
55-
boxShadow: state.isFocused ? "0 0 0 1px var(--sl-color-gray-3)" : "none",
56-
}),
57-
menu: (base) => ({
58-
...base,
59-
backgroundColor: "var(--sl-color-gray-6)",
60-
borderColor: "var(--sl-color-gray-4)",
61-
}),
62-
option: (base, state) => ({
63-
...base,
64-
backgroundColor: state.isFocused
65-
? "var(--sl-color-gray-5)"
66-
: "var(--sl-color-gray-6)",
67-
color: "var(--sl-color-gray-1)",
68-
"&:active": {
69-
backgroundColor: "var(--sl-color-gray-4)",
70-
},
71-
}),
72-
singleValue: (base) => ({
73-
...base,
74-
color: "var(--sl-color-gray-1)",
75-
}),
76-
input: (base) => ({
77-
...base,
78-
color: "var(--sl-color-gray-1)",
79-
}),
80-
groupHeading: (base) => ({
81-
...base,
82-
color: "var(--sl-color-gray-3)",
83-
}),
84-
};
85-
8639
useEffect(() => {
8740
const url = new URL(window.location.href);
8841
const param = url.searchParams.get("product");
@@ -100,6 +53,7 @@ export default function ProductSelect({ products, groups }: Props) {
10053

10154
const handleChange = (option: Option | null) => {
10255
if (!option) return;
56+
10357
setSelectedOption(option);
10458

10559
const event = new Event("change");
@@ -114,13 +68,13 @@ export default function ProductSelect({ products, groups }: Props) {
11468
};
11569

11670
return (
117-
<Select
71+
<ReactSelect
11872
id="changelogs-next-filter"
11973
className="mt-2"
12074
options={options}
12175
value={selectedOption}
122-
onChange={handleChange}
123-
styles={selectStyles}
76+
onChange={(e) => handleChange(e as Option | null)}
77+
urlParam="product"
12478
/>
12579
);
12680
}

src/content/docs/style-guide/components/resources-by-selector.mdx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,24 @@ The `ResourcesBySelector` component allows you to pull in documentation resource
1414
import { ResourcesBySelector } from "~/components";
1515

1616
<ResourcesBySelector
17-
tags={["AI"]}
18-
types={["reference-architecture","design-guide","reference-architecture-diagram"]}
17+
directory="workers/examples/"
18+
types={["example"]}
19+
filters={["languages", "tags"]}
1920
/>
2021
```
2122

2223
### Inputs
2324

2425
- `types` <Type text="string[]" />
2526

26-
An array of `pcx_content_type` values to filter by.
27+
An array of `pcx_content_type` values to filter by.
2728

2829
- `tags` <Type text="string[]" /> <MetaInfo text="optional" />
2930

30-
An array of `tags` values to filter by.
31+
An array of `tags` values to filter by.
3132

32-
To see a list of the available tags, and which pages are associated with them, refer to [this list](/style-guide/frontmatter/tags/).
33+
To see a list of the available tags, and which pages are associated with them, refer to [this list](/style-guide/frontmatter/tags/).
3334

3435
- `products` <Type text="string[]" /> <MetaInfo text="optional" />
3536

36-
An array of `products` values to filter by.
37+
An array of `products` values to filter by.

0 commit comments

Comments
 (0)