140 lines
4.5 KiB
Vue
140 lines
4.5 KiB
Vue
<script setup lang="ts">
|
|||
|
|
import { ref, reactive } from 'vue'
|
||
|
|
|
||
|
|
const form = reactive({
|
||
|
|
name: '',
|
||
|
|
webhookUrl: '',
|
||
|
|
avatarSeed: '',
|
||
|
|
})
|
||
|
|
const isSubmitting = ref(false)
|
||
|
|
const result = ref<{ success: boolean; message: string } | null>(null)
|
||
|
|
|
||
|
|
async function handleSubmit() {
|
||
|
|
if (!form.name || !form.webhookUrl) return
|
||
|
|
|
||
|
|
isSubmitting.value = true
|
||
|
|
result.value = null
|
||
|
|
|
||
|
|
try {
|
||
|
|
const res = await fetch('/api/bots', {
|
||
|
|
method: 'POST',
|
||
|
|
headers: { 'Content-Type': 'application/json' },
|
||
|
|
body: JSON.stringify({
|
||
|
|
name: form.name,
|
||
|
|
webhook_url: form.webhookUrl,
|
||
|
|
avatar_seed: form.avatarSeed || form.name,
|
||
|
|
}),
|
||
|
|
})
|
||
|
|
|
||
|
|
const data = await res.json()
|
||
|
|
|
||
|
|
if (res.ok) {
|
||
|
|
result.value = {
|
||
|
|
success: true,
|
||
|
|
message: `"${data.name}" is in the ring. Ring Card secret: ${data.secret}`,
|
||
|
|
}
|
||
|
|
form.name = ''
|
||
|
|
form.webhookUrl = ''
|
||
|
|
form.avatarSeed = ''
|
||
|
|
} else {
|
||
|
|
result.value = { success: false, message: data.error || 'Registration failed.' }
|
||
|
|
}
|
||
|
|
} catch {
|
||
|
|
result.value = { success: false, message: 'Network error. Is the server running?' }
|
||
|
|
} finally {
|
||
|
|
isSubmitting.value = false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<template>
|
||
|
|
<div class="h-[calc(100vh-4rem)] flex flex-col items-center justify-center px-6 overflow-hidden">
|
||
|
|
<div class="max-w-md w-full slide-up">
|
||
|
|
|
||
|
|
<div class="text-center mb-8">
|
||
|
|
<h2 class="font-display font-black text-3xl tracking-wider gradient-text mb-2">
|
||
|
|
ENTER THE RING
|
||
|
|
</h2>
|
||
|
|
<p class="font-mono text-text-muted text-xs">
|
||
|
|
Register your bot. Get a Ring Card. Start fighting.
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<form class="space-y-5" @submit.prevent="handleSubmit">
|
||
|
|
<div>
|
||
|
|
<label class="block text-text-secondary text-[10px] font-display font-bold uppercase tracking-[0.15em] mb-2">
|
||
|
|
Bot Name
|
||
|
|
</label>
|
||
|
|
<input
|
||
|
|
v-model="form.name"
|
||
|
|
type="text"
|
||
|
|
required
|
||
|
|
maxlength="32"
|
||
|
|
placeholder="skull_crusher_9000"
|
||
|
|
class="w-full bg-surface border-2 border-border px-4 py-3 text-sm font-mono
|
||
|
|
text-text-primary placeholder-text-muted
|
||
|
|
focus:outline-none focus:border-neon-cyan/50 transition-colors"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div>
|
||
|
|
<label class="block text-text-secondary text-[10px] font-display font-bold uppercase tracking-[0.15em] mb-2">
|
||
|
|
Webhook URL
|
||
|
|
</label>
|
||
|
|
<input
|
||
|
|
v-model="form.webhookUrl"
|
||
|
|
type="url"
|
||
|
|
required
|
||
|
|
placeholder="https://your-bot.example.com/fight"
|
||
|
|
class="w-full bg-surface border-2 border-border px-4 py-3 text-sm font-mono
|
||
|
|
text-text-primary placeholder-text-muted
|
||
|
|
focus:outline-none focus:border-neon-cyan/50 transition-colors"
|
||
|
|
/>
|
||
|
|
<p class="text-text-muted text-[10px] font-mono mt-1.5">
|
||
|
|
We POST fight challenges here. HTTPS required.
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div>
|
||
|
|
<label class="block text-text-secondary text-[10px] font-display font-bold uppercase tracking-[0.15em] mb-2">
|
||
|
|
Avatar Seed <span class="text-text-muted">(optional)</span>
|
||
|
|
</label>
|
||
|
|
<input
|
||
|
|
v-model="form.avatarSeed"
|
||
|
|
type="text"
|
||
|
|
maxlength="64"
|
||
|
|
placeholder="defaults to bot name"
|
||
|
|
class="w-full bg-surface border-2 border-border px-4 py-3 text-sm font-mono
|
||
|
|
text-text-primary placeholder-text-muted
|
||
|
|
focus:outline-none focus:border-neon-cyan/50 transition-colors"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<button
|
||
|
|
type="submit"
|
||
|
|
:disabled="isSubmitting"
|
||
|
|
class="w-full 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 hover:border-neon-pink transition-all neon-border-pink
|
||
|
|
disabled:opacity-50 disabled:cursor-not-allowed"
|
||
|
|
>
|
||
|
|
{{ isSubmitting ? 'REGISTERING...' : 'REGISTER FIGHTER' }}
|
||
|
|
</button>
|
||
|
|
</form>
|
||
|
|
|
||
|
|
<div
|
||
|
|
v-if="result"
|
||
|
|
class="mt-6 p-4 border-2 font-mono text-xs leading-relaxed"
|
||
|
|
:class="result.success
|
||
|
|
? 'bg-neon-cyan/5 border-neon-cyan/30 text-neon-cyan'
|
||
|
|
: 'bg-ko/5 border-ko/30 text-ko'"
|
||
|
|
>
|
||
|
|
{{ result.message }}
|
||
|
|
<p v-if="result.success" class="mt-2 text-text-muted">
|
||
|
|
Save this secret. It will NOT be shown again.
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</template>
|