feat(machine): redesign idle screen with circular touch zones
Full-canvas layout: brand zone with logo/badges/balance at top, two circular touch zones (Buy=bitcoin orange, Sell=green) with zone-glow animation. Show per-flow commission rates (Buy/Sell). Move light/dark toggle to App.vue for omnipresence. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9cfd2f2907
commit
263165b495
1 changed files with 63 additions and 70 deletions
|
|
@ -3,16 +3,14 @@ import { ref, computed, watch } from 'vue'
|
|||
import { useRouter } from 'vue-router'
|
||||
import { nip19 } from 'nostr-tools'
|
||||
import { useAtmStore } from '@/stores/atm'
|
||||
import { useTheme } from '@/composables/useTheme'
|
||||
import { initialContext } from '@lamassu/state-machine'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent } from '@/components/ui/card'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import BitcoinIcon from '@/components/BitcoinIcon.vue'
|
||||
import QRCode from '@/components/QRCode.vue'
|
||||
|
||||
const router = useRouter()
|
||||
const atmStore = useAtmStore()
|
||||
const { colorMode } = useTheme()
|
||||
const lndconnectUrl = import.meta.env.VITE_LNDCONNECT_URL || ''
|
||||
const showZeusQR = ref(false)
|
||||
const showLpQR = ref(false)
|
||||
|
|
@ -61,75 +59,82 @@ function handleCashOut() {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex min-h-0 flex-1 flex-col items-center justify-center gap-4 overflow-auto p-4 sm:gap-6 md:gap-8 md:p-8"
|
||||
>
|
||||
<!-- Logo -->
|
||||
<div class="flex flex-col items-center gap-1 sm:gap-2">
|
||||
<div class="flex min-h-0 flex-1 flex-col">
|
||||
<!-- Brand Zone (top ~30%) -->
|
||||
<div class="flex flex-col items-center justify-center gap-2 pt-[4vh] pb-[2vh]">
|
||||
<img
|
||||
src="/logo.png"
|
||||
alt="Lamassu"
|
||||
class="h-20 w-20 animate-float drop-shadow-[0_0_24px_var(--primary)] sm:h-28 sm:w-28 md:h-40 md:w-40"
|
||||
class="h-[12vh] w-[12vh] animate-float drop-shadow-[0_0_24px_var(--primary)]"
|
||||
/>
|
||||
<h1 class="text-2xl font-bold text-primary sm:text-3xl md:text-4xl">Bitcoinmat</h1>
|
||||
<!-- Footer badges -->
|
||||
<div class="mt-2 flex flex-wrap items-center justify-center gap-2 sm:mt-4 sm:gap-4">
|
||||
<Badge variant="outline" class="border-success text-success text-xs sm:text-sm"
|
||||
>No KYC</Badge
|
||||
>
|
||||
<Badge variant="outline" class="border-primary text-primary text-xs sm:text-sm"
|
||||
>No Registration</Badge
|
||||
>
|
||||
<Badge variant="outline" class="border-bitcoin text-bitcoin text-xs sm:text-sm"
|
||||
>Just Bitcoin</Badge
|
||||
>
|
||||
<h1 class="text-[5vh] font-bold text-primary leading-tight">Bitcoinmat</h1>
|
||||
<div class="flex flex-wrap items-center justify-center gap-3">
|
||||
<Badge variant="outline" class="border-success text-success text-lg">No KYC</Badge>
|
||||
<Badge variant="outline" class="border-primary text-primary text-lg">No Registration</Badge>
|
||||
<Badge variant="outline" class="border-bitcoin text-bitcoin text-lg">Just Bitcoin</Badge>
|
||||
</div>
|
||||
<!-- Balance + Commission rates -->
|
||||
<div
|
||||
class="mt-1 flex flex-wrap items-center justify-center gap-4 text-[2vh] text-muted-foreground"
|
||||
>
|
||||
<span v-if="atmStore.balanceSats !== null">
|
||||
Available:
|
||||
<span class="font-bold text-primary"
|
||||
>{{ atmStore.balanceSats.toLocaleString() }} sats</span
|
||||
>
|
||||
</span>
|
||||
<span>
|
||||
Buy:
|
||||
<span class="font-bold text-bitcoin"
|
||||
>{{
|
||||
(
|
||||
(atmStore.context?.cashInFeePercent ?? initialContext.cashInFeePercent) * 100
|
||||
).toFixed(2)
|
||||
}}%</span
|
||||
>
|
||||
</span>
|
||||
<span>
|
||||
Sell:
|
||||
<span class="font-bold text-success"
|
||||
>{{
|
||||
(
|
||||
(atmStore.context?.cashOutFeePercent ?? initialContext.cashOutFeePercent) * 100
|
||||
).toFixed(2)
|
||||
}}%</span
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Balance -->
|
||||
<div v-if="atmStore.balanceSats !== null" class="text-center">
|
||||
<p class="text-sm text-muted-foreground">Available Balance</p>
|
||||
<p class="text-xl font-bold text-primary sm:text-2xl">
|
||||
{{ atmStore.balanceSats.toLocaleString() }} sats
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="flex flex-col gap-4 sm:flex-row sm:gap-6 md:gap-8">
|
||||
<!-- Touch Zones (fills remaining space) -->
|
||||
<div class="flex flex-1 items-center justify-center gap-[8vw] pb-[4vh]">
|
||||
<!-- Buy Bitcoin -->
|
||||
<Card
|
||||
class="h-40 w-40 cursor-pointer border-2 border-success/50 bg-success/20 transition-all hover:scale-105 hover:border-success hover:bg-success/30 active:scale-95 sm:h-52 sm:w-52 md:h-64 md:w-64"
|
||||
<button
|
||||
class="flex aspect-square w-[36vh] flex-col items-center justify-center gap-4 rounded-full border-2 border-bitcoin/50 bg-bitcoin/10 transition-all active:scale-[0.97] animate-zone-glow"
|
||||
style="--glow-color: var(--bitcoin)"
|
||||
@click="handleCashIn"
|
||||
>
|
||||
<CardContent
|
||||
class="flex h-full flex-col items-center justify-center gap-2 p-4 sm:gap-3 sm:p-6"
|
||||
>
|
||||
<BitcoinIcon :size="48" class="shrink-0 sm:hidden" />
|
||||
<BitcoinIcon :size="64" class="hidden shrink-0 sm:block" />
|
||||
<span class="text-lg font-bold text-success sm:text-xl">Buy Bitcoin</span>
|
||||
<span class="hidden text-sm text-foreground/70 sm:block">Insert cash, receive sats</span>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<BitcoinIcon :size="100" class="shrink-0" />
|
||||
<span class="text-[3.5vh] font-bold text-bitcoin">Buy Bitcoin</span>
|
||||
<span class="text-[1.8vh] text-foreground/70">Insert cash, receive sats</span>
|
||||
</button>
|
||||
|
||||
<!-- Sell Bitcoin -->
|
||||
<Card
|
||||
class="h-40 w-40 cursor-pointer border-2 border-warning/50 bg-warning/20 transition-all hover:scale-105 hover:border-warning hover:bg-warning/30 active:scale-95 sm:h-52 sm:w-52 md:h-64 md:w-64"
|
||||
<button
|
||||
class="flex aspect-square w-[36vh] flex-col items-center justify-center gap-4 rounded-full border-2 border-success/50 bg-success/10 transition-all active:scale-[0.97] animate-zone-glow"
|
||||
style="--glow-color: var(--success)"
|
||||
@click="handleCashOut"
|
||||
>
|
||||
<CardContent
|
||||
class="flex h-full flex-col items-center justify-center gap-2 p-4 sm:gap-3 sm:p-6"
|
||||
>
|
||||
<span class="text-5xl sm:text-7xl">💵</span>
|
||||
<span class="text-lg font-bold text-warning sm:text-xl">Sell Bitcoin</span>
|
||||
<span class="hidden text-sm text-foreground/70 sm:block">Pay invoice, receive cash</span>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<span class="text-[8vh] leading-none">💵</span>
|
||||
<span class="text-[3.5vh] font-bold text-success">Sell Bitcoin</span>
|
||||
<span class="text-[1.8vh] text-foreground/70">Pay invoice, receive cash</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Dev QR buttons -->
|
||||
<div
|
||||
v-if="atmStore.debugMode"
|
||||
class="flex flex-wrap items-center justify-center gap-2 sm:gap-4"
|
||||
class="absolute bottom-16 left-1/2 -translate-x-1/2 flex flex-wrap items-center justify-center gap-4"
|
||||
>
|
||||
<Button
|
||||
v-if="lndconnectUrl"
|
||||
|
|
@ -159,8 +164,7 @@ function handleCashOut() {
|
|||
>
|
||||
<p class="text-sm text-white/70">Scan with Zeus to connect to lnd-alice</p>
|
||||
<div class="rounded-2xl">
|
||||
<QRCode :value="lndconnectUrl" :size="280" class="sm:hidden" />
|
||||
<QRCode :value="lndconnectUrl" :size="400" class="hidden sm:block" />
|
||||
<QRCode :value="lndconnectUrl" :size="400" />
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<Button
|
||||
|
|
@ -185,10 +189,9 @@ function handleCashOut() {
|
|||
>
|
||||
<p class="text-sm text-white/70">Lightning.Pub nprofile</p>
|
||||
<div class="rounded-2xl">
|
||||
<QRCode :value="lpNprofile" :size="280" class="sm:hidden" />
|
||||
<QRCode :value="lpNprofile" :size="400" class="hidden sm:block" />
|
||||
<QRCode :value="lpNprofile" :size="400" />
|
||||
</div>
|
||||
<code class="max-w-[90vw] truncate text-xs text-white/50 sm:max-w-md">{{ lpNprofile }}</code>
|
||||
<code class="max-w-[90vw] truncate text-xs text-white/50">{{ lpNprofile }}</code>
|
||||
<div class="flex items-center gap-2">
|
||||
<Button variant="outline" size="sm" class="text-white" @click="copyToClipboard(lpNprofile)">
|
||||
{{ copied ? 'Copied!' : 'Copy' }}
|
||||
|
|
@ -199,22 +202,12 @@ function handleCashOut() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Light/dark toggle -->
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="absolute bottom-4 left-4 text-xs text-muted-foreground"
|
||||
@click="colorMode = colorMode === 'dark' ? 'light' : 'dark'"
|
||||
>
|
||||
{{ colorMode === 'dark' ? '☀' : '☾' }}
|
||||
</Button>
|
||||
|
||||
<!-- Debug toggle (only visible when debug bar is hidden, never in production) -->
|
||||
<Button
|
||||
v-if="!atmStore.debugMode && atmStore.allowMockFallback"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="absolute bottom-4 right-4 text-xs text-muted-foreground"
|
||||
size="kiosk"
|
||||
class="absolute bottom-6 right-6 text-lg text-muted-foreground"
|
||||
@click="atmStore.toggleDebug"
|
||||
>
|
||||
Show Debug
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue