@@ -0,0 +1,136 @@
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 Meta from "../../components/Meta";
6+import CopyLink from "../../components/CopyLink";
7+import Container from "../../components/Container";
8+import SingleColumn from "../../components/SingleColumn";
9+import ErrorPage from "../404";
10+import Section from "../../components/Section";
11+import ob from "urbit-ob";
12+import { decode } from "html-entities";
13+import Markdown from "../../components/Markdown";
14+
15+const GroupPage = ({ data, markdown, params }) => {
16+ const { group } = params;
17+ if (!ob.isValidPatp(group[0])) {
18+ return <ErrorPage />;
19+ }
20+
21+ return (
22+ <Container>
23+ <Head>
24+ <title>{data.title} • Groups • urbit.org</title>
25+ {Meta(data)}
26+ </Head>
27+ <SingleColumn>
28+ <Section className="space-y-12" narrow>
29+ <div className="flex items-center space-x-4">
30+ {/* Group logo and fallback */}
31+ {data.image ? (
32+ <img
33+ className="rounded-xl"
34+ src={data.image}
35+ height={100}
36+ width={100}
37+ />
38+ ) : (
39+ <img
40+ className="object-contain shadow-sm rounded-xl"
41+ style={{ height: 100, width: 100 }}
42+ src="https://media.urbit.org/logo/urbit-logo-card.png"
43+ />
44+ )}
45+ <div className="flex flex-col">
46+ <h2>{data.title}</h2>
47+ <p>Urbit Group</p>
48+ </div>
49+ </div>
50+ <div className="flex flex-col md:flex-row space-y-4 md:space-y-0 justify-between">
51+ <div className="flex flex-col">
52+ <p className="font-bold text-wall-400">Group Type</p>
53+ <p>{data.type ? data.type : "Unknown"}</p>
54+ </div>
55+ <div className="flex flex-col">
56+ <p className="font-bold text-wall-400">Members</p>
57+ <p>
58+ {data.participant_range ? data.participant_range : "Unknown"}
59+ </p>
60+ </div>
61+ <div className="flex flex-col">
62+ <p className="font-bold text-wall-400">Host</p>
63+ <Link href={`/id/${group[0]}`}>
64+ <a className="type-ui font-mono text-green-400">{group[0]}</a>
65+ </Link>
66+ </div>
67+ <CopyLink content={data.shortcode ? data.shortcode : data.title} />
68+ </div>
69+ {(data.description !== "A group on Urbit." || markdown) && (
70+ <div className="flex flex-col space-y-4">
71+ <p className="font-bold text-wall-400">Description</p>
72+ {markdown ? (
73+ <div
74+ className="flex flex-col space-y-4"
75+ dangerouslySetInnerHTML={{ __html: decode(markdown) }}
76+ />
77+ ) : (
78+ <p>{data.description}</p>
79+ )}
80+ </div>
81+ )}
82+ <hr className="text-wall-200" />
83+ <div className="flex flex-col space-y-6">
84+ <h3>
85+ Urbit is a clean-slate, peer-to-peer operating system and network.
86+ </h3>
87+ <div className="flex flex-col space-y-4">
88+ <p className="text-sm font-semibold text-wall-400">
89+ Get on the network and join this group.
90+ </p>
91+ {/* TODO: Joining groups guide. */}
92+ <button className="button-lg max-w-xs bg-green-400 text-white">
93+ How to join a group
94+ </button>
95+ </div>
96+ </div>
97+ <hr className="text-wall-200" />
98+ <div className="flex flex-col space-y-1">
99+ <p>Have a group you'd like to share publicly through urbit.org?</p>
100+ {/* TODO Submission guide. */}
101+ <p className="type-ui text-green-400">
102+ Learn how to submit your group.
103+ </p>
104+ </div>
105+ <Link href="/">
106+ <a className="text-xl pt-8 block font-semibold">Urbit.org</a>
107+ </Link>
108+ </Section>
109+ </SingleColumn>
110+ </Container>
111+ );
112+};
113+
114+export const getServerSideProps = async ({ params }) => {
115+ let { data, content } = getPage(
116+ join(process.cwd(), "content/group", params.group?.join("/") || "/")
117+ ) || { data: {}, content: {} };
118+
119+ if (!data.title) {
120+ data = { title: params.group?.join("/"), description: "A group on Urbit." };
121+ }
122+
123+ const markdown = content
124+ ? await Markdown({ post: { content: content } })
125+ : "";
126+
127+ return {
128+ props: {
129+ data,
130+ markdown,
131+ params,
132+ },
133+ };
134+};
135+
136+export default GroupPage;