@@ -1,323 +0,0 @@
1−import { Component, createRef } from "react";
2−import { glossary } from "../lib/glossary";
3−import Link from "next/link";
4−import { withRouter } from "next/router";
5−import { configure, HotKeys } from "react-hotkeys";
6−import classnames from "classnames";
7−
8−{
9− /* const SearchContext = createContext(); */
10−}
11−
12−const glossarySearch = (query) => {
13− return glossary.filter((entry) => {
14− return query.toLowerCase() === entry.name || entry.symbol === query;
15− });
16−};
17−
18−function GlossaryResult(props) {
19− const selectedClassnames = classnames({
20− "bg-green": props.selected,
21− });
22−
23− const codeBg = classnames({
24− "bg-wall": !props.selected,
25− "bg-washedWhite": props.selected,
26− });
27−
28− const text = classnames({
29− "text-black": !props.selected,
30− "text-white": props.selected,
31− });
32−
33− return (
34− <button
35− tabIndex={props.index}
36− id={props.link + "-" + props.index}
37− className={`cursor-pointer flex text-left w-full ${selectedClassnames}`}
38− onMouseEnter={() => props.setCursor(props.index)}
39− onClick={() => props.onSelect()}
40− >
41− <div className="font-semibold p-3">
42− <p className={`text-base ${text}`}>
43− {props.symbol.length > 0 && (
44− <code className={`mr-1 rounded px-1 py-0.5 ${codeBg}`}>
45− {props.symbol}
46− </code>
47− )}
48− {props.name}
49− </p>
50− <p className={`font-normal text-base mt-1 ${text}`}>{props.desc}</p>
51− </div>
52− </button>
53− );
54−}
55−
56−function Result(props) {
57− const selectedClassnames = classnames({
58− "bg-green": props.selected,
59− });
60− const text = classnames({
61− "text-black": !props.selected,
62− "text-white": props.selected,
63− });
64− const description = classnames({
65− "text-gray": !props.selected,
66− "text-midWhite": props.selected,
67− });
68− return (
69− <button
70− tabIndex={props.index}
71− id={props.slug + "-" + props.index}
72− className={`cursor-pointer flex text-left w-full ${selectedClassnames}`}
73− onMouseEnter={() => props.setCursor(props.index)}
74− onClick={() => props.onSelect()}
75− >
76− <div className="p-3">
77− <p className={`font-medium text-base ${text}`}>
78− {props.parent !== "Content" ? `${props.parent} /` : ""} {props.title}
79− </p>
80− <p
81− className={`text-base font-regular text-small text-gray ${description}`}
82− >
83− {props.content}
84− </p>
85− </div>
86− </button>
87− );
88−}
89−
90−function Subheading(props) {
91− return (
92− <div className="sticky top-0 flex font-semibold text-sm p-3 py-1 w-full bg-ultraDeepWall text-white">
93− <p className="font-semibold text-sm">{props.title}</p>
94− </div>
95− );
96−}
97−
98−class Search extends Component {
99− constructor(props) {
100− super(props);
101− this.state = {
102− query: "",
103− active: false,
104− results: [],
105− cursor: 0,
106− };
107− this.scrollBox = createRef();
108− this.searchEndpoint = this.searchEndpoint.bind(this);
109− this.onChange = this.onChange.bind(this);
110− this.onFocus = this.onFocus.bind(this);
111− this.onNavUp = this.onNavUp.bind(this);
112− this.onNavDown = this.onNavDown.bind(this);
113− this.onSelect = this.onSelect.bind(this);
114− this.setCursor = this.setCursor.bind(this);
115− }
116−
117− searchEndpoint(query) {
118− return `/api/search?q=${this.state.query}`;
119− }
120−
121− onChange(event) {
122− const query = event.target.value;
123− this.setState({ query });
124−
125− if (query.length) {
126− fetch(this.searchEndpoint(query))
127− .then((res) => res.json())
128− .then((res) => {
129− // Wrap results in an object which will tell React what component to use to render results.
130− const results = res.results.map((item) => ({
131− type: "RESULT",
132− content: item,
133− }));
134−
135− const glossaryResults = glossarySearch(query).map((item) => ({
136− type: "GLOSSARY_RESULT",
137− content: item,
138− }));
139−
140− const list = [...glossaryResults, ...results];
141−
142− this.setState({ results: list });
143− });
144− } else {
145− this.setState({ results: [] });
146− }
147− }
148−
149− onFocus() {
150− this.setState({ active: true });
151− }
152−
153− onNavUp(event) {
154− // prevents cursor from moving in search input
155− event.preventDefault();
156− this.setState({ cursor: this.state.cursor - 1 });
157− }
158−
159− onNavDown(event) {
160− const offset = this[`result-${this.state.cursor}`].offsetTop;
161− const height = this[`result-${this.state.cursor}`].clientHeight;
162−
163− this.scrollBox.current.scrollTop = offset - height;
164− console.log(offset - height);
165−
166− {
167− /* const elem = this[`result-${this.state.cursor}`] */
168− }
169−
170− {
171− /* console.log(elem) */
172− }
173− // prevents cursor from moving in search input
174− {
175− /* console.log(this[`result-${this.state.cursor}`].offsetTop) */
176− }
177− {
178− /* this.scrollBox.scrollTop = this[`result-${this.state.cursor}`].offsetTop */
179− }
180− {
181− /* this[`result-${this.state.cursor}`].scrollIntoView({behavior: 'smooth'}); */
182− }
183− {
184− /* this[`result-${this.state.cursor}`].offsetTop = 0 */
185− }
186−
187− {
188− /* this[`result-${this.state.cursor}`].scrollIntoView(); */
189− }
190− {
191− /* elem.scrollTop = 0; */
192− }
193− event.preventDefault();
194− this.setState({ cursor: this.state.cursor + 1 });
195− }
196−
197− onSelect(event) {
198− const { state, props } = this;
199− const cursorItem = state.results[state.cursor].content;
200−
201− if (cursorItem.link) {
202− window.location.href = cursorItem.link;
203− }
204−
205− if (cursorItem.slug) {
206− props.router.push(cursorItem.slug);
207− }
208−
209− this.setState({
210− active: false,
211− query: "",
212− results: [],
213− });
214−
215− props.closeSearch();
216− }
217−
218− setCursor(num) {
219− this.setState({ cursor: num });
220− }
221−
222− applyRef(index, ref) {
223− this[`result-${index}`] = ref;
224− }
225−
226− render() {
227− const { state, props } = this;
228−
229− const keyMap = {
230− onNavUp: ["up"],
231− onNavDown: ["down"],
232− onSelect: ["enter"],
233− };
234−
235− const handlers = {
236− onNavUp: (event) => this.onNavUp(event),
237− onNavDown: (event) => this.onNavDown(event),
238− onSelect: (event) => this.onSelect(event),
239− };
240−
241− if (props.showSearch) {
242− return (
243− <HotKeys handlers={handlers} keyMap={keyMap}>
244− <div
245− onClick={props.closeSearch}
246− className="fixed w-screen h-screen bg-washedWall z-50 flex flex-col items-center p-4"
247− >
248− <div className="relative flex flex-col max-w-screen-lg md:my-32 w-full md:w-10/12 lg:w-8/12 xl:w-6/12 rounded-xl bg-white min-h-0 overflow-hidden">
249− <div className="relative">
250− <input
251− className="text-lg md:text-xl lg:text-2xl font-medium text-green bg-transparent py-2 px-4 outline-none relative w-full"
252− onChange={this.onChange}
253− onFocus={this.onFocus}
254− placeholder="Search..."
255− type="text"
256− value={state.query}
257− onClick={(e) => e.stopPropagation()}
258− autoFocus={true}
259− />
260−
261− <span
262− onClick={props.toggleSearch}
263− className="absolute cursor-pointer right-1.5 top-1.5 md:right-2 md:top-2 lg:right-2.5 lg:top-2.5"
264− >
265− <p className="px-2 h-8 bg-wall flex items-center justify-center text-sm rounded">
266− ESC
267− </p>
268− </span>
269− </div>
270−
271− <div
272− ref={this.scrollBox}
273− className={
274− "overflow-y-scroll border-t-2 border-wall" +
275− (state.query.length > 0 ? "" : "hidden border-transparent")
276− }
277− >
278− {state.active && state.query !== ""
279− ? state.results.map((item, index) => {
280− if (item.type === "GLOSSARY_RESULT") {
281− return (
282− <div ref={this.applyRef.bind(this, index)}>
283− <GlossaryResult
284− key={item.content.link + "-" + index}
285− index={index}
286− setCursor={this.setCursor}
287− selected={index === state.cursor}
288− onSelect={this.onSelect}
289− {...item.content}
290− />
291− </div>
292− );
293− }
294−
295− if (item.type === "RESULT") {
296− return (
297− <div ref={this.applyRef.bind(this, index)}>
298− <Result
299− key={item.content.slug + "-" + index}
300− index={index}
301− setCursor={this.setCursor}
302− selected={index === state.cursor}
303− onSelect={this.onSelect}
304− {...item.content}
305− />
306− </div>
307− );
308− }
309− return null;
310− })
311− : null}
312− </div>
313− </div>
314− </div>
315− </HotKeys>
316− );
317− } else {
318− return null;
319− }
320− }
321−}
322−
323−export default withRouter(Search);