Skip to content

Commit d10a3ef

Browse files
Copilotzachrenwick
andcommitted
feat: optimize index.html for mobile devices
Co-authored-by: zachrenwick <26368788+zachrenwick@users.noreply.github.com>
1 parent 05bba78 commit d10a3ef

1 file changed

Lines changed: 149 additions & 62 deletions

File tree

index.html

Lines changed: 149 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,19 @@
2222
<style>
2323
/* Edward Tufte–inspired theme: high data-ink ratio, restrained palette */
2424
* { margin: 0; padding: 0; box-sizing: border-box; }
25+
26+
/* Use a JS-set custom property for the true viewport height on mobile,
27+
falling back to 100dvh (dynamic viewport height) then 100vh. */
28+
:root { --vh: 1vh; }
29+
2530
body {
2631
font-family: 'ET Book', Palatino, 'Palatino Linotype', 'Book Antiqua', Georgia, serif;
2732
background: #fffff8;
2833
color: #111;
2934
display: flex;
3035
flex-direction: column;
31-
height: 100vh;
36+
height: 100dvh;
37+
height: calc(var(--vh, 1vh) * 100);
3238
overflow: hidden;
3339
}
3440
header {
@@ -53,6 +59,7 @@
5359
padding: 6px 28px;
5460
border-bottom: 1px solid #eee;
5561
flex-shrink: 0;
62+
line-height: 1.6;
5663
}
5764
.help kbd {
5865
background: #f0f0f0;
@@ -62,6 +69,9 @@
6269
font-size: 0.72rem;
6370
font-family: monospace;
6471
}
72+
/* Show/hide desktop vs. touch hint rows */
73+
.help-desktop { display: block; }
74+
.help-touch { display: none; }
6575
#chart {
6676
flex: 1;
6777
min-height: 0;
@@ -80,6 +90,43 @@
8090
border-top: 1px solid #eee;
8191
text-align: right;
8292
flex-shrink: 0;
93+
white-space: nowrap;
94+
overflow: hidden;
95+
text-overflow: ellipsis;
96+
}
97+
98+
/* ── Mobile styles ── */
99+
@media (max-width: 600px) {
100+
header {
101+
padding: 10px 14px 7px;
102+
}
103+
header h1 {
104+
font-size: 1rem;
105+
}
106+
header p {
107+
font-size: 0.75rem;
108+
}
109+
.help {
110+
padding: 5px 14px;
111+
font-size: 0.7rem;
112+
}
113+
.help kbd {
114+
font-size: 0.68rem;
115+
}
116+
.stats {
117+
padding: 3px 14px;
118+
font-size: 0.65rem;
119+
}
120+
#fallback {
121+
padding: 20px;
122+
font-size: 0.9rem;
123+
}
124+
}
125+
126+
/* Show touch hints on true touch-primary devices */
127+
@media (hover: none) and (pointer: coarse) {
128+
.help-desktop { display: none; }
129+
.help-touch { display: block; }
83130
}
84131
</style>
85132
</head>
@@ -90,10 +137,18 @@ <h1>Quantum Metric sessions_archive Schema</h1>
90137
<p>Quantum Metric — BigQuery Schema Tree</p>
91138
</header>
92139
<div class="help">
93-
<kbd>Click</kbd> node to expand / collapse &nbsp;·&nbsp;
94-
<kbd>Scroll</kbd> to zoom &nbsp;·&nbsp;
95-
<kbd>Drag</kbd> to pan &nbsp;·&nbsp;
96-
<kbd>Right-click</kbd> to reset view
140+
<span class="help-desktop">
141+
<kbd>Click</kbd> node to expand / collapse &nbsp;·&nbsp;
142+
<kbd>Scroll</kbd> to zoom &nbsp;·&nbsp;
143+
<kbd>Drag</kbd> to pan &nbsp;·&nbsp;
144+
<kbd>Right-click</kbd> to reset view
145+
</span>
146+
<span class="help-touch">
147+
<kbd>Tap</kbd> node to expand / collapse &nbsp;·&nbsp;
148+
<kbd>Pinch</kbd> to zoom &nbsp;·&nbsp;
149+
<kbd>Drag</kbd> to pan &nbsp;·&nbsp;
150+
<kbd>Double-tap</kbd> to reset view
151+
</span>
97152
</div>
98153
<div id="chart"></div>
99154
<div id="fallback">Schema data is missing or invalid. See source comments for regeneration steps.</div>
@@ -170,77 +225,109 @@ <h1>Quantum Metric sessions_archive Schema</h1>
170225
var chartDom = document.getElementById('chart');
171226
var chart = echarts.init(chartDom);
172227

