on master help sign in
ecosystem: break sidebar + archive + ecosystem directories into components
commit7cb29030435bddfced83635ef2387c0113714e81 authorMatilde Park <matilde.park@urbit.org> dateTue 29 Nov 2022, 16:53 (4 years ago) parent31e8a0a
3 files changed+276−237
components/ecosystem/EcosystemSidebar.js+77 components/ecosystem/SpotlightArchive.js+64 pages/ecosystem/index.js+135−237
components/ecosystem/EcosystemSidebar.jsnew file+77
@@ -0,0 +1,77 @@
1+import { useRouter } from "next/router";
2+import classnames from "classnames";
3+function ActiveLink({ children, href, className, currentPath }) {
4+ // special casing this behaviour which overloads one nav
5+ const archive = Boolean(
6+ currentPath === "/ecosystem?type=archive" && href === "/ecosystem"
7+ );
8+ const activeClassName = classnames({
9+ "text-wall-800": currentPath === href || archive,
10+ "text-wall-400": currentPath !== href && !archive,
11+ });
12+
13+ return (
14+ <Link href={href} passHref>
15+ <a className={`${className} ${activeClassName}`}>{children}</a>
16+ </Link>
17+ );
18+}
19+
20+export default function EcosystemSidebar() {
21+ const router = useRouter();
22+ let currentPath = router.asPath;
23+ return (
24+ <div className="flex flex-col space-y-4 pr-24">
25+ <ActiveLink
26+ currentPath={currentPath}
27+ className="type-ui"
28+ href="/ecosystem"
29+ >
30+ Spotlight
31+ </ActiveLink>
32+ <ActiveLink
33+ currentPath={currentPath}
34+ className="type-ui"
35+ href="/ecosystem?type=organizations"
36+ >
37+ Organizations
38+ </ActiveLink>
39+ <ActiveLink
40+ currentPath={currentPath}
41+ className="type-ui"
42+ href="/ecosystem?type=applications"
43+ >
44+ Applications
45+ </ActiveLink>
46+ <ActiveLink
47+ currentPath={currentPath}
48+ className="type-ui"
49+ href="/ecosystem?type=groups"
50+ >
51+ Groups
52+ </ActiveLink>
53+ <ActiveLink
54+ currentPath={currentPath}
55+ className="type-ui"
56+ href="/ecosystem?type=groups"
57+ >
58+ Marketplaces
59+ </ActiveLink>
60+ <ActiveLink
61+ currentPath={currentPath}
62+ className="mr-5 type-ui"
63+ href="/ecosystem?type=podcasts"
64+ >
65+ Podcasts
66+ </ActiveLink>
67+
68+ <ActiveLink
69+ currentPath={currentPath}
70+ className="mr-5 type-ui"
71+ href="/ecosystem?type=articles"
72+ >
73+ Articles
74+ </ActiveLink>
75+ </div>
76+ );
77+}
components/ecosystem/SpotlightArchive.jsnew file+64
@@ -0,0 +1,64 @@
1+import { Container, IntraNav, SingleColumn, Section } from "@urbit/foundation-design-system";
2+import Header from "../Header";
3+import Footer from "../Footer";
4+import Meta from "../Meta";
5+import Head from "next/head";
6+import EcosystemSidebar from "./EcosystemSidebar";
7+
8+export default function SpotlightArchive({ posts, search }) {
9+ const post = {
10+ title: "Spotlight Archive",
11+ description: "The archive of ecosystem spotlights.",
12+ };
13+ return (
14+ <Container>
15+ <Head>
16+ <title>Archive • Spotlight • Urbit</title>
17+ {Meta(post)}
18+ </Head>
19+ <IntraNav ourSite="https://urbit.org" search={search} />
20+ <SingleColumn>
21+ <Header search={search} />
22+ <Section>
23+ <div className="measure">
24+ <h1>Ecosystem</h1>
25+ </div>
26+ </Section>
27+ <Section className="flex">
28+ <Sidebar>
29+ <EcosystemSidebar />
30+ </Sidebar>
31+ <div>
32+ <h3 className="mb-12">Spotlight Archive</h3>
33+ {posts.map((post) => {
34+ return (
35+ <div key={post.slug} className="mb-24 cursor-pointer">
36+ <Link href={`/ecosystem/spotlight/${post.slug}`}>
37+ <div>
38+ <h3 className="text-green-400">{post.title}</h3>
39+ <div className="type-ui mt-2">
40+ {["featured-1", "featured-2", "featured-3"].map(
41+ (feat, i) => {
42+ if (post?.[feat]) {
43+ return (
44+ <>
45+ {i ? ", " : ""}
46+ <span>{post[feat].title}</span>
47+ </>
48+ );
49+ }
50+ }
51+ )}
52+ </div>
53+ </div>
54+ </Link>
55+ </div>
56+ );
57+ })}
58+ </div>
59+ </Section>
60+ </SingleColumn>
61+ <Footer />
62+ </Container>
63+ );
64+}
pages/ecosystem/index.js+135−237
@@ -6,7 +6,6 @@ import {
66 SingleColumn,
77 Section,
88 IntraNav,
9− Markdown,
109 getAllPosts,
1110 generateDisplayDate,
1211 formatDate,
@@ -14,6 +13,7 @@ import {
1413import Header from "../../components/Header";
1514import Footer from "../../components/Footer";
1615import Sidebar from "../../components/Sidebar";
16+import SpotlightArchive from "../../components/ecosystem/SpotlightArchive";
1717import Post from "../../components/ecosystem/Post";
1818import classnames from "classnames";
1919import Link from "next/link";
@@ -37,10 +37,15 @@ export default function Ecosystem({
3737
3838 const { type } = router.query;
3939
40+ // Route ?type=archive to below component;
41+ // otherwise, show directory of ecosystem type
42+ // If no param, we show the spotlight for the month
4043 if (type === "archive") {
4144 return <SpotlightArchive posts={posts} search={search} />;
4245 }
4346
47+ const spotlight = type === undefined;
48+
4449 let title;
4550 if (type) {
4651 switch (type) {
@@ -92,21 +97,19 @@ export default function Ecosystem({
9297 </Sidebar>
9398 <div
9499 className={classnames("w-full", {
95− "max-w-prose": type === undefined,
100+ "max-w-prose": spotlight,
96101 })}
97102 >
98− {type === undefined && (
99− <h3>{`Ecosystem Spotlight - ${post.title}`}</h3>
100− )}
101− {type === undefined && (
103+ {/* Default layout */}
104+ {spotlight && (
102105 <>
106+ <h3>{`Ecosystem Spotlight - ${post.title}`}</h3>
103107 <Post post={post} />
104108 <Link href="/ecosystem/?type=archive" passHref>
105109 <a className="button-lg bg-wall-600 text-white w-fit">
106110 Spotlight Archive
107111 </a>
108112 </Link>
109−
110113 <div className="pt-36">
111114 <h3 className="pb-2">Urbit Monthly</h3>
112115 <p className="pb-8">
@@ -117,124 +120,36 @@ export default function Ecosystem({
117120 </div>
118121 </>
119122 )}
120−
123+ {/* Ecosystem type layouts */}
121124 <div
122125 className={classnames("grid gap-12 w-full", {
123126 "grid-cols-2 md:grid-cols-3": type == "organizations" || type == "marketplaces",
124127 "grid-cols-1": type === "podcasts" || type === "articles",
125128 "grid-cols-1 md:grid-cols-1 lg:grid-cols-1 xl:grid-cols-2":
126129 type === "applications" || type === "groups",
127− hidden: type === undefined,
130+ hidden: spotlight,
128131 })}
129132 >
130133 {type === "organizations" &&
131− organizations.map((org) => (
132− <Link href={`/organizations/${org.slug}`}>
133− <div className="flex flex-col space-y-4 items-center cursor-pointer hover:opacity-90">
134− <img className="w-36 rounded-xl" src={org.image} />
135− <p className="text-center font-bold">{org.title}</p>
136− </div>
137− </Link>
138− ))}
134+ <Organizations dir={organizations} />
135+ }
139136
140137 {type === "applications" &&
141− applications.map((app) => (
142− <Link href={`/applications/${app.ship}/${app.slug}`}>
143− <div className="flex space-x-4 items-center cursor-pointer hover:opacity-90">
144− <div
145− className="h-36 w-36 rounded-xl items-center justify-center shrink-0 overflow-hidden"
146− style={{
147− backgroundColor: app?.bgColor || "rgba(0,0,0,0)",
148− }}
149− >
150− {app?.image && (
151− <img
152− className="items-center h-36 w-36"
153− src={app.image}
154− />
155− )}
156− </div>
157− <div className="">
158− <p className="text-left font-bold">{app.title}</p>
159− <p className="text-left text-wall-400 font-light">
160− {app.description}
161− </p>
162− </div>
163− </div>
164− </Link>
165− ))}
138+ <Applications dir={applications} />
139+ }
166140 {type === "groups" &&
167− groups.map((group) => (
168− <Link href={`/groups/${group.ship}/${group.slug}`}>
169− <div className="flex space-x-4 items-center cursor-pointer hover:opacity-90">
170− <div
171− className="h-36 w-36 rounded-xl items-center justify-center shrink-0 overflow-hidden"
172− style={{
173− backgroundColor: group?.tile?.startsWith("#")
174− ? group?.tile
175− : "rgba(0,0,0,0)",
176− }}
177− >
178− {!group?.tile?.startsWith("#") && (
179− <img
180− className="items-center h-36 w-36"
181− src={group.tile}
182− />
183− )}
184− </div>
185− <div className="">
186− <p className="text-left font-bold">{group.title}</p>
187− <p className="text-left text-wall-400 font-light">
188− {group.description}
189− </p>
190− </div>
191− </div>
192− </Link>
193− ))}
141+ <Groups dir={groups} />
142+ }
194143 {type === "marketplaces" &&
195− marketplaces.map((market) => (
196− <Link href={`/marketplaces/${market.slug}`}>
197− <div className="flex flex-col space-y-4 justify-center items-center cursor-pointer hover:opacity-90">
198− <img className="w-36 rounded-xl" src={market.image} />
199− <p className="text-center font-bold">{market.title}</p>
200− </div>
201− </Link>
202− ))}
144+ <Marketplaces dir={marketplaces} />
145+ }
203146 {type === "podcasts" &&
204− podcasts.map((pod) => (
205− <Link href={`/podcasts/${pod.slug}`}>
206− <div className="flex cursor-pointer space-x-4 items-center hover:opacity-90">
207− <img className="w-28" src={pod.image} />
208− <div className="flex flex-col space-y-2 min-w-0">
209− <p className="font-bold">{pod.podcast}</p>
210− <p className="min-w-0 min-h-0 leading-5 ">
211− {pod.title}
212− </p>
213− <p className="text-wall-400">
214− {formatDate(generateDisplayDate(pod.date))}
215− </p>
216− </div>
217− </div>
218− </Link>
219− ))}
147+ <Podcasts dir={podcasts} />
148+ }
220149
221150 {type === "articles" &&
222− articles.map((article) => (
223− <Link href={`/articles/${article.slug}`}>
224− <div className="flex cursor-pointer space-x-4 items-center hover:opacity-90">
225− <img className="w-28" src={article.image} />
226− <div className="flex flex-col space-y-2 min-w-0">
227− <p className="font-bold">{article.publication}</p>
228− <p className="min-w-0 min-h-0 leading-5 ">
229− {article.title}
230− </p>
231− <p className="text-wall-400">
232− {formatDate(generateDisplayDate(article.date))}
233− </p>
234− </div>
235− </div>
236− </Link>
237− ))}
151+ <Articles dir={articles} />
152+ }
238153 </div>
239154 </div>
240155 </div>
@@ -245,149 +160,132 @@ export default function Ecosystem({
245160 );
246161}
247162
248−function ActiveLink({ children, href, className, currentPath }) {
249− // special casing this behaviour which overloads one nav
250− const archive = Boolean(
251− currentPath === "/ecosystem?type=archive" && href === "/ecosystem"
252− );
253− const activeClassName = classnames({
254− "text-wall-800": currentPath === href || archive,
255− "text-wall-400": currentPath !== href && !archive,
256− });
257−
258− return (
259− <Link href={href} passHref>
260− <a className={`${className} ${activeClassName}`}>{children}</a>
163+const Organizations = ({ dir }) => {
164+ return dir.map((org) => (
165+ <Link href={`/organizations/${org.slug}`}>
166+ <div className="flex flex-col space-y-4 items-center cursor-pointer hover:opacity-90">
167+ <img className="w-36 rounded-xl" src={org.image} />
168+ <p className="text-center font-bold">{org.title}</p>
169+ </div>
261170 </Link>
262− );
171+ ))
263172}
264173
265−function EcosystemSidebar() {
266− const router = useRouter();
267− let currentPath = router.asPath;
268− return (
269− <div className="flex flex-col space-y-4 pr-24">
270− <ActiveLink
271− currentPath={currentPath}
272− className="type-ui"
273− href="/ecosystem"
274− >
275− Spotlight
276− </ActiveLink>
277− <ActiveLink
278− currentPath={currentPath}
279− className="type-ui"
280− href="/ecosystem?type=organizations"
281− >
282− Organizations
283− </ActiveLink>
284− <ActiveLink
285− currentPath={currentPath}
286− className="type-ui"
287− href="/ecosystem?type=applications"
288− >
289− Applications
290− </ActiveLink>
291− <ActiveLink
292− currentPath={currentPath}
293− className="type-ui"
294− href="/ecosystem?type=groups"
295− >
296− Groups
297− </ActiveLink>
298− <ActiveLink
299− currentPath={currentPath}
300− className="type-ui"
301− href="/ecosystem?type=groups"
302− >
303− Marketplaces
304− </ActiveLink>
305− <ActiveLink
306− currentPath={currentPath}
307− className="mr-5 type-ui"
308− href="/ecosystem?type=podcasts"
309− >
310− Podcasts
311− </ActiveLink>
174+const Applications = ({ dir }) => {
175+ return dir.map((app) => (
176+ <Link href={`/applications/${app.ship}/${app.slug}`}>
177+ <div className="flex space-x-4 items-center cursor-pointer hover:opacity-90">
178+ <div
179+ className="h-36 w-36 rounded-xl items-center justify-center shrink-0 overflow-hidden"
180+ style={{
181+ backgroundColor: app?.bgColor || "rgba(0,0,0,0)",
182+ }}
183+ >
184+ {app?.image && (
185+ <img
186+ className="items-center h-36 w-36"
187+ src={app.image}
188+ />
189+ )}
190+ </div>
191+ <div className="">
192+ <p className="text-left font-bold">{app.title}</p>
193+ <p className="text-left text-wall-400 font-light">
194+ {app.description}
195+ </p>
196+ </div>
197+ </div>
198+ </Link>
199+ ))
200+}
312201
313− <ActiveLink
314− currentPath={currentPath}
315− className="mr-5 type-ui"
316− href="/ecosystem?type=articles"
317− >
318− Articles
319− </ActiveLink>
202+const Groups = ({ dir }) => {
203+ return dir.map((group) => (
204+ <Link href={`/groups/${group.ship}/${group.slug}`}>
205+ <div className="flex space-x-4 items-center cursor-pointer hover:opacity-90">
206+ <div
207+ className="h-36 w-36 rounded-xl items-center justify-center shrink-0 overflow-hidden"
208+ style={{
209+ backgroundColor: group?.tile?.startsWith("#")
210+ ? group?.tile
211+ : "rgba(0,0,0,0)",
212+ }}
213+ >
214+ {!group?.tile?.startsWith("#") && (
215+ <img
216+ className="items-center h-36 w-36"
217+ src={group.tile}
218+ />
219+ )}
220+ </div>
221+ <div className="">
222+ <p className="text-left font-bold">{group.title}</p>
223+ <p className="text-left text-wall-400 font-light">
224+ {group.description}
225+ </p>
226+ </div>
227+ </div>
228+ </Link>
229+ ))
230+}
320231
232+const Marketplaces = ({ dir }) => {
233+ return dir.map((market) => (
234+ <Link href={`/marketplaces/${market.slug}`}>
235+ <div className="flex flex-col space-y-4 justify-center items-center cursor-pointer hover:opacity-90">
236+ <img className="w-36 rounded-xl" src={market.image} />
237+ <p className="text-center font-bold">{market.title}</p>
238+ </div>
239+ </Link>
240+ ))
241+}
321242
322− </div>
323− );
243+const Podcasts = ({ dir }) => {
244+ return dir.map((pod) => (
245+ <Link href={`/podcasts/${pod.slug}`}>
246+ <div className="flex cursor-pointer space-x-4 items-center hover:opacity-90">
247+ <img className="w-28" src={pod.image} />
248+ <div className="flex flex-col space-y-2 min-w-0">
249+ <p className="font-bold">{pod.podcast}</p>
250+ <p className="min-w-0 min-h-0 leading-5 ">
251+ {pod.title}
252+ </p>
253+ <p className="text-wall-400">
254+ {formatDate(generateDisplayDate(pod.date))}
255+ </p>
256+ </div>
257+ </div>
258+ </Link>
259+ ))
324260}
325261
326−function SpotlightArchive({ posts, search }) {
327− const post = {
328− title: "Spotlight Archive",
329− description: "The archive of ecosystem spotlights.",
330− };
331− return (
332− <Container>
333− <Head>
334− <title>Archive • Spotlight • Urbit</title>
335− {Meta(post)}
336− </Head>
337− <IntraNav ourSite="https://urbit.org" search={search} />
338− <SingleColumn>
339− <Header search={search} />
340− <Section>
341− <div className="measure">
342− <h1>Ecosystem</h1>
343− </div>
344− </Section>
345− <Section className="flex">
346− <Sidebar>
347− <EcosystemSidebar />
348− </Sidebar>
349− <div>
350− <h3 className="mb-12">Spotlight Archive</h3>
351− {posts.map((post) => {
352− return (
353− <div key={post.slug} className="mb-24 cursor-pointer">
354− <Link href={`/ecosystem/spotlight/${post.slug}`}>
355− <div>
356− <h3 className="text-green-400">{post.title}</h3>
357− <div className="type-ui mt-2">
358− {["featured-1", "featured-2", "featured-3"].map(
359− (feat, i) => {
360− if (post?.[feat]) {
361− return (
362− <>
363− {i ? ", " : ""}
364− <span>{post[feat].title}</span>
365− </>
366− );
367− }
368− }
369− )}
370− </div>
371− </div>
372− </Link>
373− </div>
374− );
375− })}
376− </div>
377− </Section>
378− </SingleColumn>
379− <Footer />
380− </Container>
381− );
262+const Articles = ({ dir }) => {
263+ return dir.map((article) => (
264+ <Link href={`/articles/${article.slug}`}>
265+ <div className="flex cursor-pointer space-x-4 items-center hover:opacity-90">
266+ <img className="w-28" src={article.image} />
267+ <div className="flex flex-col space-y-2 min-w-0">
268+ <p className="font-bold">{article.publication}</p>
269+ <p className="min-w-0 min-h-0 leading-5 ">
270+ {article.title}
271+ </p>
272+ <p className="text-wall-400">
273+ {formatDate(generateDisplayDate(article.date))}
274+ </p>
275+ </div>
276+ </div>
277+ </Link>
278+ ))
382279}
383280
384−export async function getStaticProps({ }) {
281+
282+export async function getStaticProps() {
385283 const posts = getAllPosts(
386284 ["title", "date", "slug", "featured-1", "featured-2", "featured-3"],
387285 "ecosystem/spotlight",
388286 "date"
389287 );
390− let post = matchEcosystemPost(getAllPosts(
288+ const post = matchEcosystemPost(getAllPosts(
391289 ["title", "date", "featured-1", "featured-2", "featured-3"],
392290 "ecosystem/spotlight",
393291 "date"