north-star / commit
add enable compass logic
src/app.js | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- src/index.html | 2 +- src/style.css | 5 +++++ 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/app.js b/src/app.js index fe06c90..ccf2c89 100644 --- a/src/app.js +++ b/src/app.js @@ -126,6 +126,34 @@ if (createRoomLink) { createRoomLink.href = BASE_ROOM_URL; } +const requiresExplicitCompassPermission = + typeof DeviceOrientationEvent !== 'undefined' && + typeof DeviceOrientationEvent.requestPermission === 'function'; +let compassEnabled = !requiresExplicitCompassPermission; + +const updateCompassButtonState = () => { + if (!calibrateHeadingLink) return; + + calibrateHeadingLink.textContent = compassEnabled ? 'Calibrate North' : 'Enable Compass'; + calibrateHeadingLink.classList.toggle('compass-required', !compassEnabled); +}; + +const requestCompassPermission = async () => { + if (!requiresExplicitCompassPermission) { + return true; + } + + try { + const permissionState = await DeviceOrientationEvent.requestPermission(); + return permissionState === 'granted'; + } catch (err) { + console.error('Failed to request compass permission', err); + return false; + } +}; + +updateCompassButtonState(); + let inviteStatusTimer = null; const setInviteStatus = (message, isError = false) => { if (!inviteRoomStatus) return; @@ -228,9 +256,22 @@ if (joinRoomLink) { } if (calibrateHeadingLink) { - calibrateHeadingLink.addEventListener('click', (event) => { + calibrateHeadingLink.addEventListener('click', async (event) => { event.preventDefault(); + if (!compassEnabled) { + const granted = await requestCompassPermission(); + if (!granted) { + alert('Compass permission was denied. Enable Motion & Orientation Access in Safari settings and try again.'); + return; + } + + compassEnabled = true; + updateCompassButtonState(); + setInviteStatus('Compass enabled'); + return; + } + if (lastRawHeading === null) { alert('Heading sensor is not ready yet. Try again in a moment.'); return; @@ -549,6 +590,11 @@ window.addEventListener('deviceorientationabsolute', (event) => { const heading = getHeadingFromEvent(event); if (heading === null) return; + if (!compassEnabled) { + compassEnabled = true; + updateCompassButtonState(); + } + hasAbsoluteOrientation = true; lastRawHeading = heading; selfHeading = normalizeAngle(heading + headingCorrectionDeg); @@ -561,6 +607,11 @@ window.addEventListener('deviceorientation', (event) => { const heading = getHeadingFromEvent(event); if (heading === null) return; + if (!compassEnabled) { + compassEnabled = true; + updateCompassButtonState(); + } + lastRawHeading = heading; selfHeading = normalizeAngle(heading + headingCorrectionDeg); requestRender(); diff --git a/src/index.html b/src/index.html index ced7d48..ddf2aab 100644 --- a/src/index.html +++ b/src/index.html @@ -28,7 +28,7 @@ </div> <div id="content"> <div class="panel-actions"> - <button id="calibrate-heading-link" class="participants-toggle" type="button">Calibrate North</button> + <button id="calibrate-heading-link" class="participants-toggle" type="button">Enable Compass</button> <button id="participants-toggle" class="participants-toggle" type="button" aria-expanded="true">Hide Participants</button> </div> diff --git a/src/style.css b/src/style.css index c3cad48..ed05958 100644 --- a/src/style.css +++ b/src/style.css @@ -179,6 +179,11 @@ a { font-weight: 700; } +.participants-toggle.compass-required { + border: 2px solid #ef4444; + box-shadow: 0 0 0 1px rgba(239, 68, 68, 0.35); +} + .participants-panel { position: absolute; right: 10px;