1// Site-specific primitives, separate from the print-poster D-shared. 2// Re-uses palette tokens from D_PALETTES.desk. 3 4const SITE_PALETTE = D_PALETTES.desk; 5 6// --- Sticky note for the web (heavier shadow, slightly larger) --- 7function WebSticky({ bg, color, rotate = -3, w, children, style = {}, font = 'caveat' }) { 8 return ( 9 <div className="zf-sticky" style={{ 10 background: bg, color: color || SITE_PALETTE.ink, width: w, 11 padding: '20px 22px', 12 fontFamily: font === 'caveat' ? '"Schoolbell", cursive' : ZF_FONTS.sans, 13 fontSize: font === 'caveat' ? 26 : 17, lineHeight: 1.35, 14 boxShadow: '3px 6px 0 rgba(0,0,0,.10), 1px 1px 14px rgba(0,0,0,.08)', 15 transform: `rotate(${rotate}deg)`, 16 ...style, 17 }}>{children}</div> 18 ); 19} 20 21// --- Tape --- 22function WebTape({ color, w = 140, h = 26, rotate = -6, style = {} }) { 23 return ( 24 <div style={{ 25 width: w, height: h, background: color, 26 boxShadow: 'inset 0 0 0 1px rgba(0,0,0,.06)', 27 transform: `rotate(${rotate}deg)`, 28 backgroundImage: 'repeating-linear-gradient(90deg, rgba(0,0,0,.06) 0 1px, transparent 1px 7px)', 29 ...style, 30 }}/> 31 ); 32} 33 34// --- Pin --- 35function WebPin({ color = SITE_PALETTE.a1, size = 16, style = {} }) { 36 return ( 37 <div style={{ 38 width: size, height: size, borderRadius: '50%', 39 background: `radial-gradient(circle at 35% 30%, #fff 0%, ${color} 45%, ${color} 100%)`, 40 boxShadow: '1px 2px 4px rgba(0,0,0,.3), inset -1px -1px 2px rgba(0,0,0,.2)', 41 ...style, 42 }}/> 43 ); 44} 45 46// --- Marker squiggle --- 47function WebSquiggle({ color, w = 200, h = 12, style = {} }) { 48 return ( 49 <svg width={w} height={h} viewBox="0 0 200 12" preserveAspectRatio="none" style={style}> 50 <path d="M2 7 Q 18 1, 35 7 T 70 7 T 105 7 T 140 7 T 175 7 T 198 7" 51 stroke={color} strokeWidth="3.5" fill="none" strokeLinecap="round"/> 52 </svg> 53 ); 54} 55 56// --- Stamp --- 57function WebStamp({ children, color, rotate = -4, style = {} }) { 58 return ( 59 <div style={{ 60 border: `3px solid ${color}`, color, padding: '8px 14px', 61 fontFamily: ZF_FONTS.mono, fontSize: 13, letterSpacing: 1.5, fontWeight: 700, 62 transform: `rotate(${rotate}deg)`, display: 'inline-block', 63 ...style, 64 }}>{children}</div> 65 ); 66} 67 68// --- Patch (torn paper) --- 69function WebPatch({ color, children, rotate = 0, style = {}, padding = '10px 16px' }) { 70 return ( 71 <div style={{ 72 background: color, padding, color: SITE_PALETTE.ink, 73 transform: `rotate(${rotate}deg)`, 74 boxShadow: '2px 3px 0 rgba(0,0,0,.18)', 75 clipPath: 'polygon(0 5%, 4% 0, 20% 3%, 40% 0, 60% 2%, 80% 0, 96% 4%, 100% 8%, 98% 30%, 100% 55%, 97% 80%, 100% 96%, 92% 100%, 75% 98%, 55% 100%, 35% 97%, 15% 100%, 3% 96%, 0 80%, 2% 55%, 0 30%)', 76 display: 'inline-block', 77 ...style, 78 }}>{children}</div> 79 ); 80} 81 82// --- Polaroid wrapper for photos --- 83function WebPolaroid({ src, alt, w = 280, h = 200, rotate = -3, caption, style = {}, tape = null }) { 84 return ( 85 <div className="zf-polaroid" style={{ 86 background: '#fff', padding: 14, paddingBottom: caption ? 38 : 14, 87 boxShadow: '5px 8px 0 rgba(0,0,0,.12), 0 0 0 1px rgba(0,0,0,.05)', 88 transform: `rotate(${rotate}deg)`, display: 'inline-block', 89 position: 'relative', 90 ...style, 91 }}> 92 <div style={{ 93 width: w, height: h, background: SITE_PALETTE.paper2, 94 backgroundImage: `url(${src})`, backgroundSize: 'cover', backgroundPosition: 'center', 95 }} aria-label={alt}/> 96 {caption && ( 97 <div style={{ 98 position: 'absolute', bottom: 8, left: 0, right: 0, textAlign: 'center', 99 fontFamily: '"Schoolbell", cursive', fontSize: 22, color: '#333', 100 }}>{caption}</div> 101 )} 102 {tape && <WebTape color={tape.color} w={tape.w || 100} rotate={tape.rotate || -18} style={{ position: 'absolute', top: -10, left: tape.left ?? '40%' }}/>} 103 </div> 104 ); 105} 106 107// --- Sticker --- 108function WebSticker({ bg, color = '#fff', children, rotate = -3, style = {} }) { 109 return ( 110 <div style={{ 111 background: bg, color, padding: '10px 16px', borderRadius: 999, 112 fontFamily: ZF_FONTS.mono, fontSize: 12, fontWeight: 700, letterSpacing: 1.5, 113 transform: `rotate(${rotate}deg)`, display: 'inline-block', 114 boxShadow: '0 0 0 3px #fff, 4px 5px 0 rgba(0,0,0,.18)', 115 ...style, 116 }}>{children}</div> 117 ); 118} 119 120// --- Hand-drawn arrow ---
121function WebArrow({ color, w = 100, h = 50, style = {} }) { 122 return ( 123 <svg width={w} height={h} viewBox="0 0 100 50" style={style}> 124 <path d="M4 35 Q 40 5, 88 22 L78 14 M88 22 L80 30" 125 stroke={color} strokeWidth="3" fill="none" 126 strokeLinecap="round" strokeLinejoin="round"/> 127 </svg> 128 ); 129} 130 131// --- Section title (with squiggle underline + handwritten subtitle) --- 132function SectionTitle({ kicker, title, sub, color, alignCenter = false }) { 133 const c = color || SITE_PALETTE.a1; 134 return ( 135 <div style={{ textAlign: alignCenter ? 'center' : 'left', marginBottom: 32 }}> 136 {kicker && ( 137 <div style={{ 138 fontFamily: ZF_FONTS.mono, fontSize: 12, letterSpacing: 3, color: c, 139 fontWeight: 700, textTransform: 'uppercase', marginBottom: 8, 140 }}>// {kicker}</div> 141 )} 142 <h2 style={{ 143 fontFamily: ZF_FONTS.display, fontWeight: 900, 144 fontSize: 'clamp(40px, 6vw, 72px)', lineHeight: 0.95, margin: 0, 145 color: SITE_PALETTE.ink, letterSpacing: 0, 146 }}>{title}</h2> 147 <WebSquiggle color={c} w={alignCenter ? 240 : 200} h={12} 148 style={{ marginTop: 6, marginLeft: alignCenter ? 'auto' : 0, marginRight: alignCenter ? 'auto' : 0, display: 'block' }}/> 149 {sub && ( 150 <div style={{ 151 fontFamily: '"Schoolbell", cursive', fontSize: 30, color: c, 152 marginTop: 6, transform: 'rotate(-1deg)', display: 'inline-block', 153 }}>{sub}</div> 154 )} 155 </div> 156 ); 157} 158 159// --- Section wrapper with paper background --- 160function Section({ id, bg = 'paper', children, style = {} }) { 161 const palette = SITE_PALETTE; 162 const bgColor = bg === 'paper2' ? palette.paper2 : bg === 'ink' ? palette.ink : palette.paper; 163 const dots = `radial-gradient(rgba(0,0,0,.04) 1px, transparent 1px)`; 164 return ( 165 <section id={id} style={{ 166 background: bgColor, 167 backgroundImage: dots, 168 backgroundSize: '4px 4px', 169 padding: 'clamp(60px, 8vw, 120px) clamp(20px, 5vw, 80px)', 170 position: 'relative', overflow: 'hidden', 171 color: bg === 'ink' ? '#fff' : palette.ink, 172 ...style, 173 }}> 174 <div style={{ maxWidth: 1200, margin: '0 auto', position: 'relative' }}> 175 {children} 176 </div> 177 </section> 178 ); 179} 180 181Object.assign(window, { 182 SITE_PALETTE, 183 WebSticky, WebTape, WebPin, WebSquiggle, WebStamp, WebPatch, 184 WebPolaroid, WebSticker, WebArrow, SectionTitle, Section, 185});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.