Toolbar Expandable

Expandable toolbar with step-based navigation

Installation

pnpm dlx shadcn@latest add "https://vritti.thesatyajit.com/r/toolbar-expandable"

Dependencies

pnpm add motion

Examples

Controlled

"use client"

import { useState } from "react"
import { FileText, Image, Music, Video } from "lucide-react"

import { Button } from "@/components/vritti/button"
import ToolbarExpandable from "@/components/vritti/toolbar-expandable"

const mediaSteps = [
  {
    id: "documents",
    title: "Documents",
    description: "Browse and manage your document files.",
    icon: FileText,
    content: (
      <div className="space-y-3">
        <div className="flex items-center justify-between rounded-md border border-border p-3">
          <div className="flex items-center gap-2">
            <FileText className="h-4 w-4 text-blue-500" />
            <span className="text-sm">report-2024.pdf</span>
          </div>
          <span className="text-xs text-muted-foreground">2.4 MB</span>
        </div>
        <div className="flex items-center justify-between rounded-md border border-border p-3">
          <div className="flex items-center gap-2">
            <FileText className="h-4 w-4 text-blue-500" />
            <span className="text-sm">notes.docx</span>
          </div>
          <span className="text-xs text-muted-foreground">128 KB</span>
        </div>
      </div>
    ),
  },
  {
    id: "images",
    title: "Images",
    description: "View and organize your image library.",
    icon: Image,
    content: (
      <div className="grid grid-cols-3 gap-2">
        {["bg-blue-100", "bg-green-100", "bg-purple-100", "bg-orange-100", "bg-pink-100", "bg-yellow-100"].map(
          (color, i) => (
            <div
              key={i}
              className={`${color} dark:opacity-50 aspect-square rounded-md flex items-center justify-center`}
            >
              <Image className="h-4 w-4 text-muted-foreground" />
            </div>
          )
        )}
      </div>
    ),
  },
  {
    id: "videos",
    title: "Videos",
    description: "Access your video collection.",
    icon: Video,
    content: (
      <div className="space-y-3">
        <div className="flex items-center justify-between rounded-md border border-border p-3">
          <div className="flex items-center gap-2">
            <Video className="h-4 w-4 text-red-500" />
            <span className="text-sm">intro-video.mp4</span>
          </div>
          <span className="text-xs text-muted-foreground">24 MB</span>
        </div>
      </div>
    ),
  },
  {
    id: "audio",
    title: "Audio",
    description: "Manage your audio files and playlists.",
    icon: Music,
    content: (
      <div className="space-y-3">
        <div className="flex items-center justify-between rounded-md border border-border p-3">
          <div className="flex items-center gap-2">
            <Music className="h-4 w-4 text-green-500" />
            <span className="text-sm">podcast-ep1.mp3</span>
          </div>
          <span className="text-xs text-muted-foreground">8.2 MB</span>
        </div>
      </div>
    ),
  },
]

export function ToolbarExpandableControlled() {
  const [expanded, setExpanded] = useState(false)
  const [activeStep, setActiveStep] = useState<string | null>(null)

  return (
    <div className="max-w-2xl mx-auto space-y-4">
      <div className="flex items-center gap-2 justify-center">
        <Button
          variant="outline"
          size="sm"
          onClick={() => {
            setExpanded(!expanded)
            if (expanded) {
              setActiveStep(null)
            } else {
              setActiveStep("documents")
            }
          }}
        >
          {expanded ? "Collapse" : "Expand"}
        </Button>
        <Button
          variant="outline"
          size="sm"
          onClick={() => {
            setActiveStep(null)
            setExpanded(false)
          }}
        >
          Reset
        </Button>
      </div>
      <ToolbarExpandable
        steps={mediaSteps}
        expanded={expanded}
        onExpandedChange={setExpanded}
        activeStep={activeStep}
        onActiveStepChange={setActiveStep}
      />
      <p className="text-center text-xs text-muted-foreground">
        Active: {activeStep ?? "none"} &middot;{" "}
        {expanded ? "Expanded" : "Collapsed"}
      </p>
    </div>
  )
}

Deployment

"use client"

import {
  CheckCircle,
  Code,
  Database,
  Palette,
  Rocket,
  Settings,
  Upload,
} from "lucide-react"

import { Button } from "@/components/vritti/button"
import ToolbarExpandable from "@/components/vritti/toolbar-expandable"

