diff --git a/landing/app/docs/[[...slug]]/page.client.tsx b/landing/app/docs/[[...slug]]/page.client.tsx index efb27ed21f..dc38bced9d 100644 --- a/landing/app/docs/[[...slug]]/page.client.tsx +++ b/landing/app/docs/[[...slug]]/page.client.tsx @@ -51,7 +51,7 @@ function useCopyButton( const cache = new Map(); const tocAction = - "inline-flex items-center gap-1.5 px-2 py-1 text-[11px] uppercase tracking-wider whitespace-nowrap transition-all duration-200 text-foreground/50 hover:text-foreground border border-transparent hover:border-foreground/10 hover:bg-foreground/5 cursor-pointer select-none [&_svg]:size-3"; + "inline-flex items-center gap-1.5 px-2 py-1 text-[11px] uppercase tracking-wider whitespace-nowrap transition-all duration-200 text-foreground/60 hover:text-foreground border border-transparent hover:border-foreground/10 hover:bg-foreground/5 cursor-pointer select-none [&_svg]:size-3"; export function LLMCopyButton() { const [isLoading, startTransition] = useTransition(); @@ -211,11 +211,11 @@ export function ViewOptions(props: { markdownUrl: string; githubUrl: string }) { href={item.href} rel="noreferrer noopener" target="_blank" - className="flex items-center gap-2.5 px-2.5 py-2 text-[12px] text-foreground/50 hover:text-foreground hover:bg-foreground/5 transition-colors duration-150 [&_svg]:size-3.5 [&_svg]:shrink-0" + className="flex items-center gap-2.5 px-2.5 py-2 text-[12px] text-foreground/60 hover:text-foreground hover:bg-foreground/5 transition-colors duration-150 [&_svg]:size-3.5 [&_svg]:shrink-0" > {item.icon} {item.title} - + ))} diff --git a/landing/app/globals.css b/landing/app/globals.css index bc11743e15..c9aee3ab77 100644 --- a/landing/app/globals.css +++ b/landing/app/globals.css @@ -759,17 +759,17 @@ html:not([data-anchor-scrolling]) { .docs-layout #nd-page article > div.\@container > a div svg { width: 12px; height: 12px; - opacity: 0.3; + opacity: 0.45; transition: opacity 200ms ease; } .docs-layout #nd-page article > div.\@container > a:hover div svg { - opacity: 0.7; + opacity: 0.8; } .docs-layout #nd-page article > div.\@container > a > p { font-size: 11px; - opacity: 0.35; + opacity: 0.5; font-family: var(--font-sans); letter-spacing: 0; } diff --git a/landing/app/pricing/pricing-client.tsx b/landing/app/pricing/pricing-client.tsx index 707eab30ba..22d1b19458 100644 --- a/landing/app/pricing/pricing-client.tsx +++ b/landing/app/pricing/pricing-client.tsx @@ -239,17 +239,17 @@ function ComparisonCell({ value }: { value: string | boolean }) { if (value === true) return ( - + ); if (value === false) return ( - + ); return ( - + {value} ); @@ -287,7 +287,7 @@ function PricingHero() { Infrastructure -

+

Dashboard, security, audit logs, and more for your auth.

@@ -301,15 +301,15 @@ function PricingHero() { tier.highlight ? "bg-foreground/[0.03]" : "" }`} > -

+

{tier.name}

{tier.price} {tier.note && ( - - {tier.note} - + + {tier.note} + )}

@@ -330,10 +330,10 @@ function PricingHero() { }} className="flex items-baseline justify-between py-1.5 border-b border-dashed border-foreground/[0.06] last:border-0" > - - {item.label} - - + + {item.label} + + {item.value} @@ -350,7 +350,7 @@ function PricingHero() { Contact Sales {/* Tier name + badge */}
-

+

{tier.name}

{isHighlighted && ( - - popular - + + popular + )}
@@ -423,24 +423,24 @@ function PricingCard({ {tier.price}
{tier.priceNote && ( - - {tier.priceNote} - + + {tier.priceNote} + )} {/* Features */}
-

+

{tier.featuresPrefix}

    {tier.features.map((feature) => (
  • - + + {feature} @@ -456,7 +456,7 @@ function PricingCard({ className={`w-full py-2.5 text-center transition-all duration-200 cursor-pointer ${ isHighlighted ? "bg-foreground text-background hover:opacity-90" - : "border border-dashed border-foreground/[0.12] text-foreground/60 dark:text-foreground/40 hover:text-foreground/70 hover:border-foreground/25 hover:bg-foreground/[0.02]" + : "border border-dashed border-foreground/[0.12] text-foreground/70 dark:text-foreground/50 hover:text-foreground/80 hover:border-foreground/25 hover:bg-foreground/[0.02]" }`} > @@ -512,25 +512,25 @@ export function PricingPageClient() { animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.3, delay: 0.05 }} > -

    - - # Framework - -

    +

    + + # Framework + +

    -

    - Community -

    - +

    + Community +

    + open source
    -

    +

    Comprehensive authentication and authorization framework.

    @@ -538,7 +538,7 @@ export function PricingPageClient() {
    Read Docs @@ -567,11 +567,11 @@ export function PricingPageClient() { animate={{ opacity: 1 }} transition={{ duration: 0.4, delay: 0.15 }} > -

    - - # Infrastructure - -

    +

    + + # Infrastructure + +

    {/* Pricing Cards */}
    @@ -587,15 +587,15 @@ export function PricingPageClient() { animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.3, delay: 0.45 }} > -

    - # feature comparison -

    +

    + # feature comparison +

    - {tierLabels.map((name) => ( @@ -603,8 +603,8 @@ export function PricingPageClient() { key={name} className={`text-center text-[10px] uppercase tracking-widest font-mono font-normal py-3 px-3 w-[18%] ${ name === "Pro" - ? "text-foreground/70 bg-foreground/[0.025]" - : "text-foreground/50 dark:text-foreground/30" +? "text-foreground/80 bg-foreground/[0.025]" + : "text-foreground/60 dark:text-foreground/40" }`} > {name} @@ -620,7 +620,7 @@ export function PricingPageClient() { i % 2 === 0 ? "bg-foreground/[0.008]" : "" }`} > - {tierKeys.map((tier) => ( diff --git a/landing/components/docs/custom-sidebar.tsx b/landing/components/docs/custom-sidebar.tsx index 95c39c0cd7..4a0dd84128 100644 --- a/landing/components/docs/custom-sidebar.tsx +++ b/landing/components/docs/custom-sidebar.tsx @@ -27,7 +27,7 @@ export const CustomItem: FC<{ item: PageTreeItem }> = ({ item }) => { ${ active ? "text-foreground bg-foreground/[0.06] border-l-2 border-foreground font-medium" - : "text-muted-foreground hover:text-foreground hover:bg-foreground/[0.04] border-l-2 border-transparent" + : "text-muted-foreground/80 hover:text-foreground hover:bg-foreground/[0.04] border-l-2 border-transparent" } `} > @@ -54,7 +54,7 @@ export const CustomFolder: FC<{ diff --git a/landing/components/docs/docs-sidebar.tsx b/landing/components/docs/docs-sidebar.tsx index 052a617cd8..1bb55068cd 100644 --- a/landing/components/docs/docs-sidebar.tsx +++ b/landing/components/docs/docs-sidebar.tsx @@ -75,13 +75,13 @@ export function DocsSidebar() { @@ -241,13 +241,13 @@ function BranchSwitcher() { "flex w-full items-center gap-2 px-3 py-2 text-[12px] transition-colors", branch === "canary" ? "text-foreground bg-foreground/5" - : "text-foreground/55 hover:text-foreground hover:bg-foreground/3", - )} - onClick={() => switchBranch("canary")} +: "text-foreground/60 hover:text-foreground hover:bg-foreground/3", + )} + onClick={() => switchBranch("canary")} > canary Pre-release @@ -288,7 +288,7 @@ function SidebarSection({ key={`sep-${item.title}-${i}`} className="flex flex-row items-center gap-2 mx-4 lg:mx-7 my-2" > -

    +

    {item.title}

    @@ -301,7 +301,7 @@ function SidebarSection({ key={`group-${item.title}-${i}`} className="flex flex-row items-center gap-2 mx-4 my-1 lg:mx-7" > -

    +

    {item.title}

    @@ -409,7 +409,7 @@ function SubpageLink({ "relative flex items-center pr-4 lg:pr-7 py-1 text-[13px] transition-all duration-150", active ? "text-foreground bg-foreground/6" - : "text-foreground/45 hover:text-foreground/75 hover:bg-foreground/3", + : "text-foreground/55 hover:text-foreground/80 hover:bg-foreground/3", )} > {children} @@ -441,14 +441,14 @@ function SidebarLink({ ${ active ? "text-foreground bg-foreground/6" - : "text-foreground/55 hover:text-foreground/85 hover:bg-foreground/3" + : "text-foreground/65 hover:text-foreground/90 hover:bg-foreground/3" } `} > {icon && ( {icon} @@ -467,7 +467,7 @@ function NewBadge({ isSelected }: { isSelected?: boolean }) { "pointer-events-none no-underline! border-dashed decoration-transparent! rounded-none px-1.5 py-0 text-[9px] uppercase tracking-wider", isSelected ? "border-solid! bg-foreground/10 text-foreground" - : "text-foreground/50 border-foreground/20", + : "text-foreground/55 border-foreground/25", )} variant="outline" > diff --git a/landing/components/docs/mdx-components.tsx b/landing/components/docs/mdx-components.tsx index 02d2887b4d..e1e9cd2928 100644 --- a/landing/components/docs/mdx-components.tsx +++ b/landing/components/docs/mdx-components.tsx @@ -77,7 +77,7 @@ export function APIMethod({ {method} - {path} + {path}
    )}
    {children}
    @@ -187,7 +187,7 @@ function TypeIcon({ type }: { type: string }) { strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" - className={cn(className, "text-foreground/30")} + className={cn(className, "text-foreground/40")} > @@ -263,7 +263,7 @@ function SchemaCodeBlock({
    -
    +			
     				{code}
     			
    @@ -319,24 +319,24 @@ export function DatabaseTable({ strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" - className="text-foreground/40" - > - +className="text-foreground/50" + > + {name ? ( - - table + + table {name} ) : ( - + Table )} {name && ( - + ({fields.length}) )} @@ -357,8 +357,8 @@ export function DatabaseTable({ className={cn( "px-2 py-0.5 font-mono text-[10px] tracking-wide transition-colors cursor-pointer", view === opt.key - ? "text-foreground/70 bg-foreground/[0.05]" - : "text-foreground/50 hover:text-foreground/50", + ? "text-foreground/80 bg-foreground/[0.05]" + : "text-foreground/55 hover:text-foreground/65", )} > {opt.label} @@ -378,8 +378,8 @@ export function DatabaseTable({ className={cn( "px-1.5 py-0.5 font-mono text-[9px] tracking-wide transition-colors cursor-pointer", sqlDialect === d.key - ? "text-foreground/60 bg-foreground/[0.05]" - : "text-foreground/20 hover:text-foreground/40", + ? "text-foreground/70 bg-foreground/[0.05]" + : "text-foreground/35 hover:text-foreground/50", )} > {d.label} @@ -397,8 +397,8 @@ export function DatabaseTable({ className={cn( "px-1.5 py-0.5 font-mono text-[9px] tracking-wide transition-colors cursor-pointer", drizzleProvider === d.key - ? "text-foreground/60 bg-foreground/[0.05]" - : "text-foreground/20 hover:text-foreground/40", + ? "text-foreground/70 bg-foreground/[0.05]" + : "text-foreground/35 hover:text-foreground/50", )} > {d.label} @@ -411,16 +411,16 @@ export function DatabaseTable({ <> {/* Column headers */}
    -
    +
    Field
    -
    +
    Type
    -
    +
    Key
    -
    +
    Description
    @@ -436,7 +436,7 @@ export function DatabaseTable({
    - + {field.type}
    @@ -454,17 +454,17 @@ export function DatabaseTable({ )} {field.isOptional && ( - + ? )} {!field.isPrimaryKey && !field.isForeignKey && !field.isOptional && ( - — + — )}
    -
    +
    {field.description}
    @@ -516,7 +516,7 @@ export function Endpoint({ )} > - {path} + {path}
    ); } @@ -590,7 +590,7 @@ export function DividerText({ children }: { children: ReactNode }) { return (
    -
    +
    {children}
    @@ -602,7 +602,7 @@ export function DividerText({ children }: { children: ReactNode }) { export function GenerateAppleJwt() { return ( -
    +
    See the Apple documentation for generating a client secret JWT.
    ); diff --git a/landing/components/docs/stepper-toc.tsx b/landing/components/docs/stepper-toc.tsx index 2cb9e4bdec..905971da00 100644 --- a/landing/components/docs/stepper-toc.tsx +++ b/landing/components/docs/stepper-toc.tsx @@ -146,7 +146,7 @@ export function StepperTOC({ items, children }: StepperTOCProps) { ? "bg-foreground border-foreground scale-125" : isVisible ? "bg-foreground/50 border-foreground/50" - : "bg-transparent border-foreground/20 group-hover:border-foreground/40" + : "bg-transparent border-foreground/30 group-hover:border-foreground/50" } `} /> @@ -157,8 +157,8 @@ export function StepperTOC({ items, children }: StepperTOCProps) { isActive ? "text-foreground" : isVisible - ? "text-foreground/50" - : "text-foreground/30 group-hover:text-foreground/60" +? "text-foreground/60" + : "text-foreground/40 group-hover:text-foreground/65" } `} > @@ -167,7 +167,7 @@ export function StepperTOC({ items, children }: StepperTOCProps) { {i < headings.length - 1 && ( - + / )} @@ -181,7 +181,7 @@ export function StepperTOC({ items, children }: StepperTOCProps) { {children && (
    {headings.length > 0 && ( - + | )} @@ -229,8 +229,8 @@ export function StepperTOC({ items, children }: StepperTOCProps) { {sub.title} diff --git a/landing/components/floating-toolbar.tsx b/landing/components/floating-toolbar.tsx index 75cf635cec..19975c471c 100644 --- a/landing/components/floating-toolbar.tsx +++ b/landing/components/floating-toolbar.tsx @@ -17,7 +17,7 @@ export function FloatingToolbar() { -
    +
    diff --git a/landing/components/landing/halftone-bg.tsx b/landing/components/landing/halftone-bg.tsx index 4b8ba3c470..cecae50133 100644 --- a/landing/components/landing/halftone-bg.tsx +++ b/landing/components/landing/halftone-bg.tsx @@ -1,7 +1,7 @@ // spell-checker:disable "use client"; -import { useEffect, useRef } from "react"; +import { useLayoutEffect, useRef } from "react"; const VERTEX_SHADER = ` attribute vec2 a_position; @@ -139,7 +139,7 @@ export function HalftoneBackground() { const smoothMouseRef = useRef({ x: -1, y: -1 }); const clickRef = useRef({ strength: 0, x: 0, y: 0 }); - useEffect(() => { + useLayoutEffect(() => { const canvas = canvasRef.current; const wrapper = wrapperRef.current; if (!canvas || !wrapper) return; @@ -225,12 +225,10 @@ export function HalftoneBackground() { const draw = () => { const elapsed = (performance.now() - startTime) / 1000; - // Smooth mouse interpolation for fluid feel const lerp = 0.08; const target = mouseRef.current; const smooth = smoothMouseRef.current; if (target.x < 0) { - // Mouse left - smoothly fade out smooth.x += (target.x - smooth.x) * 0.02; smooth.y += (target.y - smooth.y) * 0.02; } else { @@ -238,7 +236,6 @@ export function HalftoneBackground() { smooth.y += (target.y - smooth.y) * lerp; } - // Decay click strength clickRef.current.strength *= 0.96; gl.uniform1f(uTime, elapsed); @@ -247,9 +244,18 @@ export function HalftoneBackground() { gl.uniform1f(uClick, clickRef.current.strength); gl.uniform2f(uClickPos, clickRef.current.x, clickRef.current.y); gl.drawArrays(gl.TRIANGLES, 0, 6); + frameRef.current = requestAnimationFrame(draw); }; + // Draw the first frame synchronously so the canvas has content before paint + gl.uniform1f(uTime, 0); + gl.uniform2f(uResolution, canvas.width, canvas.height); + gl.uniform2f(uMouse, -1, -1); + gl.uniform1f(uClick, 0); + gl.uniform2f(uClickPos, 0, 0); + gl.drawArrays(gl.TRIANGLES, 0, 6); + frameRef.current = requestAnimationFrame(draw); return () => { @@ -268,10 +274,13 @@ export function HalftoneBackground() { return ( ); } diff --git a/landing/components/landing/hero-readme.tsx b/landing/components/landing/hero-readme.tsx index d176a5e71d..06da61ec77 100644 --- a/landing/components/landing/hero-readme.tsx +++ b/landing/components/landing/hero-readme.tsx @@ -1530,11 +1530,11 @@ export function HeroReadMe({ transition={{ duration: 0.4, delay: 0.3 }} className="overflow-y-auto overflow-x-hidden no-scrollbar pt-[30px] pb-0" > -

    +

    README

    -

    +

    Better Auth is an authentication and authorization framework. It provides a comprehensive set of features out of the box and includes a Plugin ecosystem that simplifies adding advanced functionalities and infrastructure to help own your auth at scale.

    @@ -1542,7 +1542,7 @@ export function HeroReadMe({
    - + Trusted By
    @@ -1550,13 +1550,13 @@ export function HeroReadMe({
    - + Features -
    +
    -
    +
    {[ { label: "Framework Agnostic", @@ -1643,7 +1643,7 @@ export function HeroReadMe({ } }} className={cn( - "group/card relative p-4 lg:p-5 border-foreground/[0.1] min-h-[180px] transition-all duration-200 hover:bg-foreground/[0.02] hover:shadow-[inset_0_1px_0_0_rgba(128,128,128,0.1)] hover:z-10", + "group/card relative p-4 lg:p-5 border-foreground/[0.15] min-h-[180px] transition-all duration-200 hover:bg-foreground/[0.02] hover:shadow-[inset_0_1px_0_0_rgba(128,128,128,0.1)] hover:z-10", // Bottom border: all except last; 3-col last row starts at 6 i < 8 && "border-b", i >= 6 && "md:border-b-0", @@ -1673,16 +1673,16 @@ export function HeroReadMe({ -
    - +
    + {String(i + 1).padStart(2, "0")} {feature.label}
    -
    +
    {feature.headline}
    -
    +
    {feature.desc}
    {"logos" in feature && feature.logos && ( diff --git a/landing/components/landing/staggered-nav-files.tsx b/landing/components/landing/staggered-nav-files.tsx index 985911e5ac..bb17d45f79 100644 --- a/landing/components/landing/staggered-nav-files.tsx +++ b/landing/components/landing/staggered-nav-files.tsx @@ -39,7 +39,7 @@ const resourceFiles: NavFileItem[] = [ function DropdownItem({ item }: { item: NavFileItem }) { return (
    - + {item.name}
    @@ -197,7 +197,7 @@ export function StaggeredNavFiles() { } } }} - className="flex items-center justify-center px-4 py-3 text-foreground/65 dark:text-foreground/50 hover:text-foreground/80 transition-colors" + className="flex items-center justify-center px-4 py-3 text-foreground/75 dark:text-foreground/60 hover:text-foreground/85 transition-colors" > {mobileMenuOpen ? ( - {item.name} +: "text-foreground/65 dark:text-foreground/50 group-hover/tab:text-foreground/75" + }`} + > + {item.name} @@ -300,13 +300,13 @@ export function StaggeredNavFiles() { ? "text-foreground" : resourcesOpen ? "text-foreground/80" - : "text-foreground/60 dark:text-foreground/40 group-hover/tab:text-foreground/70" - }`} - > - resources +: "text-foreground/65 dark:text-foreground/50 group-hover/tab:text-foreground/75" + }`} + > + resources setMobileView("nav")} - className="flex items-center gap-2 px-5 py-2.5 text-foreground/55 dark:text-foreground/35 hover:text-foreground/60 transition-colors border-b border-foreground/[0.06]" + className="flex items-center gap-2 px-5 py-2.5 text-foreground/65 dark:text-foreground/45 hover:text-foreground/70 transition-colors border-b border-foreground/[0.06]" > - setMobileDocSection((prev) => +: "text-foreground/70 hover:text-foreground hover:bg-foreground/3", + )} + onClick={() => + setMobileDocSection((prev) => prev === index ? -1 : index, ) } @@ -568,10 +568,10 @@ export function StaggeredNavFiles() { "relative flex items-center gap-2.5 px-5 py-1.5 text-[14px] transition-all duration-150", pathname === section.href ? "text-foreground bg-foreground/6" - : "text-foreground/70 dark:text-foreground/55 hover:text-foreground/85 hover:bg-foreground/3", - )} - > - Overview +: "text-foreground/75 dark:text-foreground/60 hover:text-foreground/90 hover:bg-foreground/3", + )} + > + Overview )} {section.list.map((item, i) => { @@ -581,7 +581,7 @@ export function StaggeredNavFiles() { key={`sep-${item.title}-${i}`} className="flex flex-row items-center gap-2 mx-5 my-2" > -

    +

    {item.title}

    @@ -603,15 +603,15 @@ export function StaggeredNavFiles() { "relative flex items-center gap-2.5 px-5 py-1.5 text-[14px] transition-all duration-150", active ? "text-foreground bg-foreground/6" - : "text-foreground/70 dark:text-foreground/55 hover:text-foreground/85 hover:bg-foreground/3", - )} - > - svg]:size-[14px] transition-colors duration-150", - active - ? "text-foreground" - : "text-foreground/70 dark:text-foreground/55", +: "text-foreground/75 dark:text-foreground/60 hover:text-foreground/90 hover:bg-foreground/3", + )} + > + svg]:size-[14px] transition-colors duration-150", + active + ? "text-foreground" + : "text-foreground/75 dark:text-foreground/60", )} > @@ -625,7 +625,7 @@ export function StaggeredNavFiles() { "pointer-events-none border-dashed rounded-none px-1.5 py-0 text-[9px] uppercase tracking-wider", active ? "border-solid bg-foreground/10 text-foreground" - : "text-foreground/65 dark:text-foreground/50 border-foreground/20", + : "text-foreground/70 dark:text-foreground/55 border-foreground/25", )} variant="outline" > @@ -651,7 +651,7 @@ export function StaggeredNavFiles() {
    + Feature + {row.label}