Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
chronark committed Oct 25, 2024
2 parents 85d9994 + eada646 commit 15b6887
Show file tree
Hide file tree
Showing 18 changed files with 1,358 additions and 1 deletion.
38 changes: 38 additions & 0 deletions apps/www/app/glossary/[slug]/faq.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";

export function FAQ(props: {
epigraph?: string;
title: string;
description: string;
items: Array<{ question: string; answer: string }>;
}) {
return (
<>
<div className="text-center space-y-4 pb-6 mx-auto">
<h3 className="not-prose blog-heading-gradient text-left font-medium tracking-tight text-4xl">
{props.title}
</h3>
<p className="font-medium leading-7 not-prose text-white/70 lg:text-xl text-sm md:text-base py-6 max-w-sm md:max-w-md lg:max-w-xl xl:max-w-4xl text-left">
{props.description}
</p>
</div>
<div className="mx-auto md:max-w-[800px]">
<Accordion type="single" collapsible className="w-full">
{props.items.map((item) => (
<AccordionItem value={item.question} key={item.question}>
<AccordionTrigger className="justify-between space-x-2">
{item.question}
</AccordionTrigger>
<AccordionContent>{item.answer}</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
</>
);
}
283 changes: 283 additions & 0 deletions apps/www/app/glossary/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
import { CTA } from "@/components/cta";
import { Frame } from "@/components/frame";

import TermsStepperMobile from "@/components/glossary/terms-stepper-mobile";
import { MDX } from "@/components/mdx-content";
import { TopLeftShiningLight, TopRightShiningLight } from "@/components/svg/background-shiny";
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { MeteorLinesAngular } from "@/components/ui/meteorLines";
import { cn } from "@/lib/utils";
import { allGlossaries } from "content-collections";
import { Zap } from "lucide-react";
import type { Metadata } from "next";
import Link from "next/link";
import { notFound } from "next/navigation";
import { FAQ } from "./faq";
import Takeaways from "./takeaways";
import TermsRolodexDesktop from "@/components/glossary/terms-rolodex-desktop";
import { FilterableCommand } from "@/components/glossary/search";

export const generateStaticParams = async () =>
allGlossaries.map((term) => ({
slug: term.slug,
}));

export function generateMetadata({
params,
}: {
params: { slug: string };
}): Metadata {
const term = allGlossaries.find((term) => term.slug === params.slug);
if (!term) {
notFound();
}
return {
title: `${term.title} | Unkey Glossary`,
description: term.description,
openGraph: {
title: `${term.title} | Unkey Glossary`,
description: term.description,
url: `https://unkey.com/glossary/${term.slug}`,
siteName: "unkey.com",
type: "article",
},
twitter: {
card: "summary_large_image",
title: `${term.title} | Unkey Glossary`,
description: term.description,
site: "@unkeydev",
creator: "@unkeydev",
},
icons: {
shortcut: "/images/landing/unkey.png",
},
};
}

const GlossaryTermWrapper = async ({ params }: { params: { slug: string } }) => {
const term = allGlossaries.find((term) => term.slug === params.slug);
if (!term) {
notFound();
}

const relatedTerms: {
slug: string;
term: string;
tldr: string;
}[] = [];
return (
<>
<div className="container pt-48 mx-auto sm:overflow-hidden md:overflow-visible scroll-smooth">
<div>
<TopLeftShiningLight className="hidden h-full -z-40 sm:block" />
</div>
<div className="w-full h-full overflow-hidden -z-20">
<MeteorLinesAngular
number={1}
xPos={0}
speed={10}
delay={5}
className="overflow-hidden"
/>
<MeteorLinesAngular
number={1}
xPos={0}
speed={10}
delay={0}
className="overflow-hidden"
/>
<MeteorLinesAngular
number={1}
xPos={100}
speed={10}
delay={7}
className="overflow-hidden md:hidden"
/>
<MeteorLinesAngular
number={1}
xPos={100}
speed={10}
delay={2}
className="overflow-hidden md:hidden"
/>
<MeteorLinesAngular
number={1}
xPos={200}
speed={10}
delay={7}
className="hidden overflow-hidden md:block"
/>
<MeteorLinesAngular
number={1}
xPos={200}
speed={10}
delay={2}
className="hidden overflow-hidden md:block"
/>
<MeteorLinesAngular
number={1}
xPos={400}
speed={10}
delay={5}
className="hidden overflow-hidden lg:block"
/>
<MeteorLinesAngular
number={1}
xPos={400}
speed={10}
delay={0}
className="hidden overflow-hidden lg:block"
/>
</div>
<div className="overflow-hidden -z-40">
<TopRightShiningLight />
</div>
<div className="w-full">
<div className="mb-24 grid grid-cols-1 gap-4 md:gap-8 pb-24 lg:grid-cols-[15rem_1fr] xl:grid-cols-[15rem_1fr_15rem]">
{/* Left Sidebar */}
<div className="block">
<div className="sticky top-24 flex flex-col">
<p className="w-full mb-4 font-semibold text-left blog-heading-gradient">
Find a term
</p>
<FilterableCommand
placeholder="Search"
className="rounded-lg mb-4 border-[.75px] border-white/20 lg:w-[232px]"
terms={allGlossaries}
/>
<div className="flex-grow">
<p className="w-full my-4 font-semibold text-left blog-heading-gradient">Terms</p>
<TermsRolodexDesktop
className="flex-grow hidden lg:block"
terms={allGlossaries.map((term) => ({ slug: term.slug, title: term.title }))}
/>
<TermsStepperMobile
className="flex-grow lg:hidden"
terms={allGlossaries.map((term) => ({ slug: term.slug, title: term.title }))}
/>
</div>
</div>
</div>
{/* Main Content */}
<div>
<div className="prose sm:prose-sm md:prose-md sm:mx-6">
<div className="flex items-center gap-5 p-0 m-0 mb-8 text-xl font-medium leading-8">
<Link href="/glossary">
<span className="text-transparent bg-gradient-to-r bg-clip-text from-white to-white/60">
Glossary
</span>
</Link>
<span className="text-white/40">/</span>
<span className="text-transparent capitalize bg-gradient-to-r bg-clip-text from-white to-white/60">
{term.term}
</span>
</div>
<h1 className="not-prose blog-heading-gradient text-left font-medium tracking-tight text-4xl">
{term.h1}
</h1>
<p className="mt-8 text-lg font-medium leading-8 not-prose text-white/60 lg:text-xl">
{term.intro}
</p>
</div>
<div className="mt-12 sm:mx-6">
<Takeaways takeaways={term.takeaways} term={term.term} />
</div>
<div className="mt-12 prose-sm md:prose-md text-white/60 sm:mx-6 prose-strong:text-white/90 prose-code:text-white/80 prose-code:bg-white/10 prose-code:px-2 prose-code:py-1 prose-code:border-white/20 prose-code:rounded-md prose-pre:p-0 prose-pre:m-0 prose-pre:leading-6">
<MDX code={term.mdx} />
</div>
<div className="mt-12 sm:mx-6">
<FAQ
items={[
{
// provide some FAQs for questions & answers about mime types:
question: "What is a mime type?",
answer:
"A mime type is a standard way to describe the format of a file. It is used to identify the type of data contained in a file, such as an image, a video, or a document. Mime types are essential for web browsers to correctly display and process different types of files.",
},
{
question: "What is the difference between a mime type and a file extension?",
answer:
"A mime type is a standard way to describe the format of a file. It is used to identify the type of data contained in a file, such as an image, a video, or a document. Mime types are essential for web browsers to correctly display and process different types of files. A file extension is a suffix added to a file name to indicate its type. It is used to help users identify the type of file and to help applications determine how to open or process the file.",
},
{
question: "Which mime types are supported by Unkey?",
answer:
"Unkey supports a wide range of mime types, including text, image, audio, video, and application-specific types. The full list of supported mime types can be found in the Unkey documentation.",
},
]}
title={`Questions & Answers about ${term.term}`}
description={`We answer common questions about ${term.term}.`}
epigraph="FAQ"
/>
</div>
</div>
{/* Right Sidebar */}
<div className="hidden xl:block">
<div className="sticky top-24 space-y-8">
{term.tableOfContents?.length !== 0 && (
<div className="not-prose">
<h3 className="text-lg font-semibold text-white mb-4">Contents</h3>
<ul className="space-y-2">
{term.tableOfContents.map((heading) => (
<li key={`#${heading?.slug}`}>
<Link
href={`#${heading?.slug}`}
className={cn("text-white/60 hover:text-white", {
"text-sm": heading?.level && heading.level > 2,
"ml-4": heading?.level && heading.level === 3,
"ml-8": heading?.level && heading.level === 4,
})}
>
{heading?.text}
</Link>
</li>
))}
</ul>
</div>
)}
{/* Related Blogs */}
<div>
<h3 className="text-lg font-semibold text-white mb-4">Related Terms</h3>
<div className="flex flex-col gap-4">
{relatedTerms.length > 0 ? (
relatedTerms.map((relatedTerm) => (
<Link
href={`/glossary/${relatedTerm.slug}`}
key={relatedTerm.slug}
className="block"
>
<Card className="w-full bg-white/5 shadow-[0_0_10px_rgba(255,255,255,0.1)] rounded-xl overflow-hidden relative border-white/20">
<CardHeader>
<Frame size="sm">
<div className="p-4 rounded-md space-y-2">
<h3 className="text-sm font-semibold flex items-center text-white">
<Zap className="mr-2 h-5 w-5" /> TL;DR
</h3>
<p className="text-sm text-white/80">{relatedTerm.tldr}</p>
</div>
</Frame>
</CardHeader>
<CardContent>
<h4 className="text-md font-semibold text-white mb-2">
{relatedTerm.term}
</h4>
</CardContent>
</Card>
</Link>
))
) : (
<p className="text-sm text-white/50">No related terms found.</p>
)}
</div>
</div>
</div>
</div>
</div>
<CTA />
</div>
</div>
</>
);
};

export default GlossaryTermWrapper;
Loading

0 comments on commit 15b6887

Please sign in to comment.