@@ -0,0 +1,155 @@
1+import Head from "next/head";
2+import Link from "next/link";
3+import { getPage } from "../../lib/lib";
4+import { join } from "path";
5+import CopyLink from "../../components/CopyLink";
6+import Container from "../../components/Container";
7+import SingleColumn from "../../components/SingleColumn";
8+import Section from "../../components/Section";
9+import ob from "urbit-ob";
10+import Markdown from "../../components/Markdown";
11+import GatewayHeader from "../../components/gateway/GatewayHeader";
12+import Gateway404 from "../../components/gateway/Gateway404";
13+import MetadataBlock from "../../components/gateway/MetadataBlock";
14+import MetadataLink from "../../components/gateway/MetadataLink";
15+import Description from "../../components/gateway/Description";
16+
17+const ApplicationPage = ({ data, markdown, params }) => {
18+ const { application } = params;
19+ if (!ob.isValidPatp(application[0])) {
20+ return <Gateway404 type="application" />;
21+ }
22+ const image = `https://urbit-id-og-cards-7mdrgkd36-urbit.vercel.app/${
23+ data.title
24+ }?images=${
25+ data.image ? data.image : "https://media.urbit.org/logo/urbit-logo-card.png"
26+ }`;
27+
28+ return (
29+ <Container>
30+ <Head>
31+ <title>{data.title} • Applications • urbit.org</title>
32+ <link rel="icon" type="image/png" href="/images/favicon.ico" />
33+ <meta
34+ name="twitter:card"
35+ content="summary_large_image"
36+ key="twitter-card"
37+ />
38+ <meta
39+ name="og:title"
40+ content={`${data.title} • Applications • urbit.org`}
41+ key="title"
42+ />
43+ <meta
44+ name="og:description"
45+ content={
46+ data?.description ||
47+ "View more about this application on urbit.org."
48+ }
49+ key="description"
50+ />
51+ <meta property="twitter:image" content={image} key="image" />
52+ </Head>
53+ <SingleColumn>
54+ <Section className="space-y-12" narrow>
55+ <GatewayHeader
56+ title={data.title}
57+ image={data?.image}
58+ item="Urbit Application"
59+ />
60+ <div className="flex flex-wrap md:flex-nowrap justify-between">
61+ <MetadataBlock
62+ title="License"
63+ content={data.license ? data.license : "Unknown"}
64+ />
65+ {data?.website && (
66+ <MetadataLink
67+ title="Website"
68+ href={data?.website}
69+ content={
70+ data?.website ? data.website.replace(/^https?:\/\//, "") : ""
71+ }
72+ />
73+ )}
74+ <MetadataBlock
75+ title="Developer"
76+ content={data.developer ? data.developer : "Unknown"}
77+ />
78+ <CopyLink
79+ className="basis-1/2 md:basis-auto"
80+ content={data.shortcode ? data.shortcode : data.title}
81+ />
82+ </div>
83+ <Description
84+ description={data.description}
85+ fallback="An application on Urbit."
86+ markdown={markdown}
87+ />
88+ <hr className="text-wall-200" />
89+ <div className="flex flex-col space-y-6">
90+ <h3>
91+ Urbit is a clean-slate, peer-to-peer operating system and network.
92+ </h3>
93+ <div className="flex flex-col space-y-4">
94+ <p className="text-sm font-semibold text-wall-400">
95+ Learn how to install an Urbit application
96+ </p>
97+ {/* TODO: Joining groups guide. */}
98+ <button className="button-lg max-w-xs bg-green-400 text-white">
99+ Installing Urbit applications
100+ </button>
101+ </div>
102+ </div>
103+ <hr className="text-wall-200" />
104+ <div className="flex flex-col space-y-1">
105+ <p>
106+ Have an application you'd like to share publicly through
107+ urbit.org?
108+ </p>
109+ {/* TODO Submission guide. */}
110+ <p className="type-ui text-green-400">
111+ Learn how to submit your application
112+ </p>
113+ </div>
114+ <Link href="/">
115+ <a className="text-xl pt-8 block font-semibold">Urbit.org</a>
116+ </Link>
117+ </Section>
118+ </SingleColumn>
119+ </Container>
120+ );
121+};
122+
123+export const getServerSideProps = async ({ params, res }) => {
124+ res.setHeader(
125+ "Cache-Control",
126+ "public, s-maxage=3600, stale-while-revalidate=604800"
127+ );
128+
129+ let { data, content } = getPage(
130+ join(
131+ process.cwd(),
132+ "content/application",
133+ params.application?.join("/") || "/"
134+ )
135+ ) || { data: {}, content: "" };
136+
137+ if (!data.title) {
138+ data = {
139+ title: params.application?.join("/"),
140+ description: "An application on Urbit.",
141+ };
142+ }
143+
144+ const markdown = await Markdown({ post: { content: content } }, true);
145+
146+ return {
147+ props: {
148+ data,
149+ markdown,
150+ params,
151+ },
152+ };
153+};
154+
155+export default ApplicationPage;