on master help sign in
various: refactor search into _app
83cdd86Matilde Park
components/Container.js+4−14
@@ -1,18 +1,8 @@
1−import { configure, GlobalHotKeys } from "react-hotkeys";
2// Ensures the root container is always 100vw, min 100vh, and centers all children along the y-axis
1// Ensures the root container is always 100vw, min 100vh, and centers all children along the y-axis
3−export default function Container({ toggleSearch, children }) {
2+export default function Container({ children }) {
4− const keyMap = { search: ["command+k", "ctrl+k", "esc"] };
5− const handlers = { search: toggleSearch };
6− configure({
7− ignoreTags: [],
8− });
9−
10 return (
3 return (
11− <>
12− <GlobalHotKeys keyMap={keyMap} handlers={handlers} />
13− <div className="flex flex-col min-h-screen w-screen items-center">
4+ <div className="flex flex-col min-h-screen w-screen items-center">
14− {children}
5+ {children}
15− </div>
6+ </div>
16− </>
17 );
7 );
18}
8}
components/Search.js+93−90
@@ -53,101 +53,104 @@ export default function Search(props) {
53 }, []);
53 }, []);
54
54
55 return (
55 return (
56+ <>
56− <div className="fixed w-screen h-screen bg-black bg-opacity-30 z-50 flex flex-col">
57+ <div className="fixed w-screen h-screen bg-black bg-opacity-30 z-50 flex flex-col">
57− <div className="p-12 w-100 flex flex-col min-h-0">
58+ <div className="p-12 w-100 flex flex-col min-h-0">
58− <div className="relative flex flex-col" ref={searchRef}>
59+ <div className="relative flex flex-col" ref={searchRef}>
59− <input
60+ <input
60− className="bg-white type-ui text-green rounded-xl border-transparent p-2 outline-none relative"
61+ className="bg-white type-ui text-green rounded-xl border-transparent p-2 outline-none relative"
61− onChange={onChange}
62+ onChange={onChange}
62− onFocus={onFocus}
63+ onFocus={onFocus}
63− placeholder="Search..."
64+ placeholder="Search..."
64− type="text"
65+ type="text"
65− value={query}
66+ value={query}
66− autoFocus={true}
67+ autoFocus={true}
67− />
68+ />
68− {query.length > 0 && (
69+ {query.length > 0 && (
69− <span
70+ <span
70− onClick={clear}
71+ onClick={clear}
71− className="absolute right-3"
72+ className="absolute right-3"
72− style={{ top: 13 }}
73+ style={{ top: 13 }}
73− >
74− <svg
75− width="16"
76− height="16"
77− viewBox="0 0 16 16"
78− fill="none"
79− xmlns="http://www.w3.org/2000/svg"
80 >
74 >
75+ <svg
76+ width="16"
77+ height="16"
78+ viewBox="0 0 16 16"
79+ fill="none"
80+ xmlns="http://www.w3.org/2000/svg"
81+ >
81− <path
82+ <path
82− fill-rule="evenodd"
83+ fill-rule="evenodd"
83− clip-rule="evenodd"
84+ clip-rule="evenodd"
84− d="M0.39382 13.7045C-0.131273 14.2296 -0.131274 15.081 0.39382 15.6061C0.918913 16.1312 1.77026 16.1312 2.29535 15.6061L7.99999 9.90142L13.7047 15.6061C14.2297 16.1312 15.0811 16.1312 15.6062 15.6061C16.1313 15.081 16.1313 14.2296 15.6062 13.7046L9.90152 7.99989L15.6061 2.29535C16.1311 1.77026 16.1312 0.918913 15.6061 0.39382C15.081 -0.131273 14.2296 -0.131273 13.7045 0.39382L7.99999 6.09836L2.29548 0.393844C1.77038 -0.131249 0.919038 -0.131249 0.393945 0.393844C-0.131148 0.918937 -0.131148 1.77028 0.393945 2.29537L6.09846 7.99989L0.39382 13.7045Z"
85+ d="M0.39382 13.7045C-0.131273 14.2296 -0.131274 15.081 0.39382 15.6061C0.918913 16.1312 1.77026 16.1312 2.29535 15.6061L7.99999 9.90142L13.7047 15.6061C14.2297 16.1312 15.0811 16.1312 15.6062 15.6061C16.1313 15.081 16.1313 14.2296 15.6062 13.7046L9.90152 7.99989L15.6061 2.29535C16.1311 1.77026 16.1312 0.918913 15.6061 0.39382C15.081 -0.131273 14.2296 -0.131273 13.7045 0.39382L7.99999 6.09836L2.29548 0.393844C1.77038 -0.131249 0.919038 -0.131249 0.393945 0.393844C-0.131148 0.918937 -0.131148 1.77028 0.393945 2.29537L6.09846 7.99989L0.39382 13.7045Z"
85− fill="black"
86+ fill="black"
86− fill-opacity="0.6"
87+ fill-opacity="0.6"
87− />
88+ />
88− </svg>
89+ </svg>
89− </span>
90+ </span>
90− )}
91+ )}
91− </div>
92+ </div>
92− <div
93+ <div
93− className={
94+ className={
94− "bg-white overflow-scroll min-h-0 rounded-xl border-transparent mt-2 " +
95+ "bg-white overflow-scroll min-h-0 rounded-xl border-transparent mt-2 " +
95− (query.length > 0 ? "" : "hidden")
96+ (query.length > 0 ? "" : "hidden")
96− }
97+ }
97− >
98+ >
98− {active && glossaryResults.length > 0 && (
99+ {active && glossaryResults.length > 0 && (
99− <ul>
100+ <ul>
100− {glossaryResults.map(({ name, link, desc, symbol }) => {
101+ {glossaryResults.map(({ name, link, desc, symbol }) => {
101− return (
102− <div className="border-b border-gray">
103− <p className="font-semibold text-sm pb-4 text-gray pl-3 pt-2">
104− Glossary Result
105− </p>
106− <li key={link} className="cursor-pointer hover:bg-wall">
107− <Link href={link} as={link}>
108− <div className="font-semibold px-3">
109− {symbol.length > 0 && (
110− <code className="mr-1">{symbol}</code>
111− )}
112− {name}
113− <p className="font-normal text-base pt-1 pb-4">
114− {desc}
115− </p>
116− </div>
117− </Link>
118− </li>
119− </div>
120− );
121− })}
122− </ul>
123− )}
124− {active && results.length > 0 && (
125− <ul className="p-2">
126− <div>
127− <p className="font-semibold text-sm pb-4 text-gray">
128− {results.length} results for "{query}"
129− </p>
130− </div>
131− {results
132− .filter((e) => e.parent !== "Glossary")
133− .map(({ title, slug, content, parent }) => {
134 return (
102 return (
103+ <div className="border-b border-gray">
104+ <p className="font-semibold text-sm pb-4 text-gray pl-3 pt-2">
105+ Glossary Result
106+ </p>
135− <li key={slug} className="cursor-pointer hover:bg-wall">
107+ <li key={link} className="cursor-pointer hover:bg-wall">
136− <Link href={slug} as={slug}>
108+ <Link href={link} as={link}>
137− <div>
138− <p className="font-medium text-base">
109+ <div className="font-semibold px-3">
139− {parent} / {title}
110+ {symbol.length > 0 && (
140− </p>
111+ <code className="mr-1">{symbol}</code>
112+ )}
113+ {name}
141− <p className="text-base font-regular">{content}</p>
114+ <p className="font-normal text-base pt-1 pb-4">
115+ {desc}
116+ </p>
142− </div>
117+ </div>
143− </Link>
118+ </Link>
144− </li>
119+ </li>
120+ </div>
145 );
121 );
146 })}
122 })}
123+ </ul>
124+ )}
125+ {active && results.length > 0 && (
126+ <ul className="p-2">
127+ <div>
128+ <p className="font-semibold text-sm pb-4 text-gray">
129+ {results.length} results for "{query}"
130+ </p>
131+ </div>
132+ {results
133+ .filter((e) => e.parent !== "Glossary")
134+ .map(({ title, slug, content, parent }) => {
135+ return (
136+ <li key={slug} className="cursor-pointer hover:bg-wall">
137+ <Link href={slug} as={slug}>
138+ <div>
139+ <p className="font-medium text-base">
140+ {parent} / {title}
141+ </p>
142+ <p className="text-base font-regular">{content}</p>
143+ </div>
144+ </Link>
145+ </li>
146+ );
147+ })}
147− </ul>
148+ </ul>
148− )}
149+ )}
150+ </div>
149 </div>
151 </div>
150 </div>
152 </div>
151− </div>
153+ {props.children}
154+ </>
152 );
155 );
153}
156}
pages/404.js+1−5
@@ -1,15 +1,11 @@
1−import { useState } from "react";
2import Container from "../components/Container";
1import Container from "../components/Container";
3import SingleColumn from "../components/SingleColumn";
2import SingleColumn from "../components/SingleColumn";
4import Header from "../components/Header";
3import Header from "../components/Header";
5import Footer from "../components/Footer";
4import Footer from "../components/Footer";
6−import Search from "../components/Search";
7
5
8export default function NotFound() {
6export default function NotFound() {
9− const [showSearch, toggleSearch] = useState(false);
10 return (
7 return (
11− <Container toggleSearch={() => toggleSearch((state) => !state)}>
8+ <Container>
12− {showSearch && <Search toggleSearch={() => toggleSearch(false)} />}
13 <SingleColumn>
9 <SingleColumn>
14 <Header toggleSearch={() => toggleSearch(true)} />
10 <Header toggleSearch={() => toggleSearch(true)} />
15 <section className="layout-wide pt-48">
11 <section className="layout-wide pt-48">
pages/_app.js+22−4
@@ -1,8 +1,26 @@
1−import 'tailwindcss/tailwind.css'
1+import "tailwindcss/tailwind.css";
2+import { useState } from "react";
3+import { configure, GlobalHotKeys } from "react-hotkeys";
4+import Search from "../components/Search";
2−import '../styles/globals.css'
5+import "../styles/globals.css";
3
6
4function MyApp({ Component, pageProps }) {
7function MyApp({ Component, pageProps }) {
8+ const [showSearch, toggleSearch] = useState(false);
9+
10+ const invertToggle = () => toggleSearch((state) => !state);
11+ const keyMap = { search: ["command+k", "ctrl+k", "esc"] };
12+ const handlers = { search: invertToggle };
13+ configure({
14+ ignoreTags: [],
15+ });
16+
17+ return (
18+ <>
19+ <GlobalHotKeys keyMap={keyMap} handlers={handlers} />
20+ {showSearch && <Search toggleSearch={() => toggleSearch(false)} />}
5− return <Component {...pageProps} />
21+ <Component {...pageProps} toggleSearch={invertToggle} />
22+ </>
23+ );
6}
24}
7
25
8−export default MyApp
26+export default MyApp;
pages/blog.js+2−6
@@ -1,19 +1,15 @@
1import Head from "next/head";
1import Head from "next/head";
2import Link from "next/link";
2import Link from "next/link";
3−import { useState } from "react";
4import Container from "../components/Container";
3import Container from "../components/Container";
5−import Search from "../components/Search";
6import Footer from "../components/Footer";
4import Footer from "../components/Footer";
7import Header from "../components/Header";
5import Header from "../components/Header";
8import SingleColumn from "../components/SingleColumn";
6import SingleColumn from "../components/SingleColumn";
9import BackgroundImage from "../components/BackgroundImage";
7import BackgroundImage from "../components/BackgroundImage";
10import { getAllPosts, formatDate } from "../lib/lib";
8import { getAllPosts, formatDate } from "../lib/lib";
11
9
12−export default function Blog({ posts }) {
10+export default function Blog({ posts, toggleSearch }) {
13− const [showSearch, toggleSearch] = useState(false);
14 return (
11 return (
15− <Container toggleSearch={() => toggleSearch((state) => !state)}>
12+ <Container>
16− {showSearch && <Search toggleSearch={() => toggleSearch(false)} />}
17 <SingleColumn>
13 <SingleColumn>
18 <Header toggleSearch={() => toggleSearch(true)} />
14 <Header toggleSearch={() => toggleSearch(true)} />
19 <section className="layout-wide">
15 <section className="layout-wide">
pages/blog/[slug].js+2−6
@@ -1,5 +1,4 @@
1import { useRouter } from "next/router";
1import { useRouter } from "next/router";
2−import { useState } from "react";
3import {
2import {
4 getPostBySlug,
3 getPostBySlug,
5 getAllPosts,
4 getAllPosts,
@@ -14,22 +13,19 @@ import Container from "../../components/Container";
14import Markdown from "../../components/Markdown";
13import Markdown from "../../components/Markdown";
15import Header from "../../components/Header";
14import Header from "../../components/Header";
16import Footer from "../../components/Footer";
15import Footer from "../../components/Footer";
17−import Search from "../../components/Search";
18import BackgroundImage from "../../components/BackgroundImage";
16import BackgroundImage from "../../components/BackgroundImage";
19import SingleColumn from "../../components/SingleColumn";
17import SingleColumn from "../../components/SingleColumn";
20import NewsletterSignup from "../../components/NewletterSignup";
18import NewsletterSignup from "../../components/NewletterSignup";
21import PostPreview from "../../components/PostPreview";
19import PostPreview from "../../components/PostPreview";
22import { name, contact } from "../../lib/constants";
20import { name, contact } from "../../lib/constants";
23
21
24−export default function Post({ post, nextPost, previousPost }) {
22+export default function Post({ post, nextPost, previousPost, toggleSearch }) {
25 const router = useRouter();
23 const router = useRouter();
26 if (!router.isFallback && !post?.slug) {
24 if (!router.isFallback && !post?.slug) {
27 return <ErrorPage />;
25 return <ErrorPage />;
28 }
26 }
29− const [showSearch, toggleSearch] = useState(false);
30 return (
27 return (
31− <Container toggleSearch={() => toggleSearch((state) => !state)}>
28+ <Container>
32− {showSearch && <Search toggleSearch={() => toggleSearch(!showSearch)} />}
33 <SingleColumn>
29 <SingleColumn>
34 <Header toggleSearch={() => toggleSearch(true)} />
30 <Header toggleSearch={() => toggleSearch(true)} />
35 <section className="flex flex-col layout-wide">
31 <section className="flex flex-col layout-wide">
pages/docs/[[...slug]].js+7−12
@@ -8,8 +8,6 @@ import { getDocs, formatDate, buildPageTree, getPage } from "../../lib/lib";
8import Markdown from "../../components/Markdown";
8import Markdown from "../../components/Markdown";
9import ContentArea from "../../components/ContentArea";
9import ContentArea from "../../components/ContentArea";
10import Sidebar from "../../components/Sidebar";
10import Sidebar from "../../components/Sidebar";
11−import Search from "../../components/Search";
12−import { configure, GlobalHotKeys } from "react-hotkeys";
13
11
14const breadcrumbs = (posts, paths) => {
12const breadcrumbs = (posts, paths) => {
15 const results = [
13 const results = [
@@ -96,21 +94,18 @@ const pageTree = (thisLink, tree, level = 0) => {
96 );
94 );
97};
95};
98
96
99−export default function DocsLayout({ posts, data, content, params }) {
97+export default function DocsLayout({
100− const [showSearch, toggleSearch] = useState(false);
98+ posts,
99+ data,
100+ content,
101+ params,
101− const toggle = () => toggleSearch((state) => !state);
102+ toggleSearch,
102− const keyMap = { search: ["command+k", "ctrl+k", "esc"] };
103+}) {
103− const handlers = { search: toggle };
104− configure({
105− ignoreTags: [],
106− });
107 return (
104 return (
108 <>
105 <>
109 <Head>
106 <Head>
110 <title>{data.title} / Documentation / Urbit.org</title>
107 <title>{data.title} / Documentation / Urbit.org</title>
111 </Head>
108 </Head>
112− <GlobalHotKeys keyMap={keyMap} handlers={handlers} />
113− {showSearch && <Search toggleSearch={() => toggleSearch(!showSearch)} />}
114 <div className="flex w-screen h-screen min-h-screen w-screen overflow-hidden">
109 <div className="flex w-screen h-screen min-h-screen w-screen overflow-hidden">
115 <Sidebar>{childPages("/docs", posts.children)}</Sidebar>
110 <Sidebar>{childPages("/docs", posts.children)}</Sidebar>
116 <ContentArea
111 <ContentArea
pages/events.js+2−6
@@ -69,13 +69,9 @@ function EventCard(props) {
69 );
69 );
70}
70}
71
71
72−export default function Events({ pastEvents, currentEvents }) {
72+export default function Events({ pastEvents, currentEvents, toggleSearch }) {
73− const [showSearch, toggleSearch] = useState(false);
74 return (
73 return (
75− <Container toggleSearch={() => toggleSearch((state) => !state)}>
74+ <Container>
76− {showSearch && (
77− <Search toggleSearch={() => toggleSearch(!toggleSearch)} />
78− )}
79 <SingleColumn>
75 <SingleColumn>
80 <Header toggleSearch={() => toggleSearch(true)} />
76 <Header toggleSearch={() => toggleSearch(true)} />
81 <section className="layout-wide">
77 <section className="layout-wide">
pages/events/[slug].js+2−6
@@ -1,5 +1,4 @@
1import { useRouter } from "next/router";
1import { useRouter } from "next/router";
2−import { useState } from "react";
3import {
2import {
4 getPostBySlug,
3 getPostBySlug,
5 getAllPosts,
4 getAllPosts,
@@ -14,22 +13,19 @@ import Container from "../../components/Container";
14import Markdown from "../../components/Markdown";
13import Markdown from "../../components/Markdown";
15import Header from "../../components/Header";
14import Header from "../../components/Header";
16import Footer from "../../components/Footer";
15import Footer from "../../components/Footer";
17−import Search from "../../components/Search";
18import BackgroundImage from "../../components/BackgroundImage";
16import BackgroundImage from "../../components/BackgroundImage";
19import SingleColumn from "../../components/SingleColumn";
17import SingleColumn from "../../components/SingleColumn";
20import NewsletterSignup from "../../components/NewletterSignup";
18import NewsletterSignup from "../../components/NewletterSignup";
21import PostPreview from "../../components/PostPreview";
19import PostPreview from "../../components/PostPreview";
22import { name, contact } from "../../lib/constants";
20import { name, contact } from "../../lib/constants";
23
21
24−export default function Event({ post, nextPost, previousPost }) {
22+export default function Event({ post, nextPost, previousPost, toggleSearch }) {
25 const router = useRouter();
23 const router = useRouter();
26 if (!router.isFallback && !post?.slug) {
24 if (!router.isFallback && !post?.slug) {
27 return <ErrorPage />;
25 return <ErrorPage />;
28 }
26 }
29− const [showSearch, toggleSearch] = useState(false);
30 return (
27 return (
31− <Container toggleSearch={() => toggleSearch((state) => !state)}>
28+ <Container>
32− {showSearch && <Search toggleSearch={() => toggleSearch(false)} />}
33 <SingleColumn>
29 <SingleColumn>
34 <Header toggleSearch={() => toggleSearch(true)} />
30 <Header toggleSearch={() => toggleSearch(true)} />
35 <section className="flex flex-col layout-wide pt-24">
31 <section className="flex flex-col layout-wide pt-24">
pages/faq.js+2−2
@@ -8,11 +8,11 @@ import SingleColumn from "../components/SingleColumn";
8import BackgroundImage from "../components/BackgroundImage";
8import BackgroundImage from "../components/BackgroundImage";
9import { getAllPosts, formatDate } from "../lib/lib";
9import { getAllPosts, formatDate } from "../lib/lib";
10
10
11−export default function Blog({ posts }) {
11+export default function Blog({ posts, toggleSearch }) {
12 return (
12 return (
13 <Container>
13 <Container>
14 <SingleColumn>
14 <SingleColumn>
15− <Header />
15+ <Header toggleSearch={() => toggleSearch(true)} />
16 <section className="layout-wide">
16 <section className="layout-wide">
17 <div className="measure">
17 <div className="measure">
18 <h2 className="pb-16">Urbit Blog</h2>
18 <h2 className="pb-16">Urbit Blog</h2>
pages/grants.js+8−6
@@ -59,12 +59,17 @@ function toggleAll(currentArray, fullSet) {
59 }
59 }
60}
60}
61
61
62−export default function Grants({ posts, categories, types, featuredGrants }) {
62+export default function Grants({
63+ posts,
64+ categories,
65+ types,
66+ featuredGrants,
67+ toggleSearch,
68+}) {
63 const [activeTags, setTags] = useState([]);
69 const [activeTags, setTags] = useState([]);
64 const [activeTypes, setTypes] = useState(types);
70 const [activeTypes, setTypes] = useState(types);
65 const [includeCompleted, setIncludeCompleted] = useState(false);
71 const [includeCompleted, setIncludeCompleted] = useState(false);
66 const [tab, setTab] = useState(0);
72 const [tab, setTab] = useState(0);
67− const [showSearch, toggleSearch] = useState(false);
68
73
69 const filteredPosts = posts.filter((post) => {
74 const filteredPosts = posts.filter((post) => {
70 // Posts are returned if they match both the selected category and selected tags, or if the user has no category filters set.
75 // Posts are returned if they match both the selected category and selected tags, or if the user has no category filters set.
@@ -85,11 +90,8 @@ export default function Grants({ posts, categories, types, featuredGrants }) {
85 });
90 });
86
91
87 return (
92 return (
88− <Container toggleSearch={() => toggleSearch((state) => !state)}>
93+ <Container>
89 <SingleColumn>
94 <SingleColumn>
90− {showSearch && (
91− <Search toggleSearch={() => toggleSearch(!toggleSearch)} />
92− )}
93 <Header toggleSearch={() => toggleSearch(true)} />
95 <Header toggleSearch={() => toggleSearch(true)} />
94 {
96 {
95 // Heading and introduction
97 // Heading and introduction
pages/index.js+2−5
@@ -5,7 +5,6 @@ import Container from "../components/Container";
5import SingleColumn from "../components/SingleColumn";
5import SingleColumn from "../components/SingleColumn";
6import Header from "../components/Header";
6import Header from "../components/Header";
7import Footer from "../components/Footer";
7import Footer from "../components/Footer";
8−import Search from "../components/Search";
9import BackgroundImage from "../components/BackgroundImage";
8import BackgroundImage from "../components/BackgroundImage";
10import TabCarousel from "../components/TabCarousel";
9import TabCarousel from "../components/TabCarousel";
11import NewsletterSignup from "../components/NewletterSignup";
10import NewsletterSignup from "../components/NewletterSignup";
@@ -13,13 +12,11 @@ import PostPreview from "../components/PostPreview";
13import { getAllPosts, formatDate, getOpenGrantsCount } from "../lib/lib";
12import { getAllPosts, formatDate, getOpenGrantsCount } from "../lib/lib";
14import { contact } from "../lib/constants";
13import { contact } from "../lib/constants";
15
14
16−export default function Home({ posts, events, openGrantsCount }) {
15+export default function Home({ posts, events, openGrantsCount, toggleSearch }) {
17 const [tab, setTab] = useState(0);
16 const [tab, setTab] = useState(0);
18− const [showSearch, toggleSearch] = useState(false);
19 return (
17 return (
20− <Container toggleSearch={() => toggleSearch((state) => !state)}>
18+ <Container>
21 <SingleColumn>
19 <SingleColumn>
22− {showSearch && <Search toggleSearch={() => toggleSearch(false)} />}
23 <Header toggleSearch={() => toggleSearch(true)} />
20 <Header toggleSearch={() => toggleSearch(true)} />
24
21
25 {
22 {