bedrock-flows 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/auth-schema.sql +8 -0
- package/bin/bedrock-flows.mjs +127 -0
- package/lib/setup.mjs +262 -0
- package/package.json +11 -0
- package/template/.storybook/main.js +46 -0
- package/template/.storybook/manager-head.html +963 -0
- package/template/.storybook/preview-head.html +35 -0
- package/template/.storybook/preview.js +23 -0
- package/template/CHANGELOG.md +236 -0
- package/template/README.md +26 -0
- package/template/apps/dashboard/index.html +15 -0
- package/template/apps/dashboard/package.json +22 -0
- package/template/apps/dashboard/src/App.module.css +1318 -0
- package/template/apps/dashboard/src/App.tsx +2716 -0
- package/template/apps/dashboard/src/auth-client.ts +17 -0
- package/template/apps/dashboard/src/changelog.tsx +92 -0
- package/template/apps/dashboard/src/index.css +86 -0
- package/template/apps/dashboard/src/main.tsx +15 -0
- package/template/apps/dashboard/src/theme.ts +31 -0
- package/template/apps/dashboard/src/vite-env.d.ts +4 -0
- package/template/apps/dashboard/vite.config.ts +48 -0
- package/template/apps/worker/.dev.vars.example +50 -0
- package/template/apps/worker/package.json +19 -0
- package/template/apps/worker/src/index.ts +295 -0
- package/template/apps/worker/tsconfig.json +11 -0
- package/template/apps/worker/wrangler.jsonc +29 -0
- package/template/bedrock.config.ts +16 -0
- package/template/design-system/README.md +97 -0
- package/template/design-system/starter-v1/components/button/component.css +42 -0
- package/template/design-system/starter-v1/components/button/danger.html +21 -0
- package/template/design-system/starter-v1/components/button/default.html +21 -0
- package/template/design-system/starter-v1/components/button/disabled.html +21 -0
- package/template/design-system/starter-v1/components/button/ghost.html +21 -0
- package/template/design-system/starter-v1/components/button/macro.njk +14 -0
- package/template/design-system/starter-v1/components/button/primary.html +21 -0
- package/template/design-system/starter-v1/components/button/variants.json +30 -0
- package/template/design-system/starter-v1/ds.json +3 -0
- package/template/design-system/starter-v1/global.css +52 -0
- package/template/design-system/starter-v1/style.css +107 -0
- package/template/gitignore +8 -0
- package/template/package.json +41 -0
- package/template/prototypes/F-001-hello/1-welcome.njk +30 -0
- package/template/prototypes/F-001-hello/2-form.njk +46 -0
- package/template/prototypes/F-001-hello/3-done.njk +29 -0
- package/template/prototypes/F-001-hello/meta.json +6 -0
- package/template/prototypes/_shared/_auth-gate.njk +54 -0
- package/template/prototypes/_shared/delivery.njk +43 -0
- package/template/prototypes/_shared/layout.njk +15 -0
- package/template/prototypes/_shared/screen.njk +1818 -0
- package/template/prototypes/_shared/wireflow.njk +4731 -0
- package/template/public/auth-gate.css +150 -0
- package/template/public/bedrock/color-inspector.js +284 -0
- package/template/public/bedrock/component-overlay.js +219 -0
- package/template/public/bedrock/data/bedrock-config.js +45 -0
- package/template/public/bedrock/font-size-overlay.js +590 -0
- package/template/public/bedrock/grid-overlay.js +379 -0
- package/template/public/bedrock/prototype-navigation.js +974 -0
- package/template/public/cmdk.js +146 -0
- package/template/public/ds-xray.css +112 -0
- package/template/public/ds-xray.js +271 -0
- package/template/public/favicon.svg +4 -0
- package/template/public/icons/bolt-fill.svg +3 -0
- package/template/public/icons/bolt.svg +3 -0
- package/template/public/icons/caret-down-fill.svg +3 -0
- package/template/public/icons/check-double.svg +4 -0
- package/template/public/icons/check.svg +3 -0
- package/template/public/icons/chevron-left.svg +3 -0
- package/template/public/icons/chevron-right.svg +3 -0
- package/template/public/icons/circle-info.svg +6 -0
- package/template/public/icons/grid.svg +6 -0
- package/template/public/icons/message-square-1.svg +3 -0
- package/template/public/icons/message-square.svg +3 -0
- package/template/public/icons/messages.svg +4 -0
- package/template/public/icons/options-horizontal.svg +5 -0
- package/template/public/icons/swatches.svg +6 -0
- package/template/public/icons/workflow.svg +6 -0
- package/template/public/lightbox.js +87 -0
- package/template/public/proto-chrome.css +596 -0
- package/template/public/screen-comments.css +723 -0
- package/template/public/wireflow-client.js +26 -0
- package/template/scripts/build-storybooks.mjs +8 -0
- package/template/scripts/dev-setup.mjs +15 -0
- package/template/scripts/generate-stories.mjs +12 -0
- package/template/scripts/generate-variants.mjs +22 -0
- package/template/tsconfig.base.json +19 -0
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typography Debug Overlay Utility
|
|
3
|
+
*
|
|
4
|
+
* Two modes:
|
|
5
|
+
* 1. Font Size Mode (Ctrl+Shift+F) - Shows font info on hover
|
|
6
|
+
* 2. Distance Mode (Ctrl+Shift+D) - Shows vertical distance between elements
|
|
7
|
+
*
|
|
8
|
+
* State is persisted in localStorage
|
|
9
|
+
*/
|
|
10
|
+
(function() {
|
|
11
|
+
const STORAGE_KEY_FONT = 'typographyOverlayFont';
|
|
12
|
+
const STORAGE_KEY_DISTANCE = 'typographyOverlayDistance';
|
|
13
|
+
const TOOLTIP_ID = 'typography-tooltip';
|
|
14
|
+
const TOAST_ID = 'typography-toast';
|
|
15
|
+
|
|
16
|
+
let fontModeEnabled = false;
|
|
17
|
+
let distanceModeEnabled = false;
|
|
18
|
+
let tooltip = null;
|
|
19
|
+
let distanceOverlays = [];
|
|
20
|
+
|
|
21
|
+
// Text elements to track
|
|
22
|
+
const TEXT_SELECTORS = 'h1, h2, h3, h4, h5, h6, p, span, a, li, td, th, label, button, input, textarea, blockquote, figcaption, cite';
|
|
23
|
+
const BLOCK_SELECTORS = 'h1, h2, h3, h4, h5, h6, p, ul, ol, blockquote, figure, pre, table, hr, div.o-prose > *';
|
|
24
|
+
|
|
25
|
+
// Inject styles
|
|
26
|
+
function injectStyles() {
|
|
27
|
+
if (document.getElementById('typography-overlay-styles')) return;
|
|
28
|
+
|
|
29
|
+
const style = document.createElement('style');
|
|
30
|
+
style.id = 'typography-overlay-styles';
|
|
31
|
+
style.textContent = `
|
|
32
|
+
#${TOOLTIP_ID} {
|
|
33
|
+
position: fixed;
|
|
34
|
+
background: #2196F3;
|
|
35
|
+
color: white;
|
|
36
|
+
font-size: 11px;
|
|
37
|
+
font-family: monospace;
|
|
38
|
+
padding: 4px 8px;
|
|
39
|
+
border-radius: 3px;
|
|
40
|
+
z-index: 99999;
|
|
41
|
+
pointer-events: none;
|
|
42
|
+
white-space: nowrap;
|
|
43
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
|
|
44
|
+
opacity: 0;
|
|
45
|
+
transition: opacity 0.15s ease;
|
|
46
|
+
}
|
|
47
|
+
#${TOOLTIP_ID}.visible {
|
|
48
|
+
opacity: 1;
|
|
49
|
+
}
|
|
50
|
+
#${TOOLTIP_ID}.distance-mode {
|
|
51
|
+
background: #FF5722;
|
|
52
|
+
}
|
|
53
|
+
.typography-highlight {
|
|
54
|
+
outline: 1px dashed #2196F3 !important;
|
|
55
|
+
outline-offset: 1px;
|
|
56
|
+
}
|
|
57
|
+
.distance-marker {
|
|
58
|
+
position: absolute;
|
|
59
|
+
pointer-events: none;
|
|
60
|
+
z-index: 99998;
|
|
61
|
+
}
|
|
62
|
+
.distance-marker__line {
|
|
63
|
+
position: absolute;
|
|
64
|
+
left: 50%;
|
|
65
|
+
width: 2px;
|
|
66
|
+
background: #FF5722;
|
|
67
|
+
transform: translateX(-50%);
|
|
68
|
+
}
|
|
69
|
+
.distance-marker__label {
|
|
70
|
+
position: absolute;
|
|
71
|
+
left: 50%;
|
|
72
|
+
transform: translateX(-50%);
|
|
73
|
+
background: #FF5722;
|
|
74
|
+
color: white;
|
|
75
|
+
font-size: 10px;
|
|
76
|
+
font-family: monospace;
|
|
77
|
+
padding: 2px 6px;
|
|
78
|
+
border-radius: 3px;
|
|
79
|
+
white-space: nowrap;
|
|
80
|
+
}
|
|
81
|
+
.distance-marker__tags {
|
|
82
|
+
opacity: 0.75;
|
|
83
|
+
font-size: 9px;
|
|
84
|
+
}
|
|
85
|
+
.distance-marker__bracket {
|
|
86
|
+
position: absolute;
|
|
87
|
+
left: calc(50% - 8px);
|
|
88
|
+
width: 16px;
|
|
89
|
+
height: 6px;
|
|
90
|
+
border: 2px solid #FF5722;
|
|
91
|
+
border-top: none;
|
|
92
|
+
}
|
|
93
|
+
.distance-marker__bracket--top {
|
|
94
|
+
border: 2px solid #FF5722;
|
|
95
|
+
border-bottom: none;
|
|
96
|
+
}
|
|
97
|
+
.distance-element-highlight {
|
|
98
|
+
outline: 2px solid #FF5722 !important;
|
|
99
|
+
outline-offset: 0px;
|
|
100
|
+
}
|
|
101
|
+
#${TOAST_ID} {
|
|
102
|
+
position: fixed;
|
|
103
|
+
bottom: 20px;
|
|
104
|
+
left: 50%;
|
|
105
|
+
transform: translateX(-50%) translateY(100px);
|
|
106
|
+
background: #1A1A2E;
|
|
107
|
+
color: white;
|
|
108
|
+
font-size: 13px;
|
|
109
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
110
|
+
padding: 10px 20px;
|
|
111
|
+
border-radius: 6px;
|
|
112
|
+
z-index: 100000;
|
|
113
|
+
pointer-events: none;
|
|
114
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
|
|
115
|
+
opacity: 0;
|
|
116
|
+
transition: transform 0.3s ease, opacity 0.3s ease;
|
|
117
|
+
}
|
|
118
|
+
#${TOAST_ID}.visible {
|
|
119
|
+
opacity: 1;
|
|
120
|
+
transform: translateX(-50%) translateY(0);
|
|
121
|
+
}
|
|
122
|
+
#${TOAST_ID} .toast-status {
|
|
123
|
+
font-weight: 600;
|
|
124
|
+
}
|
|
125
|
+
#${TOAST_ID} .toast-status--on {
|
|
126
|
+
color: #4CAF50;
|
|
127
|
+
}
|
|
128
|
+
#${TOAST_ID} .toast-status--off {
|
|
129
|
+
color: #F44336;
|
|
130
|
+
}
|
|
131
|
+
`;
|
|
132
|
+
document.head.appendChild(style);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Create tooltip element
|
|
136
|
+
function createTooltip() {
|
|
137
|
+
if (tooltip) return;
|
|
138
|
+
|
|
139
|
+
tooltip = document.createElement('div');
|
|
140
|
+
tooltip.id = TOOLTIP_ID;
|
|
141
|
+
document.body.appendChild(tooltip);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Show toast notification
|
|
145
|
+
let toastTimeout = null;
|
|
146
|
+
function showToast(message, isEnabled) {
|
|
147
|
+
injectStyles();
|
|
148
|
+
let toast = document.getElementById(TOAST_ID);
|
|
149
|
+
if (!toast) {
|
|
150
|
+
toast = document.createElement('div');
|
|
151
|
+
toast.id = TOAST_ID;
|
|
152
|
+
document.body.appendChild(toast);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const statusClass = isEnabled ? 'toast-status--on' : 'toast-status--off';
|
|
156
|
+
const statusText = isEnabled ? 'ON' : 'OFF';
|
|
157
|
+
toast.innerHTML = `${message}: <span class="toast-status ${statusClass}">${statusText}</span>`;
|
|
158
|
+
|
|
159
|
+
// Clear any existing timeout
|
|
160
|
+
if (toastTimeout) {
|
|
161
|
+
clearTimeout(toastTimeout);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Show toast
|
|
165
|
+
requestAnimationFrame(() => {
|
|
166
|
+
toast.classList.add('visible');
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Hide after 2 seconds
|
|
170
|
+
toastTimeout = setTimeout(() => {
|
|
171
|
+
toast.classList.remove('visible');
|
|
172
|
+
}, 2000);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Get font info for an element
|
|
176
|
+
function getFontInfo(element) {
|
|
177
|
+
const style = window.getComputedStyle(element);
|
|
178
|
+
const fontSize = style.fontSize;
|
|
179
|
+
const fontWeight = style.fontWeight;
|
|
180
|
+
const lineHeight = style.lineHeight;
|
|
181
|
+
const fontFamily = style.fontFamily.split(',')[0].replace(/['"]/g, '').trim();
|
|
182
|
+
|
|
183
|
+
const weightNames = {
|
|
184
|
+
'100': 'Thin',
|
|
185
|
+
'200': 'ExtraLight',
|
|
186
|
+
'300': 'Light',
|
|
187
|
+
'400': 'Regular',
|
|
188
|
+
'500': 'Medium',
|
|
189
|
+
'600': 'SemiBold',
|
|
190
|
+
'700': 'Bold',
|
|
191
|
+
'800': 'ExtraBold',
|
|
192
|
+
'900': 'Black'
|
|
193
|
+
};
|
|
194
|
+
const weightName = weightNames[fontWeight] || fontWeight;
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
size: fontSize,
|
|
198
|
+
weight: weightName,
|
|
199
|
+
lineHeight: lineHeight,
|
|
200
|
+
family: fontFamily
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Format line height for display
|
|
205
|
+
function formatLineHeight(lineHeight, fontSize) {
|
|
206
|
+
if (lineHeight === 'normal') return 'normal';
|
|
207
|
+
|
|
208
|
+
if (lineHeight.endsWith('px')) {
|
|
209
|
+
const lhPx = parseFloat(lineHeight);
|
|
210
|
+
const fsPx = parseFloat(fontSize);
|
|
211
|
+
const ratio = (lhPx / fsPx).toFixed(2);
|
|
212
|
+
return `${lineHeight} (${ratio})`;
|
|
213
|
+
}
|
|
214
|
+
return lineHeight;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Font mode mouse move handler
|
|
218
|
+
function handleFontMouseMove(e) {
|
|
219
|
+
if (!fontModeEnabled || !tooltip) return;
|
|
220
|
+
|
|
221
|
+
const element = document.elementFromPoint(e.clientX, e.clientY);
|
|
222
|
+
if (!element || element.closest('#protoNav') || !element.matches(TEXT_SELECTORS)) {
|
|
223
|
+
tooltip.classList.remove('visible');
|
|
224
|
+
document.querySelectorAll('.typography-highlight').forEach(el => {
|
|
225
|
+
el.classList.remove('typography-highlight');
|
|
226
|
+
});
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
document.querySelectorAll('.typography-highlight').forEach(el => {
|
|
231
|
+
el.classList.remove('typography-highlight');
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
element.classList.add('typography-highlight');
|
|
235
|
+
|
|
236
|
+
const info = getFontInfo(element);
|
|
237
|
+
const tagName = element.tagName.toLowerCase();
|
|
238
|
+
|
|
239
|
+
tooltip.className = '';
|
|
240
|
+
tooltip.id = TOOLTIP_ID;
|
|
241
|
+
tooltip.innerHTML = `
|
|
242
|
+
<strong><${tagName}></strong> ${info.size} · ${info.weight}<br>
|
|
243
|
+
line-height: ${formatLineHeight(info.lineHeight, info.size)}<br>
|
|
244
|
+
${info.family}
|
|
245
|
+
`;
|
|
246
|
+
tooltip.classList.add('visible');
|
|
247
|
+
|
|
248
|
+
positionTooltip(e.clientX, e.clientY);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Position tooltip near cursor
|
|
252
|
+
function positionTooltip(x, y) {
|
|
253
|
+
if (!tooltip) return;
|
|
254
|
+
|
|
255
|
+
const tooltipRect = tooltip.getBoundingClientRect();
|
|
256
|
+
let posX = x + 15;
|
|
257
|
+
let posY = y + 15;
|
|
258
|
+
|
|
259
|
+
if (posX + tooltipRect.width > window.innerWidth) {
|
|
260
|
+
posX = x - tooltipRect.width - 10;
|
|
261
|
+
}
|
|
262
|
+
if (posY + tooltipRect.height > window.innerHeight) {
|
|
263
|
+
posY = y - tooltipRect.height - 10;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
tooltip.style.left = posX + 'px';
|
|
267
|
+
tooltip.style.top = posY + 'px';
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Clear distance overlays
|
|
271
|
+
function clearDistanceOverlays() {
|
|
272
|
+
distanceOverlays.forEach(el => el.remove());
|
|
273
|
+
distanceOverlays = [];
|
|
274
|
+
document.querySelectorAll('.distance-element-highlight').forEach(el => {
|
|
275
|
+
el.classList.remove('distance-element-highlight');
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Create distance marker between two elements
|
|
280
|
+
function createDistanceMarker(el1, el2, container) {
|
|
281
|
+
const rect1 = el1.getBoundingClientRect();
|
|
282
|
+
const rect2 = el2.getBoundingClientRect();
|
|
283
|
+
const containerRect = container.getBoundingClientRect();
|
|
284
|
+
|
|
285
|
+
// Calculate the gap between bottom of el1 and top of el2
|
|
286
|
+
const gap = rect2.top - rect1.bottom;
|
|
287
|
+
|
|
288
|
+
if (gap <= 0) return; // Elements overlap or touch
|
|
289
|
+
|
|
290
|
+
const marker = document.createElement('div');
|
|
291
|
+
marker.className = 'distance-marker';
|
|
292
|
+
|
|
293
|
+
// Position marker
|
|
294
|
+
const markerLeft = Math.max(rect1.left, rect2.left) + Math.min(rect1.width, rect2.width) / 2;
|
|
295
|
+
marker.style.left = (markerLeft + window.scrollX) + 'px';
|
|
296
|
+
marker.style.top = (rect1.bottom + window.scrollY) + 'px';
|
|
297
|
+
marker.style.width = '40px';
|
|
298
|
+
marker.style.height = gap + 'px';
|
|
299
|
+
|
|
300
|
+
// Add line
|
|
301
|
+
const line = document.createElement('div');
|
|
302
|
+
line.className = 'distance-marker__line';
|
|
303
|
+
line.style.top = '0';
|
|
304
|
+
line.style.height = gap + 'px';
|
|
305
|
+
marker.appendChild(line);
|
|
306
|
+
|
|
307
|
+
// Add top bracket
|
|
308
|
+
const bracketTop = document.createElement('div');
|
|
309
|
+
bracketTop.className = 'distance-marker__bracket distance-marker__bracket--top';
|
|
310
|
+
bracketTop.style.top = '0';
|
|
311
|
+
marker.appendChild(bracketTop);
|
|
312
|
+
|
|
313
|
+
// Add bottom bracket
|
|
314
|
+
const bracketBottom = document.createElement('div');
|
|
315
|
+
bracketBottom.className = 'distance-marker__bracket';
|
|
316
|
+
bracketBottom.style.bottom = '0';
|
|
317
|
+
marker.appendChild(bracketBottom);
|
|
318
|
+
|
|
319
|
+
// Add label with element tags
|
|
320
|
+
const tag1 = el1.tagName.toLowerCase();
|
|
321
|
+
const tag2 = el2.tagName.toLowerCase();
|
|
322
|
+
const label = document.createElement('div');
|
|
323
|
+
label.className = 'distance-marker__label';
|
|
324
|
+
label.style.top = (gap / 2 - 10) + 'px';
|
|
325
|
+
label.innerHTML = `<span class="distance-marker__tags">${tag1}+${tag2}</span> ${Math.round(gap)}px`;
|
|
326
|
+
marker.appendChild(label);
|
|
327
|
+
|
|
328
|
+
document.body.appendChild(marker);
|
|
329
|
+
distanceOverlays.push(marker);
|
|
330
|
+
|
|
331
|
+
// Highlight elements
|
|
332
|
+
el1.classList.add('distance-element-highlight');
|
|
333
|
+
el2.classList.add('distance-element-highlight');
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Find block-level elements and show distances
|
|
337
|
+
function showDistances() {
|
|
338
|
+
clearDistanceOverlays();
|
|
339
|
+
|
|
340
|
+
// Find prose containers and content areas
|
|
341
|
+
const containers = document.querySelectorAll('.o-prose, .c-article, .c-detail-section, .c-article__section, main');
|
|
342
|
+
|
|
343
|
+
containers.forEach(container => {
|
|
344
|
+
// Get direct children that are block elements
|
|
345
|
+
const children = container.querySelectorAll(':scope > h1, :scope > h2, :scope > h3, :scope > h4, :scope > h5, :scope > h6, :scope > p, :scope > ul, :scope > ol, :scope > blockquote, :scope > figure, :scope > pre, :scope > table, :scope > div:not([class*="marker"])');
|
|
346
|
+
|
|
347
|
+
const blockElements = Array.from(children).filter(el => {
|
|
348
|
+
const style = window.getComputedStyle(el);
|
|
349
|
+
return style.display === 'block' || style.display === 'list-item';
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
// Create markers between consecutive elements
|
|
353
|
+
for (let i = 0; i < blockElements.length - 1; i++) {
|
|
354
|
+
createDistanceMarker(blockElements[i], blockElements[i + 1], container);
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
// Also check within o-prose for nested elements
|
|
359
|
+
document.querySelectorAll('.o-prose').forEach(prose => {
|
|
360
|
+
const elements = prose.querySelectorAll('h1, h2, h3, h4, h5, h6, p, ul, ol, blockquote, figure');
|
|
361
|
+
const blockElements = Array.from(elements).filter(el => {
|
|
362
|
+
const parent = el.parentElement;
|
|
363
|
+
// Only direct children of prose or other block elements
|
|
364
|
+
return parent === prose || parent.matches('li, blockquote, figure');
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
for (let i = 0; i < blockElements.length - 1; i++) {
|
|
368
|
+
// Check if they're siblings or close in the DOM
|
|
369
|
+
const el1 = blockElements[i];
|
|
370
|
+
const el2 = blockElements[i + 1];
|
|
371
|
+
|
|
372
|
+
// Skip if already has a marker nearby
|
|
373
|
+
const rect1 = el1.getBoundingClientRect();
|
|
374
|
+
const rect2 = el2.getBoundingClientRect();
|
|
375
|
+
const gap = rect2.top - rect1.bottom;
|
|
376
|
+
|
|
377
|
+
if (gap > 0 && gap < 200) {
|
|
378
|
+
// Check if marker already exists for this gap
|
|
379
|
+
const existingMarker = distanceOverlays.find(m => {
|
|
380
|
+
const mTop = parseFloat(m.style.top);
|
|
381
|
+
return Math.abs(mTop - (rect1.bottom + window.scrollY)) < 5;
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
if (!existingMarker) {
|
|
385
|
+
createDistanceMarker(el1, el2, prose);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Distance mode mouse move handler (shows info about hovered gap)
|
|
393
|
+
function handleDistanceMouseMove(e) {
|
|
394
|
+
if (!distanceModeEnabled || !tooltip) return;
|
|
395
|
+
|
|
396
|
+
// Find if we're hovering over a distance marker label
|
|
397
|
+
const label = document.elementFromPoint(e.clientX, e.clientY);
|
|
398
|
+
|
|
399
|
+
if (label && label.closest('#protoNav')) {
|
|
400
|
+
tooltip.classList.remove('visible');
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (label && label.classList.contains('distance-marker__label')) {
|
|
405
|
+
tooltip.className = '';
|
|
406
|
+
tooltip.id = TOOLTIP_ID;
|
|
407
|
+
tooltip.classList.add('distance-mode', 'visible');
|
|
408
|
+
tooltip.innerHTML = `Distance: <strong>${label.textContent}</strong>`;
|
|
409
|
+
positionTooltip(e.clientX, e.clientY);
|
|
410
|
+
} else {
|
|
411
|
+
tooltip.classList.remove('visible');
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Enable font mode
|
|
416
|
+
function enableFontMode() {
|
|
417
|
+
fontModeEnabled = true;
|
|
418
|
+
disableDistanceMode(true); // Disable other mode but don't save
|
|
419
|
+
injectStyles();
|
|
420
|
+
createTooltip();
|
|
421
|
+
document.addEventListener('mousemove', handleFontMouseMove);
|
|
422
|
+
localStorage.setItem(STORAGE_KEY_FONT, 'true');
|
|
423
|
+
console.log('[Typography Overlay] Font Size Mode ON (Ctrl+Shift+F)');
|
|
424
|
+
|
|
425
|
+
window.dispatchEvent(new CustomEvent('typographyOverlayToggled', {
|
|
426
|
+
detail: { mode: 'font', enabled: true }
|
|
427
|
+
}));
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// Disable font mode
|
|
431
|
+
function disableFontMode(skipSave) {
|
|
432
|
+
fontModeEnabled = false;
|
|
433
|
+
document.removeEventListener('mousemove', handleFontMouseMove);
|
|
434
|
+
|
|
435
|
+
if (tooltip) {
|
|
436
|
+
tooltip.classList.remove('visible');
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
document.querySelectorAll('.typography-highlight').forEach(el => {
|
|
440
|
+
el.classList.remove('typography-highlight');
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
if (!skipSave) {
|
|
444
|
+
localStorage.setItem(STORAGE_KEY_FONT, 'false');
|
|
445
|
+
console.log('[Typography Overlay] Font Size Mode OFF');
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
window.dispatchEvent(new CustomEvent('typographyOverlayToggled', {
|
|
449
|
+
detail: { mode: 'font', enabled: false }
|
|
450
|
+
}));
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Get scroll container (prototype wrapper or window)
|
|
454
|
+
function getScrollContainer() {
|
|
455
|
+
return document.getElementById('protoSiteWrapper') || window;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// Enable distance mode
|
|
459
|
+
function enableDistanceMode() {
|
|
460
|
+
distanceModeEnabled = true;
|
|
461
|
+
disableFontMode(true); // Disable other mode but don't save
|
|
462
|
+
injectStyles();
|
|
463
|
+
createTooltip();
|
|
464
|
+
showDistances();
|
|
465
|
+
document.addEventListener('mousemove', handleDistanceMouseMove);
|
|
466
|
+
window.addEventListener('scroll', showDistances, true);
|
|
467
|
+
window.addEventListener('resize', showDistances);
|
|
468
|
+
// Also listen on prototype wrapper if it exists
|
|
469
|
+
const protoWrapper = document.getElementById('protoSiteWrapper');
|
|
470
|
+
if (protoWrapper) {
|
|
471
|
+
protoWrapper.addEventListener('scroll', showDistances);
|
|
472
|
+
}
|
|
473
|
+
localStorage.setItem(STORAGE_KEY_DISTANCE, 'true');
|
|
474
|
+
console.log('[Typography Overlay] Distance Mode ON (Ctrl+Shift+D)');
|
|
475
|
+
|
|
476
|
+
window.dispatchEvent(new CustomEvent('typographyOverlayToggled', {
|
|
477
|
+
detail: { mode: 'distance', enabled: true }
|
|
478
|
+
}));
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Disable distance mode
|
|
482
|
+
function disableDistanceMode(skipSave) {
|
|
483
|
+
distanceModeEnabled = false;
|
|
484
|
+
document.removeEventListener('mousemove', handleDistanceMouseMove);
|
|
485
|
+
window.removeEventListener('scroll', showDistances, true);
|
|
486
|
+
window.removeEventListener('resize', showDistances);
|
|
487
|
+
// Also remove from prototype wrapper if it exists
|
|
488
|
+
const protoWrapper = document.getElementById('protoSiteWrapper');
|
|
489
|
+
if (protoWrapper) {
|
|
490
|
+
protoWrapper.removeEventListener('scroll', showDistances);
|
|
491
|
+
}
|
|
492
|
+
clearDistanceOverlays();
|
|
493
|
+
|
|
494
|
+
if (tooltip) {
|
|
495
|
+
tooltip.classList.remove('visible');
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (!skipSave) {
|
|
499
|
+
localStorage.setItem(STORAGE_KEY_DISTANCE, 'false');
|
|
500
|
+
console.log('[Typography Overlay] Distance Mode OFF');
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
window.dispatchEvent(new CustomEvent('typographyOverlayToggled', {
|
|
504
|
+
detail: { mode: 'distance', enabled: false }
|
|
505
|
+
}));
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Toggle font mode
|
|
509
|
+
function toggleFontMode() {
|
|
510
|
+
if (fontModeEnabled) {
|
|
511
|
+
disableFontMode();
|
|
512
|
+
showToast('Font Size Mode', false);
|
|
513
|
+
} else {
|
|
514
|
+
enableFontMode();
|
|
515
|
+
showToast('Font Size Mode', true);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Toggle distance mode
|
|
520
|
+
function toggleDistanceMode() {
|
|
521
|
+
if (distanceModeEnabled) {
|
|
522
|
+
disableDistanceMode();
|
|
523
|
+
showToast('Distance Mode', false);
|
|
524
|
+
} else {
|
|
525
|
+
enableDistanceMode();
|
|
526
|
+
showToast('Distance Mode', true);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Expose global API
|
|
531
|
+
window.TypographyOverlay = {
|
|
532
|
+
toggleFontMode: toggleFontMode,
|
|
533
|
+
toggleDistanceMode: toggleDistanceMode,
|
|
534
|
+
enableFontMode: enableFontMode,
|
|
535
|
+
disableFontMode: disableFontMode,
|
|
536
|
+
enableDistanceMode: enableDistanceMode,
|
|
537
|
+
disableDistanceMode: disableDistanceMode,
|
|
538
|
+
isFontModeEnabled: function() { return fontModeEnabled; },
|
|
539
|
+
isDistanceModeEnabled: function() { return distanceModeEnabled; },
|
|
540
|
+
refreshDistances: showDistances
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
// Legacy API
|
|
544
|
+
window.FontSizeOverlay = {
|
|
545
|
+
toggle: toggleFontMode,
|
|
546
|
+
enable: enableFontMode,
|
|
547
|
+
disable: disableFontMode,
|
|
548
|
+
isEnabled: function() { return fontModeEnabled; }
|
|
549
|
+
};
|
|
550
|
+
|
|
551
|
+
// Listen for keyboard shortcuts
|
|
552
|
+
document.addEventListener('keydown', function(e) {
|
|
553
|
+
// Ctrl+Shift+F for font size mode
|
|
554
|
+
if (e.ctrlKey && e.shiftKey && (e.key === 'F' || e.key === 'f')) {
|
|
555
|
+
e.preventDefault();
|
|
556
|
+
toggleFontMode();
|
|
557
|
+
}
|
|
558
|
+
// Ctrl+Shift+D for distance mode
|
|
559
|
+
if (e.ctrlKey && e.shiftKey && (e.key === 'D' || e.key === 'd')) {
|
|
560
|
+
e.preventDefault();
|
|
561
|
+
toggleDistanceMode();
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
// Restore state from localStorage on page load
|
|
566
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
567
|
+
const savedFont = localStorage.getItem(STORAGE_KEY_FONT);
|
|
568
|
+
const savedDistance = localStorage.getItem(STORAGE_KEY_DISTANCE);
|
|
569
|
+
|
|
570
|
+
if (savedFont === 'true') {
|
|
571
|
+
enableFontMode();
|
|
572
|
+
} else if (savedDistance === 'true') {
|
|
573
|
+
enableDistanceMode();
|
|
574
|
+
}
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
// If DOM is already loaded
|
|
578
|
+
if (document.readyState !== 'loading') {
|
|
579
|
+
const savedFont = localStorage.getItem(STORAGE_KEY_FONT);
|
|
580
|
+
const savedDistance = localStorage.getItem(STORAGE_KEY_DISTANCE);
|
|
581
|
+
|
|
582
|
+
if (savedFont === 'true') {
|
|
583
|
+
enableFontMode();
|
|
584
|
+
} else if (savedDistance === 'true') {
|
|
585
|
+
enableDistanceMode();
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
console.log('[Typography Overlay] Ready. Ctrl+Shift+F for font sizes, Ctrl+Shift+D for distances.');
|
|
590
|
+
})();
|