Add Nostr relay + seed data to Docker deployment
- Add nostr-rs-relay service to docker-compose for persistent comments, reactions, and profiles on the dev server - Add one-shot seeder container that auto-populates the relay with test personas, reactions, and comments on first deploy - Proxy WebSocket connections through nginx at /relay so the frontend connects to the relay on the same host (no CORS) - Make relay URL dynamic: reads from VITE_NOSTR_RELAYS in dev, auto-detects /relay proxy path in production Docker builds - Make seed scripts configurable via RELAY_URL and ORIGIN env vars - Add wait-for-relay script for reliable container orchestration - Add "Resume last played" hero banner on My List tab Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -9,8 +9,27 @@ import { RelayPool } from 'applesauce-relay'
|
||||
// Relay pool for all WebSocket connections
|
||||
export const pool = new RelayPool()
|
||||
|
||||
// App relays (local dev relay)
|
||||
export const APP_RELAYS = ['ws://localhost:7777']
|
||||
/**
|
||||
* Determine app relay URLs at runtime.
|
||||
*
|
||||
* Priority:
|
||||
* 1. VITE_NOSTR_RELAYS env var (set in .env for local dev)
|
||||
* 2. Auto-detect: proxy through same host at /relay (Docker / production)
|
||||
*/
|
||||
function getAppRelays(): string[] {
|
||||
const envRelays = import.meta.env.VITE_NOSTR_RELAYS as string | undefined
|
||||
if (envRelays) {
|
||||
const parsed = envRelays.split(',').map((r: string) => r.trim()).filter(Boolean)
|
||||
if (parsed.length > 0) return parsed
|
||||
}
|
||||
|
||||
// Production / Docker: relay is proxied through nginx at /relay
|
||||
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
|
||||
return [`${protocol}//${window.location.host}/relay`]
|
||||
}
|
||||
|
||||
// App relays (local dev relay or proxied production relay)
|
||||
export const APP_RELAYS = getAppRelays()
|
||||
|
||||
// Lookup relays for profile metadata
|
||||
export const LOOKUP_RELAYS = ['wss://purplepag.es']
|
||||
|
||||
@@ -20,6 +20,15 @@
|
||||
<!-- Hero Content -->
|
||||
<div class="relative mx-auto px-4 md:px-8 h-full flex items-center pt-16" style="max-width: 90%;">
|
||||
<div class="max-w-2xl space-y-2.5 md:space-y-3 animate-fade-in">
|
||||
|
||||
<!-- Resume label (My List only) -->
|
||||
<div v-if="isMyListTab && resumeItem" class="flex items-center gap-2 text-xs md:text-sm text-white/70 uppercase tracking-widest font-medium">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
Continue where you left off
|
||||
</div>
|
||||
|
||||
<!-- Title -->
|
||||
<h1 class="hero-title w-full text-3xl md:text-5xl lg:text-6xl font-bold drop-shadow-2xl leading-tight uppercase" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-weight: 700;">
|
||||
{{ featuredContent?.title || 'GOD BLESS BITCOIN' }}
|
||||
@@ -30,8 +39,16 @@
|
||||
{{ featuredContent?.description || 'A groundbreaking documentary exploring the intersection of faith, finance, and the future of money through the lens of Bitcoin.' }}
|
||||
</p>
|
||||
|
||||
<!-- Meta Info -->
|
||||
<div v-if="featuredContent" class="flex items-center gap-2.5 text-xs md:text-sm text-white/80">
|
||||
<!-- Progress bar (My List resume) -->
|
||||
<div v-if="isMyListTab && resumeItem" class="flex items-center gap-3 pt-0.5">
|
||||
<div class="flex-1 h-1.5 bg-white/15 rounded-full overflow-hidden max-w-xs">
|
||||
<div class="h-full bg-white/80 rounded-full transition-all duration-500" :style="{ width: `${resumeItem.progress}%` }"></div>
|
||||
</div>
|
||||
<span class="text-xs text-white/60 font-medium">{{ resumeItem.progress }}% watched</span>
|
||||
</div>
|
||||
|
||||
<!-- Meta Info (non-resume) -->
|
||||
<div v-else-if="featuredContent" class="flex items-center gap-2.5 text-xs md:text-sm text-white/80">
|
||||
<span v-if="featuredContent.rating" class="bg-white/20 px-2.5 py-0.5 rounded">{{ featuredContent.rating }}</span>
|
||||
<span v-if="featuredContent.releaseYear">{{ featuredContent.releaseYear }}</span>
|
||||
<span v-if="featuredContent.duration">{{ featuredContent.duration }}min</span>
|
||||
@@ -44,7 +61,7 @@
|
||||
<svg class="w-4 h-4 md:w-5 md:h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M8 5v14l11-7z"/>
|
||||
</svg>
|
||||
Play
|
||||
{{ isMyListTab && resumeItem ? 'Resume' : 'Play' }}
|
||||
</button>
|
||||
<button @click="handleInfoClick" class="hero-info-button flex items-center gap-2">
|
||||
<svg class="w-4 h-4 md:w-5 md:h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
|
||||
Reference in New Issue
Block a user