deliver.ui

Installation

Every component assumes a Next.js app with Tailwind, shadcn/ui and Framer Motion. Set that up once, then copy any component in.

  1. 1

    Create a Next.js app

    npx create-next-app@latest my-app --typescript --tailwind --app
  2. 2

    Add shadcn/ui

    npx shadcn@latest init
  3. 3

    Add Framer Motion

    npm install motion

    Framer Motion is published as motion now. Import it from motion/react.

  4. 4

    Add the shared helpers

    The pieces every component builds on: the class merger, the shared springs, the button, the scroll helpers. Save them at these paths once.

    src/components/ui/button.tsx

    import * as React from "react";
    import { Slot } from "@radix-ui/react-slot";
    import { cva, type VariantProps } from "class-variance-authority";
    import { cn } from "@/lib/utils";
    
    // Deliver's button (deliverwebsite.com .btn): hover sweeps a light across the face,
    // press pushes it 2px down onto its edge.
    const DELIVER_BUTTON =
      "group relative isolate gap-1.5 overflow-hidden rounded-lg font-semibold transition-all duration-200 active:translate-y-0.5 active:duration-75 before:absolute before:inset-0 before:-z-10 before:-translate-x-full before:bg-linear-105 before:from-transparent before:from-35% before:to-transparent before:to-65% before:transition-transform before:duration-1400 hover:before:translate-x-full";
    
    // shadcn/ui button, plus Deliver's brand and line buttons and the "ink" pill the navbar demos use.
    const buttonVariants = cva(
      "inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-full text-sm font-medium transition-colors outline-none focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
      {
        variants: {
          variant: {
            default: "bg-primary text-primary-foreground hover:bg-primary/90",
            brand: cn(DELIVER_BUTTON, "bg-key text-white shadow-brand before:via-white/25 hover:bg-key-hover active:shadow-brand-pressed"),
            line: cn(DELIVER_BUTTON, "bg-line-face text-foreground shadow-line before:via-foreground/15 hover:bg-line-face-hover active:shadow-line-pressed"),
            ink: "bg-ink text-white hover:bg-primary",
            inverse: "bg-white text-ink hover:bg-white/85",
            outline: "border bg-background hover:bg-muted",
            ghost: "hover:bg-muted",
          },
          size: {
            default: "h-10 px-5",
            sm: "h-8 px-3.5 text-xs",
            lg: "h-12 px-6 text-base",
            icon: "size-10",
          },
        },
        defaultVariants: { variant: "default", size: "default" },
      },
    );
    
    type ButtonProps = React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & { asChild?: boolean };
    
    export function Button({ className, variant, size, asChild = false, ...props }: ButtonProps) {
      const Component = asChild ? Slot : "button";
      return <Component data-slot="button" className={cn(buttonVariants({ variant, size, className }))} {...props} />;
    }
    
    export { buttonVariants };
    
  5. 5

    Copy a component

    Open any component, switch to Code, and copy each file to the same path in your project.