const deploymentSteps = [
  {
    id: "setup",
    title: "Project Setup",
    description:
      "Initialize your project with the required dependencies and configuration.",
    icon: Settings,
    content: (
      <div className="space-y-4">
        <div className="space-y-2">
          <label htmlFor="project-name" className="text-sm font-medium block">
            Project Name
          </label>
          <input
            id="project-name"
            placeholder="my-awesome-app"
            className="flex h-10 w-full rounded-md border border-border bg-background px-3 py-2 text-sm"
          />
        </div>
        <div className="space-y-2">
          <label className="text-sm font-medium block">Framework</label>
          <select className="w-full h-10 px-3 border border-border rounded-md bg-background text-sm">
            <option>Next.js</option>
            <option>React</option>
            <option>Vue.js</option>
          </select>
        </div>
        <Button className="w-full">
          <Code className="w-4 h-4 mr-2" />
          Initialize Project
        </Button>
      </div>
    ),
  },
  {
    id: "configure",
    title: "Configuration",
    description:
      "Set up environment variables and project settings for optimal performance.",
    icon: Database,
    content: (
      <div className="space-y-4">
        <div className="space-y-2">
          <label htmlFor="api-key" className="text-sm font-medium block">
            API Key
          </label>
          <input
            id="api-key"
            type="password"
            placeholder="Enter your API key"
            className="flex h-10 w-full rounded-md border border-border bg-background px-3 py-2 text-sm"
          />
        </div>
        <div className="space-y-2">
          <label htmlFor="database-url" className="text-sm font-medium block">
            Database URL
          </label>
          <input
            id="database-url"
            placeholder="postgresql://..."
            className="flex h-10 w-full rounded-md border border-border bg-background px-3 py-2 text-sm"
          />
        </div>
        <Button variant="outline" className="w-full bg-transparent">
          <Settings className="w-4 h-4 mr-2" />
          Save Configuration
        </Button>
      </div>
    ),
  },
  {
    id: "customize",
    title: "Customize Design",
    description:
      "Personalize your application's appearance and branding elements.",
    icon: Palette,
    content: (
      <div className="space-y-4">
        <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
          <div className="space-y-2">
            <label className="text-sm font-medium block">Primary Color</label>
            <div className="flex gap-2">
              <div className="w-8 h-8 bg-blue-500 rounded-md border-2 border-blue-600"></div>
              <div className="w-8 h-8 bg-green-500 rounded-md"></div>
              <div className="w-8 h-8 bg-purple-500 rounded-md"></div>
            </div>
          </div>
          <div className="space-y-2">
            <label className="text-sm font-medium block">Theme</label>
            <select className="w-full h-10 px-3 border border-border rounded-md bg-background text-sm">
              <option>Light</option>
              <option>Dark</option>
              <option>Auto</option>
            </select>
          </div>
        </div>
        <Button variant="outline" className="w-full bg-transparent">
          <Palette className="w-4 h-4 mr-2" />
          Apply Theme
        </Button>
      </div>
    ),
  },
  {
    id: "upload",
    title: "Upload Assets",
    description:
      "Upload your project files, images, and other assets to the platform.",
    icon: Upload,
    content: (
      <div className="space-y-4">
        <div className="border-2 border-dashed border-gray-300 rounded-lg p-6 text-center">
          <Upload className="w-8 h-8 mx-auto mb-2 text-gray-400" />
          <p className="text-sm text-gray-600 mb-2">
            Drag and drop files here
          </p>
          <Button variant="outline" size="sm">
            Choose Files
          </Button>
        </div>
        <Button className="w-full">
          <Upload className="w-4 h-4 mr-2" />
          Upload Assets
        </Button>
      </div>
    ),
  },
  {
    id: "deploy",
    title: "Deploy",
    description:
      "Deploy your application to production with automatic scaling and monitoring.",
    icon: Rocket,
    content: (
      <div className="space-y-4">
        <div className="bg-green-50 border border-green-200 rounded-lg p-4">
          <div className="flex items-center gap-2 mb-2">
            <CheckCircle className="w-5 h-5 text-green-600" />
            <span className="font-medium text-green-800">Ready to Deploy</span>
          </div>
          <p className="text-sm text-green-700">
            All checks passed. Your application is ready for production
            deployment.
          </p>
        </div>
        <div className="space-y-2">
          <label className="text-sm font-medium block">
            Deployment Region
          </label>
          <select className="w-full h-10 px-3 border border-border rounded-md bg-background text-sm">
            <option>US East (Virginia)</option>
            <option>US West (California)</option>
            <option>Europe (Frankfurt)</option>
            <option>Asia Pacific (Singapore)</option>
          </select>
        </div>
        <Button className="w-full bg-green-600 hover:bg-green-700">
          <Rocket className="w-4 h-4 mr-2" />
          Deploy to Production
        </Button>
      </div>
    ),
  },
]

export function ToolbarExpandableDeployment() {
  return (
    <div className="max-w-2xl mx-auto">
      <ToolbarExpandable steps={deploymentSteps} />
    </div>
  )
}