"use client"
import type React from "react"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Badge } from "@/components/ui/badge"
import { useState, useRef, useEffect } from "react"
// Define our spacing scale in rem units
const spacingScale = [
{ name: "0.25rem", value: "0.25rem", tailwind: "1", px: "4px", description: "Tight spacing" },
{ name: "0.5rem", value: "0.5rem", tailwind: "2", px: "8px", description: "Small spacing" },
{ name: "0.75rem", value: "0.75rem", tailwind: "3", px: "12px", description: "Compact spacing" },
{ name: "1rem", value: "1rem", tailwind: "4", px: "16px", description: "Base spacing" },
{ name: "1.25rem", value: "1.25rem", tailwind: "5", px: "20px", description: "Comfortable spacing" },
{ name: "1.5rem", value: "1.5rem", tailwind: "6", px: "24px", description: "Relaxed spacing" },
{ name: "2rem", value: "2rem", tailwind: "8", px: "32px", description: "Section spacing" },
{ name: "2.5rem", value: "2.5rem", tailwind: "10", px: "40px", description: "Large spacing" },
{ name: "3rem", value: "3rem", tailwind: "12", px: "48px", description: "Extra large spacing" },
{ name: "4rem", value: "4rem", tailwind: "16", px: "64px", description: "Maximum spacing" },
]
// Spacing Notation Component
function SpacingNotation({
value,
direction = "all",
label,
color = "primary",
}: {
value: string
direction?: "top" | "bottom" | "left" | "right" | "horizontal" | "vertical" | "all"
label?: string
color?: "primary" | "secondary" | "accent" | "muted"
}) {
const colorClasses = {
primary: "border-primary bg-primary/10 text-primary",
secondary: "border-orange-500 bg-orange-500/10 text-orange-600",
accent: "border-green-500 bg-green-500/10 text-green-600",
muted: "border-muted-foreground bg-muted text-muted-foreground",
}
const directionSymbols = {
top: "↑",
bottom: "↓",
left: "←",
right: "→",
horizontal: "↔",
vertical: "↕",
all: "⊞",
}
return (
{directionSymbols[direction]}
{value}
{label && ({label})}
)
}
// Interactive Annotated Component with precise positioning
function InteractiveAnnotatedComponent({
children,
spacingAreas = [],
title,
}: {
children: React.ReactNode
spacingAreas?: Array<{
type: "padding" | "margin" | "gap"
value: string
direction?: "top" | "bottom" | "left" | "right" | "horizontal" | "vertical" | "all"
selector: string // CSS selector to target the specific element
spacingType: "padding" | "margin" | "gap"
label?: string
description?: string
}>
title: string
}) {
const [hoveredArea, setHoveredArea] = useState(null)
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 })
const [overlayPositions, setOverlayPositions] = useState<
Array<{ top: number; left: number; width: number; height: number }>
>([])
const containerRef = useRef(null)
// Calculate overlay positions based on actual DOM elements
useEffect(() => {
if (!containerRef.current) return
const positions = spacingAreas.map((area) => {
const element = containerRef.current?.querySelector(area.selector) as HTMLElement
if (!element) return { top: 0, left: 0, width: 0, height: 0 }
const containerRect = containerRef.current!.getBoundingClientRect()
const elementRect = element.getBoundingClientRect()
// Get computed styles to calculate actual spacing
const computedStyle = window.getComputedStyle(element)
let overlayRect = {
top: elementRect.top - containerRect.top,
left: elementRect.left - containerRect.left,
width: elementRect.width,
height: elementRect.height,
}
// Adjust overlay based on spacing type
if (area.spacingType === "padding") {
// For padding, highlight the inner content area
const paddingTop = Number.parseFloat(computedStyle.paddingTop)
const paddingLeft = Number.parseFloat(computedStyle.paddingLeft)
const paddingRight = Number.parseFloat(computedStyle.paddingRight)
const paddingBottom = Number.parseFloat(computedStyle.paddingBottom)
overlayRect = {
top: overlayRect.top + paddingTop,
left: overlayRect.left + paddingLeft,
width: overlayRect.width - paddingLeft - paddingRight,
height: overlayRect.height - paddingTop - paddingBottom,
}
} else if (area.spacingType === "margin") {
// For margin, highlight the margin area around the element
const marginTop = Number.parseFloat(computedStyle.marginTop)
const marginLeft = Number.parseFloat(computedStyle.marginLeft)
const marginRight = Number.parseFloat(computedStyle.marginRight)
const marginBottom = Number.parseFloat(computedStyle.marginBottom)
overlayRect = {
top: overlayRect.top - marginTop,
left: overlayRect.left - marginLeft,
width: overlayRect.width + marginLeft + marginRight,
height: overlayRect.height + marginTop + marginBottom,
}
}
return overlayRect
})
setOverlayPositions(positions)
}, [spacingAreas])
const handleMouseMove = (e: React.MouseEvent) => {
const rect = e.currentTarget.getBoundingClientRect()
setMousePosition({
x: e.clientX - rect.left,
y: e.clientY - rect.top,
})
}
const getAreaColor = (type: "padding" | "margin" | "gap") => {
switch (type) {
case "padding":
return "bg-primary/30 border-primary border-2"
case "margin":
return "bg-orange-500/30 border-orange-500 border-2"
case "gap":
return "bg-green-500/30 border-green-500 border-2"
}
}
const getNotationColor = (type: "padding" | "margin" | "gap") => {
switch (type) {
case "padding":
return "primary" as const
case "margin":
return "secondary" as const
case "gap":
return "accent" as const
}
}
return (
{title}
setHoveredArea(null)}
>
{/* Component */}
{children}
{/* Interactive spacing overlays */}
{overlayPositions.map((position, index) => (
setHoveredArea(index)}
onMouseLeave={() => setHoveredArea(null)}
/>
))}
{/* Tooltip */}
{hoveredArea !== null && (
200 ? "translateX(-100%)" : "none",
}}
>
{spacingAreas[hoveredArea].type}
{spacingAreas[hoveredArea].description && ` • ${spacingAreas[hoveredArea].description}`}
)}
)
}
export function SpacingSection() {
const [selectedExample, setSelectedExample] = useState("button")
return (
Spacing
Our spacing system uses a consistent scale based on rem units. Hover over components below to explore their
spacing interactively.
{/* Notation System Legend */}
Interactive Spacing Notation
Directions
Top
Bottom
Left
Right
Horizontal
Vertical
How to Use
• Hover over components to see spacing
• Colored overlays show spacing areas
• Tooltips display exact values
• Direction arrows indicate application
{/* Spacing Scale */}
Spacing Scale
{spacingScale.map((spacing, index) => (
{/* Value and Tailwind class */}
{spacing.name}
{spacing.tailwind}
({spacing.px})
{/* Visual representation */}
))}
{/* Interactive Component Examples */}
Interactive Examples
{["button", "card", "form"].map((example) => (
))}
Hover over the components below to explore their spacing interactively.
{selectedExample === "button" && (
)}
{selectedExample === "card" && (
Card Title
Card content with consistent internal spacing for optimal readability and visual hierarchy.
)}
{selectedExample === "form" && (
)}
{/* Additional Interactive Examples */}
Component Spacing Patterns
Design
Development
Featured
Urgent
{/* Usage Guidelines */}
Spacing Guidelines
Component padding
Use 1rem (16px) for default internal spacing
Related elements
Use 1rem (16px) gap between related items
Section spacing
Use 2rem (32px) between distinct sections
Interactive exploration
Hover over components to understand their spacing structure
Consistency
Maintain consistent spacing within component types
Responsive scaling
Consider reducing spacing on smaller screens
)
}