@@ -0,0 +1,341 @@
1+// All sections in one template
3+// Get content from content/ecosystem/spotlight, content/applications, content/marketplaces, content/organizations, content/podcasts, content/groups
4+import { useRouter } from "next/router";
5+import Head from "next/head";
6+import Meta from "../../components/Meta";
13+} from "foundation-design-system";
14+import Header from "../../components/Header";
15+import Footer from "../../components/Footer";
16+import Sidebar from "../../components/Sidebar";
17+import Post from "../../components/ecosystem/Post";
18+import classnames from "classnames";
19+import Link from "next/link";
20+import { getAllPosts } from "../../lib/lib";
22+import path from "path";
23+import Contact from "../../components/Contact";
24+import { generateDisplayDate, formatDate } from "../../lib/lib";
26+export default function Ecosystem({
35+ const router = useRouter();
37+ const { type } = router.query;
39+ if (type === "archive") {
40+ return <SpotlightArchive posts={posts} search={search} />;
47+ title = "Applications";
50+ title = "Marketplaces";
55+ case "organizations":
56+ title = "Organizations";
67+ description: "Explore the Urbit ecosystem.",
72+ <title>{title} • Urbit</title>
75+ <IntraNav ourSite="https://urbit.org" search={search} />
81+ <Section className="justify-center">
82+ <div className="flex justify-between sidebar">
87+ className={classnames("w-full", {
88+ "max-w-prose": type === undefined,
91+ {type === undefined && (
92+ <h3>{`Ecosystem Spotlight - ${post.title}`}</h3>
94+ {type === undefined && (
97+ <Link href="/ecosystem/?type=archive" passHref>
98+ <a className="button-lg bg-wall-600 text-white w-fit">
105+ className={classnames("grid grid-cols-2 gap-12 w-full", {
106+ "md:grid-cols-3": type !== "podcasts",
107+ hidden: type === undefined,
110+ {type === "organizations" &&
111+ organizations.map((org) => (
112+ <Link href={`/organizations/${org.slug}`}>
113+ <div className="flex flex-col space-y-4 justify-center items-center cursor-pointer">
114+ <img className="w-36" src={org.image} />
115+ <p className="text-center font-bold">{org.title}</p>
119+ {type === "applications" &&
120+ applications.map((app) => (
121+ <Link href={`/applications/${app.ship}/${app.slug}`}>
122+ <div className="flex flex-col space-y-4 justify-center items-center cursor-pointer">
124+ className="w-36 h-36 overflow-hidden rounded-xl"
126+ backgroundColor: app?.bgColor || "rgba(0,0,0,0)",
130+ <img className="w-full h-full" src={app.image} />
133+ <p className="text-center font-bold">{app.title}</p>
137+ {type === "marketplaces" &&
138+ marketplaces.map((market) => (
139+ <Link href={`/marketplaces/${market.slug}`}>
140+ <div className="flex flex-col space-y-4 justify-center items-center cursor-pointer">
141+ <img className="w-36" src={market.image} />
142+ <p className="text-center font-bold">{market.title}</p>
146+ {type === "podcasts" &&
147+ podcasts.map((pod) => (
148+ <Link href={`/podcasts/${pod.slug}`}>
149+ <div className="flex cursor-pointer space-x-4 items-center">
150+ <img className="w-36" src={pod.image} />
151+ <div className="flex flex-col space-y-4">
152+ <p className="font-bold">{pod.podcast}</p>
154+ <p className="text-wall-400">{pod.date}</p>
162+ <Contact emphasize className="pt-36 self-center w-fit mx-auto" />
170+function ActiveLink({ children, href, className, currentPath }) {
171+ // special casing this behaviour which overloads one nav
172+ const archive = Boolean(
173+ currentPath === "/ecosystem?type=archive" && href === "/ecosystem"
175+ const activeClassName = classnames({
176+ "text-wall-600": currentPath === href || archive,
177+ "text-wall-500": currentPath !== href && !archive,
181+ <Link href={href} passHref>
182+ <a className={`${className} ${activeClassName}`}>{children}</a>
187+function EcosystemSidebar() {
188+ const router = useRouter();
189+ let currentPath = router.asPath;
191+ <div className="flex flex-col space-y-4 pr-24">
193+ currentPath={currentPath}
200+ currentPath={currentPath}
202+ href="/ecosystem?type=organizations"
207+ currentPath={currentPath}
209+ href="/ecosystem?type=applications"
214+ currentPath={currentPath}
216+ href="/ecosystem?type=marketplaces"
221+ currentPath={currentPath}
222+ className="mr-5 type-ui"
223+ href="/ecosystem?type=podcasts"
231+function SpotlightArchive({ posts, search }) {
233+ title: "Spotlight Archive",
234+ description: "The archive of ecosystem spotlights.",
239+ <title>Archive • Spotlight • Urbit</title>
242+ <IntraNav ourSite="https://urbit.org" search={search} />
246+ <div className="measure">
250+ <Section className="flex">
252+ <EcosystemSidebar />
255+ <h3 className="mb-12">Spotlight Archive</h3>
256+ {posts.map((post) => {
258+ <div key={post.slug} className="mb-24 cursor-pointer">
259+ <Link href={`/ecosystem/spotlight/${post.slug}`}>
261+ <h3 className="text-green-400">{post.title}</h3>
262+ <div className="type-ui mt-2">
263+ {["featured-1", "featured-2", "featured-3"].map(
269+ <span>{post[feat].title}</span>
289+export async function getStaticProps({}) {
290+ const posts = getAllPosts(
291+ ["title", "date", "slug", "featured-1", "featured-2", "featured-3"],
292+ "ecosystem/spotlight",
295+ let post = getAllPosts(
296+ ["title", "date", "featured-1", "featured-2", "featured-3"],
297+ "ecosystem/spotlight",
300+ ["featured-1", "featured-2", "featured-3"].forEach((feat) => {
302+ post[feat].content = JSON.stringify(
304+ post: { content: post[feat].content },
309+ const marketplaces = getAllPosts(["title", "image", "slug"], "marketplaces");
310+ const podcasts = getAllPosts(
311+ ["title", "image", "date", "podcast", "slug"],
314+ const organizations = getAllPosts(
315+ ["title", "image", "slug"],
318+ const applications = fs
319+ .readdirSync(path.join(process.cwd(), "content/applications"), {
320+ withFileTypes: true,
322+ .filter((f) => f.isDirectory())
325+ ["title", "bgColor", "image", "slug"],
326+ `applications/${dir.name}`
328+ .map((e) => ({ ...e, ship: dir.name }))
333+ const nameA = a.title.toLowerCase();
334+ const nameB = b.title.toLowerCase();
335+ return nameA < nameB ? -1 : 1;
339+ props: { posts, post, applications, marketplaces, podcasts, organizations },