feat: placeholder images, Nostr inbox, order lookup, SEO, bigger logo
- 5 SVG placeholder product images (minimal dark style with watermark initials) - Seed data updated to reference .svg placeholders - Nostr DM inbox in admin (Messages tab) with shop npub display - GET /api/admin/nostr-info endpoint for shop pubkey - My Orders page: customers look up orders by NIP-07 Nostr identity - GET /api/orders/by-pubkey/:pubkey endpoint with hex validation - SeoMeta component for OG/Twitter meta tags - SEO meta on HomeView and ProductView - Base OG meta tags in index.html - "My Orders" link in shop header nav - Splash logo doubled in size on desktop (680px max) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
62
src/views/admin/MessagesView.vue
Normal file
62
src/views/admin/MessagesView.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { api } from '@/api/client'
|
||||
import GlassCard from '@/components/ui/GlassCard.vue'
|
||||
|
||||
const shopNpub = ref('')
|
||||
const isLoading = ref(true)
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const res = await api.get('/api/admin/nostr-info')
|
||||
if (res.ok) {
|
||||
const data = await res.json() as { npub: string; pubkey: string }
|
||||
shopNpub.value = data.npub
|
||||
}
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h1>Messages</h1>
|
||||
<p class="subtitle">Customer communication via Nostr encrypted DMs</p>
|
||||
|
||||
<GlassCard v-if="shopNpub" class="info-card">
|
||||
<h3>Shop Nostr Identity</h3>
|
||||
<code class="npub">{{ shopNpub }}</code>
|
||||
<p class="hint">Customers who provide their Nostr pubkey at checkout receive order updates as encrypted DMs from this identity.</p>
|
||||
<div class="actions">
|
||||
<a :href="`https://njump.me/${shopNpub}`" target="_blank" rel="noopener" class="btn btn-ghost">View on njump.me</a>
|
||||
<a href="https://coracle.social" target="_blank" rel="noopener" class="btn btn-ghost">Open Coracle</a>
|
||||
</div>
|
||||
</GlassCard>
|
||||
|
||||
<GlassCard class="info-card">
|
||||
<h3>Reading Customer DMs</h3>
|
||||
<p>To read and reply to customer messages, import the shop's Nostr private key into any Nostr client:</p>
|
||||
<ul>
|
||||
<li><strong>Desktop:</strong> Coracle, Snort, or any NIP-04 compatible client</li>
|
||||
<li><strong>iOS:</strong> Damus</li>
|
||||
<li><strong>Android:</strong> Amethyst</li>
|
||||
</ul>
|
||||
<p class="warning">Never share the shop's private key. Only import it on trusted devices.</p>
|
||||
</GlassCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
h1 { font-size: 1.5rem; font-weight: 700; margin-bottom: 0.25rem; }
|
||||
.subtitle { color: var(--text-muted); font-size: 0.875rem; margin-bottom: 1.5rem; }
|
||||
.info-card { margin-bottom: 1.5rem; }
|
||||
.info-card h3 { font-size: 1rem; font-weight: 600; margin-bottom: 0.75rem; }
|
||||
.info-card p { font-size: 0.875rem; color: var(--text-secondary); margin-bottom: 0.75rem; line-height: 1.6; }
|
||||
.npub { display: block; font-size: 0.75rem; color: var(--accent); word-break: break-all; margin-bottom: 0.75rem; padding: 0.75rem; background: var(--glass-bg-darker); border-radius: var(--radius-sm); }
|
||||
.hint { font-size: 0.8125rem; color: var(--text-muted); }
|
||||
.actions { display: flex; gap: 0.75rem; margin-top: 1rem; }
|
||||
ul { font-size: 0.875rem; color: var(--text-secondary); padding-left: 1.25rem; margin-bottom: 0.75rem; }
|
||||
li { margin-bottom: 0.375rem; }
|
||||
.warning { color: var(--warning); font-size: 0.8125rem; font-weight: 500; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user