Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
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
19 changes: 18 additions & 1 deletion app/blog/[...slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { ContentColumns } from "@/components/layout";
import { BlogPostSidebar } from "@/components/blog/BlogPostSidebar";
import { DocBodyChrome } from "@/components/DocBodyChrome";
import { MainContentWrapper } from "@/components/MainContentWrapper";
import { PageFooterNav } from "@/components/PageFooterNav";
import { getPageFooterItems } from "@/lib/page-footer-nav";

type PageProps = {
params: Promise<{ slug: string[] }>;
Expand All @@ -17,10 +19,24 @@ export default async function BlogPostPage(props: PageProps) {
const { slug } = await props.params;
const result = await loadPage(blogSource, slug);
if (!result) notFound();
const { MDX } = result;
const { page, MDX } = result;

const { tags, total } = getBlogTagCounts();

const footerItems = getPageFooterItems(
blogSource
.getPages()
.filter(
(page) => page.url !== "/blog" && page.data.showInBlogIndex !== false,
),
page.url,
{
getDate: (page) => page.data.date as string | undefined,
getTitle: (page) => page.data.title,
},
);


return (
<ContentColumns
leftSidebar={<BlogPostSidebar tags={tags} totalPosts={total} />}
Expand All @@ -32,6 +48,7 @@ export default async function BlogPostPage(props: PageProps) {
<MDX components={getMDXComponents()} />
</DocBodyChrome>
</MainContentWrapper>
<PageFooterNav items={footerItems} className="mt-10" />
</div>
</ContentColumns>
);
Expand Down
12 changes: 12 additions & 0 deletions app/changelog/[...slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { DocBodyChrome } from "@/components/DocBodyChrome";
import { ChangelogFrontMatterProvider } from "@/components/changelog/ChangelogFrontMatterContext";
import type { ChangelogFrontMatter } from "@/components/changelog/ChangelogFrontMatterContext";
import { MainContentWrapper } from "@/components/MainContentWrapper";
import { PageFooterNav } from "@/components/PageFooterNav";
import { getPageFooterItems } from "@/lib/page-footer-nav";

type PageProps = {
params: Promise<{ slug: string[] }>;
Expand All @@ -22,6 +24,15 @@ export default async function ChangelogPostPage(props: PageProps) {
const frontMatter = primitiveOnly(
page.data as unknown as Record<string, unknown>
) as ChangelogFrontMatter;
const footerItems = getPageFooterItems(
changelogSource.getPages().filter((page) => page.url !== "/changelog"),
page.url,
{
getDate: (page) => page.data.date as string | undefined,
getTitle: (page) => page.data.title,
},
);


return (
<ContentColumns footerClassName="xl:max-w-[680px]">
Expand All @@ -32,6 +43,7 @@ export default async function ChangelogPostPage(props: PageProps) {
<MDX components={getMDXComponents()} />
</DocBodyChrome>
</MainContentWrapper>
<PageFooterNav items={footerItems} className="mt-10" />
</ChangelogFrontMatterProvider>
</div>
</ContentColumns>
Expand Down
60 changes: 21 additions & 39 deletions components/Availability.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { Check, X } from "lucide-react";

const plans = [
{ id: "hobby", label: "Hobby" },
{ id: "core", label: "Core" },
Expand All @@ -11,26 +9,20 @@ const plans = [
const availabilities: {
id: string;
label?: string;
shortLabel?: string;
Icon: any;
}[] = [
{
id: "ee",
label: "Enterprise Edition",
shortLabel: "Enterprise",
Icon: Check,
},
{
id: "team-add-on",
label: "Teams Add-on required",
shortLabel: "Team",
Icon: Check,
},
{ id: "full", Icon: Check },
{ id: "private-beta", label: "Private Beta", Icon: Check },
{ id: "public-beta", label: "Public Beta", Icon: Check },
{ id: "not-available", label: "Not Available", Icon: X },
];
{
id: "ee",
label: "Enterprise Edition",
},
{
id: "team-add-on",
label: "Teams Add-on required",
},
{ id: "full", label: "Available" },
{ id: "private-beta", label: "Private Beta" },
{ id: "public-beta", label: "Public Beta" },
{ id: "not-available", label: "Not Available" },
];

export function AvailabilityBanner(props: {
availability: Record<
Comment thread
claude[bot] marked this conversation as resolved.
Expand All @@ -48,30 +40,20 @@ export function AvailabilityBanner(props: {
}));

return (
<div className="border-t border-b py-3 my-4">
<div className="font-semibold text-primary/60 mb-2">
<div className="my-4 border relative border-line-structure bg-surface-bg">
<div className="flex list-none items-center justify-between px-4 py-2 text-text-primary with-stripes border-b border-line-structure">
Where is this feature available?
</div>
<ul className="flex flex-row gap-3 w-full justify-between flex-wrap">
<ul className="grid justify-between px-0! my-0! divide-y md:divide-x md:divide-y-0 md:grid-cols-5 grid-cols-1 not-prose">
{availablePlans.map((plan) => (
<li
key={plan.id}
className="flex flex-row gap-2 md:flex-col md:items-center"
className="grid grid-cols-2 md:grid-cols-1 relative px-4 py-2 md:py-4 not-prose items-center gap-y-1"
>
<div className="font-medium">{plan.label}</div>
<div className="md:flex md:items-center">
<plan.availability.Icon className="w-4 h-4 inline-block mr-1 lg:mr-2" />
{plan.availability.label && (
<span className="hidden md:inline-block text-xs">
({plan.availability.label})
</span>
)}
{plan.availability.shortLabel && (
<span className="inline-block md:hidden text-xs">
({plan.availability.shortLabel})
</span>
)}
</div>
<div className="text-xs font-medium">{plan.label}</div>
<span className="text-xs">
{plan.availability.label}
</span>
</li>
))}
</ul>
Expand Down
4 changes: 1 addition & 3 deletions components/BrandAssets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ export function BrandDownloadButton() {
type BrandAssetVariant = "light" | "dark";

interface BrandAssetCardProps {
href: string;
src: string;
alt: string;
label: string;
Expand All @@ -38,7 +37,6 @@ interface BrandAssetCardProps {
}

export function BrandAssetCard({
href,
src,
alt,
label,
Expand All @@ -48,7 +46,7 @@ export function BrandAssetCard({
return (
<a
download
href={href}
href={src}
className="block no-underline relative group border border-line-structure bg-surface-bg rounded-[2px] corner-box-corners--hover corner-box-hover-stripes transition-[background] duration-180 ease-out"
>
<div
Expand Down
83 changes: 83 additions & 0 deletions components/Details.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
"use client";

import * as React from "react";

import { cn } from "@/lib/utils";

type DetailsProps = React.DetailedHTMLProps<
React.DetailsHTMLAttributes<HTMLDetailsElement>,
HTMLDetailsElement
>;

type SummaryProps = React.DetailedHTMLProps<
React.HTMLAttributes<HTMLElement>,
HTMLElement
>;

const DetailsContext = React.createContext<{ isOpen: boolean } | null>(null);

export function Details({
children,
className,
open,
onToggle,
...props
}: DetailsProps) {
const [isOpen, setIsOpen] = React.useState(Boolean(open));

React.useEffect(() => {
setIsOpen(Boolean(open));
}, [open]);

return (
<DetailsContext.Provider value={{ isOpen }}>
<div
className={cn(
"relative my-4 border border-line-structure bg-surface-bg",
isOpen ? "corner-box-corners" : "corner-box-corners--hover"
)}
>
<details
className={cn(
"group relative overflow-hidden bg-surface-bg [&_summary~*]:px-4 [&_summary~*]:text-text-secondary [&_summary+*]:pt-4 [&_summary~*:last-child]:pb-4 [&_summary~p:first-of-type]:mt-0 [&_summary~p:last-of-type]:mb-0",
className
)}
open={open}
onToggle={(event) => {
setIsOpen(event.currentTarget.open);
onToggle?.(event);
}}
{...props}
>
{children}
</details>
</div>
</DetailsContext.Provider>
);
}

export function Summary({ children, className, ...props }: SummaryProps) {
const context = React.useContext(DetailsContext);

return (
<summary
className={cn(
"flex list-none items-center justify-between gap-4 px-4 py-2 text-text-primary cursor-pointer [&::-webkit-details-marker]:hidden",
context?.isOpen ? "with-stripes border-b border-line-structure" : "hover:bg-surface-1",
className
)}
{...props}
>
<span>{children}</span>
<div
aria-hidden
className={cn(
"shrink-0 text-base leading-none w-3 text-center select-none",
context?.isOpen ? "text-text-primary" : "text-text-tertiary"
)}
>
{context?.isOpen ? "-" : "+"}
</div>
</summary>
);
}
57 changes: 9 additions & 48 deletions components/DocsFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,13 @@

import { useMemo } from "react";
import { usePathname } from "next/navigation";
import { ArrowLeft, ArrowRight } from "lucide-react";
import { useFooterItems } from "fumadocs-ui/utils/use-footer-items";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";

type FooterItem = {
name: string;
description?: string;
url: string;
};
import { PageFooterNav, type PageFooterNavItem } from "./PageFooterNav";

type DocsFooterProps = React.ComponentProps<"div"> & {
items?: {
previous?: FooterItem;
next?: FooterItem;
previous?: PageFooterNavItem;
next?: PageFooterNavItem;
};
};

Expand All @@ -42,47 +34,16 @@ export function DocsFooter({ items, className, ...props }: DocsFooterProps) {
if (currentIndex === -1) return {};

return {
previous: footerItems[currentIndex - 1] as FooterItem | undefined,
next: footerItems[currentIndex + 1] as FooterItem | undefined,
previous: footerItems[currentIndex - 1] as PageFooterNavItem | undefined,
next: footerItems[currentIndex + 1] as PageFooterNavItem | undefined,
};
}, [footerItems, items, pathname]);

const { previous, next } = resolvedItems;

if (!previous && !next) return null;

return (
<div
className={cn("flex flex-col sm:flex-row gap-2", className)}
<PageFooterNav
items={resolvedItems}
className={className}
{...props}
>
{previous ? (
<Button
href={previous.url}
variant="secondary"
size="small"
wrapperClassName="flex-1 min-w-0 sm:max-w-[50%]"
icon={<ArrowLeft className="h-3.5 w-3.5" />}
>
{previous.name}
</Button>
) : (
<div className="hidden sm:block flex-1" />
)}

{next ? (
<Button
href={next.url}
variant="secondary"
size="small"
className="!justify-end"
wrapperClassName="flex-1 min-w-0 sm:max-w-[50%] sm:ml-auto"
icon={<ArrowRight className="h-3.5 w-3.5" />}
iconPosition="end"
>
{next.name}
</Button>
) : null}
</div>
/>
);
}
Loading
Loading