Replace copy button with text box for sharing
Simple solution: show the link in a selectable text box Works everywhere without clipboard API issues 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
+6
-3
@@ -1100,9 +1100,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="margin-top: 14px; display: flex; align-items: center; gap: 12px;">
|
<div style="margin-top: 14px;">
|
||||||
<button id="copyLinkBtn" type="button" disabled>Copy link</button>
|
<button id="copyLinkBtn" type="button" disabled>Share</button>
|
||||||
<span id="copyLinkConfirm" style="display: none; font-size: 8px; color: var(--gb-lightest);">Link copied!</span>
|
<div id="shareLinkBox" style="display: none; margin-top: 12px;">
|
||||||
|
<input type="text" id="shareLinkInput" readonly style="width: 100%; font-size: 8px; padding: 10px;" />
|
||||||
|
<div style="margin-top: 6px; font-size: 8px; color: var(--gb-dark);">Select and copy the link above</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
+11
-43
@@ -58,7 +58,8 @@ class MotifApp {
|
|||||||
private iosAudioState!: HTMLElement;
|
private iosAudioState!: HTMLElement;
|
||||||
|
|
||||||
private copyLinkBtn!: HTMLButtonElement;
|
private copyLinkBtn!: HTMLButtonElement;
|
||||||
private copyLinkConfirm!: HTMLElement;
|
private shareLinkBox!: HTMLElement;
|
||||||
|
private shareLinkInput!: HTMLInputElement;
|
||||||
|
|
||||||
// Embed snippet UI
|
// Embed snippet UI
|
||||||
private embedSection: HTMLElement | null = null;
|
private embedSection: HTMLElement | null = null;
|
||||||
@@ -135,7 +136,8 @@ class MotifApp {
|
|||||||
this.motifDuration = document.getElementById('motifDuration')!;
|
this.motifDuration = document.getElementById('motifDuration')!;
|
||||||
|
|
||||||
this.copyLinkBtn = document.getElementById('copyLinkBtn') as HTMLButtonElement;
|
this.copyLinkBtn = document.getElementById('copyLinkBtn') as HTMLButtonElement;
|
||||||
this.copyLinkConfirm = document.getElementById('copyLinkConfirm') as HTMLElement;
|
this.shareLinkBox = document.getElementById('shareLinkBox') as HTMLElement;
|
||||||
|
this.shareLinkInput = document.getElementById('shareLinkInput') as HTMLInputElement;
|
||||||
|
|
||||||
// iOS audio unlock UI (Motif)
|
// iOS audio unlock UI (Motif)
|
||||||
this.iosAudioBanner = document.getElementById('iosAudioBanner')!;
|
this.iosAudioBanner = document.getElementById('iosAudioBanner')!;
|
||||||
@@ -183,7 +185,7 @@ class MotifApp {
|
|||||||
this.motifProgressBar.addEventListener('input', seekHandler);
|
this.motifProgressBar.addEventListener('input', seekHandler);
|
||||||
this.motifProgressBar.addEventListener('change', seekHandler);
|
this.motifProgressBar.addEventListener('change', seekHandler);
|
||||||
|
|
||||||
this.copyLinkBtn.addEventListener('click', () => void this.handleCopyLink());
|
this.copyLinkBtn.addEventListener('click', () => this.handleCopyLink());
|
||||||
|
|
||||||
// Embed snippet copy (may be disabled / not-live)
|
// Embed snippet copy (may be disabled / not-live)
|
||||||
this.copyEmbedBtn?.addEventListener('click', () => void this.copyEmbedSnippet());
|
this.copyEmbedBtn?.addEventListener('click', () => void this.copyEmbedSnippet());
|
||||||
@@ -737,14 +739,12 @@ class MotifApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleCopyLink(): Promise<void> {
|
private handleCopyLink(): void {
|
||||||
if (!this.hasGenerated) return;
|
if (!this.hasGenerated) return;
|
||||||
const result = this.searchResults[this.selectedResultIndex];
|
const result = this.searchResults[this.selectedResultIndex];
|
||||||
if (!result?.midiUrl) return;
|
if (!result?.midiUrl) return;
|
||||||
|
|
||||||
const title = this.cleanTitleForShare(result.title || 'WARIO SYNTH');
|
// Build share URL
|
||||||
|
|
||||||
// Build share URL immediately (no async before copy/share!)
|
|
||||||
let shareUrl: string;
|
let shareUrl: string;
|
||||||
if (result.source === 'bitmidi') {
|
if (result.source === 'bitmidi') {
|
||||||
const m = String(result.midiUrl).match(/\/uploads\/(\d+)\.mid/i);
|
const m = String(result.midiUrl).match(/\/uploads\/(\d+)\.mid/i);
|
||||||
@@ -757,42 +757,10 @@ class MotifApp {
|
|||||||
shareUrl = `${window.location.origin}/play?u=${encodeURIComponent(result.midiUrl)}`;
|
shareUrl = `${window.location.origin}/play?u=${encodeURIComponent(result.midiUrl)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// On mobile: use native share sheet (better UX)
|
// Show the link in a text box for easy copying
|
||||||
if (navigator.share) {
|
this.shareLinkInput.value = shareUrl;
|
||||||
try {
|
this.shareLinkBox.style.display = 'block';
|
||||||
await navigator.share({
|
this.shareLinkInput.select();
|
||||||
title: `${title} - WARIO SYNTH`,
|
|
||||||
url: shareUrl
|
|
||||||
});
|
|
||||||
this.copyLinkConfirm.style.display = 'inline';
|
|
||||||
this.copyLinkConfirm.textContent = 'Shared!';
|
|
||||||
window.setTimeout(() => {
|
|
||||||
this.copyLinkConfirm.style.display = 'none';
|
|
||||||
}, 2000);
|
|
||||||
return;
|
|
||||||
} catch {
|
|
||||||
// User cancelled or share failed - fall through to clipboard
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Desktop: copy to clipboard
|
|
||||||
try {
|
|
||||||
this.copyLinkBtn.disabled = true;
|
|
||||||
await navigator.clipboard.writeText(shareUrl);
|
|
||||||
this.copyLinkConfirm.style.display = 'inline';
|
|
||||||
this.copyLinkConfirm.textContent = 'Link copied!';
|
|
||||||
window.setTimeout(() => {
|
|
||||||
this.copyLinkConfirm.style.display = 'none';
|
|
||||||
}, 3000);
|
|
||||||
} catch (err) {
|
|
||||||
this.copyLinkConfirm.style.display = 'inline';
|
|
||||||
this.copyLinkConfirm.textContent = 'Copy failed';
|
|
||||||
window.setTimeout(() => {
|
|
||||||
this.copyLinkConfirm.style.display = 'none';
|
|
||||||
}, 3000);
|
|
||||||
} finally {
|
|
||||||
this.copyLinkBtn.disabled = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private setState(state: 'idle' | 'results' | 'selected' | 'generated'): void {
|
private setState(state: 'idle' | 'results' | 'selected' | 'generated'): void {
|
||||||
|
|||||||
Reference in New Issue
Block a user