fix: early name validation, fighter glow, reduced visual noise

- Add /api/auth/check-name endpoint for early name availability check
- JoinBoutPage checks name availability at naming step (not after webhook)
- FightCardPage: replace poster containers with circular glow behind sprites
- Reduce synthwave grid and CRT overlay opacity for cleaner backgrounds
- BotProfilePage: webhook management, owner-only fields
- useNostr: normalize bot data, guard auto-restore, clearAllState helper
- bots.ts: expose owner-only webhook info on stats endpoint

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-08 11:03:16 +00:00
co-authored by Claude Opus 4.6
parent 2d8cdcc60a
commit 9a11c48487
7 changed files with 405 additions and 120 deletions
+46 -5
View File
@@ -144,6 +144,7 @@ function handleGenerateLogin() {
}
async function handleNsecBackupDone() {
if (isLoading) return
showNsecBackup.value = false
try {
const result = await login()
@@ -206,7 +207,9 @@ function pickCharacter(id: string) {
step.value = 'name-bot'
}
function confirmName() {
const isCheckingName = ref(false)
async function confirmName() {
const name = botName.value.trim()
if (!name || name.length < 2) {
error.value = 'Name must be at least 2 characters.'
@@ -217,6 +220,21 @@ function confirmName() {
return
}
error.value = ''
isCheckingName.value = true
try {
const res = await fetch(`/api/auth/check-name/${encodeURIComponent(name)}`)
if (res.ok) {
const data = await res.json()
if (!data.available) {
error.value = 'That name is taken. Pick another.'
return
}
}
} catch {
// If check fails, proceed anyway — server will catch it at registration
} finally {
isCheckingName.value = false
}
step.value = 'bot-setup'
}
@@ -269,6 +287,21 @@ async function confirmHumanName() {
return
}
error.value = ''
isCheckingName.value = true
try {
const res = await fetch(`/api/auth/check-name/${encodeURIComponent(name)}`)
if (res.ok) {
const data = await res.json()
if (!data.available) {
error.value = 'That name is taken. Pick another.'
return
}
}
} catch {
// proceed — server catches at registration
} finally {
isCheckingName.value = false
}
step.value = 'human-guide'
}
@@ -598,10 +631,14 @@ function handleSignOut() {
<button
class="flex-1 py-3 bg-neon-cyan/10 border-2 border-neon-cyan/50 text-neon-cyan
font-display font-bold text-sm tracking-wider
hover:bg-neon-cyan/20 transition-all"
hover:bg-neon-cyan/20 transition-all
disabled:opacity-50 disabled:cursor-wait
flex items-center justify-center gap-2"
:disabled="isCheckingName"
@click="confirmName"
>
NEXT
<span v-if="isCheckingName" class="w-4 h-4 border-2 border-neon-cyan/30 border-t-neon-cyan rounded-full animate-spin" />
{{ isCheckingName ? 'CHECKING...' : 'NEXT' }}
</button>
</div>
</template>
@@ -852,10 +889,14 @@ function handleSignOut() {
<button
class="flex-1 py-3 bg-neon-pink/10 border-2 border-neon-pink/50 text-neon-pink
font-display font-bold text-sm tracking-wider
hover:bg-neon-pink/20 transition-all"
hover:bg-neon-pink/20 transition-all
disabled:opacity-50 disabled:cursor-wait
flex items-center justify-center gap-2"
:disabled="isCheckingName"
@click="confirmHumanName"
>
NEXT
<span v-if="isCheckingName" class="w-4 h-4 border-2 border-neon-pink/30 border-t-neon-pink rounded-full animate-spin" />
{{ isCheckingName ? 'CHECKING...' : 'NEXT' }}
</button>
</div>
</template>