feat(ui): show Lightning.Pub nprofile QR on wallets support page
ShockWallet users can scan the nprofile to connect to the ATM's Lightning.Pub instance. QR is built from VITE_LIGHTNING_PUB_PUBKEY and VITE_RELAY_URL env vars with a graceful fallback. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8960249499
commit
0ee93aff74
1 changed files with 48 additions and 1 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
|
import { nip19 } from 'nostr-tools'
|
||||||
import { marked } from 'marked'
|
import { marked } from 'marked'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { Card, CardContent } from '@/components/ui/card'
|
import { Card, CardContent } from '@/components/ui/card'
|
||||||
|
|
@ -21,6 +22,15 @@ import { QrCode, ExternalLink } from 'lucide-vue-next'
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const isElectron = typeof window !== 'undefined' && window.electronAPI !== undefined
|
const isElectron = typeof window !== 'undefined' && window.electronAPI !== undefined
|
||||||
|
|
||||||
|
// 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 })
|
||||||
|
})
|
||||||
|
|
||||||
interface SupportPage {
|
interface SupportPage {
|
||||||
id: string
|
id: string
|
||||||
title: string
|
title: string
|
||||||
|
|
@ -47,7 +57,13 @@ const defaultPages: SupportPage[] = [
|
||||||
|
|
||||||
Tap a QR icon to scan and download a wallet.
|
Tap a QR icon to scan and download a wallet.
|
||||||
|
|
||||||
**Non-custodial** means you hold your own keys and have full control of your Bitcoin. **KYC-free** means no identity verification is required. Partial (~) means limits apply without verification.`,
|
**Non-custodial** means you hold your own keys and have full control of your Bitcoin. **KYC-free** means no identity verification is required. Partial (~) means limits apply without verification.
|
||||||
|
|
||||||
|
## Using ShockWallet with this ATM
|
||||||
|
|
||||||
|
Scan the QR code below to add this ATM's Lightning node to your ShockWallet. This lets you send and receive sats directly through the ATM's payment system.
|
||||||
|
|
||||||
|
[lp-nprofile]`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'faq',
|
id: 'faq',
|
||||||
|
|
@ -116,6 +132,7 @@ type Segment =
|
||||||
| { type: 'qr'; content: string }
|
| { type: 'qr'; content: string }
|
||||||
| { type: 'table'; table: ParsedTable }
|
| { type: 'table'; table: ParsedTable }
|
||||||
| { type: 'qr-placeholder' }
|
| { type: 'qr-placeholder' }
|
||||||
|
| { type: 'lp-nprofile' }
|
||||||
|
|
||||||
/** Parse markdown table into structured data */
|
/** Parse markdown table into structured data */
|
||||||
function parseMarkdownTable(tableLines: string[]): ParsedTable | null {
|
function parseMarkdownTable(tableLines: string[]): ParsedTable | null {
|
||||||
|
|
@ -188,6 +205,9 @@ function parseContent(md: string): Segment[] {
|
||||||
} else if (trimmed === '[operator-qr-placeholder]') {
|
} else if (trimmed === '[operator-qr-placeholder]') {
|
||||||
flushHtml()
|
flushHtml()
|
||||||
segments.push({ type: 'qr-placeholder' })
|
segments.push({ type: 'qr-placeholder' })
|
||||||
|
} else if (trimmed === '[lp-nprofile]') {
|
||||||
|
flushHtml()
|
||||||
|
segments.push({ type: 'lp-nprofile' })
|
||||||
} else {
|
} else {
|
||||||
htmlBlock += line + '\n'
|
htmlBlock += line + '\n'
|
||||||
}
|
}
|
||||||
|
|
@ -304,6 +324,33 @@ function goBack() {
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
<!-- Lightning.Pub nprofile QR -->
|
||||||
|
<Card v-else-if="seg.type === 'lp-nprofile'" class="my-6 mx-auto max-w-xs">
|
||||||
|
<CardContent class="flex flex-col items-center gap-3 p-6">
|
||||||
|
<template v-if="lpNprofile">
|
||||||
|
<div class="rounded-xl bg-white p-3">
|
||||||
|
<QrcodeVue
|
||||||
|
:value="lpNprofile"
|
||||||
|
:size="180"
|
||||||
|
level="L"
|
||||||
|
render-as="svg"
|
||||||
|
background="#ffffff"
|
||||||
|
foreground="#000000"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span class="text-xs text-muted-foreground font-mono text-center break-all px-2">
|
||||||
|
{{ lpNprofile.slice(0, 32) }}...
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<QrCode class="h-16 w-16 text-muted-foreground/30" />
|
||||||
|
<span class="text-sm text-muted-foreground/50 text-center">
|
||||||
|
Lightning.Pub not configured
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
<!-- Table with inline QR codes -->
|
<!-- Table with inline QR codes -->
|
||||||
<div v-else-if="seg.type === 'table'" class="mb-8">
|
<div v-else-if="seg.type === 'table'" class="mb-8">
|
||||||
<Table class="text-sm sm:text-base lg:text-xl w-full">
|
<Table class="text-sm sm:text-base lg:text-xl w-full">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue