media-query-debugger
Version:
Advanced responsive debugger and responsive design testing tool with device mockups, media query monitoring, and debugging features for React applications
1 lines • 39.1 kB
Source Map (JSON)
{"version":3,"sources":["../src/components/ResponsiveDebugger.tsx","../src/hooks/useViewport.ts","../src/hooks/useBreakpoint.ts","../src/hooks/useMediaQuery.ts","../src/constants/index.ts","../src/lib/utils.ts","../src/components/DebuggerPanel.tsx","../src/components/ErrorBoundary.tsx","../src/components/DeviceMockup.tsx"],"sourcesContent":["\"use client\"\n\nimport { useState, useEffect } from \"react\"\nimport { Monitor } from \"lucide-react\"\nimport type { ResponsiveDebuggerProps } from \"../types\"\nimport { useViewport } from \"../hooks/useViewport\"\nimport { useBreakpoint } from \"../hooks/useBreakpoint\"\nimport { DEFAULT_BREAKPOINTS, DEFAULT_DEVICES, KEYBOARD_SHORTCUTS } from \"../constants\"\nimport { cn } from \"../lib/utils\"\nimport { DebuggerPanel } from \"./DebuggerPanel\"\nimport { ErrorBoundary } from \"./ErrorBoundary\"\n\nexport function ResponsiveDebugger({\n breakpoints = DEFAULT_BREAKPOINTS,\n devices = DEFAULT_DEVICES,\n position = \"bottom-right\",\n theme = \"dark\",\n defaultOpen = false,\n className,\n style,\n onBreakpointChange,\n onViewportChange,\n enableKeyboardShortcuts = true,\n keyboardShortcuts = KEYBOARD_SHORTCUTS,\n}: ResponsiveDebuggerProps) {\n const [isOpen, setIsOpen] = useState(defaultOpen)\n const [isMinimized, setIsMinimized] = useState(false)\n\n const viewport = useViewport()\n const breakpoint = useBreakpoint({ breakpoints })\n\n // Handle keyboard shortcuts\n useEffect(() => {\n if (!enableKeyboardShortcuts) return\n\n const handleKeyDown = (event: KeyboardEvent) => {\n const { toggle, close } = keyboardShortcuts\n\n if (event.key === \"Escape\" && close === \"escape\" && isOpen) {\n setIsOpen(false)\n return\n }\n\n // Handle toggle shortcut (cmd+shift+d by default)\n if (toggle === \"cmd+shift+d\" && event.metaKey && event.shiftKey && event.key === \"D\") {\n event.preventDefault()\n setIsOpen(!isOpen)\n }\n }\n\n document.addEventListener(\"keydown\", handleKeyDown)\n return () => document.removeEventListener(\"keydown\", handleKeyDown)\n }, [enableKeyboardShortcuts, keyboardShortcuts, isOpen])\n\n // Notify parent components of changes\n useEffect(() => {\n onBreakpointChange?.(breakpoint.current)\n }, [breakpoint.current, onBreakpointChange])\n\n useEffect(() => {\n onViewportChange?.(viewport)\n }, [viewport, onViewportChange])\n\n const getPositionClasses = () => {\n switch (position) {\n case \"top-left\":\n return \"top-6 left-6\"\n case \"top-right\":\n return \"top-6 right-6\"\n case \"bottom-left\":\n return \"bottom-6 left-6\"\n case \"bottom-right\":\n default:\n return \"bottom-6 right-6\"\n }\n }\n\n const getBadgePosition = () => {\n switch (position) {\n case \"top-left\":\n return \"top-24 left-6\"\n case \"top-right\":\n return \"top-24 right-6\"\n case \"bottom-left\":\n return \"bottom-24 left-6\"\n case \"bottom-right\":\n default:\n return \"bottom-24 right-6\"\n }\n }\n\n if (!isOpen) {\n return (\n <ErrorBoundary>\n {/* Floating Trigger Button */}\n <button\n onClick={() => setIsOpen(true)}\n className={cn(\n \"fixed z-50 w-16 h-16 rounded-full shadow-2xl transition-all duration-200 hover:scale-105\",\n \"bg-gradient-to-r from-slate-700 to-slate-800 hover:from-slate-600 hover:to-slate-700\",\n \"border border-slate-600/50 backdrop-blur-sm\",\n \"flex items-center justify-center\",\n getPositionClasses(),\n className,\n )}\n style={style}\n title=\"Open Breakpoint Debugger (⌘⇧D)\"\n >\n <Monitor className=\"w-7 h-7 text-slate-200\" />\n </button>\n\n {/* Mini Status Badge */}\n <div className={cn(\"fixed z-50\", getBadgePosition())}>\n <div className=\"bg-slate-900/90 text-slate-200 backdrop-blur-sm border border-slate-700/50 px-3 py-1 rounded-full text-sm font-mono\">\n {breakpoint.current.toUpperCase()} • {viewport.width}×{viewport.height}\n </div>\n </div>\n </ErrorBoundary>\n )\n }\n\n return (\n <ErrorBoundary>\n <div className={cn(\"fixed z-50\", getPositionClasses(), className)} style={style}>\n <DebuggerPanel\n breakpoints={breakpoints}\n devices={devices}\n viewport={viewport}\n breakpoint={breakpoint}\n theme={theme}\n isMinimized={isMinimized}\n onMinimize={setIsMinimized}\n onClose={() => setIsOpen(false)}\n />\n </div>\n </ErrorBoundary>\n )\n}\n","\"use client\"\n\nimport { useState, useEffect } from \"react\"\nimport type { ViewportInfo } from \"../types\"\n\nexport function useViewport(): ViewportInfo {\n const [viewport, setViewport] = useState<ViewportInfo>({\n width: 0,\n height: 0,\n aspectRatio: 0,\n devicePixelRatio: 1,\n orientation: \"portrait\",\n })\n\n useEffect(() => {\n if (typeof window === \"undefined\") return\n\n const updateViewport = () => {\n const width = window.innerWidth\n const height = window.innerHeight\n\n setViewport({\n width,\n height,\n aspectRatio: width / height,\n devicePixelRatio: window.devicePixelRatio || 1,\n orientation: width > height ? \"landscape\" : \"portrait\",\n })\n }\n\n // Set initial value\n updateViewport()\n\n // Listen for resize events\n window.addEventListener(\"resize\", updateViewport)\n window.addEventListener(\"orientationchange\", updateViewport)\n\n return () => {\n window.removeEventListener(\"resize\", updateViewport)\n window.removeEventListener(\"orientationchange\", updateViewport)\n }\n }, [])\n\n return viewport\n}\n","\"use client\"\n\nimport { useState, useEffect } from \"react\"\nimport { useMediaQuery } from \"./useMediaQuery\"\nimport type { BreakpointHookOptions } from \"../types\"\nimport { DEFAULT_BREAKPOINTS } from \"../constants\"\n\nexport function useBreakpoint(options: BreakpointHookOptions = {}) {\n const { breakpoints = DEFAULT_BREAKPOINTS, defaultBreakpoint = \"xs\" } = options\n\n const [currentBreakpoint, setCurrentBreakpoint] = useState(defaultBreakpoint)\n const breakpointQueries = Object.entries(breakpoints).map(([name, width]) => ({\n name,\n width,\n }))\n\n const queries = breakpointQueries.map((bp) => useMediaQuery(`(min-width: ${bp.width}px)`))\n\n useEffect(() => {\n // Find the largest matching breakpoint\n const matchingBreakpoints = breakpointQueries\n .filter((bp, index) => queries[index])\n .sort((a, b) => b.width - a.width)\n\n const newBreakpoint = matchingBreakpoints.length > 0 ? matchingBreakpoints[0].name : defaultBreakpoint\n\n if (newBreakpoint !== currentBreakpoint) {\n setCurrentBreakpoint(newBreakpoint)\n }\n }, [queries.join(\",\"), currentBreakpoint, defaultBreakpoint])\n\n return {\n current: currentBreakpoint,\n breakpoints: breakpointQueries.reduce(\n (acc, bp, index) => ({\n ...acc,\n [bp.name]: queries[index],\n }),\n {} as Record<string, boolean>,\n ),\n isAbove: (breakpoint: string) => {\n const targetWidth = breakpoints[breakpoint]\n if (!targetWidth) return false\n return breakpointQueries.some((bp, index) => bp.width >= targetWidth && queries[index])\n },\n isBelow: (breakpoint: string) => {\n const targetWidth = breakpoints[breakpoint]\n if (!targetWidth) return false\n return !breakpointQueries.some((bp, index) => bp.width >= targetWidth && queries[index])\n },\n }\n}\n","\"use client\"\n\nimport { useState, useEffect } from \"react\"\nimport type { MediaQueryHookOptions } from \"../types\"\n\nexport function useMediaQuery(query: string, options: MediaQueryHookOptions = {}): boolean {\n const { defaultMatches = false, matchMedia } = options\n\n const [matches, setMatches] = useState(defaultMatches)\n\n useEffect(() => {\n if (typeof window === \"undefined\") return\n\n const mediaQueryList = (matchMedia || window.matchMedia)(query)\n\n const updateMatches = () => setMatches(mediaQueryList.matches)\n\n // Set initial value\n updateMatches()\n\n // Listen for changes\n if (mediaQueryList.addEventListener) {\n mediaQueryList.addEventListener(\"change\", updateMatches)\n return () => mediaQueryList.removeEventListener(\"change\", updateMatches)\n } else {\n // Fallback for older browsers\n mediaQueryList.addListener(updateMatches)\n return () => mediaQueryList.removeListener(updateMatches)\n }\n }, [query, matchMedia])\n\n return matches\n}\n","import type { ResponsiveConfig, Device } from \"../types\"\n\nexport const DEFAULT_BREAKPOINTS: ResponsiveConfig = {\n sm: 640,\n md: 768,\n lg: 1024,\n xl: 1280,\n \"2xl\": 1536,\n}\n\nexport const DEFAULT_DEVICES: Device[] = [\n {\n name: \"iPhone 14 Pro\",\n width: 393,\n height: 852,\n category: \"mobile\",\n pixelRatio: 3,\n userAgent: \"iPhone\",\n },\n {\n name: \"iPhone SE\",\n width: 375,\n height: 667,\n category: \"mobile\",\n pixelRatio: 2,\n userAgent: \"iPhone\",\n },\n {\n name: \"Samsung Galaxy S23\",\n width: 384,\n height: 854,\n category: \"mobile\",\n pixelRatio: 3,\n userAgent: \"Android\",\n },\n {\n name: \"iPad Air\",\n width: 820,\n height: 1180,\n category: \"tablet\",\n pixelRatio: 2,\n userAgent: \"iPad\",\n },\n {\n name: \"iPad Pro 12.9\",\n width: 1024,\n height: 1366,\n category: \"tablet\",\n pixelRatio: 2,\n userAgent: \"iPad\",\n },\n {\n name: \"MacBook Air\",\n width: 1440,\n height: 900,\n category: \"desktop\",\n pixelRatio: 2,\n userAgent: \"MacOS\",\n },\n {\n name: \"MacBook Pro 16\",\n width: 1728,\n height: 1117,\n category: \"desktop\",\n pixelRatio: 2,\n userAgent: \"MacOS\",\n },\n {\n name: \"Desktop 1080p\",\n width: 1920,\n height: 1080,\n category: \"desktop\",\n pixelRatio: 1,\n userAgent: \"Desktop\",\n },\n {\n name: \"Desktop 4K\",\n width: 3840,\n height: 2160,\n category: \"desktop\",\n pixelRatio: 2,\n userAgent: \"Desktop\",\n },\n]\n\nexport const KEYBOARD_SHORTCUTS = {\n toggle: \"cmd+shift+d\",\n close: \"escape\",\n}\n","import { type ClassValue, clsx } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n\nexport function formatViewportSize(width: number, height: number): string {\n return `${width} × ${height}`\n}\n\nexport function getDeviceCategory(width: number): \"mobile\" | \"tablet\" | \"desktop\" {\n if (width < 768) return \"mobile\"\n if (width < 1024) return \"tablet\"\n return \"desktop\"\n}\n\nexport function debounce<T extends (...args: any[]) => any>(func: T, wait: number): (...args: Parameters<T>) => void {\n let timeout: NodeJS.Timeout | null = null\n\n return (...args: Parameters<T>) => {\n if (timeout) clearTimeout(timeout)\n timeout = setTimeout(() => func(...args), wait)\n }\n}\n","\"use client\"\n\nimport { useState } from \"react\"\nimport { Monitor, ChevronDown, ChevronUp, X, Zap, Smartphone, Eye, Settings } from \"lucide-react\"\nimport type { Device, ResponsiveConfig, ViewportInfo } from \"../types\"\nimport { cn } from \"../lib/utils\"\n\ninterface DebuggerPanelProps {\n breakpoints: ResponsiveConfig\n devices: Device[]\n viewport: ViewportInfo\n breakpoint: any\n theme: \"light\" | \"dark\" | \"auto\"\n isMinimized: boolean\n onMinimize: (minimized: boolean) => void\n onClose: () => void\n}\n\nexport function DebuggerPanel({\n breakpoints,\n devices,\n viewport,\n breakpoint,\n theme,\n isMinimized,\n onMinimize,\n onClose,\n}: DebuggerPanelProps) {\n const [activeTab, setActiveTab] = useState(\"breakpoints\")\n\n return (\n <div className=\"w-[420px] max-h-[85vh] overflow-hidden\">\n <div className=\"bg-slate-900/95 backdrop-blur-xl border border-slate-700/50 shadow-2xl rounded-lg\">\n {/* Header */}\n <div className=\"p-4 border-b border-slate-700/50\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <div className=\"w-8 h-8 rounded-lg bg-gradient-to-r from-blue-600/20 to-purple-600/20 flex items-center justify-center\">\n <Monitor className=\"w-4 h-4 text-blue-400\" />\n </div>\n <h3 className=\"text-lg font-semibold text-slate-100\">Breakpoint Debugger</h3>\n </div>\n <div className=\"flex items-center gap-1\">\n <button\n onClick={() => onMinimize(!isMinimized)}\n className=\"w-8 h-8 text-slate-400 hover:text-slate-200 hover:bg-slate-800 rounded flex items-center justify-center transition-colors\"\n >\n {isMinimized ? <ChevronUp className=\"w-4 h-4\" /> : <ChevronDown className=\"w-4 h-4\" />}\n </button>\n <button\n onClick={onClose}\n className=\"w-8 h-8 text-slate-400 hover:text-slate-200 hover:bg-slate-800 rounded flex items-center justify-center transition-colors\"\n >\n <X className=\"w-4 h-4\" />\n </button>\n </div>\n </div>\n\n {/* Status */}\n <div className=\"flex items-center justify-between pt-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"bg-gradient-to-r from-blue-600/20 to-purple-600/20 border border-blue-500/30 text-blue-300 px-2 py-1 rounded text-sm\">\n {breakpoint.current.toUpperCase()}\n </div>\n <span className=\"text-sm font-mono text-slate-400\">\n {viewport.width} × {viewport.height}\n </span>\n </div>\n <div className=\"flex items-center gap-1\">\n <div className=\"w-2 h-2 rounded-full bg-green-400 animate-pulse\" />\n <span className=\"text-xs text-slate-400\">Live</span>\n </div>\n </div>\n </div>\n\n {/* Content */}\n {!isMinimized && (\n <div className=\"p-0\">\n {/* Tabs */}\n <div className=\"grid grid-cols-4 bg-slate-800/50 border-b border-slate-700/50\">\n {[\n { id: \"breakpoints\", label: \"Breakpoints\", icon: Zap },\n { id: \"devices\", label: \"Devices\", icon: Smartphone },\n { id: \"mockups\", label: \"Mockups\", icon: Eye },\n { id: \"tools\", label: \"Tools\", icon: Settings },\n ].map((tab) => {\n const Icon = tab.icon\n return (\n <button\n key={tab.id}\n onClick={() => setActiveTab(tab.id)}\n className={cn(\n \"flex items-center justify-center gap-1 px-3 py-2 text-xs transition-colors\",\n activeTab === tab.id\n ? \"bg-slate-700 text-slate-200\"\n : \"text-slate-400 hover:text-slate-200 hover:bg-slate-800/50\",\n )}\n >\n <Icon className=\"w-3 h-3\" />\n {tab.label}\n </button>\n )\n })}\n </div>\n\n {/* Tab Content */}\n <div className=\"max-h-96 overflow-y-auto p-4\">\n {activeTab === \"breakpoints\" && (\n <div className=\"space-y-4\">\n <div className=\"space-y-3\">\n <h4 className=\"text-sm font-medium text-slate-200\">Current Breakpoint</h4>\n <div className=\"flex items-center gap-1 h-4\">\n {Object.entries(breakpoints).map(([name, width]) => (\n <div\n key={name}\n className={cn(\n \"h-full flex-1 rounded-sm transition-all duration-300\",\n breakpoint.current === name\n ? \"bg-gradient-to-r from-blue-500 to-purple-500\"\n : \"bg-slate-600\",\n )}\n title={`${name}: ${width}px`}\n />\n ))}\n </div>\n <div className=\"flex justify-between text-xs text-slate-500\">\n <span>xs</span>\n {Object.keys(breakpoints).map((name) => (\n <span key={name}>{name}</span>\n ))}\n </div>\n </div>\n\n <div className=\"h-px bg-slate-700/50\" />\n\n <div className=\"space-y-3\">\n <h4 className=\"text-sm font-medium text-slate-200\">Media Query Status</h4>\n <div className=\"space-y-2\">\n {Object.entries(breakpoints).map(([name, width]) => (\n <div key={name} className=\"flex items-center justify-between\">\n <code className=\"text-xs bg-slate-800/50 text-slate-300 px-2 py-1 rounded border border-slate-700/50\">\n (min-width: {width}px)\n </code>\n <div\n className={cn(\n \"text-xs px-2 py-1 rounded\",\n breakpoint.breakpoints[name]\n ? \"bg-green-600/20 border border-green-500/30 text-green-300\"\n : \"bg-slate-700/50 border border-slate-600/50 text-slate-400\",\n )}\n >\n {breakpoint.breakpoints[name] ? \"Active\" : \"Inactive\"}\n </div>\n </div>\n ))}\n </div>\n </div>\n </div>\n )}\n\n {activeTab === \"devices\" && (\n <div className=\"space-y-3\">\n <h4 className=\"text-sm font-medium text-slate-200\">Device Presets</h4>\n <div className=\"grid gap-2\">\n {devices.map((device) => (\n <div\n key={device.name}\n className=\"flex items-center justify-between p-3 rounded-lg border bg-slate-800/30 border-slate-700/50 hover:bg-slate-800/50 hover:border-slate-600/50 transition-all duration-200\"\n >\n <div className=\"flex items-center gap-3\">\n <div\n className={cn(\n \"w-8 h-8 rounded-lg flex items-center justify-center\",\n device.category === \"mobile\"\n ? \"bg-green-600/20\"\n : device.category === \"tablet\"\n ? \"bg-blue-600/20\"\n : \"bg-purple-600/20\",\n )}\n >\n <Smartphone\n className={cn(\n \"w-4 h-4\",\n device.category === \"mobile\"\n ? \"text-green-400\"\n : device.category === \"tablet\"\n ? \"text-blue-400\"\n : \"text-purple-400\",\n )}\n />\n </div>\n <div>\n <span className=\"text-sm font-medium text-slate-200\">{device.name}</span>\n <div className=\"text-xs text-slate-400\">{device.userAgent}</div>\n </div>\n </div>\n <div className=\"text-right\">\n <span className=\"text-xs font-mono text-slate-400\">\n {device.width}×{device.height}\n </span>\n <div className=\"text-xs text-slate-500\">{device.pixelRatio}x DPR</div>\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Add other tab contents here */}\n </div>\n </div>\n )}\n </div>\n </div>\n )\n}\n","\"use client\"\n\nimport type React from \"react\"\nimport { Component, type ReactNode } from \"react\"\nimport { AlertTriangle, RefreshCw } from \"lucide-react\"\n\ninterface ErrorBoundaryState {\n hasError: boolean\n error?: Error\n}\n\ninterface ErrorBoundaryProps {\n children: ReactNode\n fallback?: ReactNode\n onError?: (error: Error, errorInfo: React.ErrorInfo) => void\n}\n\nexport class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {\n constructor(props: ErrorBoundaryProps) {\n super(props)\n this.state = { hasError: false }\n }\n\n static getDerivedStateFromError(error: Error): ErrorBoundaryState {\n return { hasError: true, error }\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {\n console.error(\"Breakpoint Debugger Error:\", error, errorInfo)\n this.props.onError?.(error, errorInfo)\n }\n\n render() {\n if (this.state.hasError) {\n if (this.props.fallback) {\n return this.props.fallback\n }\n\n return (\n <div className=\"fixed bottom-6 right-6 z-50 w-96\">\n <div className=\"bg-red-900/20 border border-red-500/30 backdrop-blur-xl rounded-lg p-4\">\n <div className=\"flex items-center gap-2 text-red-400 mb-3\">\n <AlertTriangle className=\"w-5 h-5\" />\n <h3 className=\"font-semibold\">Debugger Error</h3>\n </div>\n <p className=\"text-sm text-red-300 mb-3\">\n The breakpoint debugger encountered an error. This might be due to browser compatibility or a temporary\n issue.\n </p>\n <div className=\"flex gap-2\">\n <button\n onClick={() => this.setState({ hasError: false })}\n className=\"flex items-center gap-2 px-3 py-1 bg-red-600 hover:bg-red-700 text-white rounded text-sm transition-colors\"\n >\n <RefreshCw className=\"w-4 h-4\" />\n Retry\n </button>\n <button\n onClick={() => window.location.reload()}\n className=\"px-3 py-1 border border-red-500/30 text-red-400 hover:bg-red-900/20 rounded text-sm transition-colors\"\n >\n Reload Page\n </button>\n </div>\n </div>\n </div>\n )\n }\n\n return this.props.children\n }\n}\n","\"use client\"\n\nimport { useState, useRef } from \"react\"\nimport { X, Maximize2, Minimize2, RotateCcw } from \"lucide-react\"\nimport type { DeviceMockupProps } from \"../types\"\nimport { cn } from \"../lib/utils\"\n\nexport function DeviceMockup({\n device,\n scale = 0.5,\n isRotated = false,\n url,\n onClose,\n onScaleChange,\n onRotate,\n className,\n style,\n}: DeviceMockupProps) {\n const [isFullscreen, setIsFullscreen] = useState(false)\n const iframeRef = useRef<HTMLIFrameElement>(null)\n\n const currentWidth = isRotated ? device.height : device.width\n const currentHeight = isRotated ? device.width : device.height\n const currentUrl = url || (typeof window !== \"undefined\" ? window.location.origin : \"\")\n\n const handleRotate = () => {\n const newRotated = !isRotated\n onRotate?.(newRotated)\n }\n\n const handleScaleChange = (newScale: number) => {\n onScaleChange?.(newScale)\n }\n\n return (\n <div\n className={cn(\n \"fixed inset-0 z-50 bg-slate-900/80 backdrop-blur-sm flex items-center justify-center p-4\",\n isFullscreen && \"p-0\",\n className,\n )}\n style={style}\n >\n {/* Controls */}\n <div className=\"absolute top-4 right-4 z-60 flex items-center gap-2\">\n <div className=\"bg-slate-800/90 backdrop-blur-sm rounded-lg p-2 border border-slate-700/50\">\n <div className=\"flex items-center gap-2 text-sm text-slate-300 mb-2\">\n <span>{device.name}</span>\n <span className=\"text-slate-500\">•</span>\n <span className=\"font-mono text-xs\">\n {currentWidth}×{currentHeight}\n </span>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <button\n onClick={handleRotate}\n className=\"text-slate-400 hover:text-slate-200 h-8 w-8 p-0 flex items-center justify-center rounded hover:bg-slate-700/50 transition-colors\"\n title=\"Rotate device\"\n >\n <RotateCcw className=\"w-4 h-4\" />\n </button>\n\n <button\n onClick={() => setIsFullscreen(!isFullscreen)}\n className=\"text-slate-400 hover:text-slate-200 h-8 w-8 p-0 flex items-center justify-center rounded hover:bg-slate-700/50 transition-colors\"\n title=\"Toggle fullscreen\"\n >\n {isFullscreen ? <Minimize2 className=\"w-4 h-4\" /> : <Maximize2 className=\"w-4 h-4\" />}\n </button>\n\n <button\n onClick={onClose}\n className=\"text-slate-400 hover:text-slate-200 h-8 w-8 p-0 flex items-center justify-center rounded hover:bg-slate-700/50 transition-colors\"\n title=\"Close mockup\"\n >\n <X className=\"w-4 h-4\" />\n </button>\n </div>\n </div>\n </div>\n\n {/* Device Frame */}\n <div className=\"transition-all duration-300\">\n {device.category === \"mobile\" && (\n <div\n className=\"relative bg-slate-900 rounded-[2.5rem] p-2 shadow-2xl border-4 border-slate-800\"\n style={{\n width: (currentWidth + 40) * scale,\n height: (currentHeight + 80) * scale,\n }}\n >\n {/* Screen */}\n <div\n className=\"w-full h-full bg-white rounded-[2rem] overflow-hidden relative\"\n style={{\n width: currentWidth * scale,\n height: currentHeight * scale,\n }}\n >\n <iframe\n ref={iframeRef}\n src={currentUrl}\n className=\"w-full h-full border-none\"\n style={{\n transform: `scale(${scale})`,\n transformOrigin: \"top left\",\n width: `${100 / scale}%`,\n height: `${100 / scale}%`,\n }}\n title={`${device.name} Mockup`}\n />\n </div>\n </div>\n )}\n </div>\n </div>\n )\n}\n"],"mappings":"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","names":["useState","useEffect","Monitor","useState","useEffect","useState","useEffect","useState","useEffect","useState","useState","useState","useEffect","Monitor","useState","X","useState","X"]}