feat(machine): add Zeus and Lightning.Pub QR codes to mock UI
dev.sh atm auto-injects VITE_LNDCONNECT_URL from lnd-3 credentials. Idle screen shows "Zeus QR" and "Lightning.Pub nprofile" buttons (debug mode) that open fullscreen overlays with scannable 400px QR codes and copy-to-clipboard support. Also makes the debug overlay collapsible. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
333b8b9357
commit
60f4eb6639
6 changed files with 122 additions and 496 deletions
|
|
@ -47,3 +47,6 @@ VITE_ATM_PRIVATE_KEY=
|
|||
|
||||
# Lightning.Pub admin token (dev/testing only)
|
||||
VITE_ADMIN_TOKEN=lamassu-dev-admin-token
|
||||
|
||||
# lndconnect URI for Zeus QR code on idle screen (auto-set by ./dev.sh atm)
|
||||
# VITE_LNDCONNECT_URL=lndconnect://192.168.1.190:8081?cert=...&macaroon=...
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-vue-next": "^0.563.0",
|
||||
"nostr-tools": "^2.10.0",
|
||||
"pinia": "^2.2.0",
|
||||
"qrcode.vue": "^3.6.0",
|
||||
"reka-ui": "^2.7.0",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { onMounted } from 'vue'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useAtmStore } from '@/stores/atm'
|
||||
import { useTheme } from '@/composables/useTheme'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
|
|
@ -7,6 +7,7 @@ import { Button } from '@/components/ui/button'
|
|||
|
||||
const atmStore = useAtmStore()
|
||||
const { current: currentTheme, themes } = useTheme()
|
||||
const debugExpanded = ref(false)
|
||||
|
||||
function formatSats(sats: number): string {
|
||||
return sats.toLocaleString()
|
||||
|
|
@ -63,9 +64,17 @@ function toggleLiveServices() {
|
|||
<!-- Debug overlay (dev only) -->
|
||||
<div
|
||||
v-if="atmStore.debugMode"
|
||||
class="fixed inset-x-0 bottom-0 z-50 max-h-52 overflow-auto bg-popover p-4 font-mono text-xs text-popover-foreground"
|
||||
class="fixed inset-x-0 bottom-0 z-50 bg-popover font-mono text-xs text-popover-foreground"
|
||||
>
|
||||
<div class="mb-2 flex items-center gap-4">
|
||||
<div class="flex items-center gap-4 px-4 py-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="h-5 px-1 text-xs text-muted-foreground"
|
||||
@click="debugExpanded = !debugExpanded"
|
||||
>
|
||||
{{ debugExpanded ? '▼' : '▲' }}
|
||||
</Button>
|
||||
<span class="text-success">State: {{ atmStore.currentState }}</span>
|
||||
<Button variant="outline" size="sm" class="h-6 text-xs" @click="toggleLiveServices">
|
||||
{{ atmStore.useLiveServices ? 'Switch to Mock' : 'Connect Live' }}
|
||||
|
|
@ -84,7 +93,9 @@ function toggleLiveServices() {
|
|||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<pre class="text-muted-foreground">{{ JSON.stringify(atmStore.context, null, 2) }}</pre>
|
||||
<div v-if="debugExpanded" class="max-h-48 overflow-auto px-4 pb-4">
|
||||
<pre class="text-muted-foreground">{{ JSON.stringify(atmStore.context, null, 2) }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,41 @@
|
|||
<script setup lang="ts">
|
||||
import { watch } from 'vue'
|
||||
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 { 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 { current: currentTheme, themes } = useTheme()
|
||||
const lndconnectUrl = import.meta.env.VITE_LNDCONNECT_URL || ''
|
||||
const showZeusQR = ref(false)
|
||||
const showLpQR = ref(false)
|
||||
const copied = ref(false)
|
||||
|
||||
// Build nprofile for Lightning.Pub (pubkey + relay hint)
|
||||
const lpNprofile = computed(() => {
|
||||
const pubkey = import.meta.env.VITE_LIGHTNING_PUB_PUBKEY
|
||||
if (!pubkey) return ''
|
||||
const relayUrl = import.meta.env.VITE_RELAY_URL
|
||||
const relays = relayUrl ? [relayUrl.replace('ws://', 'wss://')] : []
|
||||
return nip19.nprofileEncode({ pubkey, relays })
|
||||
})
|
||||
|
||||
async function copyToClipboard(value: string) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(value)
|
||||
copied.value = true
|
||||
setTimeout(() => {
|
||||
copied.value = false
|
||||
}, 2000)
|
||||
} catch {
|
||||
// clipboard unavailable
|
||||
}
|
||||
}
|
||||
|
||||
// Watch for state changes and navigate accordingly
|
||||
watch(
|
||||
|
|
@ -79,19 +104,72 @@ function handleCashOut() {
|
|||
<Badge variant="outline" class="border-bitcoin text-bitcoin">Just Bitcoin</Badge>
|
||||
</div>
|
||||
|
||||
<!-- Theme switcher -->
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xs text-muted-foreground">Theme:</span>
|
||||
<!-- Dev QR buttons -->
|
||||
<div v-if="atmStore.debugMode" class="flex items-center gap-4">
|
||||
<Button
|
||||
v-for="theme in themes"
|
||||
:key="theme.id"
|
||||
:variant="currentTheme === theme.id ? 'default' : 'outline'"
|
||||
v-if="lndconnectUrl"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="h-7 text-xs"
|
||||
@click="currentTheme = theme.id"
|
||||
class="text-xs text-muted-foreground"
|
||||
@click="showZeusQR = true"
|
||||
>
|
||||
{{ theme.label }}
|
||||
Zeus QR (lnd-3)
|
||||
</Button>
|
||||
<Button
|
||||
v-if="lpNprofile"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="text-xs text-muted-foreground"
|
||||
@click="showLpQR = true"
|
||||
>
|
||||
Lightning.Pub nprofile
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<!-- Zeus QR fullscreen overlay -->
|
||||
<div
|
||||
v-if="showZeusQR"
|
||||
class="fixed inset-0 z-[100] flex flex-col items-center justify-center gap-4 bg-black/90"
|
||||
@click.self="showZeusQR = false"
|
||||
>
|
||||
<p class="text-sm text-white/70">Scan with Zeus to connect to lnd-3</p>
|
||||
<div class="rounded-2xl bg-white p-4">
|
||||
<QRCode :value="lndconnectUrl" :size="400" />
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
class="text-white"
|
||||
@click="copyToClipboard(lndconnectUrl)"
|
||||
>
|
||||
{{ copied ? 'Copied!' : 'Copy' }}
|
||||
</Button>
|
||||
<Button variant="outline" size="sm" class="text-white" @click="showZeusQR = false">
|
||||
Close
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Lightning.Pub nprofile QR fullscreen overlay -->
|
||||
<div
|
||||
v-if="showLpQR"
|
||||
class="fixed inset-0 z-[100] flex flex-col items-center justify-center gap-4 bg-black/90"
|
||||
@click.self="showLpQR = false"
|
||||
>
|
||||
<p class="text-sm text-white/70">Lightning.Pub nprofile</p>
|
||||
<div class="rounded-2xl bg-white p-4">
|
||||
<QRCode :value="lpNprofile" :size="400" />
|
||||
</div>
|
||||
<code class="max-w-md 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' }}
|
||||
</Button>
|
||||
<Button variant="outline" size="sm" class="text-white" @click="showLpQR = false">
|
||||
Close
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Debug toggle -->
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue