g1t/apps/web/app/routes/policy.tsx

70 lines2,425 bytesCodeBlame

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1import { data, Link } from "react-router";
2
3import type { Route } from "./+types/policy";
4import { Contents, PolicyText, TrustPage, outline } from "../components/legal-doc";
5import { POLICIES, POLICIES_UPDATED, longDate } from "../lib/legal";
6import { page } from "../lib/meta";
7import acceptableUse from "../content/policies/acceptable-use.md?raw";
8import privacy from "../content/policies/privacy.md?raw";
9import refunds from "../content/policies/refunds.md?raw";
10import subprocessors from "../content/policies/subprocessors.md?raw";
11import terms from "../content/policies/terms.md?raw";
12
13/** Each policy's text, written in Markdown in app/content/policies. */
14const TEXT: Record<string, string> = {
15 terms,
16 privacy,
17 "acceptable-use": acceptableUse,
18 refunds,
19 subprocessors,
20};
21
22export function loader({ params }: Route.LoaderArgs) {
23 const policy = POLICIES.find((p) => p.slug === params.policy);
24 if (!policy || !TEXT[policy.slug]) throw data(null, { status: 404 });
25 return { policy };
26}
27
28export function meta({ loaderData, ...args }: Route.MetaArgs) {
29 const policy = loaderData?.policy;
30 return page(args, {
31 title: policy ? `${policy.title} · g1t` : "Policies · g1t",
32 description: policy?.summary,
33 });
34}
35
36export default function Policy({ loaderData }: Route.ComponentProps) {
37 const { policy } = loaderData;
38 const source = TEXT[policy.slug];
39 return (
40 <TrustPage
41 eyebrow={
42 <Link to="/policies" className="hover:underline hover:underline-offset-4">
43 Policies
44 </Link>
45 }
46 title={policy.title}
47 lede={<p className="text-sm">Last updated {longDate(POLICIES_UPDATED)}.</p>}
48 aside={<Contents items={outline(source)} />}
49 >
50 <PolicyText source={source} />
51 <nav aria-label="Other policies" className="mt-14 max-w-3xl border-t border-line pt-6">
52 <p className="text-sm font-medium">Other policies</p>
53 <ul className="mt-3 flex flex-wrap gap-x-5 gap-y-2 text-sm text-muted">
54 {POLICIES.filter((p) => p.slug !== policy.slug).map((p) => (
55 <li key={p.slug}>
56 <Link to={`/policies/${p.slug}`} className="hover:text-fg">
57 {p.title}
58 </Link>
59 </li>
60 ))}
61 <li>
62 <Link to="/security" className="hover:text-fg">
63 Security
64 </Link>
65 </li>
66 </ul>
67 </nav>
68 </TrustPage>
69 );
70}