Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions apps/site/src/app/terms/_components/terms-accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
"use client";

import { useState } from "react";
import type { ReactNode } from "react";
import { cn } from "@/lib/cn";

type Section = {
title: string;
content: ReactNode;
};

function AccordionItem({
section,
isOpen,
onToggle,
}: {
section: Section;
isOpen: boolean;
onToggle: () => void;
}) {
const anchorId = section.title.trim().toLowerCase().replace(/\s+/g, "-");

return (
<div className="scroll-mt-16 md:scroll-mt-24 border-t border-stroke-neutral" id={anchorId}>
<button
type="button"
className="flex w-full items-center justify-between py-3 text-left cursor-pointer"
onClick={onToggle}
aria-expanded={isOpen}
>
<span className="text-lg font-bold leading-[25px] text-foreground-neutral">
{section.title}
</span>
<i
className={cn(
"fa-regular text-foreground-neutral-weaker text-lg",
isOpen ? "fa-chevron-up" : "fa-chevron-down",
)}
/>
</button>
{isOpen && (
<div className="pb-4 text-foreground-neutral-weak text-left [&_p]:my-4 [&_a]:underline [&_a]:transition-colors [&_a]:duration-150 hover:[&_a]:text-foreground-neutral [&_ul]:list-revert [&_ul]:m-revert [&_ul]:p-revert [&_ol]:list-revert [&_ol]:m-revert [&_ol]:p-revert [&_li]:my-2 print:text-foreground-neutral">
{section.content}
</div>
)}
</div>
);
}

export function TermsAccordion({ sections }: { sections: Section[] }) {
const [expandAll, setExpandAll] = useState(false);
const [selected, setSelected] = useState(0);

const toggleAll = () => {
if (expandAll) {
setSelected(-1);
setExpandAll(false);
} else {
setExpandAll(true);
}
};

const toggleItem = (idx: number) => {
if (expandAll) setExpandAll(false);
setSelected(selected === idx ? -1 : idx);
};

const printPage = () => {
setExpandAll(true);
setTimeout(() => window.print(), 50);
};

return (
<>
{/* Controls — sticky sidebar on desktop, horizontal row on mobile */}
<div className="flex items-start flex-row-reverse gap-4 justify-between pt-14 pb-14 md:justify-center md:sticky md:top-[120px] md:flex-col md:pt-14 md:pb-24 md:self-start print:hidden">
<button
type="button"
className="text-foreground-orm hover:text-foreground-orm-strong transition-all duration-300 cursor-pointer"
onClick={toggleAll}
>
<span className="text-lg leading-6 font-semibold underline">
{expandAll ? "Collapse" : "Expand"} all
</span>
<i
className={`fa-regular fa-${expandAll ? "minus" : "plus"} ml-2 text-base`}
/>
</button>
<button
type="button"
className="text-foreground-orm hover:text-foreground-orm-strong transition-all duration-300 cursor-pointer"
onClick={printPage}
>
<span className="text-lg leading-6 font-semibold underline">
Print
</span>
<i className="fa-regular fa-print ml-2 text-base" />
</button>
</div>

{/* Accordion content */}
<div className="w-full pb-24 md:pt-10">
{sections.map((section, idx) => (
<AccordionItem
key={idx}
section={section}
isOpen={expandAll || selected === idx}
onToggle={() => toggleItem(idx)}
/>
))}
</div>
</>
);
}
35 changes: 35 additions & 0 deletions apps/site/src/app/terms/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { Metadata } from "next";
import { termsSections, termsLastUpdated } from "@/data/terms";
import { TermsAccordion } from "./_components/terms-accordion";

export const metadata: Metadata = {
title: "Terms of Service | Prisma",
description:
"Read the Prisma Terms of Service governing your use of Prisma products and services.",
};

export default function TermsPage() {
return (
<main className="flex-1 w-full z-1 -mt-24 pt-24 bg-[linear-gradient(180deg,#171937_0%,transparent_20%)]">
{/* Hero */}
<div className="text-center py-16">
<h1 className="text-5xl font-bold font-sans-display text-foreground-neutral mb-6">
Terms of Service
</h1>
<p className="text-lg text-foreground-neutral-weak">
<b>Last updated:</b> {termsLastUpdated}
</p>
</div>

{/* Separator */}
<div className="max-w-[1248px] mx-auto px-2.5 md:px-6">
<hr className="border-stroke-neutral" />
</div>

{/* Content */}
<div className="mx-auto w-full max-w-[1248px] px-2.5 md:px-6 grid gap-4 grid-rows-[auto_1fr] md:grid-cols-[150px_1fr] lg:grid-cols-[1fr_640px_1fr] print:grid-cols-[100%]">
<TermsAccordion sections={termsSections} />
</div>
</main>
);
}
Loading
Loading