🛠️ Update dependencies in composer.lock to latest versions

- Upgraded multiple packages, including `brick/math`, `guzzlehttp/guzzle`, `laravel/framework`, `spatie/image`, and more.
- Ensured compatibility with project requirements by verifying dependency interrelations.
This commit is contained in:
HolgerHatGarKeineNode
2026-06-22 16:00:36 +02:00
parent d07d2b3fba
commit d242933410
6 changed files with 879 additions and 932 deletions
@@ -109,6 +109,13 @@ new class extends Component
Flux::toast('Watchtower-Adresse in die Zwischenablage kopiert!');
}
public function copyBlossomUrl(): void
{
$blossomUrl = 'https://blossom.einundzwanzig.space';
$this->js("navigator.clipboard.writeText('{$blossomUrl}')");
Flux::toast('Blossom-Adresse in die Zwischenablage kopiert!');
}
public function handleNostrLoggedIn($signedEvent = null): void
{
NostrAuth::loginWithSignedEvent($signedEvent);
@@ -130,241 +137,313 @@ new class extends Component
?>
<div>
@php($isActiveMember = $currentPleb && $currentPleb->association_status->value > 1 && $currentYearIsPaid)
<!-- Header -->
<div class="mb-8">
<div class="mb-6">
<h1 class="text-2xl md:text-3xl text-[#1B1B1B] dark:text-zinc-100 font-bold">
Vorteile deiner Mitgliedschaft
</h1>
<p class="mt-2 max-w-2xl text-sm text-zinc-600 dark:text-zinc-400">
Diese Dienste betreiben wir exklusiv für aktive Vereinsmitglieder. Klicke bei jedem Dienst auf
<span class="font-medium">„Anleitung anzeigen"</span>, um die Einrichtung Schritt für Schritt zu sehen.
</p>
</div>
<!-- Benefits Grid - Responsive Layout -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<!-- Membership status strip (statt wiederholter Hinweise pro Karte) -->
@if($isActiveMember)
<flux:callout variant="success" icon="check-circle" class="mb-6">
<flux:callout.heading>Mitgliedschaft aktiv</flux:callout.heading>
<flux:callout.text>Alle vier Dienste unten sind für dich freigeschaltet.</flux:callout.text>
</flux:callout>
@else
<flux:callout variant="warning" icon="lock-closed" class="mb-6">
<flux:callout.heading>Dienste gesperrt</flux:callout.heading>
<flux:callout.text>
Aktiviere deine Mitgliedschaft, um Relay, NIP-05, Watchtower und den Blossom-Medienserver zu nutzen.
</flux:callout.text>
<x-slot name="actions">
<flux:button :href="route('association.profile')" size="sm" variant="primary" wire:navigate>
Mitgliedschaft aktivieren
</flux:button>
</x-slot>
</flux:callout>
@endif
<!-- Benefits Grid - 2 Spalten auf Desktop für ruhigere, scanbare Übersicht -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 items-start">
<!-- Benefit 1: Nostr Relay -->
<div
class="bg-linear-to-br from-amber-50 to-orange-50 dark:from-amber-300/10 dark:to-orange-900/10 rounded-lg p-4 border border-amber-200 dark:border-amber-200/30">
<flux:card
class="{{ $isActiveMember ? '' : 'opacity-60' }} border-amber-200 dark:border-amber-200/30">
<div class="flex items-start gap-3">
<div class="shrink-0">
<div
class="w-8 h-8 rounded-full bg-amber-100 dark:bg-amber-900/60 flex items-center justify-center">
<i class="fa-sharp-duotone fa-solid fa-bolt text-amber-600 dark:text-amber-400 text-base"></i>
</div>
<div
class="shrink-0 w-10 h-10 rounded-full bg-amber-100 dark:bg-amber-900/60 flex items-center justify-center">
<i class="fa-sharp-duotone fa-solid fa-bolt text-amber-600 dark:text-amber-400 text-lg"></i>
</div>
<div class="flex-1 min-w-0">
<h3 class="text-lg font-semibold text-zinc-800 dark:text-zinc-100 mb-1">
Nostr Relay
</h3>
<p class="text-sm text-zinc-600 dark:text-zinc-400">
Exklusive Schreib-Rechte auf Premium Nostr Relay von Einundzwanzig.
<div class="flex items-center justify-between gap-2">
<h3 class="text-lg font-semibold text-zinc-800 dark:text-zinc-100">Nostr Relay</h3>
@if($isActiveMember)
<flux:badge color="green" size="sm">Aktiv</flux:badge>
@else
<flux:badge color="zinc" size="sm" icon="lock-closed">Mitglieder</flux:badge>
@endif
</div>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
Exklusive Schreib-Rechte auf dem Premium Outbox-Relay von Einundzwanzig.
</p>
@if($currentPleb && $currentPleb->association_status->value > 1 && $currentYearIsPaid)
<div class="mt-3 space-y-2">
<p class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
Ein Outbox-Relay ist wie ein Postbote für deine Nostr-Nachrichten. Es speichert und
verteilt deine Posts. Um unser Relay nutzen zu können, musst du es in deinem
Nostr-Client hinzufügen.
</p>
<p class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
Gehe in deinem Nostr-Client zu den Einstellungen (meistens "Settings" oder
"Relays") und füge folgende Outbox-Relay-Adresse hinzu:
</p>
<div class="flex items-center gap-2 mt-2">
<code
class="text-xs bg-zinc-100 dark:bg-zinc-800 px-2 py-1 rounded text-zinc-700 dark:text-zinc-300 font-mono cursor-pointer hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors"
wire:click="copyRelayUrl">
wss://nostr.einundzwanzig.space
</code>
</div>
<p class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
<strong>Wichtige Hinweise:</strong> Du kannst deine Posts auf mehreren Relays gleichzeitig
veröffentlichen. So stellst du sicher, dass deine Inhalte auch über unser Relay erreichbar sind.
</p>
</div>
@endif
</div>
</div>
</div>
@if($isActiveMember)
<div class="mt-4 flex items-center gap-2">
<code
class="flex-1 text-xs bg-zinc-100 dark:bg-zinc-800 px-3 py-2 rounded text-zinc-700 dark:text-zinc-300 font-mono cursor-pointer hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors break-all"
wire:click="copyRelayUrl"
title="Klicken zum Kopieren">
wss://nostr.einundzwanzig.space
</code>
<flux:button wire:click="copyRelayUrl" size="sm" variant="ghost" icon="clipboard"
aria-label="Relay-Adresse kopieren"/>
</div>
<flux:accordion class="mt-3">
<flux:accordion.item heading="Anleitung anzeigen">
<div class="space-y-2 text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
<p>
Ein Outbox-Relay ist wie ein Postbote für deine Nostr-Nachrichten: Es speichert
und verteilt deine Posts.
</p>
<p>
Gehe in deinem Nostr-Client zu den Einstellungen (meist „Settings" oder „Relays")
und füge die Adresse oben als Outbox-Relay hinzu.
</p>
<p>
<strong>Tipp:</strong> Du kannst auf mehreren Relays gleichzeitig veröffentlichen
so sind deine Inhalte auch über unser Relay erreichbar.
</p>
</div>
</flux:accordion.item>
</flux:accordion>
@endif
</flux:card>
<!-- Benefit 2: NIP-05 -->
<div
class="bg-linear-to-br from-emerald-50 to-teal-50 dark:from-emerald-300/10 dark:to-teal-900/10 rounded-lg p-4 border border-emerald-200 dark:border-emerald-200/30">
<div class="flex items-start gap-3 mb-3">
<div class="shrink-0">
<div
class="w-8 h-8 rounded-full bg-emerald-100 dark:bg-emerald-900/60 flex items-center justify-center">
<i class="fa-sharp-duotone fa-solid fa-check-circle text-emerald-600 dark:text-emerald-400 text-base"></i>
</div>
<flux:card
class="{{ $isActiveMember ? '' : 'opacity-60' }} border-emerald-200 dark:border-emerald-200/30">
<div class="flex items-start gap-3">
<div
class="shrink-0 w-10 h-10 rounded-full bg-emerald-100 dark:bg-emerald-900/60 flex items-center justify-center">
<i class="fa-sharp-duotone fa-solid fa-check-circle text-emerald-600 dark:text-emerald-400 text-lg"></i>
</div>
<div class="flex-1 min-w-0">
<h3 class="text-lg font-semibold text-zinc-800 dark:text-zinc-100 mb-1">
Get NIP-05 verified
</h3>
<p class="text-sm text-zinc-600 dark:text-zinc-400">
<div class="flex items-center justify-between gap-2">
<h3 class="text-lg font-semibold text-zinc-800 dark:text-zinc-100">NIP-05 Verifizierung</h3>
@if($isActiveMember)
<flux:badge color="green" size="sm">Aktiv</flux:badge>
@else
<flux:badge color="zinc" size="sm" icon="lock-closed">Mitglieder</flux:badge>
@endif
</div>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
Verifiziere deine Identität mit einem menschenlesbaren Nostr-Namen.
</p>
</div>
</div>
<!-- NIP-05 Input -->
@if($currentPleb && $currentPleb->association_status->value > 1 && $currentYearIsPaid)
<div class="space-y-3">
@if($isActiveMember)
<div class="mt-4 space-y-3">
<flux:field>
<flux:label>Dein NIP-05 Handle</flux:label>
<flux:input.group>
<flux:input
wire:model.live.debounce="nip05Handle"
placeholder="dein-name"
/>
<flux:input wire:model.live.debounce="nip05Handle" placeholder="dein-name"/>
<flux:input.group.suffix>@einundzwanzig.space</flux:input.group.suffix>
</flux:input.group>
<flux:error name="nip05Handle"/>
</flux:field>
<div class="flex gap-3">
<flux:button
wire:click="saveNip05Handle"
wire:loading.attr="disabled"
size="sm"
variant="primary">
Speichern
</flux:button>
</div>
<flux:button wire:click="saveNip05Handle" wire:loading.attr="disabled" size="sm" variant="primary">
Speichern
</flux:button>
<!-- Rules Info -->
<div
class="mt-3 p-3 bg-white/50 dark:bg-zinc-800/50 rounded border border-zinc-200 dark:border-zinc-600">
<p class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
<strong>Regeln für dein Handle:</strong> Nur Kleinbuchstaben (a-z), Zahlen
(0-9) und die Zeichen "-" und "_" sind erlaubt. Dein Handle wird automatisch
kleingeschrieben.
</p>
</div>
<!-- Explanation -->
<div
class="mt-4 p-3 bg-white/50 dark:bg-zinc-800/50 rounded border border-zinc-200 dark:border-zinc-600">
<p class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
<flux:link href="https://nostr.how/en/guides/get-verified#self-hosted"
target="_blank">NIP-05
</flux:link>
verifiziert deine Identität auf Nostr. Das Handle ist wie eine
E-Mail-Adresse (z.B. name@einundzwanzig.space). Clients zeigen ein Häkchen
für verifizierte Benutzer. Dies macht dein Profil einfacher zu teilen und
vertrauenswürdiger.
</p>
</div>
<!-- NIP-05 Verification Status -->
@if($nip05Verified)
<flux:callout variant="success" icon="check-circle" class="mt-4">
<p class="font-medium text-zinc-800 dark:text-zinc-100">
Du hast {{ count($nip05VerifiedHandles) }} aktive Handles für deinen Pubkey!
</p>
@if($nip05HandleMismatch)
<p class="text-sm text-zinc-600 dark:text-zinc-400 mt-1">
Die Synchronisation zu <strong class="break-all">{{ $nip05Handle }}@einundzwanzig.space</strong> wird automatisch im Hintergrund durchgeführt.
</p>
@endif
<flux:callout variant="success" icon="check-circle">
<flux:callout.text>
Du hast {{ count($nip05VerifiedHandles) }} aktive Handles für deinen Pubkey.
@if($nip05HandleMismatch)
Die Synchronisation zu
<strong class="break-all">{{ $nip05Handle }}@einundzwanzig.space</strong>
läuft automatisch im Hintergrund.
@endif
</flux:callout.text>
</flux:callout>
<!-- List of all active handles -->
<div class="mt-4 p-4 bg-white/50 dark:bg-zinc-800/50 rounded border border-zinc-200 dark:border-zinc-600">
<p class="text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-2">
Deine aktivierten Handles:
</p>
<div class="p-3 bg-white/50 dark:bg-zinc-800/50 rounded border border-zinc-200 dark:border-zinc-600">
<p class="text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-2">Deine aktivierten Handles:</p>
<ul class="space-y-2">
@foreach($nip05VerifiedHandles as $handle)
<li class="flex items-center gap-2 text-sm">
<span class="break-all text-zinc-800 dark:text-zinc-200 font-mono">
{{ $handle }}@einundzwanzig.space
</span>
<flux:badge color="green" size="xs">OK</flux:badge>
<li class="flex items-center gap-2 text-sm" wire:key="handle-{{ $handle }}">
<span class="break-all text-zinc-800 dark:text-zinc-200 font-mono">{{ $handle }}@einundzwanzig.space</span>
<flux:badge color="green" size="sm">OK</flux:badge>
</li>
@endforeach
</ul>
</div>
@elseif($nip05Handle)
<flux:callout variant="secondary" icon="information-circle" class="mt-4">
<p class="font-medium text-zinc-800 dark:text-zinc-100">
Dein Handle <strong class="break-all">{{ $nip05Handle }}@einundzwanzig.space</strong> ist noch nicht aktiv.
</p>
<p class="text-sm text-zinc-600 dark:text-zinc-400 mt-1">
Das Handle ist gespeichert, aber noch nicht in der NIP-05 Konfiguration veröffentlicht.
Der Vorstand wird dies bald aktivieren.
</p>
<flux:callout variant="secondary" icon="information-circle">
<flux:callout.text>
Dein Handle <strong class="break-all">{{ $nip05Handle }}@einundzwanzig.space</strong>
ist gespeichert, aber noch nicht aktiv. Der Vorstand schaltet es bald frei.
</flux:callout.text>
</flux:callout>
@endif
</div>
@else
<div class="text-xs text-zinc-500 dark:text-zinc-400 italic">
Aktiviere deine Mitgliedschaft, um NIP-05 zu verifizieren.
<flux:accordion>
<flux:accordion.item heading="Was ist NIP-05 & welche Regeln gelten?">
<div class="space-y-2 text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
<p>
<flux:link href="https://nostr.how/en/guides/get-verified#self-hosted" target="_blank">NIP-05</flux:link>
funktioniert wie eine E-Mail-Adresse (z.B. name@einundzwanzig.space) und zeigt
in Clients ein Häkchen das macht dein Profil vertrauenswürdiger und leichter teilbar.
</p>
<p>
<strong>Regeln für dein Handle:</strong> Nur Kleinbuchstaben (az), Zahlen (09)
sowie -" und „_". Großbuchstaben werden automatisch kleingeschrieben.
</p>
</div>
</flux:accordion.item>
</flux:accordion>
</div>
@endif
</div>
</flux:card>
<!-- Benefit 3: Lightning Watchtower -->
<div
class="bg-linear-to-br from-purple-50 to-blue-50 dark:from-purple-300/10 dark:to-blue-900/10 rounded-lg p-4 border border-purple-200 dark:border-purple-200/30">
<div class="flex items-start gap-3 mb-3">
<div class="shrink-0">
<div
class="w-8 h-8 rounded-full bg-purple-100 dark:bg-purple-900/60 flex items-center justify-center">
<i class="fa-sharp-duotone fa-solid fa-shield-halved text-purple-600 dark:text-purple-400 text-base"></i>
</div>
<flux:card
class="{{ $isActiveMember ? '' : 'opacity-60' }} border-purple-200 dark:border-purple-200/30">
<div class="flex items-start gap-3">
<div
class="shrink-0 w-10 h-10 rounded-full bg-purple-100 dark:bg-purple-900/60 flex items-center justify-center">
<i class="fa-sharp-duotone fa-solid fa-shield-halved text-purple-600 dark:text-purple-400 text-lg"></i>
</div>
<div class="flex-1 min-w-0">
<h3 class="text-lg font-semibold text-zinc-800 dark:text-zinc-100 mb-1">
Lightning Watchtower
</h3>
<p class="text-sm text-zinc-600 dark:text-zinc-400">
Nutze unseren Watchtower zum Schutz deiner Lightning Channel.
<div class="flex items-center justify-between gap-2">
<h3 class="text-lg font-semibold text-zinc-800 dark:text-zinc-100">Lightning Watchtower</h3>
@if($isActiveMember)
<flux:badge color="green" size="sm">Aktiv</flux:badge>
@else
<flux:badge color="zinc" size="sm" icon="lock-closed">Mitglieder</flux:badge>
@endif
</div>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
Schütze deine Lightning Channel auch wenn deine Node offline ist.
</p>
</div>
</div>
@if($currentPleb && $currentPleb->association_status->value > 1 && $currentYearIsPaid)
<div class="space-y-3">
<p class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
Ein Watchtower überwacht deine Lightning Channel und schützt sie, falls deine Node
offline ist. Wenn du die Zahlung von Channel-Closing-Transaktionen verpasst, kümmert sich
der Watchtower darum und verhindert den Verlust deiner Sats.
</p>
<p class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
Um unseren Watchtower zu nutzen, füge folgende URI in deiner Lightning Node
Konfiguration hinzu:
</p>
<div class="flex items-center gap-2">
<code
class="text-xs bg-zinc-100 dark:bg-zinc-800 px-2 py-1 rounded text-zinc-700 dark:text-zinc-300 font-mono cursor-pointer hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors break-all"
wire:click="copyWatchtowerUrl">
03a09f56bba3d2c200cc55eda2f1f069564a97c1fb74345e1560e2868a8ab3d7d0@62.171.139.240:9911
</code>
</div>
<div
class="mt-3 p-3 bg-white/50 dark:bg-zinc-800/50 rounded border border-zinc-200 dark:border-zinc-600">
<p class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed font-medium mb-2">
Einrichtung für gängige Lightning Clients:
</p>
<ul class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed space-y-1 list-disc list-inside">
<li><strong>LND:</strong> <flux:link href="https://docs.lightning.engineering/lightning-network-tools/lnd/watchtower" target="_blank">https://docs.lightning.engineering/lightning-network-tools/lnd/watchtower</flux:link></li>
<li><strong>Core Lightning:</strong> Nutze den <code class="bg-zinc-200 dark:bg-zinc-700 px-1 rounded">watchtower-client</code> Plugin mit der URI</li>
<li><strong>Eclair:</strong> Füge die URI zu den Watchtower-Einstellungen in deiner eclair.conf hinzu</li>
</ul>
</div>
<p class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
<strong>Wichtig:</strong> Der Watchtower überwacht deine Channel passiv. Er hat keinen Zugriff auf
deine privaten Schlüssel oder dein Guthaben.
</p>
</div>
@else
<div class="text-xs text-zinc-500 dark:text-zinc-400 italic">
Aktiviere deine Mitgliedschaft, um den Lightning Watchtower zu nutzen.
@if($isActiveMember)
<div class="mt-4 flex items-center gap-2">
<code
class="flex-1 text-xs bg-zinc-100 dark:bg-zinc-800 px-3 py-2 rounded text-zinc-700 dark:text-zinc-300 font-mono cursor-pointer hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors break-all"
wire:click="copyWatchtowerUrl"
title="Klicken zum Kopieren">
03a09f56bba3d2c200cc55eda2f1f069564a97c1fb74345e1560e2868a8ab3d7d0@62.171.139.240:9911
</code>
<flux:button wire:click="copyWatchtowerUrl" size="sm" variant="ghost" icon="clipboard"
aria-label="Watchtower-Adresse kopieren"/>
</div>
<flux:accordion class="mt-3">
<flux:accordion.item heading="Anleitung anzeigen">
<div class="space-y-2 text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
<p>
Ein Watchtower überwacht deine Channel und springt ein, falls deine Node offline ist
so verhinderst du den Verlust deiner Sats bei unfairen Channel-Schließungen.
</p>
<p>Füge die URI oben in deiner Lightning-Node-Konfiguration hinzu:</p>
<ul class="space-y-1 list-disc list-inside">
<li><strong>LND:</strong> <flux:link href="https://docs.lightning.engineering/lightning-network-tools/lnd/watchtower" target="_blank">Doku</flux:link></li>
<li><strong>Core Lightning:</strong> <code class="bg-zinc-200 dark:bg-zinc-700 px-1 rounded">watchtower-client</code>-Plugin mit der URI</li>
<li><strong>Eclair:</strong> URI in der <code class="bg-zinc-200 dark:bg-zinc-700 px-1 rounded">eclair.conf</code> ergänzen</li>
</ul>
<p>
<strong>Wichtig:</strong> Der Watchtower überwacht passiv. Er hat keinen Zugriff auf
deine privaten Schlüssel oder dein Guthaben.
</p>
</div>
</flux:accordion.item>
</flux:accordion>
@endif
</div>
</flux:card>
<!-- Benefit 4: Blossom Medienserver (NEU) -->
<flux:card
class="{{ $isActiveMember ? '' : 'opacity-60' }} border-rose-200 dark:border-rose-200/30">
<div class="flex items-start gap-3">
<div
class="shrink-0 w-10 h-10 rounded-full bg-rose-100 dark:bg-rose-900/60 flex items-center justify-center">
<i class="fa-sharp-duotone fa-solid fa-cloud-arrow-up text-rose-600 dark:text-rose-400 text-lg"></i>
</div>
<div class="flex-1 min-w-0">
<div class="flex items-center justify-between gap-2">
<h3 class="text-lg font-semibold text-zinc-800 dark:text-zinc-100">Blossom Medienserver</h3>
<div class="flex items-center gap-1.5">
<flux:badge color="rose" size="sm">NEU</flux:badge>
@if($isActiveMember)
<flux:badge color="green" size="sm">Aktiv</flux:badge>
@else
<flux:badge color="zinc" size="sm" icon="lock-closed">Mitglieder</flux:badge>
@endif
</div>
</div>
<p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
Dein eigener Speicher für Bilder &amp; Videos auf Nostr betrieben vom Verein.
</p>
</div>
</div>
@if($isActiveMember)
<div class="mt-4 flex items-center gap-2">
<code
class="flex-1 text-xs bg-zinc-100 dark:bg-zinc-800 px-3 py-2 rounded text-zinc-700 dark:text-zinc-300 font-mono cursor-pointer hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors break-all"
wire:click="copyBlossomUrl"
title="Klicken zum Kopieren">
https://blossom.einundzwanzig.space
</code>
<flux:button wire:click="copyBlossomUrl" size="sm" variant="ghost" icon="clipboard"
aria-label="Blossom-Adresse kopieren"/>
</div>
<flux:accordion class="mt-3">
<flux:accordion.item heading="Was ist Blossom & wie nutze ich ihn?">
<div class="space-y-3 text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
<p>
Wenn du auf Nostr ein Bild oder Video postest, muss diese Datei irgendwo gespeichert
werden. Bisher landet sie oft auf fremden Gratis-Servern, die jederzeit verschwinden
können. Mit unserem <strong>Blossom-Server</strong> liegen deine Medien stattdessen
sicher auf einem Server des Vereins schnell, zuverlässig und nur für Mitglieder.
</p>
<div>
<p class="font-medium text-zinc-700 dark:text-zinc-300 mb-1">So nutzt du ihn:</p>
<ol class="space-y-1 list-decimal list-inside">
<li>Öffne deinen Nostr-Client (z.B. Amethyst, Primal, nostrudel, Nostur).</li>
<li>Gehe zu den Einstellungen <strong>„Medienserver"</strong> (manchmal „Media
Servers", „File Storage" oder „Blossom").</li>
<li>Füge die Adresse oben hinzu und setze sie als Standard.</li>
<li>Fertig! Deine hochgeladenen Bilder &amp; Videos landen ab jetzt auf dem
Vereinsserver.</li>
</ol>
</div>
<p>
<strong>Sicher:</strong> Die Anmeldung passiert automatisch über deinen Nostr-Schlüssel
nur Vereinsmitglieder können hochladen, und deine privaten Schlüssel verlassen
niemals dein Gerät.
</p>
</div>
</flux:accordion.item>
</flux:accordion>
@endif
</flux:card>
</div>
</div>
@@ -653,268 +653,57 @@ new class extends Component {
<flux:heading size="xl" level="1">Vorteile deiner Mitgliedschaft</flux:heading>
<flux:separator variant="subtle" class="mb-6"/>
<!-- Benefits Grid -->
<div class="grid grid-cols-1 gap-4">
<!-- Benefit 1 -->
<div
class="bg-linear-to-br from-amber-50 to-orange-50 dark:from-amber-300/10 dark:to-orange-900/10 rounded-lg p-4 border border-amber-200 dark:border-amber-200/30">
<div class="flex items-start gap-3">
<div class="shrink-0">
<div
class="w-8 h-8 rounded-full bg-amber-100 dark:bg-amber-900/60 flex items-center justify-center">
<i class="fa-sharp-duotone fa-solid fa-bolt text-amber-600 dark:text-amber-400 text-base"></i>
</div>
</div>
<div class="flex-1 min-w-0">
<h3 class="text-lg font-semibold text-text-primary mb-1">
Nostr Relay
</h3>
<p class="text-sm text-text-secondary">
Exklusive Schreib-Rechte auf Premium Nostr Relay von Einundzwanzig.
</p>
@if($currentPleb && $currentPleb->association_status->value > 1 && $currentYearIsPaid)
<div class="mt-3 space-y-2">
<p class="text-xs text-text-secondary leading-relaxed">
Ein Outbox-Relay ist wie ein Postbote für deine Nostr-Nachrichten. Es
speichert und
verteilt deine Posts. Um unser Relay nutzen zu können, musst du es in
deinem
Nostr-Client hinzufügen.
</p>
<p class="text-xs text-text-secondary leading-relaxed">
Gehe in deinem Nostr-Client zu den Einstellungen (meistens "Settings"
oder
"Relays") und füge folgende Outbox-Relay-Adresse hinzu:
</p>
<div class="flex items-center gap-2 mt-2">
<code
class="text-xs bg-bg-elevated px-2 py-1 rounded text-text-secondary font-mono cursor-pointer hover:bg-bg-surface transition-colors"
wire:click="copyRelayUrl">
wss://nostr.einundzwanzig.space
</code>
</div>
<p class="text-xs text-text-secondary leading-relaxed">
<strong>Wichtige Hinweise:</strong> Du kannst deine Posts auf mehreren
Relays gleichzeitig
veröffentlichen. So stellst du sicher, dass deine Inhalte auch über
unser Relay erreichbar sind.
</p>
</div>
@endif
</div>
<!-- Kompakte Vorteils-Liste (Details & Einrichtung auf der Vorteile-Seite) -->
<ul class="space-y-4">
<li class="flex items-start gap-3">
<div
class="shrink-0 w-9 h-9 rounded-full bg-amber-100 dark:bg-amber-900/60 flex items-center justify-center">
<i class="fa-sharp-duotone fa-solid fa-bolt text-amber-600 dark:text-amber-400"></i>
</div>
</div>
<!-- Benefit 2: NIP-05 -->
<div
class="bg-linear-to-br from-emerald-50 to-teal-50 dark:from-emerald-300/10 dark:to-teal-900/10 rounded-lg p-4 border border-emerald-200 dark:border-emerald-200/30">
<div class="flex items-start gap-3 mb-3">
<div class="shrink-0">
<div
class="w-8 h-8 rounded-full bg-emerald-100 dark:bg-emerald-900/60 flex items-center justify-center">
<i class="fa-sharp-duotone fa-solid fa-check-circle text-emerald-600 dark:text-emerald-400 text-base"></i>
</div>
</div>
<div class="flex-1 min-w-0">
<h3 class="text-lg font-semibold text-text-primary mb-1">
Get NIP-05 verified
</h3>
<p class="text-sm text-text-secondary">
Verifiziere deine Identität mit einem menschenlesbaren Nostr-Namen.
</p>
</div>
<div class="min-w-0">
<h3 class="text-sm font-semibold text-text-primary">Nostr Relay</h3>
<p class="text-xs text-text-secondary">Premium Outbox-Relay von Einundzwanzig.</p>
</div>
<!-- NIP-05 Input -->
@if($currentPleb && $currentPleb->association_status->value > 1 && $currentYearIsPaid)
<div class="space-y-3">
<flux:field>
<flux:label>Dein NIP-05 Handle</flux:label>
<flux:input.group>
<flux:input
wire:model.live.debounce="profileForm.nip05Handle"
placeholder="dein-name"
wire:dirty.class="border-amber-500 dark:border-amber-400"
/>
<flux:input.group.suffix class="!bg-[#4a7c59] !text-white font-medium">@einundzwanzig.space</flux:input.group.suffix>
</flux:input.group>
<flux:error name="profileForm.nip05Handle"/>
<div wire:dirty wire:target="profileForm.nip05Handle" class="text-xs text-amber-600 dark:text-amber-400 mt-1">
Nicht gespeichert...
</div>
</flux:field>
<div class="flex gap-3">
<flux:button
wire:click="saveNip05Handle"
wire:loading.attr="disabled"
size="sm"
variant="outline">
<span wire:loading.remove wire:target="saveNip05Handle">Speichern</span>
<span wire:loading wire:target="saveNip05Handle">Speichert...</span>
</flux:button>
</div>
<!-- Rules Info -->
<div
class="mt-3 p-3 bg-bg-elevated rounded border border-border-default">
<p class="text-xs text-text-secondary leading-relaxed">
<strong>Regeln für dein Handle:</strong> Nur Kleinbuchstaben (a-z), Zahlen
(0-9) und die Zeichen "-" und "_" sind erlaubt. Dein Handle wird automatisch
kleingeschrieben.
</p>
</div>
<!-- Explanation -->
<div
class="mt-4 p-3 bg-bg-elevated rounded border border-border-default">
<p class="text-xs text-text-secondary leading-relaxed">
<flux:link href="https://nostr.how/en/guides/get-verified#self-hosted"
target="_blank">NIP-05
</flux:link>
verifiziert deine Identität auf Nostr. Das Handle ist wie eine
E-Mail-Adresse (z.B. name@einundzwanzig.space). Clients zeigen ein Häkchen
für verifizierte Benutzer. Dies macht dein Profil einfacher zu teilen und
vertrauenswürdiger.
</p>
</div>
<!-- NIP-05 Verification Status -->
@if($nip05Verified)
<flux:callout variant="success" icon="check-circle" class="mt-4">
<p class="font-medium text-text-primary">
Du hast {{ count($nip05VerifiedHandles) }} aktive Handles für deinen
Pubkey!
</p>
@if($nip05HandleMismatch)
<p class="text-sm text-text-secondary mt-1">
Die Synchronisation zu <strong
class="break-all">{{ $profileForm->nip05Handle }}
@einundzwanzig.space</strong> wird automatisch im Hintergrund
durchgeführt.
</p>
@endif
</flux:callout>
<!-- List of all active handles -->
<div
class="mt-4 p-4 bg-bg-elevated rounded border border-border-default">
<p class="text-sm font-medium text-text-secondary mb-2">
Deine aktivierten Handles:
</p>
<ul class="space-y-2">
@foreach($nip05VerifiedHandles as $handle)
<li class="flex items-center gap-2 text-sm">
<span
class="break-all text-text-primary font-mono">
{{ $handle }}@einundzwanzig.space
</span>
<flux:badge color="green" size="xs">OK</flux:badge>
</li>
@endforeach
</ul>
</div>
@elseif($profileForm->nip05Handle)
<flux:callout variant="secondary" icon="information-circle" class="mt-4">
<p class="font-medium text-text-primary">
Dein Handle <strong class="break-all">{{ $profileForm->nip05Handle }}
@einundzwanzig.space</strong> ist noch nicht aktiv.
</p>
<p class="text-sm text-text-secondary mt-1">
Das Handle ist gespeichert, aber noch nicht in der NIP-05 Konfiguration
veröffentlicht.
Der Vorstand wird dies bald aktivieren.
</p>
</flux:callout>
@endif
</div>
@else
<div class="text-xs text-text-tertiary italic">
Aktiviere deine Mitgliedschaft, um NIP-05 zu verifizieren.
</div>
@endif
</div>
<!-- Benefit 3: Lightning Watchtower -->
<div
class="bg-linear-to-br from-purple-50 to-blue-50 dark:from-purple-300/10 dark:to-blue-900/10 rounded-lg p-4 border border-purple-200 dark:border-purple-200/30">
<div class="flex items-start gap-3 mb-3">
<div class="shrink-0">
<div
class="w-8 h-8 rounded-full bg-purple-100 dark:bg-purple-900/60 flex items-center justify-center">
<i class="fa-sharp-duotone fa-solid fa-shield-halved text-purple-600 dark:text-purple-400 text-base"></i>
</div>
</div>
<div class="flex-1 min-w-0">
<h3 class="text-lg font-semibold text-text-primary mb-1">
Lightning Watchtower
</h3>
<p class="text-sm text-text-secondary">
Nutze unseren Watchtower zum Schutz deiner Lightning Channel.
</p>
</div>
</li>
<li class="flex items-start gap-3">
<div
class="shrink-0 w-9 h-9 rounded-full bg-emerald-100 dark:bg-emerald-900/60 flex items-center justify-center">
<i class="fa-sharp-duotone fa-solid fa-check-circle text-emerald-600 dark:text-emerald-400"></i>
</div>
@if($currentPleb && $currentPleb->association_status->value > 1 && $currentYearIsPaid)
<div class="space-y-3">
<p class="text-xs text-text-secondary leading-relaxed">
Ein Watchtower überwacht deine Lightning Channel und schützt sie, falls deine
Node
offline ist. Wenn du die Zahlung von Channel-Closing-Transaktionen verpasst,
kümmert sich
der Watchtower darum und verhindert den Verlust deiner Sats.
</p>
<p class="text-xs text-text-secondary leading-relaxed">
Um unseren Watchtower zu nutzen, füge folgende URI in deiner Lightning Node
Konfiguration hinzu:
</p>
<div class="flex items-center gap-2">
<code
class="text-xs bg-bg-elevated px-2 py-1 rounded text-text-secondary font-mono cursor-pointer hover:bg-bg-surface transition-colors break-all"
wire:click="copyWatchtowerUrl">
03a09f56bba3d2c200cc55eda2f1f069564a97c1fb74345e1560e2868a8ab3d7d0@62.171.139.240:9911
</code>
</div>
<div
class="mt-3 p-3 bg-bg-elevated rounded border border-border-default">
<p class="text-xs text-text-secondary leading-relaxed font-medium mb-2">
Einrichtung für gängige Lightning Clients:
</p>
<ul class="text-xs text-text-secondary leading-relaxed space-y-1 list-disc list-inside">
<li><strong>LND:</strong>
<flux:link
href="https://docs.lightning.engineering/lightning-network-tools/lnd/watchtower"
target="_blank">
https://docs.lightning.engineering/lightning-network-tools/lnd/watchtower
</flux:link>
</li>
<li><strong>Core Lightning:</strong> Nutze den <code
class="bg-bg-elevated px-1 rounded">watchtower-client</code>
Plugin mit der URI
</li>
<li><strong>Eclair:</strong> Füge die URI zu den Watchtower-Einstellungen in
deiner eclair.conf hinzu
</li>
</ul>
</div>
<p class="text-xs text-text-secondary leading-relaxed">
<strong>Wichtig:</strong> Der Watchtower überwacht deine Channel passiv. Er hat
keinen Zugriff auf
deine privaten Schlüssel oder dein Guthaben.
</p>
<div class="min-w-0">
<h3 class="text-sm font-semibold text-text-primary">NIP-05 Verifizierung</h3>
<p class="text-xs text-text-secondary">Menschenlesbarer, verifizierter Nostr-Name.</p>
</div>
</li>
<li class="flex items-start gap-3">
<div
class="shrink-0 w-9 h-9 rounded-full bg-purple-100 dark:bg-purple-900/60 flex items-center justify-center">
<i class="fa-sharp-duotone fa-solid fa-shield-halved text-purple-600 dark:text-purple-400"></i>
</div>
<div class="min-w-0">
<h3 class="text-sm font-semibold text-text-primary">Lightning Watchtower</h3>
<p class="text-xs text-text-secondary">Schutz für deine Lightning Channel.</p>
</div>
</li>
<li class="flex items-start gap-3">
<div
class="shrink-0 w-9 h-9 rounded-full bg-rose-100 dark:bg-rose-900/60 flex items-center justify-center">
<i class="fa-sharp-duotone fa-solid fa-cloud-arrow-up text-rose-600 dark:text-rose-400"></i>
</div>
<div class="min-w-0">
<div class="flex items-center gap-2">
<h3 class="text-sm font-semibold text-text-primary">Blossom Medienserver</h3>
<flux:badge color="rose" size="sm">NEU</flux:badge>
</div>
@else
<div class="text-xs text-text-tertiary italic">
Aktiviere deine Mitgliedschaft, um den Lightning Watchtower zu nutzen.
</div>
@endif
</div>
<p class="text-xs text-text-secondary">Eigener Speicher für Bilder &amp; Videos auf Nostr.</p>
</div>
</li>
</ul>
</div>
<flux:button :href="route('association.benefits')" wire:navigate variant="primary" size="sm"
icon:trailing="arrow-right" class="mt-6 w-full">
Alle Details &amp; Einrichtung
</flux:button>
</div>
</div>
</flux:card>