PageSourceSearch

https://zefix.org/site/site-primitives.jsx

js zefix.org collected 2026-10-04 19:41:37 UTC 6,843 bytes, 185 lines download raw bytes

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.