on master help sign in
adding articles ecosystem section and new tlon public group
4d7198aGordon
components/ecosystem/BasicPage.js+25−2
@@ -28,6 +28,7 @@ export default function BasicPage({
28 metaPost.title = `${post.title} - ${section}`;
28 metaPost.title = `${post.title} - ${section}`;
29 metaPost.description =
29 metaPost.description =
30 section === "Podcast" ? `${post.podcast} - ${post.date}` : post.description;
30 section === "Podcast" ? `${post.podcast} - ${post.date}` : post.description;
31+ section === "Article" ? `${post.publication} - ${post.date}` : post.description;
31 return (
32 return (
32 <Container>
33 <Container>
33 <Head>
34 <Head>
@@ -43,7 +44,7 @@ export default function BasicPage({
43 <div className="flex items-center space-x-4">
44 <div className="flex items-center space-x-4">
44 <img src={post.image} className="w-36" />
45 <img src={post.image} className="w-36" />
45 <div className="flex flex-col pl-2">
46 <div className="flex flex-col pl-2">
46− <h1 className={classnames({ "text-3xl": section === "Podcast" })}>
47+ <h1 className={classnames({ "text-3xl": section === "Podcast" },{ "text-3xl": section === "Article" })}>
47 {post.title}
48 {post.title}
48 </h1>
49 </h1>
49 <p>{section}</p>
50 <p>{section}</p>
@@ -58,13 +59,26 @@ export default function BasicPage({
58 <p>{post.podcast}</p>
59 <p>{post.podcast}</p>
59 </div>
60 </div>
60 )}
61 )}
62+ {post?.publication && (
63+ <div className="flex flex-col">
64+ <p className="font-bold text-wall-400">Publication</p>
65+ <p>{post.publication}</p>
66+ </div>
67+ )}
68+ {post?.author && (
69+ <div className="flex flex-col">
70+ <p className="font-bold text-wall-400">Author</p>
71+ <p>{post.author}</p>
72+ </div>
73+ )}
61 {post?.date && (
74 {post?.date && (
62 <div className="flex flex-col">
75 <div className="flex flex-col">
63 <p className="font-bold text-wall-400">Date</p>
76 <p className="font-bold text-wall-400">Date</p>
64 <p className="shrink-0">{post.date}</p>
77 <p className="shrink-0">{post.date}</p>
65 </div>
78 </div>
66 )}
79 )}
80+
67− {post?.URL && section !== "Podcast" && (
81+ {post?.URL && section !== "Podcast" && section !== "Article" && (
68 <div className="flex flex-col">
82 <div className="flex flex-col">
69 <p className="font-bold text-wall-400">Website</p>
83 <p className="font-bold text-wall-400">Website</p>
70 <a
84 <a
@@ -75,6 +89,7 @@ export default function BasicPage({
75 </a>
89 </a>
76 </div>
90 </div>
77 )}
91 )}
92+
78 {post?.URL && section === "Urbit Marketplace" && (
93 {post?.URL && section === "Urbit Marketplace" && (
79 <div className="flex flex-col">
94 <div className="flex flex-col">
80 <p className="font-bold text-wall-400">Accepts</p>
95 <p className="font-bold text-wall-400">Accepts</p>
@@ -93,6 +108,14 @@ export default function BasicPage({
93 &nbsp;Listen
108 &nbsp;Listen
94 </a>
109 </a>
95 )}
110 )}
111+ {post?.URL && section === "Article" && (
112+ <a
113+ href={post.URL}
114+ className="button-lg bg-green-400 text-white cursor-pointer flex space-x-2"
115+ >
116+ Read
117+ </a>
118+ )}
96 </div>
119 </div>
97 <div className="flex">
120 <div className="flex">
98 <div className="markdown w-full">
121 <div className="markdown w-full">
components/ecosystem/IndexCard.js+1
@@ -43,6 +43,7 @@ const badge = (type) => {
43 "bg-[#83b2d4]": type === "Application",
43 "bg-[#83b2d4]": type === "Application",
44 "bg-wall-600": type === "Podcast",
44 "bg-wall-600": type === "Podcast",
45 "bg-[#8dd5b1]": type === "Marketplace",
45 "bg-[#8dd5b1]": type === "Marketplace",
46+ "bg-[#000000]": type === "Article",
46 }
47 }
47 )}
48 )}
48 >
49 >
components/ecosystem/Post.js+8
@@ -49,6 +49,14 @@ export default function Post({ post }) {
49 </Link>
49 </Link>
50 )}
50 )}
51
51
52+ {post[feat].type === "Article" && (
53+ <Link href={href || "#"} passHref>
54+ <a class="button-sm text-white flex-col bg-green-400 cursor-pointer pr-4 w-fit">
55+ Listen to {post[feat].type}
56+ </a>
57+ </Link>
58+ )}
59+
52 {post[feat].type === "Application" && (
60 {post[feat].type === "Application" && (
53 <Link href={href || "#"} passHref>
61 <Link href={href || "#"} passHref>
54 <a class="button-sm text-white flex-col bg-green-400 cursor-pointer pr-4 w-fit">
62 <a class="button-sm text-white flex-col bg-green-400 cursor-pointer pr-4 w-fit">
content/articles/2022-09-29_the-dream-of-digital-homesteading.mdnew file+10
@@ -0,0 +1,10 @@
1++++
2+title = "The Dream of Digital Homesteading"
3+publication = "Compact"
4+author = "Geoff Schullenberger"
5+date = "2022-09-29"
6+URL = "https://compactmag.com/article/the-dream-of-digital-homesteading"
7+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/articles/compactmag.png"
8++++
9+
10+Geoff Schullenberger attends Assembly 2022 and chronicles his impressions and thoughts.
content/groups/~nibset-napwyn/tlon-public.mdnew file+12
@@ -0,0 +1,12 @@
1++++
2+title = "Tlon Public"
3+shortcode = "~nibset-napwyn/tlon-public"
4+description = "Updates, announcements, and broadcasts from Tlon."
5+type = "Public"
6+tile = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/organizations/tlon.png"
7+participant_range = "200+"
8++++
9+
10+Download the latest alphas of Tlon products, check out Tlon's visual inspiration and design work, and chat with Tlon team about their software.
11+
12+![](https://storage.googleapis.com/media.urbit.org/site/ecosystem/groups/tlon-public.png)
pages/articles/[slug].jsnew file+84
@@ -0,0 +1,84 @@
1+import BasicPage from "../../components/ecosystem/BasicPage";
2+import {
3+ Markdown,
4+ getAllPosts,
5+ getPostBySlug,
6+ getPostSlugs,
7+} from "@urbit/foundation-design-system";
8+import Link from "next/link";
9+
10+export default function Article({
11+ post,
12+ markdown,
13+ search,
14+ index,
15+ spotlights = [],
16+}) {
17+ return (
18+ <BasicPage
19+ section="Article"
20+ post={post}
21+ markdown={markdown}
22+ search={search}
23+ index={index}
24+ >
25+ {spotlights.length > 0 && (
26+ <p>
27+ Featured in{" "}
28+ {spotlights.map((e, i) => (
29+ <>
30+ {i ? ", " : ""}
31+ <Link href={`/ecosystem/spotlight/${e.slug}`}>{e.title}</Link>
32+ </>
33+ ))}
34+ </p>
35+ )}
36+ </BasicPage>
37+ );
38+}
39+
40+export async function getStaticProps({ params }) {
41+ const post = getPostBySlug(
42+ params.slug,
43+ ["title", "slug", "URL", "publication", "date", "image", "content"],
44+ "articles"
45+ );
46+
47+ const spotlights = getAllPosts(
48+ ["title", "slug", "featured-1", "featured-2", "featured-3"],
49+ "ecosystem/spotlight"
50+ ).filter(
51+ (e) =>
52+ e?.["featured-1"]?.title === post.title ||
53+ e?.["featured-2"]?.title === post.title ||
54+ e?.["featured-3"]?.title === post.title
55+ );
56+
57+ let { index } = post?.extra || { index: null };
58+
59+ if (index === undefined) {
60+ index = null;
61+ }
62+
63+ const markdown = JSON.stringify(Markdown.parse({ post }));
64+ return {
65+ props: { post, markdown, spotlights, index },
66+ };
67+}
68+
69+export async function getStaticPaths() {
70+ const posts = getPostSlugs("articles");
71+
72+ const slugs = posts.map((e) => e.slice(0, -3));
73+
74+ return {
75+ paths: slugs.map((post) => {
76+ return {
77+ params: {
78+ slug: post,
79+ },
80+ };
81+ }),
82+ fallback: false,
83+ };
84+}
pages/ecosystem/index.js+43−2
@@ -30,6 +30,7 @@ export default function Ecosystem({
30 marketplaces,
30 marketplaces,
31 organizations,
31 organizations,
32 podcasts,
32 podcasts,
33+ articles
33}) {
34}) {
34 const router = useRouter();
35 const router = useRouter();
35
36
@@ -54,6 +55,9 @@ export default function Ecosystem({
54 case "organizations":
55 case "organizations":
55 title = "Organizations • Ecosystem";
56 title = "Organizations • Ecosystem";
56 break;
57 break;
58+ case "articles":
59+ title = "Articles • Ecosystem";
60+ break;
57 default:
61 default:
58 title = "Ecosystem Spotlight";
62 title = "Ecosystem Spotlight";
59 }
63 }
@@ -112,8 +116,8 @@ export default function Ecosystem({
112
116
113 <div
117 <div
114 className={classnames("grid gap-12 w-full", {
118 className={classnames("grid gap-12 w-full", {
115− "grid-cols-2 md:grid-cols-3": type !== "podcasts",
119+ "grid-cols-2 md:grid-cols-3": type == "organizations" || type == "marketplaces",
116− "grid-cols-1": type === "podcasts",
120+ "grid-cols-1": type === "podcasts" || type === "articles",
117 "grid-cols-1 md:grid-cols-1 lg:grid-cols-1 xl:grid-cols-2":
121 "grid-cols-1 md:grid-cols-1 lg:grid-cols-1 xl:grid-cols-2":
118 type === "applications" || type === "groups",
122 type === "applications" || type === "groups",
119 hidden: type === undefined,
123 hidden: type === undefined,
@@ -209,6 +213,26 @@ export default function Ecosystem({
209 </div>
213 </div>
210 </Link>
214 </Link>
211 ))}
215 ))}
216+
217+ {type === "articles" &&
218+ articles.map((article) => (
219+ <Link href={`/articles/${article.slug}`}>
220+ <div className="flex cursor-pointer space-x-4 items-center hover:opacity-90">
221+ <img className="w-28" src={article.image} />
222+ <div className="flex flex-col space-y-2 min-w-0">
223+ <p className="font-bold">{article.publication}</p>
224+ <p className="min-w-0 min-h-0 leading-5 ">
225+ {article.title}
226+ </p>
227+ <p className="text-wall-400">
228+ {formatDate(generateDisplayDate(article.date))}
229+ </p>
230+ </div>
231+ </div>
232+ </Link>
233+ ))}
234+
235+
212 </div>
236 </div>
213 </div>
237 </div>
214 </div>
238 </div>
@@ -283,6 +307,16 @@ function EcosystemSidebar() {
283 >
307 >
284 Podcasts
308 Podcasts
285 </ActiveLink>
309 </ActiveLink>
310+
311+ <ActiveLink
312+ currentPath={currentPath}
313+ className="mr-5 type-ui"
314+ href="/ecosystem?type=articles"
315+ >
316+ Articles
317+ </ActiveLink>
318+
319+
286 </div>
320 </div>
287 );
321 );
288}
322}
@@ -362,6 +396,11 @@ export async function getStaticProps({}) {
362 "podcasts",
396 "podcasts",
363 "date"
397 "date"
364 );
398 );
399+ const articles = getAllPosts(
400+ ["title", "image", "date", "publication", "author", "slug"],
401+ "articles",
402+ "date"
403+ );
365 const organizations = getAllPosts(
404 const organizations = getAllPosts(
366 ["title", "image", "slug"],
405 ["title", "image", "slug"],
367 "organizations"
406 "organizations"
@@ -411,6 +450,7 @@ export async function getStaticProps({}) {
411 ...applications.map((e) => ({ ...e, type: "Application" })),
450 ...applications.map((e) => ({ ...e, type: "Application" })),
412 ...organizations.map((e) => ({ ...e, type: "Organization" })),
451 ...organizations.map((e) => ({ ...e, type: "Organization" })),
413 ...podcasts.map((e) => ({ ...e, type: "Podcast" })),
452 ...podcasts.map((e) => ({ ...e, type: "Podcast" })),
453+ ...articles.map((e) => ({ ...e, type: "Article" })),
414 ...marketplaces.map((e) => ({ ...e, type: "Marketplace" })),
454 ...marketplaces.map((e) => ({ ...e, type: "Marketplace" })),
415 ].filter((e) => e.title === post[feat].title)?.[0];
455 ].filter((e) => e.title === post[feat].title)?.[0];
416 post[feat].image = post[feat]?.image || matchedPost?.image || null;
456 post[feat].image = post[feat]?.image || matchedPost?.image || null;
@@ -433,6 +473,7 @@ export async function getStaticProps({}) {
433 marketplaces,
473 marketplaces,
434 podcasts,
474 podcasts,
435 organizations,
475 organizations,
476+ articles
436 },
477 },
437 };
478 };
438}
479}