Add iOS audio unlock banner to play page
Shows "Tap to enable audio on iOS" banner on iOS devices. Hides automatically once audio is unlocked via button or play. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -294,6 +294,28 @@
|
||||
color: var(--gb-lightest);
|
||||
}
|
||||
|
||||
/* iOS audio unlock banner */
|
||||
.ios-audio-banner {
|
||||
margin-top: calc(var(--spacing-unit) * 2);
|
||||
padding: calc(var(--spacing-unit) * 2);
|
||||
border-top: 2px solid var(--gb-light);
|
||||
display: none; /* toggled by JS */
|
||||
text-align: center;
|
||||
}
|
||||
.ios-audio-banner p {
|
||||
font-size: 8px;
|
||||
color: var(--gb-light);
|
||||
margin: 0 0 calc(var(--spacing-unit)) 0;
|
||||
line-height: 2;
|
||||
}
|
||||
.ios-audio-banner button {
|
||||
background: var(--gb-lightest);
|
||||
color: var(--gb-darkest);
|
||||
border: var(--pixel-border) solid var(--gb-light);
|
||||
padding: 12px 20px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
.footer {
|
||||
margin-top: calc(var(--spacing-unit) * 4);
|
||||
@@ -338,6 +360,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- iOS Audio Unlock -->
|
||||
<div id="iosAudioBanner" class="ios-audio-banner">
|
||||
<p>Tap to enable audio on iOS</p>
|
||||
<button id="enableAudioBtn" type="button">Enable Audio</button>
|
||||
</div>
|
||||
|
||||
<!-- CTA -->
|
||||
<div class="cta-link-inline">
|
||||
<a id="generateOwn" href="/">Generate your own</a>
|
||||
|
||||
+29
-1
@@ -1,7 +1,7 @@
|
||||
import { MIDIService } from './services/MIDIService';
|
||||
import { MIDIParser } from './midi/MIDIParser';
|
||||
import { MotifEngine } from './core/MotifEngine';
|
||||
import { unlockAudio } from './utils/audioUnlock';
|
||||
import { unlockAudio, isAudioReady } from './utils/audioUnlock';
|
||||
import type { NoteEvent } from './types';
|
||||
|
||||
function qs(id: string): HTMLElement {
|
||||
@@ -140,6 +140,33 @@ async function main(): Promise<void> {
|
||||
const currentTimeEl = qs('playCurrentTime') as HTMLElement;
|
||||
const durationEl = qs('playDuration') as HTMLElement;
|
||||
const timeRow = qs('playTimeRow') as HTMLElement;
|
||||
const iosAudioBanner = qs('iosAudioBanner') as HTMLElement;
|
||||
const enableAudioBtn = qs('enableAudioBtn') as HTMLButtonElement;
|
||||
|
||||
// Detect iOS/Safari for audio unlock banner
|
||||
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) ||
|
||||
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
|
||||
|
||||
function updateIOSBanner(): void {
|
||||
if (isIOS && !isAudioReady()) {
|
||||
iosAudioBanner.style.display = 'block';
|
||||
} else {
|
||||
iosAudioBanner.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// Show banner on iOS if needed
|
||||
updateIOSBanner();
|
||||
|
||||
// Handle enable audio button
|
||||
enableAudioBtn.addEventListener('click', async () => {
|
||||
try {
|
||||
await unlockAudio();
|
||||
updateIOSBanner();
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
});
|
||||
|
||||
const { midiUrl: u, title } = buildMidiUrlFromParams();
|
||||
|
||||
@@ -290,6 +317,7 @@ async function main(): Promise<void> {
|
||||
try {
|
||||
// Wait for unlock to complete
|
||||
await unlockPromise;
|
||||
updateIOSBanner(); // Hide banner once audio is unlocked
|
||||
|
||||
// First play generates the artifact (deterministically from MIDI structure).
|
||||
if (!isGenerated) {
|
||||
|
||||
Reference in New Issue
Block a user