@@ -1,393 +0,0 @@
1−import { Component } from "react";
2−import { withRouter } from "next/router";
3−import debounce from "lodash.debounce";
4−import Downshift from "downshift";
5−import ob from "urbit-ob";
6−import Sigil from "../components/Sigil";
7−
8−class Search extends Component {
9− constructor(props) {
10− super(props);
11− this.state = {
12− results: [],
13− };
14− this.searchEndpoint = this.searchEndpoint.bind(this);
15− this.onInputValueChange = this.onInputValueChange.bind(this);
16− this.onSelect = this.onSelect.bind(this);
17− this.patpSearch = this.patpSearch.bind(this);
18− this.devSearch = this.devSearch.bind(this);
19− this.opsSearch = this.opsSearch.bind(this);
20− }
21−
22− searchEndpoint(query) {
23− return `/api/search?q=${encodeURIComponent(query)}`;
24− }
25−
26− devSearch(query) {
27− return `/api/dev-search?q=${encodeURIComponent(query)}`;
28− }
29−
30− opsSearch(query) {
31− return `/api/ops-search?q=${encodeURIComponent(query)}`;
32− }
33−
34− patpSearch(query) {
35− return (
36− (ob.isValidPatp(`~${deSig(query.toLowerCase())}`) &&
37− `~${deSig(query.toLowerCase())}`.length < 15) ||
38− (!isNaN(query) && query <= 4294967295)
39− );
40− }
41−
42− onSelect(item) {
43− this.setState({
44− query: "",
45− results: [],
46− });
47−
48− if (item.url) {
49− this.props.router.push(`${item.url}${item?.slug ? item.slug : ""}`);
50− return this.props.closeSearch();
51− }
52− if (item.slug) {
53− this.props.router.push(item.slug);
54− return this.props.closeSearch();
55− }
56− }
57−
58− onInputValueChange = debounce(async (query) => {
59− if (query.length) {
60− const search = fetch(this.searchEndpoint(query))
61− .then((res) => res.json())
62− .then(async (res) => {
63− return [...res.glossary.map((item) => ({
64− type: "GLOSSARY_RESULT",
65− content: item
66− })), ...res.results.map((item) => ({
67− type: "RESULT",
68− content: item,
69− }))];
70− });
71−
72− const patp = this.patpSearch(query)
73− ? !isNaN(query)
74− ? ob.patp(query)
75− : ob.patp(ob.patp2dec(`~${deSig(query)}`))
76− : null;
77−
78− const patpResult = this.patpSearch(query)
79− ? [
80− {
81− type: "PATP",
82− content: {
83− patp: patp,
84− slug: `/ids/${patp}`,
85− },
86− },
87− ]
88− : [];
89−
90− const devSearch = fetch(this.devSearch(query))
91− .then((res) => res.json())
92− .then((res) => {
93− return [...res.glossary.map((item) => ({
94− type: "GLOSSARY_RESULT",
95− content: item
96− })), ...res.results.map((item) => ({
97− type: "DEV_RESULT",
98− content: item,
99− }))];
100− });
101−
102− const opsSearch = fetch(this.opsSearch(query))
103− .then((res) => res.json())
104− .then((res) => {
105− return [...res.glossary.map((item) => ({
106− type: "GLOSSARY_RESULT",
107− content: item
108− })), ...res.results.map((item) => ({
109− type: "OPS_RESULT",
110− content: item,
111− }))];
112− });
113−
114− const [results, devResults, opsResults] =
115− await Promise.all([search, devSearch, opsSearch]);
116−
117− const list = [
118− ...patpResult,
119− ...results,
120− ...devResults,
121− ...opsResults,
122− ]
123− .sort((a, b) => {
124− const aNum = a?.type === "GLOSSARY_RESULT" ? 1 : -1;
125− const bNum = b?.type === "GLOSSARY_RESULT" ? 1 : -1;
126− return bNum - aNum;
127− });;
128−
129− this.setState({ results: list });
130− } else {
131− this.setState({ results: [] });
132− }
133− }, 250);
134−
135− render() {
136− const { state, props } = this;
137−
138− if (props.showSearch) {
139− return (
140− <Downshift
141− onSelect={(selection) => this.onSelect(selection)}
142− onInputValueChange={(event) => this.onInputValueChange(event)}
143− itemToString={(item) => (item ? item.slug : "")}
144− defaultHighlightedIndex={0}
145− >
146− {({
147− getInputProps,
148− getItemProps,
149− getLabelProps,
150− getMenuProps,
151− isOpen,
152− inputValue,
153− highlightedIndex,
154− selectedItem,
155− getRootProps,
156− }) => (
157− <div className="fixed w-screen h-screen z-50 flex flex-col items-center p-4">
158− <div
159− onClick={(event) => props.closeSearch(event)}
160− className="top-0 left-0 fixed w-screen h-screen bg-washedWall"
161− />
162− <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">
163− <div
164− style={{ display: "inline-block" }}
165− {...getRootProps({}, { suppressRefError: true })}
166− >
167− <input
168− autoFocus
169− className="text-lg md:text-xl lg:text-2xl font-medium text-green-400 bg-transparent py-2 px-4 outline-none relative w-full"
170− placeholder="Search..."
171− type="text"
172− onClick={(e) => e.stopPropagation()}
173− {...getInputProps({
174− onKeyDown: (event) => {
175− if (event.key === "Escape") {
176− // Prevent Downshift's default 'Escape' behavior.
177− event.nativeEvent.preventDownshiftDefault = true;
178− this.props.closeSearch(event);
179− }
180− },
181− })}
182− />
183− </div>
184− <ul {...getMenuProps()} className="overflow-y-scroll">
185− {isOpen
186− ? state.results.map((item, index) => {
187− const selected = highlightedIndex === index;
188− if (item.type === "PATP") {
189− return (
190− <li
191− className={`cursor-pointer p-2 flex space-x-2 items-center text-left w-full ${selected ? "bg-green-400" : ""
192− }`}
193− {...getItemProps({
194− key: item.content.slug + "-" + index,
195− index,
196− item: item.content,
197− selected: highlightedIndex === index,
198− })}
199− >
200− <div className="rounded-md overflow-hidden">
201− <Sigil
202− patp={item.content.patp}
203− size={25}
204− icon
205− />
206− </div>
207− <p className="font-mono">{item.content.patp}</p>
208− </li>
209− );
210− }
211− if (item.type === "GLOSSARY_RESULT") {
212− return (
213− <li
214− className={`cursor-pointer flex text-left w-full ${selected ? "bg-green-400" : ""
215− }`}
216− {...getItemProps({
217− key: item.content.slug + "-" + index,
218− index,
219− item: item.content,
220− selected: highlightedIndex === index,
221− })}
222− >
223− <div className="font-semibold p-3">
224− <p
225− className={`text-base ${selected ? "text-white" : "text-wall-600"
226− }`}
227− >
228− {item.content.symbol.length > 0 && (
229− <code
230− className={`mr-1 rounded px-1 py-0.5 ${selected
231− ? "bg-washedWhite"
232− : "bg-wall-100"
233− }`}
234− >
235− {item.content.symbol}
236− </code>
237− )}
238− {item.content.name}
239− </p>
240− <p
241− className={`font-normal text-base mt-1 ${selected ? "text-white" : "text-wall-600"
242− }`}
243− dangerouslySetInnerHTML={{
244− __html: item.content.desc,
245− }}
246− ></p>
247− </div>
248− </li>
249− );
250− }
251− if (item.type === "RESULT") {
252− return (
253− <li
254− className={`cursor-pointer flex text-left w-full ${selected ? "bg-green-400" : ""
255− }`}
256− {...getItemProps({
257− key: item.content.link + "-" + index,
258− index,
259− item: item.content,
260− selected,
261− })}
262− >
263− <div className="p-3">
264− <p
265− className={`font-medium text-base ${selected ? "text-white" : "text-wall-600"
266− }`}
267− >
268− {item.content.parent !== "Content"
269− ? `${item.content.parent} /`
270− : ""}{" "}
271− {item.content.title}
272− </p>
273− <p
274− className={`text-base font-regular text-small ${selected ? "text-midWhite" : "text-wall-500"
275− }`}
276− >
277− {item.content.content}
278− {item?.content?.foundOnPage && (
279− <span className="italic block">
280− Found in page content
281− </span>
282− )}
283− </p>
284− </div>
285− </li>
286− );
287− }
288− if (item.type === "DEV_RESULT") {
289− const devItem = Object.assign({}, item.content);
290− devItem[
291− "slug"
292− ] = `https://developers.urbit.org${item.content.slug}`;
293− return (
294− <li
295− className={`cursor-pointer flex text-left w-full ${selected ? "bg-green-400" : ""
296− }`}
297− {...getItemProps({
298− key: item.content.link + "-" + index,
299− index,
300− item: devItem,
301− selected,
302− })}
303− >
304− <div className="p-3">
305− <p
306− className={`font-medium text-base ${selected ? "text-white" : "text-wall-600"
307− }`}
308− >
309− <span className="text-wall-400">
310− {item.content.parent !== "Content"
311− ? `developers.urbit.org / ${item.content.parent} /`
312− : "developers.urbit.org /"}{" "}
313− </span>
314− {item.content.title}
315− </p>
316− <p
317− className={`text-base font-regular text-small ${selected ? "text-midWhite" : "text-wall-500"
318− }`}
319− >
320− {item.content.content}
321− {item?.content?.foundOnPage && (
322− <span className="italic block">
323− Found in page content
324− </span>
325− )}
326− </p>
327− </div>
328− </li>
329− );
330− }
331− if (item.type === "OPS_RESULT") {
332− const opsItem = Object.assign({}, item.content);
333− opsItem[
334− "slug"
335− ] = `https://operators.urbit.org${item.content.slug}`;
336− return (
337− <li
338− className={`cursor-pointer flex text-left w-full ${selected ? "bg-green-400" : ""
339− }`}
340− {...getItemProps({
341− key: item.content.link + "-" + index,
342− index,
343− item: opsItem,
344− selected,
345− })}
346− >
347− <div className="p-3">
348− <p
349− className={`font-medium text-base ${selected ? "text-white" : "text-wall-600"
350− }`}
351− >
352− <span className="text-wall-400">
353− {item.content.parent !== "Content"
354− ? `operators.urbit.org / ${item.content.parent} /`
355− : "operators.urbit.org /"}{" "}
356− </span>
357− {item.content.title}
358− </p>
359− <p
360− className={`text-base font-regular text-small ${selected ? "text-midWhite" : "text-wall-500"
361− }`}
362− >
363− {item.content.content}
364− {item?.content?.foundOnPage && (
365− <span className="italic block">
366− Found in page content
367− </span>
368− )}
369− </p>
370− </div>
371− </li>
372− );
373− }
374− return null;
375− })
376− : null}
377− </ul>
378− </div>
379− </div>
380− )}
381− </Downshift>
382− );
383− } else {
384− return null;
385− }
386− }
387−}
388−
389−function deSig(string) {
390− return string.startsWith("~") ? string.substring(1) : string;
391−}
392−
393−export default withRouter(Search);