fix: mobile nostr signer detection, mobile TTS auto-unlock, button loaders

- Nostr signer: poll for window.nostr up to 3s on mobile (Amber injects
  late). Both login() and handleSignerLogin() now wait before failing.
- Mobile TTS: install global one-time click/touch/keydown handler to
  auto-unlock AudioContext when fight pages mount. Previously only
  triggered by explicit sound toggle, so mobile TTS silently failed.
- Add loading spinners to "I BUILD BOTS" and "I FIGHT MYSELF" buttons.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-09 14:44:38 +00:00
co-authored by Claude Opus 4.6
parent 4897335686
commit dd3cbdae7f
5 changed files with 80 additions and 18 deletions
+29 -10
View File
@@ -10,7 +10,7 @@ import WalletConnect from '../components/WalletConnect.vue'
import { authFetch } from '../lib/nostr-auth'
const router = useRouter()
const { pubkey, bot, profilePicUrl, isLoggedIn, hasExtension, hasStoredKey, isLoading, login, generateLogin, loginWithNsec, registerBot, registerHuman, getStoredNsec, logout } = useNostr()
const { pubkey, bot, profilePicUrl, isLoggedIn, hasExtension, hasStoredKey, isLoading, login, waitForSigner, generateLogin, loginWithNsec, registerBot, registerHuman, getStoredNsec, logout } = useNostr()
const showNsecBackup = ref(false)
const generatedNsec = ref('')
const nsecInput = ref('')
@@ -185,10 +185,16 @@ async function handleLogin() {
}
}
function handleSignerLogin() {
async function handleSignerLogin() {
if (!window.nostr) {
error.value = 'No Nostr signer detected. Install a NIP-07 extension (Nos2x, Alby) or use Amber on Android.'
return
// Mobile signers inject late — wait briefly
error.value = 'Looking for signer...'
const found = await waitForSigner(3000)
if (!found) {
error.value = 'No Nostr signer detected. Install a NIP-07 extension (Nos2x, Alby) or use Amber on Android.'
return
}
error.value = ''
}
handleLogin()
}
@@ -295,14 +301,21 @@ async function confirmName() {
step.value = 'bot-setup'
}
function chooseBot() {
const isChoosingMode = ref(false)
async function chooseBot() {
isChoosingMode.value = true
isHumanMode.value = false
await new Promise(r => setTimeout(r, 0)) // Let spinner render
step.value = 'pick-character'
isChoosingMode.value = false
}
function chooseHuman() {
async function chooseHuman() {
isChoosingMode.value = true
isHumanMode.value = true
await new Promise(r => setTimeout(r, 0))
step.value = 'pick-human-avatar'
isChoosingMode.value = false
}
const humanAvatarList = [
@@ -640,10 +653,13 @@ function handleSignOut() {
<div class="space-y-4">
<button
class="w-full py-5 px-4 bg-neon-cyan/5 border-2 border-neon-cyan/40 text-left
hover:bg-neon-cyan/10 hover:border-neon-cyan/70 transition-all group"
hover:bg-neon-cyan/10 hover:border-neon-cyan/70 transition-all group
disabled:opacity-50 disabled:cursor-wait"
:disabled="isChoosingMode"
@click="chooseBot"
>
<span class="font-display font-black text-lg tracking-wider text-neon-cyan block mb-1">
<span class="font-display font-black text-lg tracking-wider text-neon-cyan block mb-1 flex items-center gap-2">
<span v-if="isChoosingMode && !isHumanMode" class="w-4 h-4 border-2 border-neon-cyan/30 border-t-neon-cyan rounded-full animate-spin" />
I BUILD BOTS
</span>
<span class="font-mono text-[10px] text-text-muted leading-relaxed block">
@@ -654,10 +670,13 @@ function handleSignOut() {
<button
class="w-full py-5 px-4 bg-neon-pink/5 border-2 border-neon-pink/40 text-left
hover:bg-neon-pink/10 hover:border-neon-pink/70 transition-all group"
hover:bg-neon-pink/10 hover:border-neon-pink/70 transition-all group
disabled:opacity-50 disabled:cursor-wait"
:disabled="isChoosingMode"
@click="chooseHuman"
>
<span class="font-display font-black text-lg tracking-wider text-neon-pink block mb-1">
<span class="font-display font-black text-lg tracking-wider text-neon-pink block mb-1 flex items-center gap-2">
<span v-if="isChoosingMode && isHumanMode" class="w-4 h-4 border-2 border-neon-pink/30 border-t-neon-pink rounded-full animate-spin" />
I FIGHT MYSELF
</span>
<span class="font-mono text-[10px] text-text-muted leading-relaxed block">