Add fullscreen toggle and wake lock to prevent screen sleep

## Features
- Fullscreen button (⛶) in header to toggle fullscreen mode
- Wake Lock API integration to keep screen on while using the app
- Sun icon (☀) indicator shows wake lock status (bright = active)

## Wake Lock behavior
- Automatically requests wake lock when page loads
- Re-acquires wake lock when returning to the page
- Visual indicator pulses when active
- Gracefully hidden if Wake Lock API not supported

## Fullscreen
- Works on Android Chrome and desktop browsers
- iOS Safari has limited support (no fullscreen API)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-03 18:34:56 -08:00
parent da5d2d6ded
commit 063949cd7d
4 changed files with 103 additions and 1 deletions

View File

@@ -550,3 +550,47 @@ body {
color: white;
padding: 0.5rem;
}
/* Fullscreen Button */
.header-btn.icon-btn {
padding: 0.5rem 0.75rem;
font-size: 1.2rem;
line-height: 1;
}
/* Wake Lock Status */
.wake-lock-status {
display: flex;
align-items: center;
padding: 0.25rem 0.5rem;
border-radius: 4px;
font-size: 1rem;
opacity: 0.4;
transition: opacity 0.3s;
}
.wake-lock-status.active {
opacity: 1;
}
.wake-lock-status .wake-icon {
color: #ffc107;
}
.wake-lock-status.active .wake-icon {
animation: pulse-glow 2s ease-in-out infinite;
}
@keyframes pulse-glow {
0%, 100% { opacity: 1; }
50% { opacity: 0.6; }
}
/* Fullscreen styles */
:fullscreen .header {
padding-top: 0.5rem;
}
:fullscreen .macro-grid {
padding-bottom: 1rem;
}

View File

@@ -33,6 +33,10 @@
<div class="status-dot"></div>
<span>Disconnected</span>
</div>
<div class="wake-lock-status" id="wake-lock-status" title="Screen wake lock">
<span class="wake-icon"></span>
</div>
<button class="header-btn icon-btn" id="fullscreen-btn" onclick="app.toggleFullscreen()" title="Toggle fullscreen"></button>
<button class="header-btn secondary" onclick="app.refresh()">Refresh</button>
</div>
</header>

View File

@@ -6,6 +6,7 @@ class MacroPadApp {
this.tabs = [];
this.currentTab = 'All';
this.ws = null;
this.wakeLock = null;
this.init();
}
@@ -15,6 +16,7 @@ class MacroPadApp {
await this.loadMacros();
this.setupWebSocket();
this.setupEventListeners();
this.setupWakeLock();
this.checkInstallPrompt();
}
@@ -245,6 +247,58 @@ class MacroPadApp {
this.loadTabs();
this.loadMacros();
}
// Fullscreen
toggleFullscreen() {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen().catch(err => {
console.log('Fullscreen error:', err);
});
} else {
document.exitFullscreen();
}
}
// Wake Lock - prevents screen from sleeping
async setupWakeLock() {
if (!('wakeLock' in navigator)) {
console.log('Wake Lock API not supported');
document.getElementById('wake-lock-status')?.remove();
return;
}
// Request wake lock
await this.requestWakeLock();
// Re-acquire wake lock when page becomes visible again
document.addEventListener('visibilitychange', async () => {
if (document.visibilityState === 'visible') {
await this.requestWakeLock();
}
});
}
async requestWakeLock() {
try {
this.wakeLock = await navigator.wakeLock.request('screen');
this.updateWakeLockStatus(true);
this.wakeLock.addEventListener('release', () => {
this.updateWakeLockStatus(false);
});
} catch (err) {
console.log('Wake Lock error:', err);
this.updateWakeLockStatus(false);
}
}
updateWakeLockStatus(active) {
const status = document.getElementById('wake-lock-status');
if (status) {
status.classList.toggle('active', active);
status.title = active ? 'Screen will stay on' : 'Screen may sleep';
}
}
}
// Initialize app

View File

@@ -1,5 +1,5 @@
// MacroPad PWA Service Worker
const CACHE_NAME = 'macropad-v2';
const CACHE_NAME = 'macropad-v3';
const ASSETS_TO_CACHE = [
'/',
'/static/css/styles.css',