Skip to content

Commit 83244b3

Browse files
authored
Add query params to dev ui (#1097)
https://github.com/Khan/perseus/assets/23404711/43efa352-2e46-4780-a640-bd95ce79803d ## Summary Add search feature and query params to dev ui to prevent needing to reset state and scroll to graph on each fast module reload. ### Issue N/A Author: nedredmond Reviewers: jeremywiebe, nedredmond, benchristel, nishasy Required Reviewers: Approved By: jeremywiebe Checks: ⌛ Upload Coverage, ❌ Publish npm snapshot (ubuntu-latest, 20.x), ✅ Extract i18n strings (ubuntu-latest, 20.x), ✅ Check builds for changes in size (ubuntu-latest, 20.x), ✅ Cypress (ubuntu-latest, 20.x), ✅ Jest Coverage (ubuntu-latest, 20.x), ✅ Publish Storybook to Chromatic (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x), ✅ gerald Pull Request URL: #1097
1 parent 5ce75a2 commit 83244b3

File tree

2 files changed

+97
-16
lines changed

2 files changed

+97
-16
lines changed

dev/gallery.tsx

Lines changed: 96 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
import {useUniqueIdWithMock, View} from "@khanacademy/wonder-blocks-core";
33
import {OptionItem, MultiSelect} from "@khanacademy/wonder-blocks-dropdown";
44
import {Strut} from "@khanacademy/wonder-blocks-layout";
5+
import SearchField from "@khanacademy/wonder-blocks-search-field";
56
import Spacing from "@khanacademy/wonder-blocks-spacing";
67
import Switch from "@khanacademy/wonder-blocks-switch";
78
import {color} from "@khanacademy/wonder-blocks-tokens";
89
import {css, StyleSheet} from "aphrodite";
910
import * as React from "react";
10-
import {useState} from "react";
11+
import {useEffect, useMemo, useState} from "react";
1112

1213
import {Renderer} from "../packages/perseus/src";
1314
import * as grapher from "../packages/perseus/src/widgets/__testdata__/grapher.testdata";
@@ -76,34 +77,79 @@ const styles = StyleSheet.create({
7677

7778
export function Gallery() {
7879
const ids = useUniqueIdWithMock();
80+
const params = useMemo(
81+
() => new URLSearchParams(window.location.search),
82+
[],
83+
);
84+
85+
const [isMobile, setIsMobile] = useState(params.get("mobile") === "true");
86+
const [mafsFlags, setMafsFlags] = useState<Array<string>>(
87+
params.get("flags")?.split(",") || [],
88+
);
89+
const [search, setSearch] = useState<string>(params.get("search") || "");
7990

80-
const [isMobile, setIsMobile] = useState(false);
81-
const [mafsFlags, setMafsFlags] = useState<Array<string>>([]);
91+
useEffect(() => {
92+
const url = new URL(window.location.href);
93+
if (isMobile) {
94+
url.searchParams.set("mobile", "true");
95+
} else {
96+
url.searchParams.delete("mobile");
97+
}
98+
if (mafsFlags.length === 0) {
99+
url.searchParams.delete("flags");
100+
} else {
101+
url.searchParams.set("flags", mafsFlags.join(","));
102+
}
103+
if (!search) {
104+
url.searchParams.delete("search");
105+
} else {
106+
url.searchParams.set("search", search);
107+
}
108+
window.history.replaceState({}, "", url.toString());
109+
}, [isMobile, mafsFlags, params, search]);
82110

83111
const mafsFlagsObject = mafsFlags.reduce((acc, flag) => {
84112
acc[flag] = true;
85113
return acc;
86114
}, {});
87115

116+
const mobileId = ids.get("mobile");
117+
const flagsId = ids.get("flags");
118+
const searchId = ids.get("search");
119+
88120
return (
89121
<View className={css(styles.page)}>
90122
<header className={css(styles.header)}>
91123
<Switch
92-
id={ids.get("mobile")}
124+
id={mobileId}
93125
checked={isMobile}
94126
onChange={setIsMobile}
95127
/>
96128
<Strut size={Spacing.xSmall_8} />
97-
<label htmlFor={ids.get("mobile")}>Mobile</label>
129+
<label htmlFor={mobileId}>Mobile</label>
98130
<Strut size={Spacing.medium_16} />
99-
<MultiSelect onChange={setMafsFlags} selectedValues={mafsFlags}>
131+
<MultiSelect
132+
id={flagsId}
133+
onChange={setMafsFlags}
134+
selectedValues={mafsFlags}
135+
>
100136
<OptionItem value="segment" label="Segment" />
101137
<OptionItem value="linear" label="Linear" />
102138
<OptionItem value="linear-system" label="Linear System" />
103139
<OptionItem value="point" label="Point" />
104140
<OptionItem value="ray" label="Ray" />
105141
<OptionItem value="polygon" label="Polygon" />
106142
</MultiSelect>
143+
<Strut size={Spacing.xSmall_8} />
144+
<label htmlFor={flagsId}>Mafs Flags</label>
145+
<Strut size={Spacing.medium_16} />
146+
<SearchField
147+
id={searchId}
148+
value={search}
149+
onChange={setSearch}
150+
/>
151+
<Strut size={Spacing.xSmall_8} />
152+
<label htmlFor={searchId}>Search Types</label>
107153
<Strut size={Spacing.medium_16} />
108154
<nav>
109155
<a href="#flipbook">Flipbook</a>
@@ -114,16 +160,22 @@ export function Gallery() {
114160
style={styles.cards}
115161
className={isMobile ? "perseus-mobile" : ""}
116162
>
117-
{questions.map((question, i) => (
118-
<QuestionRenderer
119-
key={i}
120-
question={question}
121-
apiOptions={{
122-
isMobile,
123-
flags: {mafs: mafsFlagsObject},
124-
}}
125-
/>
126-
))}
163+
{questions
164+
.filter((question) =>
165+
search
166+
? graphTypeContainsText(question, search)
167+
: true,
168+
)
169+
.map((question, i) => (
170+
<QuestionRenderer
171+
key={i}
172+
question={question}
173+
apiOptions={{
174+
isMobile,
175+
flags: {mafs: mafsFlagsObject},
176+
}}
177+
/>
178+
))}
127179
</View>
128180
</main>
129181
</View>
@@ -150,3 +202,31 @@ function QuestionRenderer({question, apiOptions = {}}: QuestionRendererProps) {
150202
</div>
151203
);
152204
}
205+
206+
const graphTypeContainsText = (
207+
question: PerseusRenderer,
208+
search: string,
209+
): boolean => {
210+
const widgetKey = Object.keys(question.widgets)[0];
211+
const widget = question.widgets[widgetKey];
212+
switch (widget.type) {
213+
case "grapher":
214+
if (
215+
widget.options.availableTypes.some((type: string) =>
216+
type.includes(search),
217+
)
218+
) {
219+
return true;
220+
}
221+
return false;
222+
case "interactive-graph":
223+
if (widget.options.graph.type.includes(search)) {
224+
return true;
225+
}
226+
return false;
227+
case "number-line":
228+
return widget.type.includes(search);
229+
default:
230+
return false;
231+
}
232+
};

dev/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"@khanacademy/pure-markdown": "^0.3.1",
2525
"@khanacademy/simple-markdown": "^0.11.4",
2626
"@khanacademy/wonder-blocks-banner": "^3.0.33",
27+
"@khanacademy/wonder-blocks-search-field": "^2.2.5",
2728
"@khanacademy/wonder-blocks-tokens": "^1.0.0"
2829
},
2930
"devDependencies": {

0 commit comments

Comments
 (0)