Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | 'use client' import { css } from '@styled/css' import { useTheme } from '@/contexts/ThemeContext' interface LayoutPreviewProps { orientation: 'portrait' | 'landscape' cols: number rows: number className?: string onClick?: () => void isSelected?: boolean maxSize?: number } /** * Visual preview of worksheet layout showing page orientation and problem grid * Can act as a button when onClick is provided */ export function LayoutPreview({ orientation, cols, rows, className, onClick, isSelected = false, maxSize = 48, }: LayoutPreviewProps) { const { resolvedTheme } = useTheme() const isDark = resolvedTheme === 'dark' // Page dimensions (aspect ratios) const pageAspect = orientation === 'portrait' ? 8.5 / 11 : 11 / 8.5 // Scale to fit in button (max dimensions) let pageWidth: number let pageHeight: number if (orientation === 'portrait') { pageHeight = maxSize pageWidth = pageHeight * pageAspect } else { pageWidth = maxSize pageHeight = pageWidth / pageAspect } // Problem cell dimensions with padding const padding = 3 const cellWidth = (pageWidth - padding * 2) / cols const cellHeight = (pageHeight - padding * 2) / rows const cellPadding = 1 const svgContent = ( <svg viewBox={`0 0 ${pageWidth} ${pageHeight}`} className={css({ rounded: 'sm', width: '100%', height: '100%', })} style={{ backgroundColor: isDark ? '#1f2937' : 'white', }} preserveAspectRatio="xMidYMid meet" > {/* Problem grid */} {Array.from({ length: rows }).map((_, rowIdx) => Array.from({ length: cols }).map((_, colIdx) => ( <rect key={`${rowIdx}-${colIdx}`} x={padding + colIdx * cellWidth + cellPadding} y={padding + rowIdx * cellHeight + cellPadding} width={cellWidth - cellPadding * 2} height={cellHeight - cellPadding * 2} fill={isDark ? '#6b7280' : '#d1d5db'} rx={0.5} /> )) )} </svg> ) // If used as a button, wrap in button element with styling if (onClick) { const aspectRatio = orientation === 'portrait' ? 8.5 / 11 : 11 / 8.5 return ( <button type="button" onClick={onClick} className={css({ display: 'flex', alignItems: 'center', justifyContent: 'center', border: '2px solid', borderColor: isSelected ? 'brand.500' : isDark ? 'gray.600' : 'gray.300', bg: isSelected ? (isDark ? 'brand.900' : 'brand.50') : isDark ? 'gray.700' : 'white', rounded: 'lg', cursor: 'pointer', transition: 'all 0.15s', p: '2', width: '100%', maxWidth: '32', _hover: { borderColor: 'brand.400', }, })} style={{ aspectRatio: aspectRatio.toString(), }} > {svgContent} </button> ) } // Otherwise just return the SVG with border const aspectRatio = orientation === 'portrait' ? 8.5 / 11 : 11 / 8.5 return ( <div className={css({ border: '1px solid', borderColor: isDark ? 'gray.600' : 'gray.300', rounded: 'sm', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', p: '1', })} style={{ width: `${maxSize}px`, aspectRatio: aspectRatio.toString(), }} > {svgContent} </div> ) } |