aboutsummaryrefslogtreecommitdiffhomepage
path: root/public/bluebey-studio/src/main.js
diff options
context:
space:
mode:
authorYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-05 13:13:01 +0900
committerYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-05 13:13:01 +0900
commite22218a01f418fffc89d0c16d88ada84a764b448 (patch)
tree99819e329aa3eaffeadb5f78004b193feafb7915 /public/bluebey-studio/src/main.js
parent71a1e45dae4548a3096a51ab4c0262e12c7203fa (diff)
bluebey-studio: スマホのパネルをハンドルのドラッグで上下に動かせるように
Diffstat (limited to 'public/bluebey-studio/src/main.js')
-rw-r--r--public/bluebey-studio/src/main.js50
1 files changed, 50 insertions, 0 deletions
diff --git a/public/bluebey-studio/src/main.js b/public/bluebey-studio/src/main.js
index e282e9d..49494a4 100644
--- a/public/bluebey-studio/src/main.js
+++ b/public/bluebey-studio/src/main.js
@@ -1356,6 +1356,56 @@ async function init() {
const panel = buildPanel(app, document.getElementById('panel'));
app.panel = panel;
+ // On a phone the panel is a bottom sheet. Its grab handle drags the sheet's top
+ // edge up and down, so the menu can be pulled out of the way of the character.
+ const panelEl = document.getElementById('panel');
+ const panelGrip = document.createElement('div');
+ panelGrip.className = 'panel-grip';
+ panelGrip.setAttribute('aria-hidden', 'true');
+ panelEl.prepend(panelGrip);
+ installSheetDrag(panelEl, panelGrip);
+
+ /** Drag on the phone sheet's handle; a no-op anywhere else. */
+ function installSheetDrag(sheet, grip) {
+ const phone = window.matchMedia('(max-width: 768px), (max-height: 500px) and (pointer: coarse)');
+ let drag = null;
+ const minHeight = () => Math.round(window.innerHeight * 0.16);
+ const maxHeight = () => Math.round(window.innerHeight * 0.94);
+
+ grip.addEventListener('pointerdown', (event) => {
+ if (!phone.matches) return;
+ const rect = sheet.getBoundingClientRect();
+ // Start from the height the sheet has now, so the first move does not jump.
+ drag = { id: event.pointerId, fromY: event.clientY, startH: rect.height };
+ sheet.style.maxHeight = 'none';
+ sheet.style.height = `${rect.height}px`;
+ try { grip.setPointerCapture(event.pointerId); } catch { /* capture is optional */ }
+ event.preventDefault();
+ });
+ grip.addEventListener('pointermove', (event) => {
+ if (!drag || event.pointerId !== drag.id) return;
+ // Dragging up grows the sheet (its top edge climbs); dragging down shrinks it.
+ const next = drag.startH + (drag.fromY - event.clientY);
+ sheet.style.height = `${Math.min(maxHeight(), Math.max(minHeight(), next))}px`;
+ event.preventDefault();
+ });
+ const end = (event) => {
+ if (!drag || (event && event.pointerId !== drag.id)) return;
+ drag = null;
+ };
+ grip.addEventListener('pointerup', end);
+ grip.addEventListener('pointercancel', end);
+
+ // A window grown to the desktop layout keeps the side column: drop the height
+ // the drag had fixed, so the panel goes back to filling the screen.
+ const clearOnDesktop = () => {
+ if (phone.matches) return;
+ sheet.style.height = '';
+ sheet.style.maxHeight = '';
+ };
+ window.addEventListener('resize', clearOnDesktop);
+ }
+
Object.assign(app.actions, {
capturePose,
applyState,