feat: add version history drawer with release notes
Introduce a footer-triggered Version History drawer with categorized release notes, hardcoded release data, and semver tracking at v0.3.0. Also ships blog blockquote/table styling, site-wide typography, home page image updates, header refinements, and related bug fixes. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -20,7 +20,7 @@ const buttonVariants = cva(
|
||||
ghost:
|
||||
"hover:bg-accent hover:text-foreground dark:hover:bg-[#FCC61D] dark:hover:text-foreground",
|
||||
link:
|
||||
"text-primary underline-offset-4 hover:text-accent hover:underline dark:hover:text-[#FCC61D]",
|
||||
"text-accent underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default: "h-9 px-4 text-sm has-[>svg]:px-3",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { type as typeScale } from "@/lib/typography"
|
||||
|
||||
function Card({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
@@ -32,7 +33,7 @@ function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="card-title"
|
||||
className={cn("leading-none font-semibold", className)}
|
||||
className={cn(typeScale["card-title"], className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
@@ -42,7 +43,7 @@ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="card-description"
|
||||
className={cn("text-muted-foreground text-sm", className)}
|
||||
className={cn(typeScale["card-desc"], className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -73,7 +73,7 @@ function EmptyDescription({ className, ...props }: React.ComponentProps<"p">) {
|
||||
<div
|
||||
data-slot="empty-description"
|
||||
className={cn(
|
||||
"text-muted-foreground [&>a:hover]:text-primary text-sm/relaxed [&>a]:underline [&>a]:underline-offset-4",
|
||||
"text-muted-foreground [&>a]:text-accent text-sm/relaxed [&>a]:underline [&>a]:underline-offset-4 hover:[&>a]:no-underline",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -145,7 +145,7 @@ function FieldDescription({ className, ...props }: React.ComponentProps<"p">) {
|
||||
className={cn(
|
||||
"text-muted-foreground text-sm leading-normal font-normal group-has-[[data-orientation=horizontal]]/field:text-balance",
|
||||
"last:mt-0 nth-last-2:-mt-1 [[data-variant=legend]+&]:-mt-1.5",
|
||||
"[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4",
|
||||
"[&>a]:text-accent [&>a]:underline [&>a]:underline-offset-4 hover:[&>a]:no-underline",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -135,7 +135,7 @@ function ItemDescription({ className, ...props }: React.ComponentProps<"p">) {
|
||||
data-slot="item-description"
|
||||
className={cn(
|
||||
"text-muted-foreground line-clamp-2 text-sm leading-normal font-normal text-balance",
|
||||
"[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4",
|
||||
"[&>a]:text-accent [&>a]:underline [&>a]:underline-offset-4 hover:[&>a]:no-underline",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -48,9 +48,12 @@ function SheetContent({
|
||||
className,
|
||||
children,
|
||||
side = "right",
|
||||
closePosition = "end",
|
||||
...props
|
||||
}: React.ComponentProps<typeof SheetPrimitive.Content> & {
|
||||
side?: "top" | "right" | "bottom" | "left"
|
||||
/** Physical corner for the close button. Use `start` for left in LTR / RTL layouts. */
|
||||
closePosition?: "start" | "end"
|
||||
}) {
|
||||
return (
|
||||
<SheetPortal>
|
||||
@@ -72,7 +75,12 @@ function SheetContent({
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<SheetPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none">
|
||||
<SheetPrimitive.Close
|
||||
className={cn(
|
||||
"ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none",
|
||||
closePosition === "start" ? "left-4" : "right-4"
|
||||
)}
|
||||
>
|
||||
<XIcon className="size-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</SheetPrimitive.Close>
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
import * as React from "react";
|
||||
import { Slot } from "@radix-ui/react-slot";
|
||||
|
||||
import {
|
||||
typographyVariants,
|
||||
type TypographyVariant,
|
||||
} from "@/lib/typography";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const defaultElement: Record<TypographyVariant, React.ElementType> = {
|
||||
display: "h1",
|
||||
h1: "h1",
|
||||
h2: "h2",
|
||||
h3: "h3",
|
||||
h4: "h4",
|
||||
"body-lg": "p",
|
||||
body: "p",
|
||||
"body-sm": "p",
|
||||
caption: "span",
|
||||
eyebrow: "p",
|
||||
label: "span",
|
||||
nav: "span",
|
||||
"nav-mobile": "span",
|
||||
"card-title": "h3",
|
||||
"card-desc": "p",
|
||||
chat: "p",
|
||||
code: "code",
|
||||
stat: "span",
|
||||
link: "span",
|
||||
"section-intro": "p",
|
||||
emphasis: "p",
|
||||
"list-title": "span",
|
||||
"cta-title": "h2",
|
||||
"display-mono": "span",
|
||||
};
|
||||
|
||||
export type TypographyProps = {
|
||||
variant: TypographyVariant;
|
||||
as?: React.ElementType;
|
||||
asChild?: boolean;
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
} & React.HTMLAttributes<HTMLElement>;
|
||||
|
||||
export function Typography({
|
||||
variant,
|
||||
as,
|
||||
asChild = false,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: TypographyProps) {
|
||||
const Comp = asChild ? Slot : (as ?? defaultElement[variant] ?? "p");
|
||||
|
||||
return (
|
||||
<Comp
|
||||
className={cn(typographyVariants({ variant }), className)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</Comp>
|
||||
);
|
||||
}
|
||||
|
||||
export {
|
||||
Display,
|
||||
PageTitle,
|
||||
SectionTitle,
|
||||
SubsectionTitle,
|
||||
SmallHeading,
|
||||
BodyLarge,
|
||||
BodyText,
|
||||
BodySmall,
|
||||
Caption,
|
||||
Eyebrow,
|
||||
CardTitleText,
|
||||
CardDescText,
|
||||
};
|
||||
|
||||
function Display(props: Omit<TypographyProps, "variant">) {
|
||||
return <Typography variant="display" {...props} />;
|
||||
}
|
||||
|
||||
function PageTitle(props: Omit<TypographyProps, "variant">) {
|
||||
return <Typography variant="h1" {...props} />;
|
||||
}
|
||||
|
||||
function SectionTitle(props: Omit<TypographyProps, "variant">) {
|
||||
return <Typography variant="h2" {...props} />;
|
||||
}
|
||||
|
||||
function SubsectionTitle(props: Omit<TypographyProps, "variant">) {
|
||||
return <Typography variant="h3" {...props} />;
|
||||
}
|
||||
|
||||
function SmallHeading(props: Omit<TypographyProps, "variant">) {
|
||||
return <Typography variant="h4" {...props} />;
|
||||
}
|
||||
|
||||
function BodyLarge(props: Omit<TypographyProps, "variant">) {
|
||||
return <Typography variant="body-lg" {...props} />;
|
||||
}
|
||||
|
||||
function BodyText(props: Omit<TypographyProps, "variant">) {
|
||||
return <Typography variant="body" {...props} />;
|
||||
}
|
||||
|
||||
function BodySmall(props: Omit<TypographyProps, "variant">) {
|
||||
return <Typography variant="body-sm" {...props} />;
|
||||
}
|
||||
|
||||
function Caption(props: Omit<TypographyProps, "variant">) {
|
||||
return <Typography variant="caption" {...props} />;
|
||||
}
|
||||
|
||||
function Eyebrow(props: Omit<TypographyProps, "variant">) {
|
||||
return <Typography variant="eyebrow" {...props} />;
|
||||
}
|
||||
|
||||
function CardTitleText(props: Omit<TypographyProps, "variant">) {
|
||||
return <Typography variant="card-title" {...props} />;
|
||||
}
|
||||
|
||||
function CardDescText(props: Omit<TypographyProps, "variant">) {
|
||||
return <Typography variant="card-desc" {...props} />;
|
||||
}
|
||||
Reference in New Issue
Block a user