173-
var option = {
174-
tooltip: {
175-
trigger: 'item',
176-
triggerOn: 'mousemove',
177-
formatter: function (params) {
178-
var d = params.data;
179-
var parts = d.name.match(/^(.+?)\s*\((.+)\)$/);
180-
if (parts) {
181-
var childCount = d.children ? d.children.length : 0;
182-
var tip = '<b>' + parts[1] + '</b><br/>Type: ' + parts[2];
183-
if (childCount > 0) tip += '<br/>Children: ' + childCount;
184-
return tip;
185-
}
186-
return '<b>' + d.name + '</b>';
187-
},
188-
backgroundColor: '#fffff8',
189-
borderColor: '#ccc',
190-
textStyle: { color: '#333', fontFamily: 'monospace', fontSize: 12 }
191-
},
192-
series: [{
193-
type: 'tree',
194-
data: [SCHEMA_DATA],
195-
orient: 'LR',
196-
top: 20,
197-
bottom: 20,
198-
left: 160,
199-
right: 260,
200-
symbolSize: 7,
201-
edgeShape: 'polyline',
202-
edgeForkPosition: '63%',
203-
initialTreeDepth: -1, // we control collapse state manually
204-
lineStyle: {
205-
color: '#ccc',
206-
width: 1
207-
},
208-
label: {
209-
position: 'left',
210-
verticalAlign: 'middle',
211-
align: 'right',
212-
fontSize: 11,
213-
fontFamily: "'SF Mono', 'Menlo', 'Monaco', 'Consolas', monospace",
214-
color: '#333'
228+
function isMobile() { return window.innerWidth <= 600; }
229+
230+
function buildOption() {
231+
var mobile = isMobile();
232+
return {
233+
tooltip: {
234+
trigger: 'item',
235+
triggerOn: 'mousemove',
236+
formatter: function (params) {
237+
var d = params.data;
238+
var parts = d.name.match(/^(.+?)\s*\((.+)\)$/);
239+
if (parts) {
240+
var childCount = d.children ? d.children.length : 0;
241+
var tip = '<b>' + parts[1] + '</b><br/>Type: ' + parts[2];
242+
if (childCount > 0) tip += '<br/>Children: ' + childCount;
243+
return tip;
244+
}
245+
return '<b>' + d.name + '</b>';
246+
},
247+
backgroundColor: '#fffff8',
248+
borderColor: '#ccc',
249+
textStyle: { color: '#333', fontFamily: 'monospace', fontSize: 12 }
215250
},
216-
leaves: {
251+
series: [{
252+
type: 'tree',
253+
data: [SCHEMA_DATA],
254+
orient: 'LR',
255+
top: 20,
256+
bottom: 20,
257+
left: mobile ? 80 : 160,
258+
right: mobile ? 120 : 260,
259+
symbolSize: mobile ? 5 : 7,
260+
edgeShape: 'polyline',
261+
edgeForkPosition: '63%',
262+
initialTreeDepth: -1, // we control collapse state manually
263+
lineStyle: {
264+
color: '#ccc',
265+
width: 1
266+
},
217267
label: {
218-
position: 'right',
268+
position: 'left',
219269
verticalAlign: 'middle',
220-
align: 'left'
221-
}
222-
},
223-
expandAndCollapse: true,
224-
animationDuration: 400,
225-
animationDurationUpdate: 400,
226-
roam: true,
227-
scaleLimit: { min: 0.3, max: 3 }
228-
}]
229-
};
270+
align: 'right',
271+
fontSize: mobile ? 9 : 11,
272+
fontFamily: "'SF Mono', 'Menlo', 'Monaco', 'Consolas', monospace",
273+
color: '#333'
274+
},
275+
leaves: {
276+
label: {
277+
position: 'right',
278+
verticalAlign: 'middle',
279+
align: 'left'
280+
}
281+
},
282+
expandAndCollapse: true,
283+
animationDuration: 400,
284+
animationDurationUpdate: 400,
285+
roam: true,
286+
scaleLimit: { min: mobile ? 0.2 : 0.3, max: 3 }
287+
}]
288+
};
289+
}
230290

231-
chart.setOption(option);
291+
chart.setOption(buildOption());
232292

233293
// ── Right-click to reset view ──
234294
chartDom.addEventListener('contextmenu', function (e) {
235295
e.preventDefault();
236296
chart.dispatchAction({ type: 'restore' });
237297
});
238298

239-
// ── Debounced resize ──
299+
// ── Double-tap to reset view (mobile) ──
300+
var DOUBLE_TAP_THRESHOLD_MS = 350;
301+
var lastTap = 0;
302+
chartDom.addEventListener('touchend', function (e) {
303+
var now = Date.now();
304+
if (now - lastTap < DOUBLE_TAP_THRESHOLD_MS) {
305+
e.preventDefault();
306+
chart.dispatchAction({ type: 'restore' });
307+
}
308+
lastTap = now;
309+
}, { passive: false });
310+
311+
// ── True viewport height for mobile browsers (hides/shows browser UI) ──
312+
function setVh() {
313+
document.documentElement.style.setProperty('--vh', window.innerHeight * 0.01 + 'px');
314+
}
315+
setVh();
316+
317+
// ── Debounced resize: update vh, re-apply options (breakpoint may change), resize chart ──
240318
var resizeTimer;
319+
var lastMobile = isMobile();
241320
window.addEventListener('resize', function () {
242321
clearTimeout(resizeTimer);
243-
resizeTimer = setTimeout(function () { chart.resize(); }, 150);
322+
resizeTimer = setTimeout(function () {
323+
setVh();
324+
var nowMobile = isMobile();
325+
if (nowMobile !== lastMobile) {
326+
lastMobile = nowMobile;
327+
chart.setOption(buildOption());
328+
}
329+
chart.resize();
330+
}, 150);
244331
});
245332
})();
246333
</script>

0 commit comments

Comments
 (0)