1import { Component, createRef } from "react";
2import { glossary } from "../lib/glossary";
3import { withRouter } from "next/router";
4import debounce from "lodash.debounce";
5import Downshift from "downshift";
6import ob from "urbit-ob";
7import Sigil from "../components/Sigil";
9class Search extends Component {
15 this.searchEndpoint = this.searchEndpoint.bind(this);
16 this.onInputValueChange = this.onInputValueChange.bind(this);
17 this.onSelect = this.onSelect.bind(this);
18 this.glossarySearch = this.glossarySearch.bind(this);
19 this.patpSearch = this.patpSearch.bind(this);
22 searchEndpoint(query) {
23 return `/api/search?q=${query}`;
26 glossarySearch(query) {
27 return glossary.filter((entry) => {
28 return query.toLowerCase() === entry.name || entry.symbol === query;
34 (ob.isValidPatp(`~${deSig(query.toLowerCase())}`) &&
35 `~${deSig(query.toLowerCase())}`.length < 15) ||
36 (!isNaN(query) && query <= 4294967295)
42 this.props.router.push(item.slug);
50 this.props.closeSearch();
53 onInputValueChange = debounce((query) => {
55 fetch(this.searchEndpoint(query))
56 .then((res) => res.json())
58 // Wrap results in an object which will tell React what component to use to render results.
59 const results = res.results.map((item) => ({
64 const patp = this.patpSearch(query)
67 : ob.patp(ob.patp2dec(`~${deSig(query)}`))
70 const patpResult = this.patpSearch(query)
82 const glossaryResults = this.glossarySearch(query).map((item) => ({
83 type: "GLOSSARY_RESULT",
87 const list = [...patpResult, ...glossaryResults, ...results];
89 this.setState({ results: list });
92 this.setState({ results: [] });
97 const { state, props } = this;
99 if (props.showSearch) {
102 onSelect={(selection) => this.onSelect(selection)}
103 onInputValueChange={(event) => this.onInputValueChange(event)}
104 itemToString={(item) => (item ? item.slug : "")}
105 defaultHighlightedIndex={0}
118 <div className="fixed w-screen h-screen z-50 flex flex-col items-center p-4">
120 onClick={(event) => props.closeSearch(event)}
121 className="top-0 left-0 fixed w-screen h-screen bg-washedWall"
123 <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">
125 style={{ display: "inline-block" }}
126 {...getRootProps({}, { suppressRefError: true })}
130 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"
131 placeholder="Search..."
133 onClick={(e) => e.stopPropagation()}
135 onKeyDown: (event) => {
136 if (event.key === "Escape") {
137 // Prevent Downshift's default 'Escape' behavior.
138 event.nativeEvent.preventDownshiftDefault = true;
139 this.props.closeSearch(event);
145 <ul {...getMenuProps()} className="overflow-y-scroll">
147 ? state.results.map((item, index) => {
148 const selected = highlightedIndex === index;
149 if (item.type === "PATP") {
152 className={`cursor-pointer p-2 flex space-x-2 items-center text-left w-full ${
153 selected ? "bg-green-400" : ""
156 key: item.content.slug + "-" + index,
159 selected: highlightedIndex === index,
162 <div className="rounded-md overflow-hidden">
164 patp={item.content.patp}
169 <p className="font-mono">{item.content.patp}</p>
173 if (item.type === "GLOSSARY_RESULT") {
176 className={`cursor-pointer flex text-left w-full ${
177 selected ? "bg-green-400" : ""
180 key: item.content.slug + "-" + index,
183 selected: highlightedIndex === index,
186 <div className="font-semibold p-3">
188 className={`text-base ${
189 selected ? "text-white" : "text-wall-600"
192 {item.content.symbol.length > 0 && (
194 className={`mr-1 rounded px-1 py-0.5 ${
200 {item.content.symbol}
206 className={`font-normal text-base mt-1 ${
207 selected ? "text-white" : "text-wall-600"
216 if (item.type === "RESULT") {
219 className={`cursor-pointer flex text-left w-full ${
220 selected ? "bg-green-400" : ""
223 key: item.content.link + "-" + index,
229 <div className="p-3">
231 className={`font-medium text-base ${
232 selected ? "text-white" : "text-wall-600"
235 {item.content.parent !== "Content"
236 ? `${item.content.parent} /`
241 className={`text-base font-regular text-small ${
242 selected ? "text-midWhite" : "text-wall-500"
245 {item.content.content}
266function deSig(string) {
267 return string.startsWith("~") ? string.substring(1) : string;
270export default withRouter(Search);
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list