🗑️ Remove unused Blade templates and components across navigation, layouts, and details, streamlining unused sections like admin, association, courses, events, and dark-mode toggle.

This commit is contained in:
HolgerHatGarKeineNode
2026-01-18 01:45:02 +01:00
parent 00216409b4
commit 22c8ad3588
37 changed files with 12 additions and 1598 deletions

View File

@@ -1,246 +0,0 @@
<?php
use App\Models\Election;
use Livewire\Component;
use swentel\nostr\Filter\Filter;
use swentel\nostr\Message\RequestMessage;
use swentel\nostr\Relay\Relay;
use swentel\nostr\Relay\RelaySet;
use swentel\nostr\Request\Request;
use swentel\nostr\Subscription\Subscription;
new class extends Component {
public bool $isAllowed = false;
public ?string $currentPubkey = null;
public ?\App\Models\EinundzwanzigPleb $currentPleb = null;
public ?array $votes = null;
public ?array $boardVotes = null;
public ?array $events = null;
public ?array $boardEvents = null;
public ?Election $election = null;
public string $signThisEvent = '';
public array $plebs = [];
public array $electionConfig = [];
protected $listeners = [
'nostrLoggedOut' => 'handleNostrLoggedOut',
'nostrLoggedIn' => 'handleNostrLoggedIn',
'echo:votes,.newVote' => 'handleNewVote',
];
public function mount(Election $election): void
{
$this->election = $election;
$this->loadEvents();
$this->loadBoardEvents();
$this->loadVotes();
$this->loadBoardVotes();
}
public function handleNostrLoggedOut(): void
{
$this->currentPubkey = null;
$this->currentPleb = null;
}
public function handleNostrLoggedIn($pubkey): void
{
$this->currentPubkey = $pubkey;
$allowedPubkeys = [
'0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033',
'430169631f2f0682c60cebb4f902d68f0c71c498fd1711fd982f052cf1fd4279',
];
if (in_array($this->currentPubkey, $allowedPubkeys, true)) {
$this->isAllowed = true;
}
dd($this->isAllowed);
}
public function handleNewVote(): void
{
$this->loadEvents();
$this->loadBoardEvents();
$this->loadVotes();
$this->loadBoardVotes();
}
public function loadVotes(): void
{
$this->votes = collect($this->events)
->map(fn ($event) => [
'created_at' => $event['created_at'],
'pubkey' => $event['pubkey'],
'forpubkey' => $this->fetchProfile($event['content']),
'type' => str($event['content'])->after(',')->toString(),
])
->sortByDesc('created_at')
->unique(fn ($event) => $event['pubkey'].$event['type'])
->values()
->groupBy('type')
->map(fn ($votes) => [
'type' => $votes[0]['type'],
'votes' => $votes->groupBy('forpubkey')->map(fn ($group) => ['count' => $group->count()])->toArray(),
])
->values()
->toArray();
}
public function loadBoardVotes(): void
{
$this->boardVotes = collect($this->boardEvents)
->map(fn ($event) => [
'created_at' => $event['created_at'],
'pubkey' => $event['pubkey'],
'forpubkey' => $this->fetchProfile($event['content']),
'type' => str($event['content'])->after(',')->toString(),
])
->sortByDesc('created_at')
->values()
->groupBy('type')
->map(fn ($votes) => [
'type' => $votes[0]['type'],
'votes' => $votes->groupBy('forpubkey')->map(fn ($group) => ['count' => $group->count()])->toArray(),
])
->values()
->toArray();
}
public function loadEvents(): void
{
$this->events = $this->loadNostrEvents([32122]);
}
public function loadBoardEvents(): void
{
$this->boardEvents = $this->loadNostrEvents([2121]);
}
public function fetchProfile($content): string
{
$pubkey = str($content)->before(',')->toString();
$profile = \App\Models\Profile::query()->where('pubkey', $pubkey)->first();
if (! $profile) {
\Artisan::call(\App\Console\Commands\Nostr\FetchProfile::class, ['--pubkey' => $pubkey]);
$profile = \App\Models\Profile::query()->where('pubkey', $pubkey)->first();
}
return $profile->pubkey;
}
public function loadNostrEvents($kinds): array
{
$subscription = new Subscription;
$subscriptionId = $subscription->setId();
$filter = new Filter;
$filter->setKinds($kinds);
$requestMessage = new RequestMessage($subscriptionId, [$filter]);
$relaySet = new RelaySet;
$relaySet->setRelays([new Relay(config('services.relay'))]);
$request = new Request($relaySet, $requestMessage);
$response = $request->send();
return collect($response[config('services.relay')])
->map(function ($event) {
if (! isset($event->event)) {
return false;
}
return [
'id' => $event->event->id,
'kind' => $event->event->kind,
'content' => $event->event->content,
'pubkey' => $event->event->pubkey,
'tags' => $event->event->tags,
'created_at' => $event->event->created_at,
];
})
->filter()
->toArray();
}
};
?>
<div>
@php
$positions = [
'presidency' => ['icon' => 'fa-crown', 'title' => 'Präsidium'],
'board' => ['icon' => 'fa-users', 'title' => 'Vorstandsmitglieder'],
];
@endphp
@if($isAllowed)
<div class="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto" x-data="electionAdminCharts()">
<!-- Dashboard actions -->
<div class="sm:flex sm:justify-between sm:items-center mb-8">
<!-- Left: Title -->
<div class="mb-4 sm:mb-0">
<h1 class="text-2xl md:text-3xl text-gray-800 dark:text-gray-100 font-bold">
Wahl des Vorstands {{ $election->year }}
</h1>
</div>
</div>
@php
$president = $positions['presidency'];
$board = $positions['board'];
@endphp
<!-- Cards -->
<div class="grid gap-y-4">
<div wire:key="presidency" wire:ignore
class="flex flex-col bg-white dark:bg-gray-800 shadow-sm rounded-xl">
<header class="px-5 py-4 border-b border-gray-100 dark:border-gray-700/60">
<h2 class="font-semibold text-gray-800 dark:text-gray-100"><i
class="fa-sharp-duotone fa-solid {{ $president['icon'] }} w-5 h-5 fill-current text-white mr-4"></i>{{ $president['title'] }}
</h2>
</header>
<div class="grow">
<!-- Change| height attribute to adjust chart height -->
<canvas x-ref="chart_presidency" width="724" height="288"
style="display: block; box-sizing: border-box; height: 288px; width: 724px;"></canvas>
</div>
</div>
<div wire:key="board" wire:ignore
class="flex flex-col bg-white dark:bg-gray-800 shadow-sm rounded-xl">
<header class="px-5 py-4 border-b border-gray-100 dark:border-gray-700/60">
<h2 class="font-semibold text-gray-800 dark:text-gray-100"><i
class="fa-sharp-duotone fa-solid {{ $board['icon'] }} w-5 h-5 fill-current text-white mr-4"></i>{{ $board['title'] }}
</h2>
</header>
<div class="grow">
<!-- Change| height attribute to adjust chart height -->
<canvas x-ref="chart_board" width="724" height="288"
style="display: block; box-sizing: border-box; height: 288px; width: 724px;"></canvas>
</div>
</div>
</div>
</div>
@else
<div class="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
<div class="bg-white dark:bg-[#1B1B1B] shadow overflow-hidden sm:rounded-lg">
<div class="px-4 py-5 sm:px-6">
<h3 class="text-lg font-medium leading-6 text-gray-900 dark:text-gray-200">Mitglieder</h3>
<p class="mt-1 max-w">
Du bist nicht berechtigt, Mitglieder zu bearbeiten.
</p>
</div>
</div>
</div>
@endif
</div>

View File

@@ -1,104 +0,0 @@
<?php
use App\Models\EinundzwanzigPleb;
use App\Models\Election;
use App\Support\NostrAuth;
use Livewire\Component;
new class extends Component {
public $layout = 'layouts.app';
public $title = __('Wahlen');
public bool $isAllowed = false;
public ?string $currentPubkey = null;
public ?EinundzwanzigPleb $currentPleb = null;
public array $elections = [];
protected $listeners = [
'nostrLoggedOut' => 'handleNostrLoggedOut',
'nostrLoggedIn' => 'handleNostrLoggedIn',
];
public function mount(): void
{
$this->elections = Election::query()
->get()
->toArray();
if (NostrAuth::check()) {
$this->currentPubkey = NostrAuth::pubkey();
$logPubkeys = [
'0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033',
'430169631f2f0682c60cebb4f902d68f0c71c498fd1711fd982f052cf1fd4279',
];
if (in_array($this->currentPubkey, $logPubkeys, true)) {
$this->isAllowed = true;
}
}
}
public function handleNostrLoggedOut(): void
{
$this->isAllowed = false;
$this->currentPubkey = null;
$this->currentPleb = null;
}
public function handleNostrLoggedIn($pubkey): void
{
NostrAuth::login($pubkey);
$this->currentPubkey = $pubkey;
$this->currentPleb = \App\Models\EinundzwanzigPleb::query()
->where('pubkey', $pubkey)->first();
$logPubkeys = [
'0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033',
'430169631f2f0682c60cebb4f902d68f0c71c498fd1711fd982f052cf1fd4279',
];
if (in_array($this->currentPubkey, $logPubkeys, true)) {
$this->isAllowed = true;
}
}
public function saveElection($index): void
{
$election = $this->elections[$index];
$electionModel = Election::find($election['id']);
$electionModel->candidates = $election['candidates'];
$electionModel->save();
}
};
?>
<div>
@if($isAllowed)
<div class="relative flex h-full">
@foreach($elections as $election)
<div class="w-full sm:w-1/3 p-4" wire:key="election-{{ $loop->index }}">
<div class="shadow-lg rounded-lg overflow-hidden">
{{ $election['year'] }}
</div>
<div class="shadow-lg rounded-lg overflow-hidden">
<x-textarea wire:model="elections.{{ $loop->index }}.candidates" rows="25"
label="candidates" placeholder=""/>
</div>
<div class="py-2">
<x-button label="Speichern" wire:click="saveElection({{ $loop->index }})" wire:loading.attr="disabled"/>
</div>
</div>
@endforeach
</div>
@else
<div class="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
<div class="bg-white dark:bg-[#1B1B1B] shadow overflow-hidden sm:rounded-lg">
<div class="px-4 py-5 sm:px-6">
<h3 class="text-lg font-medium leading-6 text-gray-900 dark:text-gray-200">Einstellungen</h3>
<p class="mt-1 max-w">
Du bist nicht berechtigt, die Einstellungen zu bearbeiten.
</p>
</div>
</div>
</div>
@endif
</div>

View File

@@ -1,771 +0,0 @@
<?php
use App\Models\Election;
use App\Models\EinundzwanzigPleb;
use App\Models\Profile;
use App\Support\NostrAuth;
use Livewire\Attributes\Computed;
use Livewire\Component;
use swentel\nostr\Event\Event as NostrEvent;
use swentel\nostr\Filter\Filter;
use swentel\nostr\Message\EventMessage;
use swentel\nostr\Message\RequestMessage;
use swentel\nostr\Relay\Relay;
use swentel\nostr\Relay\RelaySet;
use swentel\nostr\Request\Request;
use swentel\nostr\Subscription\Subscription;
new class extends Component {
public bool $isAllowed = false;
public bool $showLog = false;
public ?string $currentPubkey = null;
public ?EinundzwanzigPleb $currentPleb = null;
public array $events = [];
public array $boardEvents = [];
public Election $election;
public array $plebs = [];
public string $search = '';
public string $signThisEvent = '';
public bool $isNotClosed = true;
public array $positions = [
'presidency' => ['icon' => 'fa-crown', 'title' => 'Präsidium'],
'board' => ['icon' => 'fa-users', 'title' => 'Vizepräsidium'],
];
protected $listeners = [
'nostrLoggedIn' => 'handleNostrLoggedIn',
'nostrLoggedOut' => 'handleNostrLoggedOut',
'echo:votes,.newVote' => 'handleNewVote',
];
#[Computed]
public function loadedEvents(): array
{
return collect($this->events)
->map(function ($event) {
$profile = Profile::query()
->where('pubkey', $event['pubkey'])
->first()
?->toArray();
$votedFor = Profile::query()
->where('pubkey', str($event['content'])->before(',')->toString())
->first()
?->toArray();
return [
'id' => $event['id'],
'kind' => $event['kind'],
'content' => $event['content'],
'pubkey' => $event['pubkey'],
'tags' => $event['tags'],
'created_at' => $event['created_at'],
'profile' => $profile,
'votedFor' => $votedFor,
'type' => str($event['content'])->after(',')->toString(),
];
})
->sortByDesc('created_at')
->unique(fn ($event) => $event['pubkey'].$event['type'])
->values()
->toArray();
}
#[Computed]
public function loadedBoardEvents(): array
{
return collect($this->boardEvents)
->map(function ($event) {
$profile = Profile::query()
->where('pubkey', $event['pubkey'])
->first()
?->toArray();
$votedFor = Profile::query()
->where('pubkey', str($event['content'])->before(',')->toString())
->first()
?->toArray();
return [
'id' => $event['id'],
'kind' => $event['kind'],
'content' => $event['content'],
'pubkey' => $event['pubkey'],
'tags' => $event['tags'],
'created_at' => $event['created_at'],
'profile' => $profile,
'votedFor' => $votedFor,
'type' => str($event['content'])->after(',')->toString(),
];
})
->sortByDesc('created_at')
->values()
->toArray();
}
#[Computed]
public function electionConfig(): array
{
$loadedEvents = $this->loadedEvents();
return collect(json_decode($this->election->candidates, true, 512, JSON_THROW_ON_ERROR))
->map(function ($c) use ($loadedEvents) {
$candidates = Profile::query()
->whereIn('pubkey', $c['c'])
->get()
->map(function ($p) use ($loadedEvents, $c) {
$votedClass = ' bg-green-500/20 text-green-700';
$notVotedClass = ' bg-gray-500/20 text-gray-100';
$hasVoted = $loadedEvents
->filter(fn ($e) => $e['type'] === $c['type'] && $e['pubkey'] === $this->currentPubkey)
->firstWhere('votedFor.pubkey', $p->pubkey);
return [
'pubkey' => $p->pubkey,
'name' => $p->name,
'picture' => $p->picture,
'votedClass' => $hasVoted ? $votedClass : $notVotedClass,
];
});
return [
'type' => $c['type'],
'c' => $c['c'],
'candidates' => $candidates,
];
})
->toArray();
}
#[Computed]
public function electionConfigBoard(): array
{
$loadedBoardEvents = $this->loadedBoardEvents();
return collect(json_decode($this->election->candidates, true, 512, JSON_THROW_ON_ERROR))
->map(function ($c) use ($loadedBoardEvents) {
$candidates = Profile::query()
->whereIn('pubkey', $c['c'])
->get()
->map(function ($p) use ($loadedBoardEvents, $c) {
$votedClass = ' bg-green-500/20 text-green-700';
$notVotedClass = ' bg-gray-500/20 text-gray-100';
$hasVoted = $loadedBoardEvents
->filter(fn ($e) => $e['type'] === $c['type'] && $e['pubkey'] === $this->currentPubkey)
->firstWhere('votedFor.pubkey', $p->pubkey);
return [
'pubkey' => $p->pubkey,
'name' => $p->name,
'picture' => $p->picture,
'votedClass' => $hasVoted ? $votedClass : $notVotedClass,
'hasVoted' => $hasVoted,
];
});
return [
'type' => $c['type'],
'c' => $c['c'],
'candidates' => $candidates,
];
})
->toArray();
}
public function mount(Election $election): void
{
$this->election = $election;
$this->plebs = EinundzwanzigPleb::query()
->with(['profile'])
->whereIn('association_status', [3, 4])
->orderBy('association_status', 'desc')
->get()
->toArray();
$this->loadEvents();
$this->loadBoardEvents();
if ($this->election->end_time?->isPast() || ! config('services.voting')) {
$this->isNotClosed = false;
}
}
public function updatedSearch($value): void
{
$this->plebs = EinundzwanzigPleb::query()
->with(['profile'])
->whereIn('association_status', [3, 4])
->where(fn ($query) => $query
->where('pubkey', 'like', "%$value%")
->orWhereHas('profile', fn ($query) => $query->where('name', 'ilike', "%$value%")))
->orderBy('association_status', 'desc')
->get()
->toArray();
}
public function handleNostrLoggedIn($pubkey): void
{
NostrAuth::login($pubkey);
$this->currentPubkey = $pubkey;
$this->currentPleb = EinundzwanzigPleb::query()->where('pubkey', $pubkey)->first();
$logPubkeys = [
'0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033',
'430169631f2f0682c60cebb4f902d68f0c71c498fd1711fd982f052cf1fd4279',
];
if (in_array($this->currentPubkey, $logPubkeys, true)) {
$this->showLog = true;
$this->isAllowed = true;
}
}
public function handleNostrLoggedOut(): void
{
$this->isAllowed = false;
$this->currentPubkey = null;
$this->currentPleb = null;
}
public function handleNewVote(): void
{
$this->loadEvents();
$this->loadBoardEvents();
}
public function loadEvents(): void
{
$this->events = $this->loadNostrEvents([32122]);
}
public function loadBoardEvents(): void
{
$this->boardEvents = $this->loadNostrEvents([2121]);
}
public function loadNostrEvents($kinds): array
{
$subscription = new Subscription;
$subscriptionId = $subscription->setId();
$filter = new Filter;
$filter->setKinds($kinds);
$requestMessage = new RequestMessage($subscriptionId, [$filter]);
$relaySet = new RelaySet;
$relaySet->setRelays([new Relay(config('services.relay'))]);
$request = new Request($relaySet, $requestMessage);
$response = $request->send();
return collect($response[config('services.relay')])
->map(function ($event) {
if (! isset($event->event)) {
return false;
}
return [
'id' => $event->event->id,
'kind' => $event->event->kind,
'content' => $event->event->content,
'pubkey' => $event->event->pubkey,
'tags' => $event->event->tags,
'created_at' => $event->event->created_at,
];
})
->filter()
->toArray();
}
public function vote($pubkey, $type, $board = false): void
{
if ($this->election->end_time?->isPast()) {
$this->isNotClosed = false;
return;
}
$note = new NostrEvent;
$note->setKind($board ? 2121 : 32122);
if (! $board) {
$dTag = sprintf('%s,%s,%s', $this->currentPleb->pubkey, date('Y'), $type);
$note->setTags([['d', $dTag]]);
}
$note->setContent("$pubkey,$type");
$this->signThisEvent = $note->toJson();
}
public function checkElection(): void
{
if ($this->election->end_time?->isPast()) {
$this->isNotClosed = false;
}
}
public function signEvent($event): void
{
$note = new NostrEvent;
$note->setId($event['id']);
$note->setSignature($event['sig']);
$note->setKind($event['kind']);
$note->setContent($event['content']);
$note->setPublicKey($event['pubkey']);
$note->setTags($event['tags']);
$note->setCreatedAt($event['created_at']);
$eventMessage = new EventMessage($note);
$relay = new Relay(config('services.relay'));
$relay->setMessage($eventMessage);
$relay->send();
\App\Support\Broadcast::on('votes')->as('newVote')->sendNow();
}
public function render()
{
return view('livewire.association.election.show')
->layout('layouts.app')
->with([
'seo' => new \RalphJSmit\Laravel\SEO\Support\SEOData(title: 'Wahlen ' . $this->election->year, description: 'Wahlen des Vereins im Jahr ' . $this->election->year)
]);
}
};
?>
<div>
@if($isAllowed)
<div x-cloak class="relative flex h-full" x-data="nostrApp(@this)"
wire:poll.600000ms="checkElection">
<!-- Inbox sidebar -->
<div id="inbox-sidebar"
class="absolute z-20 top-0 bottom-0 w-full md:w-auto md:static md:top-auto md:bottom-auto -mr-px md:translate-x-0 transition-transform duration-200 ease-in-out"
:class="inboxSidebarOpen ? 'translate-x-0' : '-translate-x-full'">
<div
class="sticky top-16 bg-white dark:bg-[#1B1B1B] overflow-x-hidden overflow-y-auto no-scrollbar shrink-0 border-r border-gray-200 dark:border-gray-700/60 md:w-[18rem] xl:w-[20rem] h-[calc(100dvh-64px)]">
<!-- #Marketing group -->
<div>
<!-- Group header -->
<div class="sticky top-0 z-10">
<div class="flex items-center bg-white dark:bg-[#1B1B1B] border-b border-gray-200 dark:border-gray-700/60 px-5 h-16">
<div class="w-full flex items-center justify-between">
<!-- Channel menu -->
<div class="relative" x-data="{ open: false }">
<button class="grow flex items-center truncate" aria-haspopup="true"
@click.prevent="open = !open" :aria-expanded="open">
<div class="truncate">
<span
class="font-semibold text-gray-800 dark:text-gray-100">2024</span>
</div>
<svg
class="w-3 h-3 shrink-0 ml-1 fill-current text-gray-400 dark:text-gray-500"
viewBox="0 0 12 12">
<path d="M5.9 11.4L.5 6l1.4-1.4 4 4 4-4L11.3 6z"/>
</svg>
</button>
<div
class="origin-top-right z-10 absolute top-full left-0 min-w-60 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700/60 py-1.5 rounded-lg shadow-lg overflow-hidden mt-1"
@click.outside="open = false" @keydown.escape.window="open = false"
x-show="open"
x-transition:enter="transition ease-out duration-200 transform"
x-transition:enter-start="opacity-0 -translate-y-2"
x-transition:enter-end="opacity-100 translate-y-0"
x-transition:leave="transition ease-out duration-200"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
x-cloak>
<ul>
<li>
<a class="font-medium text-sm text-gray-600 dark:text-gray-300 hover:text-gray-800 dark:hover:text-gray-200 block py-1.5 px-3"
href="#0" @click="open = false" @focus="open = true"
@focusout="open = false">
<div class="flex items-center justify-between">
<div class="grow flex items-center truncate">
<div class="truncate">2024</div>
</div>
<svg
class="w-3 h-3 shrink-0 fill-current text-orange-500 ml-1"
viewBox="0 0 12 12">
<path
d="M10.28 1.28L3.989 7.575 1.695 5.28A1 1 0 00.28 6.695l3 3a1 1 0 001.414 0l7-7A1 1 0 0010.28 1.28z"/>
</svg>
</div>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<!-- Group body -->
<div class="px-5 py-4">
<!-- Search form -->
<form class="relative">
<label for="inbox-search" class="sr-only">Search</label>
<input
wire:model.live.debounce="search"
id="inbox-search" class="form-input w-full pl-9 bg-white dark:bg-gray-800"
type="search" placeholder="Suche…"/>
<button class="absolute inset-0 right-auto group" type="submit" aria-label="Search">
<svg
class="shrink-0 fill-current text-gray-400 dark:text-gray-500 group-hover:text-gray-500 dark:group-hover:text-gray-400 ml-3 mr-2"
width="16" height="16" viewBox="0 0 16 16"
xmlns="http://www.w3.org/2000/svg">
<path
d="M7 14c-3.86 0-7-3.14-7-7s3.14-7 7-7 7 3.14 7 7-3.14 7-7 7zM7 2C4.243 2 2 4.243 2 7s2.243 5 5 5 5-2.243 5-5-2.243-5-5-5z"/>
<path
d="M15.707 14.293L13.314 11.9a8.019 8.019 0 01-1.414 1.414l2.393 2.393a.997.997 0 001.414 0 .999.999 0 000-1.414z"/>
</svg>
</button>
</form>
<!-- Inbox -->
<div class="mt-4">
<div class="text-xs font-semibold text-gray-400 dark:text-gray-500 uppercase mb-3">
Plebs
</div>
<ul class="mb-6">
@foreach($plebs as $pleb)
<li class="-mx-2">
<div class="flex w-full p-2 rounded text-left">
<img class="w-8 h-8 rounded-full mr-2 bg-black"
src="{{ $pleb['profile']['picture'] ?? 'https://robohash.org/test' }}"
onerror="this.onerror=null; this.src='https://robohash.org/test';"
width="32"
height="32"
alt="A"/>
<div class="grow truncate">
<div class="flex items-center justify-between mb-1.5">
<div class="truncate">
<span
class="text-sm font-semibold text-gray-800 dark:text-gray-100 truncate">{{ $pleb['profile']['name'] ?? $pleb['pubkey'] }}</span>
</div>
<div class="text-xs text-gray-500 font-medium">
<x-badge
:color="\App\Enums\AssociationStatus::from($pleb['association_status'])->color()"
:label="\App\Enums\AssociationStatus::from($pleb['association_status'])->label()"/>
</div>
</div>
<div
class="text-xs font-medium text-gray-800 dark:text-gray-100 truncate mb-0.5">
<div class="flex items-center space-x-2 h-5">
@foreach($positions as $name => $p)
@php
$votedResult = $this->loadedEvents->filter(fn ($e) => $e['pubkey'] === $pleb['pubkey'])->firstWhere('type', $name);
@endphp
<div class="flex space-x-2"
wire:key="p_{{ $name }}">
@if($votedResult)
<i class="fa-sharp-duotone fa-solid {{ $p['icon'] }} w-4 h-4 fill-current text-green-500"></i>
@endif
</div>
@endforeach
</div>
</div>
</div>
</div>
</li>
@endforeach
</ul>
</div>
</div>
</div>
</div>
<!-- Inbox body -->
@if($currentPubkey)
<div class="grow flex flex-col md:translate-x-0 transition-transform duration-300 ease-in-out"
:class="inboxSidebarOpen ? 'translate-x-1/3' : 'translate-x-0'">
<!-- Header -->
<div class="sticky top-16">
<div
class="flex items-center justify-between before:absolute before:inset-0 before:backdrop-blur-md before:bg-gray-50/90 dark:before:bg-[#1B1B1B]/90 before:-z-10 border-b border-gray-200 dark:border-gray-700/60 px-4 sm:px-6 md:px-5 h-16">
<div
class="flex flex-col space-y-2 sm:space-y-0 sm:flex-row justify-between items-center w-full">
<div>
@if($isNotClosed)
<x-badge success
label="Die Wahl ist geöffnet bis zum {{ $election->end_time?->timezone('Europe/Berlin')->format('d.m.Y H:i') }}"/>
@else
<x-badge negative label="Die Wahl ist geschlossen"/>
@endif
</div>
<div>
<x-button secondary
:href="route('association.election.admin', ['election' => $election])"
label="Wahl-Admin"/>
</div>
</div>
</div>
</div>
<!-- Body -->
<div class="grow px-4 sm:px-6 md:px-5 py-4">
<!-- Mail subject -->
<header class="sm:flex sm:items-start space-x-4 mb-4">
<h1 class="text-xl leading-snug text-gray-800 dark:text-gray-100 font-bold mb-1 sm:mb-0 ml-2">
Wahlen
</h1>
<button
class="text-xs inline-flex font-bold bg-amber-500/20 text-sky-700 rounded-full text-center px-2.5 py-1 whitespace-nowrap">
2024
</button>
</header>
<!-- Messages box -->
<div
class="shadow-sm rounded-xl px-6 divide-y divide-gray-200 dark:divide-gray-700/60">
<!-- Mail -->
<div class="py-6">
<h1 class="text-xl leading-snug text-gray-800 dark:text-gray-100 font-bold mb-1 sm:mb-0 ml-2">
Wahl des Präsidiums
</h1>
<div class="grid sm:grid-cols-2 gap-6">
<div
class="bg-white dark:bg-gray-800 shadow-sm rounded-xl">
<div class="flex flex-col h-full p-5">
<header>
<div class="flex items-center justify-between">
<i class="fa-sharp-duotone fa-solid {{ $positions['presidency']['icon'] }} w-9 h-9 fill-current text-white"></i>
</div>
</header>
<div class="grow mt-2">
<div
class="inline-flex text-gray-800 dark:text-gray-100 hover:text-gray-900 dark:hover:text-white mb-1">
<h2 class="text-xl leading-snug font-semibold">{{ $positions['presidency']['title'] }}</h2>
</div>
<div class="text-sm">
@php
$votedResult = $this->loadedEvents->filter(fn ($event) => $event['pubkey'] === $currentPubkey)->firstWhere('type', 'presidency');
$votedName = $votedResult['votedFor']['name'] ?? 'error';
@endphp
@if($votedResult)
<span>Du hast "{{ $votedName }}" gewählt</span>
@else
<span>Wähle deinen Kandidaten für das Präsidium.</span>
@endif
</div>
</div>
<footer class="mt-5">
<div class="grid sm:grid-cols-2 gap-2">
@foreach($this->electionConfig->firstWhere('type', 'presidency')['candidates'] ?? [] as $c)
<div
@if($isNotClosed)wire:click="vote('{{ $c['pubkey'] }}', 'presidency')"
@endif
class="{{ $c['votedClass'] }} cursor-pointer text-xs inline-flex font-medium rounded-full text-center px-2.5 py-1">
<div class="flex items-center">
<img class="w-6 h-6 rounded-full mr-2 bg-black"
src="{{ $c['picture'] ?? 'https://robohash.org/' . $c['pubkey'] }}"
onerror="this.onerror=null; this.src='https://robohash.org/{{ $c['pubkey'] }}';"
width="24" height="24"
alt="{{ $c['name'] }}"/>
{{ $c['name'] }}
</div>
</div>
@endforeach
</div>
</footer>
</div>
</div>
</div>
<h1 class="mt-6 text-xl leading-snug text-gray-800 dark:text-gray-100 font-bold mb-1 sm:mb-0 ml-2">
Wahl der übrigen Vorstandsmitglieder
</h1>
<div class="grid gap-6">
<div
class="bg-white dark:bg-gray-800 shadow-sm rounded-xl">
<div class="flex flex-col h-full p-5">
<div class="grow mt-2">
<div class="text-sm">
<span>Klicke auf den Kandidaten, um seine Position als Vorstandsmitglied zu bestätigen.</span>
</div>
</div>
<footer class="mt-5">
<div class="grid sm:grid-cols-4 gap-2">
@foreach($this->electionConfigBoard->firstWhere('type', 'board')['candidates'] ?? [] as $c)
<div
@if($isNotClosed && !$c['hasVoted'])wire:click="vote('{{ $c['pubkey'] }}', 'board', true)"
@endif
class="{{ $c['votedClass'] }} cursor-pointer text-xs inline-flex font-medium rounded-full text-center px-2.5 py-1">
<div class="flex items-center">
<img class="w-6 h-6 rounded-full mr-2 bg-black"
src="{{ $c['picture'] ?? 'https://robohash.org/' . $c['pubkey'] }}"
onerror="this.onerror=null; this.src='https://robohash.org/{{ $c['pubkey'] }}';"
width="24" height="24"
alt="{{ $c['name'] }}"/>
{{ $c['name'] }}
</div>
</div>
@endforeach
</div>
</footer>
</div>
</div>
</div>
</div>
</div>
<!-- Log events -->
<div x-cloak x-show="showLog" class="mt-6 hidden sm:block">
<div class="bg-white dark:bg-gray-800 shadow-sm rounded-xl mb-8">
<header class="px-5 py-4">
<h2 class="font-semibold text-gray-800 dark:text-gray-100">Präsidium Log <span
class="text-gray-400 dark:text-gray-500 font-medium">{{ count($this->loadedEvents) }}</span>
</h2>
</header>
<div>
<!-- Table -->
<div class="overflow-x-auto">
<table
class="table-auto w-full dark:text-gray-300 divide-y divide-gray-100 dark:divide-gray-700/60">
<!-- Table header -->
<thead
class="text-xs uppercase text-gray-500 dark:text-gray-400 bg-gray-50 dark:bg-gray-900/20 border-t border-gray-100 dark:border-gray-700/60">
<tr>
<th class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div class="font-semibold text-left">ID</div>
</th>
<th class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div class="font-semibold text-left">Kind</div>
</th>
<th class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div class="font-semibold text-left">Pubkey</div>
</th>
<th class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div class="font-semibold text-left">Created At</div>
</th>
<th class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div class="font-semibold text-left">Voted For</div>
</th>
<th class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div class="font-semibold text-left">Type</div>
</th>
</tr>
</thead>
<!-- Table body -->
<tbody class="text-sm">
@foreach($this->loadedEvents as $event)
<tr>
<td class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div
class="font-medium">{{ Str::limit($event['id'], 10) }}</div>
</td>
<td class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div>{{ $event['kind'] }}</div>
</td>
<td class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div>{{ $event['profile']['name'] ?? '' }}</div>
</td>
<td class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div>{{ $event['created_at'] }}</div>
</td>
<td class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div>{{ $event['votedFor']['name'] ?? '' }}</div>
</td>
<td class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div>{{ $event['type'] }}</div>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
<div x-cloak x-show="showLog" class="mt-6 hidden sm:block">
<div class="bg-white dark:bg-gray-800 shadow-sm rounded-xl mb-8">
<header class="px-5 py-4">
<h2 class="font-semibold text-gray-800 dark:text-gray-100">Board Log <span
class="text-gray-400 dark:text-gray-500 font-medium">{{ count($this->loadedBoardEvents) }}</span>
</h2>
</header>
<div>
<!-- Table -->
<div class="overflow-x-auto">
<table
class="table-auto w-full dark:text-gray-300 divide-y divide-gray-100 dark:divide-gray-700/60">
<!-- Table header -->
<thead
class="text-xs uppercase text-gray-500 dark:text-gray-400 bg-gray-50 dark:bg-gray-900/20 border-t border-gray-100 dark:border-gray-700/60">
<tr>
<th class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div class="font-semibold text-left">ID</div>
</th>
<th class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div class="font-semibold text-left">Kind</div>
</th>
<th class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div class="font-semibold text-left">Pubkey</div>
</th>
<th class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div class="font-semibold text-left">Created At</div>
</th>
<th class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div class="font-semibold text-left">Voted For</div>
</th>
<th class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div class="font-semibold text-left">Type</div>
</th>
</tr>
</thead>
<!-- Table body -->
<tbody class="text-sm">
@foreach($this->loadedBoardEvents as $event)
<tr>
<td class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div
class="font-medium">{{ Str::limit($event['id'], 10) }}</div>
</td>
<td class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div>{{ $event['kind'] }}</div>
</td>
<td class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div>{{ $event['profile']['name'] ?? '' }}</div>
</td>
<td class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div>{{ $event['created_at'] }}</div>
</td>
<td class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div>{{ $event['votedFor']['name'] ?? '' }}</div>
</td>
<td class="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
<div>{{ $event['type'] }}</div>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
@endif
</div>
@else
<div class="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
<div class="bg-white dark:bg-[#1B1B1B] shadow overflow-hidden sm:rounded-lg">
<div class="px-4 py-5 sm:px-6">
<h3 class="text-lg font-medium leading-6 text-gray-900 dark:text-gray-200">Wahlen</h3>
<p class="mt-1 max-w">
Du bist nicht berechtigt, die Wahlen einzusehen.
</p>
</div>
</div>
</div>
@endif
</div>

View File

@@ -1,90 +0,0 @@
<?php
use App\Models\EinundzwanzigPleb;
use App\Support\NostrAuth;
use Livewire\Component;
new class extends Component {
public bool $isAllowed = false;
public ?string $currentPubkey = null;
public ?EinundzwanzigPleb $currentPleb = null;
protected $listeners = [
'nostrLoggedOut' => 'handleNostrLoggedOut',
'nostrLoggedIn' => 'handleNostrLoggedIn',
];
public function mount(): void
{
if (NostrAuth::check()) {
$this->currentPubkey = NostrAuth::pubkey();
$this->currentPleb = \App\Models\EinundzwanzigPleb::query()
->where('pubkey', $this->currentPubkey)->first();
$allowedPubkeys = [
'0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033',
'430169631f2f0682c60cebb4f902d68f0c71c498fd1711fd982f052cf1fd4279',
'7acf30cf60b85c62b8f654556cc21e4016df8f5604b3b6892794f88bb80d7a1d',
'f240be2b684f85cc81566f2081386af81d7427ea86250c8bde6b7a8500c761ba',
'19e358b8011f5f4fc653c565c6d4c2f33f32661f4f90982c9eedc292a8774ec3',
'acbcec475a1a4f9481939ecfbd1c3d111f5b5a474a39ae039bbc720fdd305bec',
];
if (in_array($this->currentPubkey, $allowedPubkeys, true)) {
$this->isAllowed = true;
}
}
}
public function handleNostrLoggedOut(): void
{
$this->isAllowed = false;
$this->currentPubkey = null;
}
public function handleNostrLoggedIn($pubkey): void
{
NostrAuth::login($pubkey);
$this->currentPubkey = $pubkey;
$this->currentPleb = \App\Models\EinundzwanzigPleb::query()
->where('pubkey', $pubkey)->first();
$allowedPubkeys = [
'0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033',
'430169631f2f0682c60cebb4f902d68f0c71c498fd1711fd982f052cf1fd4279',
'7acf30cf60b85c62b8f654556cc21e4016df8f5604b3b6892794f88bb80d7a1d',
'f240be2b684f85cc81566f2081386af81d7427ea86250c8bde6b7a8500c761ba',
'19e358b8011f5f4fc653c565c6d4c2f33f32661f4f90982c9eedc292a8774ec3',
'acbcec475a1a4f9481939ecfbd1c3d111f5b5a474a39ae039bbc720fdd305bec',
];
if (in_array($this->currentPubkey, $allowedPubkeys, true)) {
$this->isAllowed = true;
}
}
public function render()
{
return view('livewire.association.members.admin')
->layout('layouts.app')
->title(__('Mitglieder'));
}
};
?>
<div>
@if($isAllowed)
<div class="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
<livewire:einundzwanzig-pleb-table/>
</div>
@else
<div class="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
<div class="bg-white dark:bg-[#1B1B1B] shadow overflow-hidden sm:rounded-lg">
<div class="px-4 py-5 sm:px-6">
<h3 class="text-lg font-medium leading-6 text-gray-900 dark:text-gray-200">Mitglieder</h3>
<p class="mt-1 max-w">
Du bist nicht berechtigt, Mitglieder zu bearbeiten.
</p>
</div>
</div>
</div>
@endif
</div>

View File

@@ -1,74 +0,0 @@
<x-layouts.app title="{{ __('Projektförderung anlegen') }}">
<div>
@if($isAllowed)
<div class="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
<div
class="flex flex-col md:flex-row items-center mb-6 space-y-4 md:space-y-0 md:space-x-4">
<div class="flex items-center justify-between w-full">
<h1 class="text-2xl md:text-3xl text-gray-800 dark:text-gray-100 font-bold">
Projektförderung anlegen
</h1>
</div>
</div>
<div class="md:flex">
<!-- Left column -->
<div class="w-full md:w-60 mb-4 md:mb-0">
<div
class="bg-white dark:bg-gray-800 shadow-sm rounded-xl p-5">
<h2 class="text-lg font-semibold text-gray-800 dark:text-gray-100 mb-4">
Formular
</h2>
<div class="space-y-4">
<div wire:dirty>
<x-input label="Name" wire:model="form.name"/>
@error('form.name')
<span class="text-red-500">{{ $message }}</span>
@enderror
</div>
<div wire:dirty>
<x-textarea label="Beschreibung" wire:model="form.description"/>
@error('form.description')
<span class="text-red-500">{{ $message }}</span>
@enderror
</div>
<button
wire:click="save"
wire:loading.attr="disabled"
class="w-full btn-sm bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-700/60 hover:border-gray-300 dark:hover:border-gray-600 text-gray-800 dark:text-gray-300">
Speichern
</button>
</div>
</div>
</div>
<!-- Right column -->
<div class="flex-1 md:ml-8">
<div
class="bg-white dark:bg-gray-800 shadow-sm rounded-xl p-5">
<h2 class="text-lg font-semibold text-gray-800 dark:text-gray-100 mb-4">
Information
</h2>
<p class="text-sm text-gray-800 dark:text-gray-100">
Fülle das Formular aus, um eine neue Projektförderung anzulegen.
</p>
</div>
</div>
</div>
</div>
@else
<div class="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
<div class="bg-white dark:bg-[#1B1B1B] shadow overflow-hidden sm:rounded-lg">
<div class="px-4 py-5 sm:px-6">
<h3 class="text-lg font-medium leading-6 text-gray-900 dark:text-gray-200">
Projektförderung
</h3>
<p class="mt-1 max-w">
Du bist nicht berechtigt, eine Projektförderung anzulegen.
</p>
</div>
</div>
</div>
@endif
</div>
</x-layouts.app>

View File

@@ -1,74 +0,0 @@
<x-layouts.app title="{{ __('Projektförderung bearbeiten') }}">
<div>
@if($isAllowed)
<div class="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
<div
class="flex flex-col md:flex-row items-center mb-6 space-y-4 md:space-y-0 md:space-x-4">
<div class="flex items-center justify-between w-full">
<h1 class="text-2xl md:text-3xl text-gray-800 dark:text-gray-100 font-bold">
Projektförderung bearbeiten
</h1>
</div>
</div>
<div class="md:flex">
<!-- Left column -->
<div class="w-full md:w-60 mb-4 md:mb-0">
<div
class="bg-white dark:bg-gray-800 shadow-sm rounded-xl p-5">
<h2 class="text-lg font-semibold text-gray-800 dark:text-gray-100 mb-4">
Formular
</h2>
<div class="space-y-4">
<div wire:dirty>
<x-input label="Name" wire:model="form.name"/>
@error('form.name')
<span class="text-red-500">{{ $message }}</span>
@enderror
</div>
<div wire:dirty>
<x-textarea label="Beschreibung" wire:model="form.description"/>
@error('form.description')
<span class="text-red-500">{{ $message }}</span>
@enderror
</div>
<button
wire:click="update"
wire:loading.attr="disabled"
class="w-full btn-sm bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-700/60 hover:border-gray-300 dark:hover:border-gray-600 text-gray-800 dark:text-gray-300">
Speichern
</button>
</div>
</div>
</div>
<!-- Right column -->
<div class="flex-1 md:ml-8">
<div
class="bg-white dark:bg-gray-800 shadow-sm rounded-xl p-5">
<h2 class="text-lg font-semibold text-gray-800 dark:text-gray-100 mb-4">
Information
</h2>
<p class="text-sm text-gray-800 dark:text-gray-100">
Bearbeite die Projektförderung und speichere deine Änderungen.
</p>
</div>
</div>
</div>
</div>
@else
<div class="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
<div class="bg-white dark:bg-[#1B1B1B] shadow overflow-hidden sm:rounded-lg">
<div class="px-4 py-5 sm:px-6">
<h3 class="text-lg font-medium leading-6 text-gray-900 dark:text-gray-200">
Projektförderung
</h3>
<p class="mt-1 max-w">
Du bist nicht berechtigt, die Projektförderung zu bearbeiten.
</p>
</div>
</div>
</div>
@endif
</div>
</x-layouts.app>

View File

@@ -1,181 +0,0 @@
<?php
use App\Models\ProjectProposal;
use App\Support\NostrAuth;
use Livewire\Component;
use WireUi\Actions\Notification;
new class extends Component {
public string $activeFilter = 'all';
public string $search = '';
public \Illuminate\Database\Eloquent\Collection $projects;
public bool $isAllowed = false;
public ?string $currentPubkey = null;
public ?\App\Models\EinundzwanzigPleb $currentPleb = null;
protected $listeners = [
'nostrLoggedIn' => 'handleNostrLoggedIn',
'nostrLoggedOut' => 'handleNostrLoggedOut',
];
public function mount(): void
{
$this->loadProjects();
if (NostrAuth::check()) {
$this->currentPubkey = NostrAuth::pubkey();
$this->currentPleb = \App\Models\EinundzwanzigPleb::query()->where('pubkey', $this->currentPubkey)->first();
$this->isAllowed = true;
}
}
public function updatedSearch(): void
{
$this->loadProjects();
}
public function loadProjects(): void
{
$this->projects = ProjectProposal::query()
->with([
'einundzwanzigPleb.profile',
'votes',
])
->where(function ($query) {
$query
->where('name', 'ilike', '%'.$this->search.'%')
->orWhere('description', 'ilike', '%'.$this->search.'%')
->orWhereHas('einundzwanzigPleb.profile', function ($q) {
$q->where('name', 'ilike', '%'.$this->search.'%');
});
})
->orderBy('created_at', 'desc')
->get();
}
public function handleNostrLoggedIn($pubkey): void
{
NostrAuth::login($pubkey);
$this->currentPubkey = $pubkey;
$this->currentPleb = \App\Models\EinundzwanzigPleb::query()->where('pubkey', $pubkey)->first();
$this->isAllowed = true;
}
public function handleNostrLoggedOut(): void
{
$this->isAllowed = false;
$this->currentPubkey = null;
$this->currentPleb = null;
}
public function confirmDelete($id): void
{
$notification = new Notification($this);
$notification->confirm([
'title' => 'Projektunterstützung löschen',
'message' => 'Bist du sicher, dass du diese Projektunterstützung löschen möchtest?',
'accept' => [
'label' => 'Ja, löschen',
'method' => 'delete',
'params' => $id,
],
]);
}
public function setFilter($filter): void
{
$this->activeFilter = $filter;
}
public function delete($id): void
{
ProjectProposal::query()->findOrFail($id)->delete();
$this->loadProjects();
}
public function render()
{
return view('livewire.association.project-support')
->layout('layouts.app')
->with([
'seo' => new \RalphJSmit\Laravel\SEO\Support\SEOData(title: 'Projekt Unterstützungen', description: 'Einundzwanzig Projektunterstützungen')
]);
}
};
?>
<div>
<div class="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
<!-- Page header -->
<div class="sm:flex sm:justify-between sm:items-center mb-5">
<!-- Left: Title -->
<div class="mb-4 sm:mb-0">
<h1 class="text-2xl md:text-3xl text-gray-800 dark:text-gray-100 font-bold">
Einundzwanzig Projektunterstützungen
</h1>
</div>
<!-- Right: Actions -->
<div class="grid grid-cols-1 sm:grid-cols-2 justify-start sm:justify-end gap-2">
<!-- Search form -->
<form class="relative">
<x-input type="search" wire:model.live.debounce="search"
placeholder="Suche"/>
</form>
<!-- Add meetup button -->
@if($currentPleb && $currentPleb->association_status->value > 1 && $currentPleb->paymentEvents()->where('year', date('Y'))->where('paid', true)->exists())
<x-button :href="route('association.projectSupport.create')" icon="plus"
label="Projekt einreichen"/>
@endif
</div>
</div>
<!-- Filters -->
<div class="mb-5">
<ul class="flex flex-wrap -m-1">
<li class="m-1">
<button wire:click="setFilter('all')"
class="inline-flex items-center justify-center text-sm font-medium leading-5 rounded-full px-3 py-1 border @if($activeFilter === 'all') border-transparent shadow-sm bg-gray-900 dark:bg-gray-100 text-white dark:text-gray-800 @else border-gray-200 dark:border-gray-700/60 hover:border-gray-300 dark:hover:border-gray-600 shadow-sm bg-white dark:bg-gray-800 text-gray-500 dark:text-gray-400 @endif transition">
Alle
</button>
</li>
<li class="m-1">
<button wire:click="setFilter('new')"
class="inline-flex items-center justify-center text-sm font-medium leading-5 rounded-full px-3 py-1 border @if($activeFilter === 'new') border-transparent shadow-sm bg-gray-900 dark:bg-gray-100 text-white dark:text-gray-800 @else border-gray-200 dark:border-gray-700/60 hover:border-gray-300 dark:hover:border-gray-600 shadow-sm bg-white dark:bg-gray-800 text-gray-500 dark:text-gray-400 @endif transition">
Neu
</button>
</li>
<li class="m-1">
<button wire:click="setFilter('supported')"
class="inline-flex items-center justify-center text-sm font-medium leading-5 rounded-full px-3 py-1 border @if($activeFilter === 'supported') border-transparent shadow-sm bg-gray-900 dark:bg-gray-100 text-white dark:text-gray-800 @else border-gray-200 dark:border-gray-700/60 hover:border-gray-300 dark:hover:border-gray-600 shadow-sm bg-white dark:bg-gray-800 text-gray-500 dark:text-gray-400 @endif transition">
Unterstützt
</button>
</li>
<li class="m-1">
<button wire:click="setFilter('rejected')"
class="inline-flex items-center justify-center text-sm font-medium leading-5 rounded-full px-3 py-1 border @if($activeFilter === 'rejected') border-transparent shadow-sm bg-gray-900 dark:bg-gray-100 text-white dark:text-gray-800 @else border-gray-200 dark:border-gray-700/60 hover:border-gray-300 dark:hover:border-gray-600 shadow-sm bg-white dark:bg-gray-800 text-gray-500 dark:text-gray-400 @endif transition">
Abgelehnt
</button>
</li>
</ul>
</div>
<div class="text-sm text-gray-500 dark:text-gray-400 italic mb-4">{{ $projects->count() }} Projekte</div>
<!-- Content -->
<div class="grid xl:grid-cols-2 gap-6 mb-8">
@foreach($this->projects as $project)
<x-project-card :project="$project" :currentPleb="$currentPleb" :section="$activeFilter"/>
@endforeach
</div>
</div>
</div>

View File

@@ -1,85 +0,0 @@
<x-layouts.app
:seo="new \RalphJSmit\Laravel\SEO\Support\SEOData(title: 'Projektförderung ' . $project->name, description: $project->description)"
>
<div>
@if($isAllowed)
<div class="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
<div
class="flex flex-col md:flex-row items-center mb-6 space-y-4 md:space-y-0 md:space-x-4">
<div class="flex items-center justify-between w-full">
<h1 class="text-2xl md:text-3xl text-gray-800 dark:text-gray-100 font-bold">
{{ $project->name }}
</h1>
<div>
@if($project->status === 'pending')
<x-badge info label="Pending"/>
@elseif($project->status === 'active')
<x-badge success label="Active"/>
@else
<x-badge neutral label="Archiviert"/>
@endif
</div>
</div>
</div>
<div class="md:flex">
<!-- Left column -->
<div class="w-full md:w-60 mb-4 md:mb-0">
<div
class="bg-white dark:bg-gray-800 shadow-sm rounded-xl p-5">
<h2 class="text-lg font-semibold text-gray-800 dark:text-gray-100 mb-4">
Details
</h2>
<dl class="space-y-3">
<div>
<dt class="text-xs font-semibold text-gray-500 uppercase mb-1">Status</dt>
<dd class="text-sm text-gray-800 dark:text-gray-100">
@if($project->status === 'pending')
Ausstehend
@elseif($project->status === 'active')
Aktiv
@else
Archiviert
@endif
</dd>
</div>
<div>
<dt class="text-xs font-semibold text-gray-500 uppercase mb-1">Erstellt am</dt>
<dd class="text-sm text-gray-800 dark:text-gray-100">
{{ $project->created_at->format('d.m.Y') }}
</dd>
</div>
</dl>
</div>
</div>
<!-- Right column -->
<div class="flex-1 md:ml-8">
<div
class="bg-white dark:bg-gray-800 shadow-sm rounded-xl p-5">
<h2 class="text-lg font-semibold text-gray-800 dark:text-gray-100 mb-4">
Beschreibung
</h2>
<p class="text-sm text-gray-800 dark:text-gray-100">
{{ $project->description ?? 'Keine Beschreibung' }}
</p>
</div>
</div>
</div>
</div>
@else
<div class="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
<div class="bg-white dark:bg-[#1B1B1B] shadow overflow-hidden sm:rounded-lg">
<div class="px-4 py-5 sm:px-6">
<h3 class="text-lg font-medium leading-6 text-gray-900 dark:text-gray-200">
Projektförderung
</h3>
<p class="mt-1 max-w">
Du bist nicht berechtigt, die Projektförderung einzusehen.
</p>
</div>
</div>
</div>
@endif
</div>
</x-layouts.app>

View File

@@ -1,207 +0,0 @@
<x-layouts.app
:seo="new \RalphJSmit\Laravel\SEO\Support\SEOData(title: 'News', description: 'Die News des Vereins.')"
>
<div>
@if($isAllowed)
<div class="px-4 sm:px-6 lg:px-8 py-8 md:py-0 w-full max-w-9xl mx-auto">
<div class="xl:flex">
<!-- Left + Middle content -->
<div class="md:flex flex-1">
<!-- Left content -->
<div class="w-full md:w-60 mb-8 md:mb-0">
<div
class="md:sticky md:top-16 md:h-[calc(100dvh-64px)] md:overflow-x-hidden md:overflow-y-auto no-scrollbar">
<div class="md:py-8">
<div class="flex justify-between items-center md:block">
<!-- Title -->
<header class="mb-6">
<h1 class="text-2xl md:text-3xl text-gray-800 dark:text-gray-100 font-bold">
News</h1>
</header>
</div>
<!-- Links -->
<div
class="flex flex-nowrap overflow-x-scroll no-scrollbar md:block md:overflow-auto px-4 md:space-y-3 -mx-4">
<!-- Group 1 -->
<div>
<div
class="text-xs font-semibold text-gray-400 dark:text-gray-500 uppercase mb-3 md:sr-only">
Menu
</div>
<ul class="flex flex-nowrap md:block mr-3 md:mr-0">
@foreach(\App\Enums\NewsCategory::selectOptions() as $category)
<li class="mr-0.5 md:mr-0 md:mb-0.5"
wire:key="category_{{ $category['value'] }}">
<div
class="flex items-center px-2.5 py-2 rounded-lg whitespace-nowrap bg-white dark:bg-gray-800">
<i class="fa-sharp-duotone fa-solid fa-{{ $category['icon'] }} shrink-0 fill-current text-amber-500 mr-2"></i>
<span
class="text-sm font-medium text-amber-500">{{ $category['label'] }}</span>
</div>
</li>
@endforeach
</ul>
</div>
</div>
</div>
</div>
</div>
<!-- Middle content -->
<div class="flex-1 md:ml-8 xl:mx-4 2xl:mx-8">
<div class="md:py-8">
<div class="space-y-2">
@forelse($news as $post)
<article wire:key="post_{{ $post->id }}"
class="bg-white dark:bg-gray-800 shadow-sm rounded-xl p-5">
<div class="flex flex-start space-x-4">
<!-- Avatar -->
<div class="shrink-0 mt-1.5">
<img class="w-8 h-8 rounded-full"
src="{{ $post->einundzwanzigPleb->profile?->picture ?? asset('einundzwanzig-alpha.jpg') }}"
width="32" height="32"
alt="{{ $post->einundzwanzigPleb->profile?->name }}">
</div>
<!-- Content -->
<div class="grow">
<!-- Title -->
<h2 class="font-semibold text-gray-800 dark:text-gray-100 mb-2">
{{ $post->name }}
</h2>
<p class="mb-6">
{{ $post->description }}
</p>
<!-- Footer -->
<footer class="flex flex-wrap text-sm">
<div
class="flex items-center after:block after:content-['·'] last:after:content-[''] after:text-sm after:text-gray-400 dark:after:text-gray-600 after:px-2">
<div
class="font-medium text-amber-500 hover:text-amber-600 dark:hover:text-amber-400">
<div class="flex items-center">
<svg class="mr-2 fill-current" width="16"
height="16"
xmlns="http://www.w3.org/2000/svg">
<path
d="M15.686 5.708 10.291.313c-.4-.4-.999-.4-1.399 0s-.4 1 0 1.399l.6.6-6.794 3.696-1-1C1.299 4.61.7 4.61.3 5.009c-.4.4-.4 1 0 1.4l1.498 1.498 2.398 2.398L.6 14.001 2 15.4l3.696-3.697L9.692 15.7c.5.5 1.199.2 1.398 0 .4-.4.4-1 0-1.4l-.999-.998 3.697-6.695.6.6c.599.6 1.199.2 1.398 0 .3-.4.3-1.1-.1-1.499Zm-7.193 6.095L4.196 7.507l6.695-3.697 1.298 1.299-3.696 6.694Z"></path>
</svg>
{{ $post->einundzwanzigPleb->profile->name }}
</div>
</div>
</div>
<div
class="flex items-center after:block after:content-['·'] last:after:content-[''] after:text-sm after:text-gray-400 dark:after:text-gray-600 after:px-2">
<span
class="text-gray-500">{{ $post->created_at->format('d.m.Y') }}</span>
</div>
</footer>
</div>
</div>
<div class="mt-2 flex justify-end w-full space-x-2">
<x-button
xs
target="_blank"
:href="url()->temporarySignedRoute('dl', now()->addMinutes(30), ['media' => $post->getFirstMedia('pdf')])"
label="Öffnen"
primary icon="cloud-arrow-down"/>
@if($canEdit)
<x-button
xs
wire:click="delete({{ $post->id }})"
wire:loading.attr="disabled"
label="Löschen"
negative icon="trash"/>
@endif
</div>
</article>
@empty
<article class="bg-white dark:bg-gray-800 shadow-sm rounded-xl p-5">
<p>Keine News vorhanden.</p>
</article>
@endforelse
</div>
</div>
</div>
</div>
<!-- Right content -->
<div class="w-full mt-8 sm:mt-0 xl:w-72">
<div
class="lg:sticky lg:top-16 lg:h-[calc(100dvh-64px)] lg:overflow-x-hidden lg:overflow-y-auto no-scrollbar">
<div class="md:py-8">
<!-- Blocks -->
<div class="space-y-4">
@if($canEdit)
<div class="bg-white dark:bg-gray-800 p-4 rounded-xl">
<div
class="text-xs font-semibold text-gray-400 dark:text-gray-500 uppercase mb-4">
News anlegen
</div>
<div class="mt-4 flex flex-col space-y-2">
<div wire:dirty>
<input class="text-gray-200" type="file" wire:model="file">
@error('file')
<span class="text-red-500">{{ $message }}</span>
@enderror
</div>
<div wire:dirty>
<x-native-select
wire:model="form.category"
label="Kategorie"
placeholder="Wähle Kategorie"
:options="\App\Enums\NewsCategory::selectOptions()"
option-label="label" option-value="value"
/>
</div>
<div wire:dirty>
<x-input label="Titel" wire:model="form.name"/>
</div>
<div wire:dirty>
<x-textarea
description="optional"
label="Beschreibung" wire:model="form.description"/>
</div>
<button
wire:click="save"
class="btn-sm w-full bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-700/60 hover:border-gray-300 dark:hover:border-gray-600 text-gray-800 dark:text-gray-300">
Hinzufügen
</button>
</div>
</div>
@endif
</div>
</div>
</div>
</div>
</div>
</div>
@else
<div class="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
<div class="bg-white dark:bg-[#1B1B1B] shadow overflow-hidden sm:rounded-lg">
<div class="px-4 py-5 sm:px-6">
<h3 class="text-lg font-medium leading-6 text-gray-900 dark:text-gray-200">
News
</h3>
<p class="mt-1 max-w">
Du bist nicht berechtigt, die News einzusehen.
</p>
</div>
</div>
</div>
@endif
</div>
</x-layouts.app>

View File

@@ -1,733 +0,0 @@
<?php
use App\Enums\AssociationStatus;
use App\Livewire\Forms\ApplicationForm;
use App\Models\EinundzwanzigPleb;
use App\Support\NostrAuth;
use Livewire\Component;
use swentel\nostr\Event\Event as NostrEvent;
use swentel\nostr\Filter\Filter;
use swentel\nostr\Message\EventMessage;
use swentel\nostr\Message\RequestMessage;
use swentel\nostr\Relay\Relay;
use swentel\nostr\Relay\RelaySet;
use swentel\nostr\Request\Request;
use swentel\nostr\Sign\Sign;
use swentel\nostr\Subscription\Subscription;
use WireUi\Actions\Notification;
new class extends Component {
public ApplicationForm $form;
public bool $no = false;
public bool $showEmail = true;
public string $fax = '';
public ?string $email = '';
public array $yearsPaid = [];
public array $events = [];
public $payments;
public int $amountToPay;
public bool $currentYearIsPaid = false;
public ?string $currentPubkey = null;
public ?EinundzwanzigPleb $currentPleb = null;
public ?string $qrCode = null;
protected $listeners = [
'nostrLoggedIn' => 'handleNostrLoggedIn',
'nostrLoggedOut' => 'handleNostrLoggedOut',
];
public function mount(): void
{
if (NostrAuth::check()) {
$this->currentPubkey = NostrAuth::pubkey();
$this->currentPleb = EinundzwanzigPleb::query()
->with([
'paymentEvents' => fn ($query) => $query->where('year', date('Y')),
])
->where('pubkey', $this->currentPubkey)->first();
if ($this->currentPleb) {
$this->email = $this->currentPleb->email;
$this->showEmail = ! $this->no;
if ($this->currentPleb->association_status === AssociationStatus::ACTIVE) {
$this->amountToPay = config('app.env') === 'production' ? 21000 : 1;
}
if ($this->currentPleb->paymentEvents->count() < 1) {
$this->createPaymentEvent();
$this->currentPleb->load('paymentEvents');
}
$this->loadEvents();
$this->listenForPayment();
}
}
}
public function handleNostrLoggedIn($pubkey): void
{
NostrAuth::login($pubkey);
$this->currentPubkey = $pubkey;
$this->currentPleb = EinundzwanzigPleb::query()
->with([
'paymentEvents' => fn ($query) => $query->where('year', date('Y')),
])
->where('pubkey', $pubkey)->first();
$this->email = $this->currentPleb->email;
$this->no = $this->currentPleb->no_email;
$this->showEmail = ! $this->no;
if ($this->currentPleb->association_status === AssociationStatus::ACTIVE) {
$this->amountToPay = config('app.env') === 'production' ? 21000 : 1;
}
if ($this->currentPleb->paymentEvents->count() < 1) {
$this->createPaymentEvent();
$this->currentPleb->load('paymentEvents');
}
$this->loadEvents();
$this->listenForPayment();
}
public function handleNostrLoggedOut(): void
{
NostrAuth::logout();
$this->currentPubkey = null;
$this->currentPleb = null;
$this->yearsPaid = [];
$this->events = [];
$this->payments = [];
$this->qrCode = null;
$this->amountToPay = config('app.env') === 'production' ? 21000 : 1;
$this->currentYearIsPaid = false;
}
public function updatedNo(): void
{
$this->showEmail = ! $this->no;
$this->currentPleb->update([
'no_email' => $this->no,
]);
}
public function updatedFax(): void
{
$this->js('alert("Markus Turm wird sich per Fax melden!")');
}
public function saveEmail(): void
{
$this->validate([
'email' => 'required|email',
]);
$this->currentPleb->update([
'email' => $this->email,
]);
$notification = new Notification($this);
$notification->success('E-Mail Adresse gespeichert.');
}
public function pay($comment): \Illuminate\Http\RedirectResponse
{
$paymentEvent = $this->currentPleb
->paymentEvents()
->where('year', date('Y'))
->first();
if ($paymentEvent->btc_pay_invoice) {
return redirect('https://pay.einundzwanzig.space/i/'.$paymentEvent->btc_pay_invoice);
}
try {
$response = \Illuminate\Support\Facades\Http::withHeaders([
'Authorization' => 'token '.config('services.btc_pay.api_key'),
])->post(
'https://pay.einundzwanzig.space/api/v1/stores/98PF86BoMd3C8P1nHHyFdoeznCwtcm5yehcAgoCYDQ2a/invoices',
[
'amount' => $this->amountToPay,
'metadata' => [
'orderId' => $comment,
'orderUrl' => url()->route('association.profile'),
'itemDesc' => 'Mitgliedsbeitrag '.date('Y').' von nostr:'.$this->currentPleb->npub,
'posData' => [
'event' => $paymentEvent->event_id,
'pubkey' => $this->currentPleb->pubkey,
'npub' => $this->currentPleb->npub,
],
],
'checkout' => [
'expirationMinutes' => 60 * 24,
'redirectURL' => url()->route('association.profile'),
'redirectAutomatically' => true,
'defaultLanguage' => 'de',
],
],
)->throw();
$paymentEvent->btc_pay_invoice = $response->json()['id'];
$paymentEvent->save();
return redirect($response->json()['checkoutLink']);
} catch (\Exception $e) {
$notification = new Notification($this);
$notification->error(
'Fehler beim Erstellen der Rechnung. Bitte versuche es später erneut: '.$e->getMessage(),
);
return redirect()->route('association.profile');
}
}
public function listenForPayment(): void
{
$paymentEvent = $this->currentPleb
->paymentEvents()
->where('year', date('Y'))
->first();
if ($paymentEvent->btc_pay_invoice) {
$response = \Illuminate\Support\Facades\Http::withHeaders([
'Authorization' => 'token '.config('services.btc_pay.api_key'),
])
->get(
'https://pay.einundzwanzig.space/api/v1/stores/98PF86BoMd3C8P1nHHyFdoeznCwtcm5yehcAgoCYDQ2a/invoices/'.$paymentEvent->btc_pay_invoice,
);
if ($response->json()['status'] === 'Expired') {
$paymentEvent->btc_pay_invoice = null;
$paymentEvent->paid = false;
$paymentEvent->save();
}
if ($response->json()['status'] === 'Settled') {
$paymentEvent->paid = true;
$paymentEvent->save();
$this->currentYearIsPaid = true;
}
}
if ($paymentEvent->paid) {
$this->currentYearIsPaid = true;
}
$paymentEvent = $paymentEvent->refresh();
$this->payments = $this->currentPleb
->paymentEvents()
->where('paid', true)
->get();
}
public function save($type): void
{
$this->form->validate();
if (! $this->form->check) {
$this->js('alert("Du musst den Statuten zustimmen.")');
return;
}
$this->currentPleb
->update([
'association_status' => $type,
]);
}
public function createPaymentEvent(): void
{
$note = new NostrEvent;
$note->setKind(32121);
$note->setContent(
'Dieses Event dient der Zahlung des Mitgliedsbeitrags für das Jahr '.date(
'Y',
).'. Bitte bezahle den Betrag von '.number_format($this->amountToPay, 0, ',', '.').' Satoshis.',
);
$note->setTags([
['d', $this->currentPleb->pubkey.','.date('Y')],
['zap', 'daf83d92768b5d0005373f83e30d4203c0b747c170449e02fea611a0da125ee6', config('services.relay'), '1'],
]);
$signer = new Sign;
$signer->signEvent($note, config('services.nostr'));
$eventMessage = new EventMessage($note);
$relayUrl = config('services.relay');
$relay = new Relay($relayUrl);
$relay->setMessage($eventMessage);
$result = $relay->send();
$this->currentPleb->paymentEvents()->create([
'year' => date('Y'),
'event_id' => $result->eventId,
'amount' => $this->amountToPay,
]);
}
public function loadEvents(): void
{
$subscription = new Subscription;
$subscriptionId = $subscription->setId();
$filter1 = new Filter;
$filter1->setKinds([32121]);
$filter1->setAuthors(['daf83d92768b5d0005373f83e30d4203c0b747c170449e02fea611a0da125ee6']);
$filters = [$filter1];
$requestMessage = new RequestMessage($subscriptionId, $filters);
$relays = [
new Relay(config('services.relay')),
];
$relaySet = new RelaySet;
$relaySet->setRelays($relays);
$request = new Request($relaySet, $requestMessage);
$response = $request->send();
$this->events = collect($response[config('services.relay')])
->map(function ($event) {
if (! isset($event->event)) {
return false;
}
return [
'id' => $event->event->id,
'kind' => $event->event->kind,
'content' => $event->event->content,
'pubkey' => $event->event->pubkey,
'tags' => $event->event->tags,
'created_at' => $event->event->created_at,
];
})
->filter()
->unique('id')
->toArray();
}
}
?>
<div>
<div class="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
<!-- Page header -->
<div class="mb-8">
<!-- Title -->
<h1 class="text-2xl md:text-3xl text-[#1B1B1B] dark:text-gray-100 font-bold">
Einundzwanzig ist, was du draus machst
</h1>
</div>
<div class="bg-white dark:bg-[#1B1B1B] shadow-sm rounded-xl mb-8">
<div class="flex flex-col md:flex-row md:-mr-px">
<!-- Sidebar -->
<div
class="flex flex-nowrap overflow-x-scroll no-scrollbar md:block md:overflow-auto px-3 py-6 border-b md:border-b-0 md:border-r border-gray-200 dark:border-gray-700/60 min-w-60 md:space-y-3">
<!-- Group 1 -->
<div>
<div class="text-xs font-semibold text-gray-400 dark:text-gray-500 uppercase mb-3">
Meine Mitgliedschaft
</div>
<ul class="flex flex-nowrap md:block mr-3 md:mr-0">
<li class="mr-0.5 md:mr-0 md:mb-0.5">
<a class="flex items-center px-2.5 py-2 rounded-lg whitespace-nowrap bg-[linear-gradient(135deg,var(--tw-gradient-stops))] from-orange-500/[0.12] dark:from-orange-500/[0.24] to-orange-500/[0.04]"
href="#0">
<i class="fa-sharp-duotone fa-solid fa-id-card-clip shrink-0 fill-current text-orange-400 mr-2"></i>
<span
class="text-sm font-medium text-orange-500 dark:text-orange-400">Status</span>
</a>
</li>
</ul>
</div>
</div>
<!-- Panel -->
<div class="grow">
<!-- Panel body -->
<div class="p-6 space-y-6">
<h2 class="sm:text-2xl text-[#1B1B1B] dark:text-gray-100 font-bold mb-5">Aktueller Status</h2>
<section>
@if(!$currentPleb)
<div class="space-y-2 mb-12">
<div class="flex justify-between items-center mb-4">
<div class="text-xl text-gray-500 dark:text-gray-400 italic">Empfohlene Nostr
Login und Signer-Apps
</div>
</div>
<div class="bg-white dark:bg-gray-800 shadow-sm rounded-xl px-5 py-4">
<div
class="md:flex justify-between items-center space-y-4 md:space-y-0 space-x-2">
<!-- Left side -->
<div class="flex items-start space-x-3 md:space-x-4">
<div>
<a class="inline-flex font-semibold text-gray-800 dark:text-gray-100"
href="https://github.com/greenart7c3/Amber">
Amber
</a>
<div class="text-sm">Perfekt für mobile Android Geräte. Eine App, in
der man alle Keys/nsecs verwalten kann.
</div>
</div>
</div>
<!-- Right side -->
<div class="flex items-center space-x-4 pl-10 md:pl-0">
<div
class="text-xs inline-flex font-medium bg-green-500/20 text-green-700 rounded-full text-center px-2.5 py-1">
Android
</div>
</div>
</div>
</div>
<div class="bg-white dark:bg-gray-800 shadow-sm rounded-xl px-5 py-4">
<div
class="md:flex justify-between items-center space-y-4 md:space-y-0 space-x-2">
<!-- Left side -->
<div class="flex items-start space-x-3 md:space-x-4">
<div>
<a class="inline-flex font-semibold text-gray-800 dark:text-gray-100"
href="https://addons.mozilla.org/en-US/firefox/addon/alby/">
Alby - Bitcoin Lightning Wallet & Nostr
</a>
<div class="text-sm">
Browser-Erweiterung in die man seinen Key/nsec eingeben kann.
Pro Alby-Konto ein nsec.
</div>
</div>
</div>
<!-- Right side -->
<div class="flex items-center space-x-4 pl-10 md:pl-0">
<div
class="text-xs inline-flex font-medium bg-yellow-500/20 text-yellow-700 rounded-full text-center px-2.5 py-1">
Browser Chrome/Firefox
</div>
</div>
</div>
</div>
<div class="bg-white dark:bg-gray-800 shadow-sm rounded-xl px-5 py-4">
<div
class="md:flex justify-between items-center space-y-4 md:space-y-0 space-x-2">
<!-- Left side -->
<div class="flex items-start space-x-3 md:space-x-4">
<div>
<a class="inline-flex font-semibold text-gray-800 dark:text-gray-100"
href="https://chromewebstore.google.com/detail/nos2x/kpgefcfmnafjgpblomihpgmejjdanjjp">
nos2x
</a>
<div class="text-sm">
Browser-Erweiterung für Chrome Browser. Multi-Key fähig.
</div>
</div>
</div>
<!-- Right side -->
<div class="flex items-center space-x-4 pl-10 md:pl-0">
<div
class="text-xs inline-flex font-medium bg-red-500/20 text-red-700 rounded-full text-center px-2.5 py-1">
Browser Chrome
</div>
</div>
</div>
</div>
<div class="bg-white dark:bg-gray-800 shadow-sm rounded-xl px-5 py-4">
<div
class="md:flex justify-between items-center space-y-4 md:space-y-0 space-x-2">
<!-- Left side -->
<div class="flex items-start space-x-3 md:space-x-4">
<div>
<a class="inline-flex font-semibold text-gray-800 dark:text-gray-100"
href="https://addons.mozilla.org/en-US/firefox/addon/nos2x-fox/">
nos2x-fox
</a>
<div class="text-sm">
Browser-Erweiterung für Firefox Browser. Multi-Key fähig.
</div>
</div>
</div>
<!-- Right side -->
<div class="flex items-center space-x-4 pl-10 md:pl-0">
<div
class="text-xs inline-flex font-medium bg-amber-500/20 text-amber-700 rounded-full text-center px-2.5 py-1">
Browser Firefox
</div>
</div>
</div>
</div>
</div>
@endif
<div class="flex flex-wrap space-y-2 sm:space-y-0 items-center justify-between">
<template x-if="$store.nostr.user">
<div class="flex items">
<img class="w-12 h-12 rounded-full"
x-bind:src="$store.nostr.user.picture || '{{ asset('apple-touch-icon.png') }}'"
alt="Avatar">
<div class="ml-4">
<h3 class="w-48 sm:w-full truncate text-lg leading-snug text-[#1B1B1B] dark:text-gray-100 font-bold"
x-text="$store.nostr.user.display_name"></h3>
<div
class="w-48 sm:w-full truncate text-sm text-gray-500 dark:text-gray-400"
x-text="$store.nostr.user.name"></div>
</div>
</div>
</template>
@if($currentPubkey && $currentPleb->association_status->value < 2)
<div
class="inline-flex min-w-80 px-4 py-2 rounded-lg text-sm bg-white dark:bg-gray-800 shadow-sm border border-gray-200 dark:border-gray-700/60 text-gray-600 dark:text-gray-100">
<div class="flex w-full justify-between items-start">
<div class="flex">
<svg class="shrink-0 fill-current text-green-500 mt-[3px] mr-3"
width="16" height="16" viewBox="0 0 16 16">
<path
d="M8 0C3.6 0 0 3.6 0 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zM7 11.4L3.6 8 5 6.6l2 2 4-4L12.4 6 7 11.4z"></path>
</svg>
<div>Profil in der Datenbank vorhanden.</div>
</div>
</div>
</div>
@endif
</div>
</section>
<section>
@if($currentPubkey && !$currentPleb->application_for && $currentPleb->association_status->value < 2)
<h3 class="text-xl leading-snug text-[#1B1B1B] dark:text-gray-100 font-bold mb-1">
Einundzwanzig Mitglied werden
</h3>
<h4 class="text-xs leading-snug text-[#1B1B1B] dark:text-gray-100 font-italic mb-1">
Nur Personen können Mitglied werden und zahlen 21.000 Satoshis im Jahr.<br>
<a href="https://einundzwanzig.space/verein/" class="text-amber-500">Firmen melden
sich bitte direkt an den Vorstand.</a>
</h4>
<div class="sm:flex sm:items-center space-y-4 sm:space-y-0 sm:space-x-4 mt-5">
<div class="sm:w-1/2 flex flex-col space-y-2">
<div class="flex items-center space-x-2">
<div wire:dirty>
<x-checkbox wire:model="form.check"
label="Ich stimme den Vereins-Statuten zu"/>
</div>
<div>
<a href="https://einundzwanzig.space/verein/" target="_blank"
class="text-amber-500">Statuten</a>
</div>
</div>
<x-button label="Mit deinem aktuellen Nostr-Profil Mitglied werden"
wire:click="save({{ AssociationStatus::PASSIVE() }})"/>
</div>
</div>
@endif
@if($currentPubkey)
<div
class="mt-6 inline-flex flex-col w-full px-4 py-2 rounded-lg text-sm bg-white dark:bg-gray-800 shadow-sm border border-gray-200 dark:border-gray-700/60 text-gray-600 dark:text-gray-400">
<div class="flex w-full justify-between items-start">
<div class="flex w-full">
<svg class="shrink-0 fill-current text-yellow-500 mt-[3px] mr-3"
width="16"
height="16" viewBox="0 0 16 16">
<path
d="M8 0C3.6 0 0 3.6 0 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm0 12c-.6 0-1-.4-1-1s.4-1 1-1 1 .4 1 1-.4 1-1 1zm1-3H7V4h2v5z"></path>
</svg>
<div class="w-full">
<div
class="w-full font-medium text-gray-800 dark:text-gray-100 mb-1">
Falls du möchtest, kannst du hier eine E-Mail Adresse
hinterlegen,
damit der Verein dich darüber informieren kann, wenn es
Neuigkeiten
gibt.<br><br>
Am besten eine anynomisierte E-Mail Adresse verwenden. Wir
sichern
diese Adresse AES-256 verschlüsselt in der Datenbank ab.
</div>
<div
class="flex flex-col sm:flex-row space-y-2 sm:space-y-0 sm:space-x-2 text-amber-500">
<x-toggle xl warning
wire:model.live="no"
wire:dirty
label="NEIN">
<x-slot name="description">
<span class="py-2 text-amber-500">Ich informiere mich selbst in der News Sektion und gebe keine E-Mail Adresse raus.</span>
</x-slot>
</x-toggle>
</div>
@if($showEmail)
<div wire:key="showEmail"
class="flex flex-col sm:flex-row space-y-2 sm:space-y-0 sm:space-x-2">
<x-input wire:model.live.debounce="fax" wire:dirty label="Fax-Nummer"/>
<x-input wire:model.live.debounce="email" wire:dirty
label="E-Mail Adresse"/>
</div>
<div wire:key="showSave" class="flex space-x-2 mt-2">
<x-button wire:click="saveEmail" label="Speichern"/>
</div>
@endif
</div>
</div>
</div>
</div>
@endif
</section>
<section>
@if($currentPleb && $currentPleb->association_status->value > 1)
<div class="flex flex-col space-y-4">
<div
class="inline-flex flex-col w-full max-w-lg px-4 py-2 rounded-lg text-sm bg-white dark:bg-gray-800 shadow-sm border border-gray-200 dark:border-gray-700/60 text-gray-600 dark:text-gray-400">
<div class="flex w-full justify-between items-start">
<div class="flex">
<svg class="shrink-0 fill-current text-green-500 mt-[3px] mr-3"
width="16"
height="16" viewBox="0 0 16 16">
<path
d="M8 0C3.6 0 0 3.6 0 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm0 12c-.6 0-1-.4-1-1s.4-1 1-1 1 .4 1 1-.4 1-1 1zm1-3H7V4h2v5z"></path>
</svg>
<div>
<div class="font-medium text-gray-800 dark:text-gray-100 mb-1">
Du bist derzeit ein Mitglied des Vereins.
</div>
</div>
</div>
</div>
</div>
</div>
@endif
</section>
<section>
@if($currentPleb && $currentPleb->association_status->value > 1)
<div
class="inline-flex flex-col w-full px-4 py-2 rounded-lg text-sm bg-white dark:bg-gray-800 shadow-sm border border-gray-200 dark:border-gray-700/60 text-gray-600 dark:text-gray-400">
<div class="flex w-full justify-between items-start">
<div class="flex">
<svg class="shrink-0 fill-current text-yellow-500 mt-[3px] mr-3" width="16"
height="16" viewBox="0 0 16 16">
<path
d="M8 0C3.6 0 0 3.6 0 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm0 12c-.6 0-1-.4-1-1s.4-1 1-1 1 .4 1 1-.4 1-1 1zm1-3H7V4h2v5z"></path>
</svg>
<div>
<div
class="font-medium text-gray-800 dark:text-gray-100 mb-1 space-y-2">
<p>Nostr Event für die Zahlung des
Mitgliedsbeitrags: <span
class="break-all">{{ $currentPleb->paymentEvents->last()->event_id }}</span>
</p>
<div>
@php
// latest event by created_at field of $events
$latestEvent = collect($events)->sortByDesc('created_at')->first();
@endphp
@if(isset($latestEvent))
<p>{{ $latestEvent['content'] }}</p>
<div class="mt-8">
@if(!$currentYearIsPaid)
<div class="flex justify-center">
<button
wire:click="pay('{{ date('Y') }}:{{ $currentPubkey }}')"
class="btn text-2xl dark:bg-gray-800 border-gray-200 dark:border-gray-700/60 hover:border-gray-300 dark:hover:border-gray-600 text-green-500"
>
<i class="fa-sharp-duotone fa-solid fa-bolt-lightning mr-2"></i>
Pay {{ $amountToPay }} Sats
</button>
</div>
@else
@if($currentYearIsPaid)
<div class="flex sm:justify-center">
<div
class="btn sm:text-2xl dark:bg-gray-800 border-gray-200 dark:border-gray-700/60 text-green-500"
>
<i class="fa-sharp-duotone fa-solid fa-check-circle mr-2"></i>
aktuelles Jahr bezahlt
</div>
</div>
@endif
@endif
</div>
@else
<div class="flex sm:justify-center">
<button
class="btn dark:bg-gray-800 border-gray-200 dark:border-gray-700/60 hover:border-gray-300 dark:hover:border-gray-600 text-amber-500"
>
<i class="fa-sharp-duotone fa-solid fa-user-helmet-safety mr-2"></i>
Unser Nostr-Relay konnte derzeit nicht erreicht
werden, um eine Zahlung zu initialisieren. Bitte
versuche es später noch einmal.
</button>
</div>
@endif
</div>
<section>
<h3 class="text-xl leading-snug text-gray-800 dark:text-gray-100 font-bold mb-1">
bisherige Zahlungen</h3>
<!-- Table -->
<table class="table-auto w-full dark:text-gray-400">
<!-- Table header -->
<thead
class="text-xs uppercase text-gray-400 dark:text-gray-500">
<tr class="flex flex-wrap md:table-row md:flex-no-wrap">
<th class="w-full hidden md:w-auto md:table-cell py-2">
<div class="font-semibold text-left">Satoshis</div>
</th>
<th class="w-full hidden md:w-auto md:table-cell py-2">
<div class="font-semibold text-left">Jahr</div>
</th>
<th class="w-full hidden md:w-auto md:table-cell py-2">
<div class="font-semibold text-left">Event-ID</div>
</th>
<th class="w-full hidden md:w-auto md:table-cell py-2">
<div class="font-semibold text-left">Quittung</div>
</th>
</tr>
</thead>
<!-- Table body -->
<tbody class="text-sm">
@foreach($payments as $payment)
<tr class="flex flex-wrap md:table-row md:flex-no-wrap border-b border-gray-200 dark:border-gray-700/60 py-2 md:py-0">
<td class="w-full block md:w-auto md:table-cell py-0.5 md:py-2">
<div
class="text-left font-medium text-gray-800 dark:text-gray-100">
<span class="sm:hidden">Sats:</span>
{{ $payment->amount }}
</div>
</td>
<td class="w-full block md:w-auto md:table-cell py-0.5 md:py-2">
<div
class="text-left"><span
class="sm:hidden">Jahr:</span>{{ $payment->year }}
</div>
</td>
<td class="w-full block md:w-auto md:table-cell py-0.5 md:py-2">
<div
class="text-left font-medium break-all">{{ $payment->event_id }}</div>
</td>
<td class="w-full block md:w-auto md:table-cell py-0.5 md:py-2">
@if($payment->btc_pay_invoice)
<x-button target="_blank" xs
label="Quittung"
href="https://pay.einundzwanzig.space/i/{{ $payment->btc_pay_invoice }}/receipt"/>
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
</section>
</div>
</div>
</div>
</div>
</div>
@endif
</section>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@@ -1,60 +0,0 @@
<div class="p-4">
@if($row->application_text )
<div class="px-4 py-2 rounded-lg text-sm bg-violet-100 text-gray-700">
<div class="flex w-full justify-between items-start">
<div class="flex">
<svg class="shrink-0 fill-current text-violet-500 mt-[3px] mr-3" width="16" height="16"
viewBox="0 0 16 16">
<path
d="M8 0C3.6 0 0 3.6 0 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm1 12H7V7h2v5zM8 6c-.6 0-1-.4-1-1s.4-1 1-1 1 .4 1 1-.4 1-1 1z"></path>
</svg>
<div>{{ $row->application_text }}</div>
</div>
</div>
</div>
@endif
<section>
<h3 class="text-xl leading-snug text-gray-800 dark:text-gray-100 font-bold mb-1">
bisherige Zahlungen</h3>
<!-- Table -->
<table class="table-auto w-full dark:text-gray-400">
<!-- Table header -->
<thead
class="text-xs uppercase text-gray-400 dark:text-gray-500">
<tr class="flex flex-wrap md:table-row md:flex-no-wrap">
<th class="w-full block md:w-auto md:table-cell py-2">
<div class="font-semibold text-left">Satoshis</div>
</th>
<th class="w-full hidden md:w-auto md:table-cell py-2">
<div class="font-semibold text-left">Jahr</div>
</th>
<th class="w-full hidden md:w-auto md:table-cell py-2">
<div class="font-semibold text-left">Event-ID</div>
</th>
</tr>
</thead>
<!-- Table body -->
<tbody class="text-sm">
@foreach($row->paymentEvents as $payment)
<tr class="flex flex-wrap md:table-row md:flex-no-wrap border-b border-gray-200 dark:border-gray-700/60 py-2 md:py-0">
<td class="w-full block md:w-auto md:table-cell py-0.5 md:py-2">
<div
class="text-left font-medium text-gray-800 dark:text-gray-100">{{ $payment->amount }}</div>
</td>
<td class="w-full block md:w-auto md:table-cell py-0.5 md:py-2">
<div
class="text-left">{{ $payment->year }}</div>
</td>
<td class="w-full block md:w-auto md:table-cell py-0.5 md:py-2">
<div
class="text-left font-medium">{{ $payment->event_id }}</div>
</td>
</tr>
@endforeach
</tbody>
</table>
</section>
</div>

View File

@@ -1,62 +0,0 @@
<x-layouts.app title="Einundzwanzig Feed">
<div class="px-8 py-8 space-y-6">
<div>
@if($newEvents)
<div class="rounded-md bg-blue-50 p-4">
<div class="flex">
<div class="flex-shrink-0">
<svg class="h-5 w-5 text-blue-400" viewBox="0 0 20 20" fill="currentColor"
aria-hidden="true">
<path fill-rule="evenodd"
d="M18 10a8 8 0 11-16 0 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z"
clip-rule="evenodd"/>
</svg>
</div>
<div class="ml-3 flex-1 md:flex md:justify-between">
<p class="text-sm text-blue-700">Es gibt neue Events...</p>
<div class="mt-3 text-sm md:ml-6 md:mt-0">
<div wire:click="loadMore"
class="cursor-pointer whitespace-nowrap font-medium text-blue-700 hover:text-blue-600">
Anzeigen
<span aria-hidden="true"> &rarr;</span>
</div>
</div>
</div>
</div>
</div>
@endif
</div>
@foreach($events as $event)
<article class="flex flex-col items-start justify-between"
wire:key="{{ $event['rendered_event']['event_id'] }}">
<div class="relative flex items-center gap-x-4">
<img
src="{{ $event['rendered_event']['profile_image'] }}"
alt="" class="h-10 w-10 rounded-full bg-gray-50">
<div class="text-sm leading-6">
<div class="font-semibold text-gray-900">
<div>
<span class="absolute inset-0"></span>
{{ $event['rendered_event']['profile_name'] }}
</div>
</div>
</div>
</div>
<div class="flex items-center gap-x-4 text-xs">
<time datetime="{{ $event['rendered_event']['created_at'] }}"
class="text-gray-500">{{ $event['rendered_event']['created_at'] }}</time>
</div>
<div class="group relative">
<div class="mt-5 line-clamp-3 text-sm leading-6 text-gray-600">
{!! $event['rendered_event']['html'] !!}
</div>
</div>
<div class="group relative">
<div class="mt-5 line-clamp-3 text-sm leading-6 text-gray-600">
<pre>{{ json_encode(json_decode($event['json'], true, 512, JSON_THROW_ON_ERROR)['tags']) }}</pre>
</div>
</div>
</article>
@endforeach
</div>
</x-layouts.app>

View File

@@ -1,30 +0,0 @@
<div
wire:ignore
x-data
x-init="
FilePond.registerPlugin(
FilePondPluginImagePreview,
FilePondPluginImageExifOrientation,
FilePondPluginFileValidateSize,
FilePondPluginImageEdit
);
FilePond.setOptions({
labelIdle: '{{ 'Drag & Drop Deiner Dateien oder <span class="filepond--label-action"> in Ordner suchen </span>' }}',
allowMultiple: {{ isset($attributes['multiple']) ? 'true' : 'false' }},
server: {
process: (fieldName, file, metadata, load, error, progress, abort, transfer, options) => {
@this.upload('{{ $attributes['wire:model'] }}', file, load, error, progress)
},
revert: (filename, load) => {
@this.removeUpload('{{ $attributes['wire:model'] }}', filename, load)
},
load: (source, load, error, progress, abort, headers) => {
@this.load('{{ $attributes['wire:model'] }}', load, error, progress, abort, headers)
},
},
});
FilePond.create($refs.input);
"
>
<input type="file" x-ref="input" name="{{ $attributes['name'] }}">
</div>

View File

@@ -1,13 +0,0 @@
@props([
'for',
'label',
])
<div class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-700 sm:pt-5">
<label for="{{ $for }}"
class="block text-sm font-medium text-gray-100 sm:mt-px sm:pt-2">
{{ $label }}
</label>
<div class="mt-1 sm:mt-0 sm:col-span-2">
{{ $slot }}
</div>
</div>

View File

@@ -1,53 +0,0 @@
<div
wire:ignore
x-data="{
value: $wire.entangle('{{ $model }}'),
init() {
this.$nextTick(() => {
setTimeout(() => {
let editor = new EasyMDE({
element: this.$refs.editor,
lineNumbers: true,
uploadImage: false,
spellChecker: false,
showIcons: [
'heading',
'heading-smaller',
'heading-bigger',
'heading-1',
'heading-2',
'heading-3',
'code',
'table',
'quote',
'strikethrough',
'unordered-list',
'ordered-list',
'clean-block',
'horizontal-rule',
'undo',
'redo',
//'upload-image',
],
});
editor.value(this.value);
editor.codemirror.on('change', () => {
this.value = editor.value();
});
}, 100); // Adjust the delay as needed
});
},
}"
class="w-full"
>
<div class="prose max-w-none">
<textarea x-ref="editor"></textarea>
</div>
<style>
.EasyMDEContainer {
background-color: white;
}
</style>
</div>

View File

@@ -1,89 +0,0 @@
<?php
use Livewire\Component;
new class extends Component {
public $currentRoute = '';
public function mount(): void
{
$currentLivewireRouteName = request()->route()->getName();
$this->currentRoute = $currentLivewireRouteName;
}
};
?>
<div class="min-w-fit">
@php
$isCurrentRouteClass = 'pl-4 pr-3 py-2 rounded-lg mb-0.5 last:mb-0 bg-[linear-gradient(135deg,var(--tw-gradient-stops))] from-orange-500/[0.12] dark:from-orange-500/[0.24] to-orange-500/[0.04]';
$isNotCurrentRouteClass = 'pl-4 pr-3 py-2 rounded-lg mb-0.5 last:mb-0';
$isCurrentSubItem = 'block text-orange-500 transition truncate';
$isNotCurrentSubItem = 'block text-gray-500/90 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition truncate';
@endphp
<!-- Sidebar backdrop (mobile only) -->
<div
class="fixed inset-0 bg-gray-900 bg-opacity-30 z-40 lg:hidden lg:z-auto transition-opacity duration-200"
:class="sidebarOpen ? 'opacity-100' : 'opacity-0 pointer-events-none'"
aria-hidden="true"
x-cloak
></div>
<!-- Sidebar -->
<div
id="sidebar"
class="flex flex-col absolute z-40 left-0 top-0 lg:static lg:left-auto lg:top-auto lg:translate-x-0 h-[100dvh] overflow-y-scroll lg:overflow-y-auto no-scrollbar w-64 lg:w-20 lg:sidebar-expanded:!w-64 2xl:!w-64 shrink-0 bg-white dark:bg-[#222222] shadow-sm rounded-r-2xl p-4 transition-all duration-200 ease-in-out"
:class="sidebarOpen ? 'translate-x-0' : '-translate-x-64'"
@click.outside="sidebarOpen = false"
@keydown.escape.window="sidebarOpen = false"
x-cloak="lg"
>
<!-- Sidebar header -->
<div class="flex justify-between mb-10 pr-3 sm:px-2">
<!-- Close button -->
<button class="lg:hidden text-gray-500 hover:text-gray-400" @click.stop="sidebarOpen = !sidebarOpen"
aria-controls="sidebar" :aria-expanded="sidebarOpen">
<span class="sr-only">Close sidebar</span>
<svg class="w-6 h-6 fill-current" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M10.7 18.7l1.4-1.4L7.8 13H20v-2H7.8l4.3-4.3-1.4-1.4L4 12z"/>
</svg>
</button>
<!-- Logo -->
<img class="w-6 h-6" src="{{ asset('einundzwanzig-alpha.jpg') }}" alt="Logo">
</div>
@php
$activeLinkGroupClass = ' bg-[linear-gradient(135deg,var(--tw-gradient-stops))] from-amber-500/[0.12] dark:from-amber-500/[0.24] to-amber-500/[0.04]';
$activeItemClass = 'block text-amber-500 transition truncate';
@endphp
<!-- Links -->
<div class="space-y-8">
{{--@include('components.layouts.navigation.meetups')--}}
@include('components.layouts.navigation.association')
{{--@include('components.layouts.navigation.events')
@include('components.layouts.navigation.courses')
@include('components.layouts.navigation.nostr')
@include('components.layouts.navigation.legacy')--}}
@include('components.layouts.navigation.admin')
</div>
<!-- Expand / collapse button -->
<div class="pt-3 hidden lg:inline-flex 2xl:hidden justify-end mt-auto">
<div class="w-12 pl-4 pr-3 py-2">
<button
class="text-gray-400 hover:text-gray-500 dark:text-gray-500 dark:hover:text-gray-400 transition-colors"
@click="sidebarExpanded = !sidebarExpanded">
<span class="sr-only">Expand / collapse sidebar</span>
<svg class="shrink-0 fill-current text-gray-400 dark:text-gray-500 sidebar-expanded:rotate-180"
xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path
d="M15 16a1 1 0 0 1-1-1V1a1 1 0 1 1 2 0v14a1 1 0 0 1-1 1ZM8.586 7H1a1 1 0 1 0 0 2h7.586l-2.793 2.793a1 1 0 1 0 1.414 1.414l4.5-4.5A.997.997 0 0 0 12 8.01M11.924 7.617a.997.997 0 0 0-.217-.324l-4.5-4.5a1 1 0 0 0-1.414 1.414L8.586 7M12 7.99a.996.996 0 0 0-.076-.373Z"/>
</svg>
</button>
</div>
</div>
</div>
</div>

View File

@@ -1,197 +0,0 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" class="dark">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{!! seo($seo ?? null) !!}
<title>{{ $title ?? 'Page Title' }}</title>
@livewireStyles
@wireUiScripts
@stack('scripts')
@vite(['resources/js/app.js','resources/css/app.css'])
@googlefonts
<script src="https://kit.fontawesome.com/866fd3d0ab.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/easymde/dist/easymde.min.css">
<script src="https://cdn.jsdelivr.net/npm/easymde/dist/easymde.min.js"></script>
@include('components.layouts.partials.styles')
</head>
<body
class="font-sans antialiased bg-gray-100 dark:bg-[#222222] text-gray-600 dark:text-gray-400"
:class="{ 'sidebar-expanded': sidebarExpanded }"
x-data="{ sidebarOpen: false, sidebarExpanded: localStorage.getItem('sidebar-expanded') == 'true', inboxSidebarOpen: false }"
x-init="$watch('sidebarExpanded', value => localStorage.setItem('sidebar-expanded', value))"
>
<x-dialog />
<x-notifications />
<script>
if (localStorage.getItem('sidebar-expanded') == 'true') {
document.querySelector('body').classList.add('sidebar-expanded');
} else {
document.querySelector('body').classList.remove('sidebar-expanded');
}
</script>
<div x-data="nostrLogin"
class="flex h-[100dvh] overflow-hidden">
<livewire:layout.sidebar/>
<div
class="relative flex flex-col flex-1 overflow-y-auto overflow-x-hidden">
<!-- Site header -->
<header
class="sticky top-0 before:absolute before:inset-0 before:backdrop-blur-md before:bg-white/90 dark:before:bg-[#222222]/90 lg:before:bg-[#222222]/90 dark:lg:before:bg-[#222222]/90 before:-z-10 max-lg:shadow-sm z-30">
<div class="px-4 sm:px-6 lg:px-8">
<div class="flex items-center justify-between h-16 lg:border-b border-gray-200 dark:border-gray-700/60">
<!-- Header: Left side -->
<div class="flex">
<!-- Hamburger button -->
<button
class="text-gray-500 hover:text-gray-600 dark:hover:text-gray-400 lg:hidden"
@click.stop="sidebarOpen = !sidebarOpen"
aria-controls="sidebar"
:aria-expanded="sidebarOpen"
>
<span class="sr-only">Open sidebar</span>
<svg class="w-6 h-6 fill-current" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<rect x="4" y="5" width="16" height="2"/>
<rect x="4" y="11" width="16" height="2"/>
<rect x="4" y="17" width="16" height="2"/>
</svg>
</button>
</div>
<!-- Header: Right side -->
<div class="flex items-center space-x-3">
{{--@include('components.layouts.partials.search-button')--}}
{{--@include('components.layouts.partials.notification-buttons')--}}
@if(\App\Support\NostrAuth::check())
<form method="post" action="{{ route('logout') }}"
@submit="$dispatch('nostrLoggedOut')">
@csrf
<x-button secondary label="Logout" type="submit"/>
</form>
@else
<x-button wire:key="loginBtn" label="Mit Nostr verbinden" @click="openNostrLogin"
x-show="!$store.nostr.user"/>
@endif
<!-- Info button -->
<div class="relative inline-flex" x-data="{ open: false }">
<button
class="w-8 h-8 flex items-center justify-center hover:bg-[#1B1B1B] lg:hover:bg-[#1B1B1B] dark:hover:bg-[#1B1B1B]/50 dark:lg:hover:bg-[#1B1B1B] rounded-full"
:class="{ 'bg-gray-200 dark:bg-[#1B1B1B]': open }"
aria-haspopup="true"
@click.prevent="open = !open"
:aria-expanded="open"
>
<span class="sr-only">Info</span>
<svg class="fill-current text-gray-500/80 dark:text-gray-400/80" width="16" height="16"
viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path
d="M9 7.5a1 1 0 1 0-2 0v4a1 1 0 1 0 2 0v-4ZM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"/>
<path fill-rule="evenodd"
d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16Zm6-8A6 6 0 1 1 2 8a6 6 0 0 1 12 0Z"/>
</svg>
</button>
<div
class="origin-top-right z-10 absolute top-full right-0 min-w-44 bg-white dark:bg-[#1B1B1B] border border-gray-200 dark:border-[#1B1B1B]/60 py-1.5 rounded-lg shadow-lg overflow-hidden mt-1"
@click.outside="open = false"
@keydown.escape.window="open = false"
x-show="open"
x-transition:enter="transition ease-out duration-200 transform"
x-transition:enter-start="opacity-0 -translate-y-2"
x-transition:enter-end="opacity-100 translate-y-0"
x-transition:leave="transition ease-out duration-200"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
x-cloak
>
<div
class="text-xs font-semibold text-gray-400 dark:text-gray-500 uppercase pt-1.5 pb-2 px-3">
Information
</div>
<ul>
<li>
<a class="font-medium text-sm text-amber-500 hover:text-amber-600 dark:hover:text-amber-400 flex items-center py-1 px-3"
target="_blank"
href="https://gitworkshop.dev/r/naddr1qvzqqqrhnypzqzklvar4enzu53t06vpzu3h465nwkzhk9p9ls4y5crwhs3lnu5pnqy88wumn8ghj7mn0wvhxcmmv9uqpxetfde6kuer6wasku7nfvukkummnw3eqdgsn8w/issues"
@click="open = false" @focus="open = true"
@focusout="open = false">
<i class="fa-sharp-duotone fa-solid fa-code w-3 h-3 fill-current text-amber-500 shrink-0 mr-2"></i>
<span>Issues/Feedback</span>
</a>
</li>
<li>
<a class="font-medium text-sm text-amber-500 hover:text-amber-600 dark:hover:text-amber-400 flex items-center py-1 px-3"
href="{{ route('changelog') }}" @click="open = false" @focus="open = true"
@focusout="open = false">
<i class="fa-sharp-duotone fa-solid fa-code w-3 h-3 fill-current text-amber-500 shrink-0 mr-2"></i>
<span>Changelog</span>
</a>
</li>
<li>
<a class="font-medium text-sm text-amber-500 hover:text-amber-600 dark:hover:text-amber-400 flex items-center py-1 px-3"
href="https://github.com/HolgerHatGarKeineNode/einundzwanzig-nostr"
target="_blank" @click="open = false" @focus="open = true"
@focusout="open = false">
<i class="fa-brands fa-github w-3 h-3 fill-current text-amber-500 shrink-0 mr-2"></i>
<span>Github</span>
</a>
</li>
<li>
<a class="font-medium text-sm text-amber-500 hover:text-amber-600 dark:hover:text-amber-400 flex items-center py-1 px-3"
href="https://einundzwanzig.space/kontakt/" target="_blank"
@click="open = false" @focus="open = true"
@focusout="open = false">
<i class="fa-sharp-duotone fa-solid fa-info w-3 h-3 fill-current text-amber-500 shrink-0 mr-2"></i>
<span>Impressum</span>
</a>
</li>
</ul>
</div>
</div>
{{--@include('components.layouts.partials.dark-mode-toggle')--}}
<!-- Divider -->
{{--<hr class="w-px h-6 bg-gray-200 dark:bg-gray-700/60 border-none"/>--}}
{{--@include('components.layouts.partials.user-button')--}}
</div>
</div>
</div>
</header>
<main class="grow">
{{ $slot }}
</main>
</div>
</div>
@livewireScriptConfig
<script>
window.wnjParams = {
position: 'bottom',
// The only accepted value is 'bottom', default is top
accent: 'orange',
// Supported values: cyan (default), green, purple, red, orange, neutral, stone
startHidden: false,
// If the host page has a button that call `getPublicKey` to start a
// login procedure, the minimized widget can be hidden until connected
compactMode: false,
// Show the minimized widget in a compact form
disableOverflowFix: false,
// If the host page on mobile has an horizontal scrolling, the floating
// element/modal are pushed to the extreme right/bottom and exit the
// viewport. A style is injected in the html/body elements fix this.
// This option permit to disable this default behavior
}
</script>
<script src="{{ asset('dist/window.nostr.min.js.js') }}"></script>
</body>
</html>

View File

@@ -1,30 +0,0 @@
<!-- Admin group -->
<div>
<h3 class="text-xs uppercase text-gray-400 dark:text-gray-500 font-semibold pl-3">
<span class="hidden lg:block lg:sidebar-expanded:hidden 2xl:hidden text-center w-6"
aria-hidden="true">•••</span>
<span class="lg:hidden lg:sidebar-expanded:block 2xl:block">Admin-Bereich</span>
</h3>
<ul class="mt-3">
{{--<li class="{{ $currentRoute === 'association.elections' ? $isCurrentRouteClass : $isNotCurrentRouteClass }}">
<a class="block text-gray-800 dark:text-gray-100 hover:text-gray-900 dark:hover:text-white truncate transition"
href="{{ route('association.elections') }}">
<div class="flex items-center">
<i class="fa-sharp-duotone fa-solid fa-booth-curtain h-4 w-4"></i>
<span
class="text-sm font-medium ml-4 lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">Einstellungen</span>
</div>
</a>
</li>--}}
<li class="{{ $currentRoute === 'association.members.admin' ? $isCurrentRouteClass : $isNotCurrentRouteClass }}">
<a class="block text-gray-800 dark:text-gray-100 hover:text-gray-900 dark:hover:text-white truncate transition"
href="{{ route('association.members.admin') }}">
<div class="flex items-center">
<i class="fa-sharp-duotone fa-solid fa-users h-4 w-4"></i>
<span
class="text-sm font-medium ml-4 lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">Mitglieder</span>
</div>
</a>
</li>
</ul>
</div>

View File

@@ -1,50 +0,0 @@
<!-- Association group -->
<div>
<h3 class="text-xs uppercase text-gray-400 dark:text-gray-500 font-semibold pl-3">
<span class="hidden lg:block lg:sidebar-expanded:hidden 2xl:hidden text-center w-6"
aria-hidden="true">•••</span>
<span class="lg:hidden lg:sidebar-expanded:block 2xl:block">Verein</span>
</h3>
<ul class="mt-3">
<li class="{{ $currentRoute === 'association.news' ? $isCurrentRouteClass : $isNotCurrentRouteClass }}">
<a class="block text-gray-800 dark:text-gray-100 hover:text-gray-900 dark:hover:text-white truncate transition"
href="{{ route('association.news') }}">
<div class="flex items-center">
<i class="fa-sharp-duotone fa-solid fa-rss h-4 w-4"></i>
<span
class="text-sm font-medium ml-4 lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">News</span>
</div>
</a>
</li>
<li class="{{ $currentRoute === 'association.profile' ? $isCurrentRouteClass : $isNotCurrentRouteClass }}">
<a class="block text-gray-800 dark:text-gray-100 hover:text-gray-900 dark:hover:text-white truncate transition"
href="{{ route('association.profile') }}">
<div class="flex items-center">
<i class="fa-sharp-duotone fa-solid fa-id-card-clip h-4 w-4"></i>
<span
class="text-sm font-medium ml-4 lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">Meine Mitgliedschaft</span>
</div>
</a>
</li>
{{--<li class="{{ $currentRoute === 'association.election' ? $isCurrentRouteClass : $isNotCurrentRouteClass }}">
<a class="block text-gray-800 dark:text-gray-100 hover:text-gray-900 dark:hover:text-white truncate transition"
href="{{ route('association.election', ['election' => date('Y')]) }}">
<div class="flex items-center">
<i class="fa-sharp-duotone fa-solid fa-check-to-slot h-4 w-4"></i>
<span
class="text-sm font-medium ml-4 lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">Vorstands-Wahlen</span>
</div>
</a>
</li>--}}
<li class="{{ $currentRoute === 'association.projectSupport' ? $isCurrentRouteClass : $isNotCurrentRouteClass }}">
<a class="block text-gray-800 dark:text-gray-100 hover:text-gray-900 dark:hover:text-white truncate transition"
href="{{ route('association.projectSupport') }}">
<div class="flex items-center">
<i class="fa-sharp-duotone fa-solid fa-hand-heart h-4 w-4"></i>
<span
class="text-sm font-medium ml-4 lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">Projekt-Unterstützungen</span>
</div>
</a>
</li>
</ul>
</div>

View File

@@ -1,88 +0,0 @@
<!-- Courses group -->
<div>
<h3 class="text-xs uppercase text-gray-400 dark:text-gray-500 font-semibold pl-3">
<span class="hidden lg:block lg:sidebar-expanded:hidden 2xl:hidden text-center w-6"
aria-hidden="true">•••</span>
<span class="lg:hidden lg:sidebar-expanded:block 2xl:block">Courses</span>
</h3>
<ul class="mt-3">
<!-- Browse -->
<li class="pl-4 pr-3 py-2 rounded-lg mb-0.5 last:mb-0"
x-data="{ open: false }">
<a class="block text-gray-800 dark:text-gray-100 truncate transition" href="#0"
@click.prevent="open = !open; sidebarExpanded = true">
<div class="flex items-center justify-between">
<div class="flex items-center">
<i class="fa-sharp-duotone fa-solid fa-graduation-cap h-4 w-4"></i>
<span
class="text-sm font-medium ml-4 lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">Browse</span>
</div>
<!-- Icon -->
<div
class="flex shrink-0 ml-2 lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">
<svg class="w-3 h-3 shrink-0 ml-1 fill-current text-gray-400 dark:text-gray-500"
:class="open ? 'rotate-180' : 'rotate-0'" viewBox="0 0 12 12">
<path d="M5.9 11.4L.5 6l1.4-1.4 4 4 4-4L11.3 6z"/>
</svg>
</div>
</div>
</a>
<div class="lg:hidden lg:sidebar-expanded:block 2xl:block">
<ul class="pl-8 mt-1" :class="open ? '!block' : 'hidden'">
<li class="mb-1 last:mb-0">
<a class="block text-amber-500 transition truncate" href="index.html">
<span
class="text-sm font-medium lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">Main</span>
</a>
</li>
<li class="mb-1 last:mb-0">
<a class="block text-gray-500/90 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition truncate"
href="analytics.html">
<span
class="text-sm font-medium lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">Analytics</span>
</a>
</li>
<li class="mb-1 last:mb-0">
<a class="block text-gray-500/90 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition truncate"
href="fintech.html">
<span
class="text-sm font-medium lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">Fintech</span>
</a>
</li>
</ul>
</div>
</li>
<!-- Manage -->
<li class="pl-4 pr-3 py-2 rounded-lg mb-0.5 last:mb-0" x-data="{ open: false }">
<a class="block text-gray-800 dark:text-gray-100 hover:text-gray-900 dark:hover:text-white truncate transition"
href="#0" @click.prevent="open = !open; sidebarExpanded = true">
<div class="flex items-center justify-between">
<div class="flex items-center">
<i class="fa-sharp-duotone fa-solid fa-pencil h-4 w-4"></i>
<span
class="text-sm font-medium ml-4 lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">Manage</span>
</div>
<!-- Icon -->
<div
class="flex shrink-0 ml-2 lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">
<svg class="w-3 h-3 shrink-0 ml-1 fill-current text-gray-400 dark:text-gray-500"
:class="open ? 'rotate-180' : 'rotate-0'" viewBox="0 0 12 12">
<path d="M5.9 11.4L.5 6l1.4-1.4 4 4 4-4L11.3 6z"/>
</svg>
</div>
</div>
</a>
<div class="lg:hidden lg:sidebar-expanded:block 2xl:block">
<ul class="pl-8 mt-1 hidden" :class="open ? '!block' : 'hidden'">
<li class="mb-1 last:mb-0">
<a class="block text-gray-500/90 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition truncate"
href="customers.html">
<span
class="text-sm font-medium lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">Manage cities</span>
</a>
</li>
</ul>
</div>
</li>
</ul>
</div>

View File

@@ -1,88 +0,0 @@
<!-- Events group -->
<div>
<h3 class="text-xs uppercase text-gray-400 dark:text-gray-500 font-semibold pl-3">
<span class="hidden lg:block lg:sidebar-expanded:hidden 2xl:hidden text-center w-6"
aria-hidden="true">•••</span>
<span class="lg:hidden lg:sidebar-expanded:block 2xl:block">Events</span>
</h3>
<ul class="mt-3">
<!-- Browse -->
<li class="pl-4 pr-3 py-2 rounded-lg mb-0.5 last:mb-0"
x-data="{ open: false }">
<a class="block text-gray-800 dark:text-gray-100 truncate transition" href="#0"
@click.prevent="open = !open; sidebarExpanded = true">
<div class="flex items-center justify-between">
<div class="flex items-center">
<i class="fa-sharp-duotone fa-solid fa-calendar h-4 w-4"></i>
<span
class="text-sm font-medium ml-4 lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">Browse</span>
</div>
<!-- Icon -->
<div
class="flex shrink-0 ml-2 lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">
<svg class="w-3 h-3 shrink-0 ml-1 fill-current text-gray-400 dark:text-gray-500"
:class="open ? 'rotate-180' : 'rotate-0'" viewBox="0 0 12 12">
<path d="M5.9 11.4L.5 6l1.4-1.4 4 4 4-4L11.3 6z"/>
</svg>
</div>
</div>
</a>
<div class="lg:hidden lg:sidebar-expanded:block 2xl:block">
<ul class="pl-8 mt-1" :class="open ? '!block' : 'hidden'">
<li class="mb-1 last:mb-0">
<a class="block text-amber-500 transition truncate" href="index.html">
<span
class="text-sm font-medium lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">Main</span>
</a>
</li>
<li class="mb-1 last:mb-0">
<a class="block text-gray-500/90 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition truncate"
href="analytics.html">
<span
class="text-sm font-medium lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">Analytics</span>
</a>
</li>
<li class="mb-1 last:mb-0">
<a class="block text-gray-500/90 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition truncate"
href="fintech.html">
<span
class="text-sm font-medium lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">Fintech</span>
</a>
</li>
</ul>
</div>
</li>
<!-- Manage -->
<li class="pl-4 pr-3 py-2 rounded-lg mb-0.5 last:mb-0" x-data="{ open: false }">
<a class="block text-gray-800 dark:text-gray-100 hover:text-gray-900 dark:hover:text-white truncate transition"
href="#0" @click.prevent="open = !open; sidebarExpanded = true">
<div class="flex items-center justify-between">
<div class="flex items-center">
<i class="fa-sharp-duotone fa-solid fa-pencil h-4 w-4"></i>
<span
class="text-sm font-medium ml-4 lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">Manage</span>
</div>
<!-- Icon -->
<div
class="flex shrink-0 ml-2 lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">
<svg class="w-3 h-3 shrink-0 ml-1 fill-current text-gray-400 dark:text-gray-500"
:class="open ? 'rotate-180' : 'rotate-0'" viewBox="0 0 12 12">
<path d="M5.9 11.4L.5 6l1.4-1.4 4 4 4-4L11.3 6z"/>
</svg>
</div>
</div>
</a>
<div class="lg:hidden lg:sidebar-expanded:block 2xl:block">
<ul class="pl-8 mt-1 hidden" :class="open ? '!block' : 'hidden'">
<li class="mb-1 last:mb-0">
<a class="block text-gray-500/90 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition truncate"
href="customers.html">
<span
class="text-sm font-medium lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">Manage cities</span>
</a>
</li>
</ul>
</div>
</li>
</ul>
</div>

View File

@@ -1,11 +0,0 @@
<!-- Legacy group -->
<div>
<h3 class="text-xs uppercase text-gray-400 dark:text-gray-500 font-semibold pl-3">
<span class="hidden lg:block lg:sidebar-expanded:hidden 2xl:hidden text-center w-6"
aria-hidden="true">•••</span>
<span class="lg:hidden lg:sidebar-expanded:block 2xl:block">Legacy</span>
</h3>
<ul class="mt-3">
</ul>
</div>

View File

@@ -1,26 +0,0 @@
<!-- Meetups group -->
<div>
<h3 class="text-xs uppercase text-gray-400 dark:text-gray-500 font-semibold pl-3">
<span class="hidden lg:block lg:sidebar-expanded:hidden 2xl:hidden text-center w-6"
aria-hidden="true">•••</span>
<span class="lg:hidden lg:sidebar-expanded:block 2xl:block">Meetups</span>
</h3>
<ul class="mt-3">
<li class="pl-4 pr-3 py-2 rounded-lg mb-0.5 last:mb-0">
<a class="block text-gray-800 dark:text-gray-100 hover:text-gray-900 dark:hover:text-white truncate transition" href="{{ route('meetups.worldmap') }}">
<div class="flex items-center">
<i class="fa-sharp-duotone fa-solid fa-map h-4 w-4"></i>
<span class="text-sm font-medium ml-4 lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">World Map</span>
</div>
</a>
</li>
<li class="pl-4 pr-3 py-2 rounded-lg mb-0.5 last:mb-0">
<a class="block text-gray-800 dark:text-gray-100 hover:text-gray-900 dark:hover:text-white truncate transition" href="{{ route('meetups.grid') }}">
<div class="flex items-center">
<i class="fa-sharp-duotone fa-solid fa-handshake-angle h-4 w-4"></i>
<span class="text-sm font-medium ml-4 lg:opacity-0 lg:sidebar-expanded:opacity-100 2xl:opacity-100 duration-200">Alle Meetups</span>
</div>
</a>
</li>
</ul>
</div>

View File

@@ -1,11 +0,0 @@
<!-- Nostr group -->
<div>
<h3 class="text-xs uppercase text-gray-400 dark:text-gray-500 font-semibold pl-3">
<span class="hidden lg:block lg:sidebar-expanded:hidden 2xl:hidden text-center w-6"
aria-hidden="true">•••</span>
<span class="lg:hidden lg:sidebar-expanded:block 2xl:block">Nostr</span>
</h3>
<ul class="mt-3">
</ul>
</div>

View File

@@ -1,22 +0,0 @@
<div>
<input type="checkbox" name="light-switch" id="light-switch" class="light-switch sr-only"/>
<label
class="flex items-center justify-center cursor-pointer w-8 h-8 hover:bg-gray-100 lg:hover:bg-gray-200 dark:hover:bg-gray-700/50 dark:lg:hover:bg-gray-800 rounded-full"
for="light-switch">
<svg class="dark:hidden fill-current text-gray-500/80 dark:text-gray-400/80" width="16"
height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path d="M8 0a1 1 0 0 1 1 1v.5a1 1 0 1 1-2 0V1a1 1 0 0 1 1-1Z"/>
<path d="M12 8a4 4 0 1 1-8 0 4 4 0 0 1 8 0Zm-4 2a2 2 0 1 0 0-4 2 2 0 0 0 0 4Z"/>
<path
d="M13.657 3.757a1 1 0 0 0-1.414-1.414l-.354.354a1 1 0 0 0 1.414 1.414l.354-.354ZM13.5 8a1 1 0 0 1 1-1h.5a1 1 0 1 1 0 2h-.5a1 1 0 0 1-1-1ZM13.303 11.889a1 1 0 0 0-1.414 1.414l.354.354a1 1 0 0 0 1.414-1.414l-.354-.354ZM8 13.5a1 1 0 0 1 1 1v.5a1 1 0 1 1-2 0v-.5a1 1 0 0 1 1-1ZM4.111 13.303a1 1 0 1 0-1.414-1.414l-.354.354a1 1 0 1 0 1.414 1.414l.354-.354ZM0 8a1 1 0 0 1 1-1h.5a1 1 0 0 1 0 2H1a1 1 0 0 1-1-1ZM3.757 2.343a1 1 0 1 0-1.414 1.414l.354.354A1 1 0 1 0 4.11 2.697l-.354-.354Z"/>
</svg>
<svg class="hidden dark:block fill-current text-gray-500/80 dark:text-gray-400/80"
width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path
d="M11.875 4.375a.625.625 0 1 0 1.25 0c.001-.69.56-1.249 1.25-1.25a.625.625 0 1 0 0-1.25 1.252 1.252 0 0 1-1.25-1.25.625.625 0 1 0-1.25 0 1.252 1.252 0 0 1-1.25 1.25.625.625 0 1 0 0 1.25c.69.001 1.249.56 1.25 1.25Z"/>
<path
d="M7.019 1.985a1.55 1.55 0 0 0-.483-1.36 1.44 1.44 0 0 0-1.53-.277C2.056 1.553 0 4.5 0 7.9 0 12.352 3.648 16 8.1 16c3.407 0 6.246-2.058 7.51-4.963a1.446 1.446 0 0 0-.25-1.55 1.554 1.554 0 0 0-1.372-.502c-4.01.552-7.539-2.987-6.97-7ZM2 7.9C2 5.64 3.193 3.664 4.961 2.6 4.82 7.245 8.72 11.158 13.36 11.04 12.265 12.822 10.341 14 8.1 14 4.752 14 2 11.248 2 7.9Z"/>
</svg>
<span class="sr-only">Switch to light / dark version</span>
</label>
</div>

View File

@@ -1,64 +0,0 @@
<div class="relative inline-flex" x-data="{ open: false }">
<button
class="w-8 h-8 flex items-center justify-center hover:bg-gray-100 lg:hover:bg-gray-200 dark:hover:bg-gray-700/50 dark:lg:hover:bg-gray-800 rounded-full"
:class="{ 'bg-gray-200 dark:bg-gray-800': open }"
aria-haspopup="true"
@click.prevent="open = !open"
:aria-expanded="open"
>
<span class="sr-only">Notifications</span>
<svg class="fill-current text-gray-500/80 dark:text-gray-400/80" width="16" height="16"
viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path
d="M7 0a7 7 0 0 0-7 7c0 1.202.308 2.33.84 3.316l-.789 2.368a1 1 0 0 0 1.265 1.265l2.595-.865a1 1 0 0 0-.632-1.898l-.698.233.3-.9a1 1 0 0 0-.104-.85A4.97 4.97 0 0 1 2 7a5 5 0 0 1 5-5 4.99 4.99 0 0 1 4.093 2.135 1 1 0 1 0 1.638-1.148A6.99 6.99 0 0 0 7 0Z"/>
<path
d="M11 6a5 5 0 0 0 0 10c.807 0 1.567-.194 2.24-.533l1.444.482a1 1 0 0 0 1.265-1.265l-.482-1.444A4.962 4.962 0 0 0 16 11a5 5 0 0 0-5-5Zm-3 5a3 3 0 0 1 6 0c0 .588-.171 1.134-.466 1.6a1 1 0 0 0-.115.82 1 1 0 0 0-.82.114A2.973 2.973 0 0 1 11 14a3 3 0 0 1-3-3Z"/>
</svg>
<div
class="absolute top-0 right-0 w-2.5 h-2.5 bg-red-500 border-2 border-gray-100 dark:border-gray-900 rounded-full"></div>
</button>
<div
class="origin-top-right z-10 absolute top-full right-0 -mr-48 sm:mr-0 min-w-80 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700/60 py-1.5 rounded-lg shadow-lg overflow-hidden mt-1"
@click.outside="open = false"
@keydown.escape.window="open = false"
x-show="open"
x-transition:enter="transition ease-out duration-200 transform"
x-transition:enter-start="opacity-0 -translate-y-2"
x-transition:enter-end="opacity-100 translate-y-0"
x-transition:leave="transition ease-out duration-200"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
x-cloak
>
<div
class="text-xs font-semibold text-gray-400 dark:text-gray-500 uppercase pt-1.5 pb-2 px-4">
Notifications
</div>
<ul>
<li class="border-b border-gray-200 dark:border-gray-700/60 last:border-0">
<a class="block py-2 px-4 hover:bg-gray-50 dark:hover:bg-gray-700/20" href="#0"
@click="open = false" @focus="open = true" @focusout="open = false">
<span class="block text-sm mb-2">📣 <span
class="font-medium text-gray-800 dark:text-gray-100">Edit your information in a swipe</span> Sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim.</span>
<span class="block text-xs font-medium text-gray-400 dark:text-gray-500">Feb 12, 2024</span>
</a>
</li>
<li class="border-b border-gray-200 dark:border-gray-700/60 last:border-0">
<a class="block py-2 px-4 hover:bg-gray-50 dark:hover:bg-gray-700/20" href="#0"
@click="open = false" @focus="open = true" @focusout="open = false">
<span class="block text-sm mb-2">📣 <span
class="font-medium text-gray-800 dark:text-gray-100">Edit your information in a swipe</span> Sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim.</span>
<span class="block text-xs font-medium text-gray-400 dark:text-gray-500">Feb 9, 2024</span>
</a>
</li>
<li class="border-b border-gray-200 dark:border-gray-700/60 last:border-0">
<a class="block py-2 px-4 hover:bg-gray-50 dark:hover:bg-gray-700/20" href="#0"
@click="open = false" @focus="open = true" @focusout="open = false">
<span class="block text-sm mb-2">🚀<span
class="font-medium text-gray-800 dark:text-gray-100">Say goodbye to paper receipts!</span> Sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim.</span>
<span class="block text-xs font-medium text-gray-400 dark:text-gray-500">Jan 24, 2024</span>
</a>
</li>
</ul>
</div>
</div>

View File

@@ -1,201 +0,0 @@
<!-- Search button -->
<div x-data="{ searchOpen: false }">
<!-- Button -->
<button
class="w-8 h-8 flex items-center justify-center hover:bg-gray-100 lg:hover:bg-gray-200 dark:hover:bg-gray-700/50 dark:lg:hover:bg-gray-800 rounded-full"
:class="{ 'bg-gray-200 dark:bg-gray-800': searchOpen }"
@click.prevent="searchOpen = true;if (searchOpen) $nextTick(()=>{$refs.searchInput.focus();});"
aria-controls="search-modal"
>
<span class="sr-only">Search</span>
<svg class="fill-current text-gray-500/80 dark:text-gray-400/80" width="16" height="16"
viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path
d="M7 14c-3.86 0-7-3.14-7-7s3.14-7 7-7 7 3.14 7 7-3.14 7-7 7ZM7 2C4.243 2 2 4.243 2 7s2.243 5 5 5 5-2.243 5-5-2.243-5-5-5Z"/>
<path
d="m13.314 11.9 2.393 2.393a.999.999 0 1 1-1.414 1.414L11.9 13.314a8.019 8.019 0 0 0 1.414-1.414Z"/>
</svg>
</button>
<!-- Modal backdrop -->
<div
class="fixed inset-0 bg-gray-900 bg-opacity-30 z-50 transition-opacity"
x-show="searchOpen"
x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-out duration-100"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
aria-hidden="true"
x-cloak
></div>
<!-- Modal dialog -->
<div
id="search-modal"
class="fixed inset-0 z-50 overflow-hidden flex items-start top-20 mb-4 justify-center px-4 sm:px-6"
role="dialog"
aria-modal="true"
x-show="searchOpen"
x-transition:enter="transition ease-in-out duration-200"
x-transition:enter-start="opacity-0 translate-y-4"
x-transition:enter-end="opacity-100 translate-y-0"
x-transition:leave="transition ease-in-out duration-200"
x-transition:leave-start="opacity-100 translate-y-0"
x-transition:leave-end="opacity-0 translate-y-4"
x-cloak
>
<div
class="bg-white dark:bg-gray-800 border border-transparent dark:border-gray-700/60 overflow-auto max-w-2xl w-full max-h-full rounded-lg shadow-lg"
@click.outside="searchOpen = false"
@keydown.escape.window="searchOpen = false"
>
<!-- Search form -->
<form class="border-b border-gray-200 dark:border-gray-700/60">
<div class="relative">
<label for="modal-search" class="sr-only">Search</label>
<input id="modal-search"
class="w-full dark:text-gray-300 bg-white dark:bg-gray-800 border-0 focus:ring-transparent placeholder-gray-400 dark:placeholder-gray-500 appearance-none py-3 pl-10 pr-4"
type="search" placeholder="Search Anything…" x-ref="searchInput"/>
<button class="absolute inset-0 right-auto group" type="submit"
aria-label="Search">
<svg
class="shrink-0 fill-current text-gray-400 dark:text-gray-500 group-hover:text-gray-500 dark:group-hover:text-gray-400 ml-4 mr-2"
width="16" height="16" viewBox="0 0 16 16"
xmlns="http://www.w3.org/2000/svg">
<path
d="M7 14c-3.86 0-7-3.14-7-7s3.14-7 7-7 7 3.14 7 7-3.14 7-7 7zM7 2C4.243 2 2 4.243 2 7s2.243 5 5 5 5-2.243 5-5-2.243-5-5-5z"/>
<path
d="M15.707 14.293L13.314 11.9a8.019 8.019 0 01-1.414 1.414l2.393 2.393a.997.997 0 001.414 0 .999.999 0 000-1.414z"/>
</svg>
</button>
</div>
</form>
<div class="py-4 px-2">
<!-- Recent searches -->
<div class="mb-3 last:mb-0">
<div
class="text-xs font-semibold text-gray-400 dark:text-gray-500 uppercase px-2 mb-2">
Recent searches
</div>
<ul class="text-sm">
<li>
<a class="flex items-center p-2 text-gray-800 dark:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700/20 rounded-lg"
href="#0" @click="searchOpen = false" @focus="searchOpen = true"
@focusout="searchOpen = false">
<svg
class="fill-current text-gray-400 dark:text-gray-500 shrink-0 mr-3"
width="16" height="16" viewBox="0 0 16 16">
<path
d="M15.707 14.293v.001a1 1 0 01-1.414 1.414L11.185 12.6A6.935 6.935 0 017 14a7.016 7.016 0 01-5.173-2.308l-1.537 1.3L0 8l4.873 1.12-1.521 1.285a4.971 4.971 0 008.59-2.835l1.979.454a6.971 6.971 0 01-1.321 3.157l3.107 3.112zM14 6L9.127 4.88l1.521-1.28a4.971 4.971 0 00-8.59 2.83L.084 5.976a6.977 6.977 0 0112.089-3.668l1.537-1.3L14 6z"/>
</svg>
<span>Form Builder - 23 hours on-demand video</span>
</a>
</li>
<li>
<a class="flex items-center p-2 text-gray-800 dark:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700/20 rounded-lg"
href="#0" @click="searchOpen = false" @focus="searchOpen = true"
@focusout="searchOpen = false">
<svg
class="fill-current text-gray-400 dark:text-gray-500 shrink-0 mr-3"
width="16" height="16" viewBox="0 0 16 16">
<path
d="M15.707 14.293v.001a1 1 0 01-1.414 1.414L11.185 12.6A6.935 6.935 0 017 14a7.016 7.016 0 01-5.173-2.308l-1.537 1.3L0 8l4.873 1.12-1.521 1.285a4.971 4.971 0 008.59-2.835l1.979.454a6.971 6.971 0 01-1.321 3.157l3.107 3.112zM14 6L9.127 4.88l1.521-1.28a4.971 4.971 0 00-8.59 2.83L.084 5.976a6.977 6.977 0 0112.089-3.668l1.537-1.3L14 6z"/>
</svg>
<span>Access Mosaic on mobile and TV</span>
</a>
</li>
<li>
<a class="flex items-center p-2 text-gray-800 dark:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700/20 rounded-lg"
href="#0" @click="searchOpen = false" @focus="searchOpen = true"
@focusout="searchOpen = false">
<svg
class="fill-current text-gray-400 dark:text-gray-500 shrink-0 mr-3"
width="16" height="16" viewBox="0 0 16 16">
<path
d="M15.707 14.293v.001a1 1 0 01-1.414 1.414L11.185 12.6A6.935 6.935 0 017 14a7.016 7.016 0 01-5.173-2.308l-1.537 1.3L0 8l4.873 1.12-1.521 1.285a4.971 4.971 0 008.59-2.835l1.979.454a6.971 6.971 0 01-1.321 3.157l3.107 3.112zM14 6L9.127 4.88l1.521-1.28a4.971 4.971 0 00-8.59 2.83L.084 5.976a6.977 6.977 0 0112.089-3.668l1.537-1.3L14 6z"/>
</svg>
<span>Product Update - Q4 2024</span>
</a>
</li>
<li>
<a class="flex items-center p-2 text-gray-800 dark:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700/20 rounded-lg"
href="#0" @click="searchOpen = false" @focus="searchOpen = true"
@focusout="searchOpen = false">
<svg
class="fill-current text-gray-400 dark:text-gray-500 shrink-0 mr-3"
width="16" height="16" viewBox="0 0 16 16">
<path
d="M15.707 14.293v.001a1 1 0 01-1.414 1.414L11.185 12.6A6.935 6.935 0 017 14a7.016 7.016 0 01-5.173-2.308l-1.537 1.3L0 8l4.873 1.12-1.521 1.285a4.971 4.971 0 008.59-2.835l1.979.454a6.971 6.971 0 01-1.321 3.157l3.107 3.112zM14 6L9.127 4.88l1.521-1.28a4.971 4.971 0 00-8.59 2.83L.084 5.976a6.977 6.977 0 0112.089-3.668l1.537-1.3L14 6z"/>
</svg>
<span>Master Digital Marketing Strategy course</span>
</a>
</li>
<li>
<a class="flex items-center p-2 text-gray-800 dark:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700/20 rounded-lg"
href="#0" @click="searchOpen = false" @focus="searchOpen = true"
@focusout="searchOpen = false">
<svg
class="fill-current text-gray-400 dark:text-gray-500 shrink-0 mr-3"
width="16" height="16" viewBox="0 0 16 16">
<path
d="M15.707 14.293v.001a1 1 0 01-1.414 1.414L11.185 12.6A6.935 6.935 0 017 14a7.016 7.016 0 01-5.173-2.308l-1.537 1.3L0 8l4.873 1.12-1.521 1.285a4.971 4.971 0 008.59-2.835l1.979.454a6.971 6.971 0 01-1.321 3.157l3.107 3.112zM14 6L9.127 4.88l1.521-1.28a4.971 4.971 0 00-8.59 2.83L.084 5.976a6.977 6.977 0 0112.089-3.668l1.537-1.3L14 6z"/>
</svg>
<span>Dedicated forms for products</span>
</a>
</li>
<li>
<a class="flex items-center p-2 text-gray-800 dark:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700/20 rounded-lg"
href="#0" @click="searchOpen = false" @focus="searchOpen = true"
@focusout="searchOpen = false">
<svg
class="fill-current text-gray-400 dark:text-gray-500 shrink-0 mr-3"
width="16" height="16" viewBox="0 0 16 16">
<path
d="M15.707 14.293v.001a1 1 0 01-1.414 1.414L11.185 12.6A6.935 6.935 0 017 14a7.016 7.016 0 01-5.173-2.308l-1.537 1.3L0 8l4.873 1.12-1.521 1.285a4.971 4.971 0 008.59-2.835l1.979.454a6.971 6.971 0 01-1.321 3.157l3.107 3.112zM14 6L9.127 4.88l1.521-1.28a4.971 4.971 0 00-8.59 2.83L.084 5.976a6.977 6.977 0 0112.089-3.668l1.537-1.3L14 6z"/>
</svg>
<span>Product Update - Q4 2024</span>
</a>
</li>
</ul>
</div>
<!-- Recent pages -->
<div class="mb-3 last:mb-0">
<div
class="text-xs font-semibold text-gray-400 dark:text-gray-500 uppercase px-2 mb-2">
Recent pages
</div>
<ul class="text-sm">
<li>
<a class="flex items-center p-2 text-gray-800 dark:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700/20 rounded-lg"
href="#0" @click="searchOpen = false" @focus="searchOpen = true"
@focusout="searchOpen = false">
<svg
class="fill-current text-gray-400 dark:text-gray-500 shrink-0 mr-3"
width="16" height="16" viewBox="0 0 16 16">
<path
d="M14 0H2c-.6 0-1 .4-1 1v14c0 .6.4 1 1 1h8l5-5V1c0-.6-.4-1-1-1zM3 2h10v8H9v4H3V2z"/>
</svg>
<span><span class="font-medium">Messages</span> - <span
class="text-gray-600 dark:text-gray-400">Conversation / / Mike Mills</span></span>
</a>
</li>
<li>
<a class="flex items-center p-2 text-gray-800 dark:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700/20 rounded-lg"
href="#0" @click="searchOpen = false" @focus="searchOpen = true"
@focusout="searchOpen = false">
<svg
class="fill-current text-gray-400 dark:text-gray-500 shrink-0 mr-3"
width="16" height="16" viewBox="0 0 16 16">
<path
d="M14 0H2c-.6 0-1 .4-1 1v14c0 .6.4 1 1 1h8l5-5V1c0-.6-.4-1-1-1zM3 2h10v8H9v4H3V2z"/>
</svg>
<span><span class="font-medium">Messages</span> - <span
class="text-gray-600 dark:text-gray-400">Conversation / / Eva Patrick</span></span>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>

View File

@@ -1,3 +0,0 @@
<style>
/**/
</style>

View File

@@ -1,49 +0,0 @@
<div class="relative inline-flex" x-data="{ open: false }">
<button
class="inline-flex justify-center items-center group"
aria-haspopup="true"
@click.prevent="open = !open"
:aria-expanded="open"
>
<img class="w-8 h-8 rounded-full" src="./images/user-avatar-32.png" width="32"
height="32" alt="User"/>
<div class="flex items-center truncate">
<span
class="truncate ml-2 text-sm font-medium text-gray-600 dark:text-gray-100 group-hover:text-gray-800 dark:group-hover:text-white">Acme Inc.</span>
<svg class="w-3 h-3 shrink-0 ml-1 fill-current text-gray-400 dark:text-gray-500"
viewBox="0 0 12 12">
<path d="M5.9 11.4L.5 6l1.4-1.4 4 4 4-4L11.3 6z"/>
</svg>
</div>
</button>
<div
class="origin-top-right z-10 absolute top-full right-0 min-w-44 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700/60 py-1.5 rounded-lg shadow-lg overflow-hidden mt-1"
@click.outside="open = false"
@keydown.escape.window="open = false"
x-show="open"
x-transition:enter="transition ease-out duration-200 transform"
x-transition:enter-start="opacity-0 -translate-y-2"
x-transition:enter-end="opacity-100 translate-y-0"
x-transition:leave="transition ease-out duration-200"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
x-cloak
>
<div class="pt-0.5 pb-2 px-3 mb-1 border-b border-gray-200 dark:border-gray-700/60">
<div class="font-medium text-gray-800 dark:text-gray-100">Acme Inc.</div>
<div class="text-xs text-gray-500 dark:text-gray-400 italic">Administrator</div>
</div>
<ul>
<li>
<a class="font-medium text-sm text-violet-500 hover:text-violet-600 dark:hover:text-violet-400 flex items-center py-1 px-3"
href="settings.html" @click="open = false" @focus="open = true"
@focusout="open = false">Settings</a>
</li>
<li>
<a class="font-medium text-sm text-violet-500 hover:text-violet-600 dark:hover:text-violet-400 flex items-center py-1 px-3"
href="signin.html" @click="open = false" @focus="open = true"
@focusout="open = false">Sign Out</a>
</li>
</ul>
</div>
</div>

View File

@@ -1,222 +0,0 @@
<x-layouts.app title="{{ __('Meetups') }}">
<div class="relative flex">
<!-- Profile sidebar -->
<div
id="profile-sidebar"
class="absolute z-20 top-0 bottom-0 w-full md:w-auto md:static md:top-auto md:bottom-auto -mr-px md:translate-x-0 transition-transform duration-200 ease-in-out"
:class="profileSidebarOpen ? 'translate-x-0' : '-translate-x-full'"
>
<div
class="sticky top-16 bg-white dark:bg-[#1B1B1B] overflow-x-hidden overflow-y-auto no-scrollbar shrink-0 border-r border-gray-200 dark:border-gray-700/60 md:w-[18rem] xl:w-[20rem] h-[calc(100dvh-64px)]">
<!-- Profile group -->
<div>
<!-- Group header -->
<div class="sticky top-0 z-10">
<div
class="flex items-center bg-white dark:bg-[#1B1B1B] border-b border-gray-200 dark:border-gray-700/60 px-5 h-16">
<div class="w-full flex items-center justify-between">
<!-- Profile image -->
<div class="relative">
<div class="grow flex items-center truncate">
<div class="truncate">
<span
class="font-semibold text-gray-800 dark:text-gray-100">All meetups</span>
</div>
</div>
</div>
<!-- Add button -->
<button
class="p-1.5 shrink-0 rounded-lg bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700/60 hover:border-gray-300 dark:hover:border-gray-600 shadow-sm ml-2">
<svg class="fill-current text-violet-500" width="16" height="16"
viewBox="0 0 16 16">
<path
d="M15 7H9V1c0-.6-.4-1-1-1S7 .4 7 1v6H1c-.6 0-1 .4-1 1s.4 1 1 1h6v6c0 .6.4 1 1 1s1-.4 1-1V9h6c.6 0 1-.4 1-1s-.4-1-1-1Z"/>
</svg>
</button>
</div>
</div>
</div>
<!-- Group body -->
<div class="px-5 py-4">
<!-- Search form -->
<div class="relative">
<label for="profile-search" class="sr-only">Search</label>
<input id="profile-search" class="form-input w-full pl-9 bg-white dark:bg-gray-800 rounded"
type="search" placeholder="Search…"/>
<button class="absolute inset-0 right-auto group cursor-default" aria-label="Search">
<svg
class="shrink-0 fill-current text-gray-400 dark:text-gray-500 group-hover:text-gray-500 dark:group-hover:text-gray-400 ml-3 mr-2"
width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path
d="M7 14c-3.86 0-7-3.14-7-7s3.14-7 7-7 7 3.14 7 7-3.14 7-7 7zM7 2C4.243 2 2 4.243 2 7s2.243 5 5 5 5-2.243 5-5-2.243-5-5-5z"/>
<path
d="M15.707 14.293L13.314 11.9a8.019 8.019 0 01-1.414 1.414l2.393 2.393a.997.997 0 001.414 0 .999.999 0 000-1.414z"/>
</svg>
</button>
</div>
<!-- Team members -->
<div class="mt-4">
<div class="text-xs font-semibold text-gray-400 dark:text-gray-500 uppercase mb-3">
Countries
</div>
<ul class="mb-6">
<li class="-mx-2">
<button
class="w-full p-2 rounded-lg bg-[linear-gradient(135deg,var(--tw-gradient-stops))] from-violet-500/[0.12] dark:from-violet-500/[0.24] to-violet-500/[0.04]"
@click="profileSidebarOpen = false">
<div class="flex items-center">
<div class="relative mr-2">
<img class="w-8 h-8 rounded-full"
src="{{ asset('vendor/blade-country-flags/1x1-de.svg') }}"
width="32" height="32" alt="User 08"/>
</div>
<div class="truncate">
<span class="text-sm font-medium text-gray-800 dark:text-gray-100">Deutschland</span>
</div>
</div>
</button>
</li>
<li class="-mx-2">
<button
class="w-full p-2"
@click="profileSidebarOpen = false">
<div class="flex items-center">
<div class="relative mr-2">
<img class="w-8 h-8 rounded-full"
src="{{ asset('vendor/blade-country-flags/1x1-at.svg') }}"
width="32" height="32" alt="User 08"/>
</div>
<div class="truncate">
<span class="text-sm font-medium text-gray-800 dark:text-gray-100">Österreich</span>
</div>
</div>
</button>
</li>
<li class="-mx-2">
<button
class="w-full p-2"
@click="profileSidebarOpen = false">
<div class="flex items-center">
<div class="relative mr-2">
<img class="w-8 h-8 rounded-full"
src="{{ asset('vendor/blade-country-flags/1x1-ch.svg') }}"
width="32" height="32" alt="User 08"/>
</div>
<div class="truncate">
<span class="text-sm font-medium text-gray-800 dark:text-gray-100">Schweiz</span>
</div>
</div>
</button>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<!-- Profile body -->
<div
class="grow flex flex-col md:translate-x-0 transition-transform duration-300 ease-in-out"
:class="profileSidebarOpen ? 'translate-x-1/3' : 'translate-x-0'"
>
<!-- Profile background -->
<div class="relative h-56 bg-gray-200 dark:bg-gray-900">
<img class="object-cover object-top h-full w-full" src="{{ asset('img/meetup_saarland.jpg') }}"
width="979" height="220"
alt="Profile background"/>
<!-- Close button -->
<button
class="md:hidden absolute top-4 left-4 sm:left-6 text-white opacity-80 hover:opacity-100"
@click.stop="profileSidebarOpen = !profileSidebarOpen"
aria-controls="profile-sidebar"
:aria-expanded="profileSidebarOpen"
>
<span class="sr-only">Close sidebar</span>
<svg class="w-6 h-6 fill-current" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M10.7 18.7l1.4-1.4L7.8 13H20v-2H7.8l4.3-4.3-1.4-1.4L4 12z"/>
</svg>
</button>
</div>
<!-- Content -->
<div class="relative px-4 sm:px-6 pb-8">
<!-- Pre-header -->
<div class="-mt-16 mb-6 sm:mb-3">
<div class="flex flex-col items-center sm:flex-row sm:justify-between sm:items-end">
<!-- Avatar -->
<div class="inline-flex -ml-1 -mt-1 mb-4 sm:mb-0" style="height: 128px">
</div>
<!-- Actions -->
<div class="flex space-x-2 sm:mb-2">
{{-- ACTIONS --}}
</div>
</div>
</div>
<div class="grid xl:grid-cols-2 gap-6 mb-8">
<!-- Item 1 -->
<article class="flex bg-white dark:bg-[#1B1B1B] shadow-sm rounded-xl overflow-hidden">
<!-- Image -->
<a class="relative block w-24 sm:w-56 xl:sidebar-expanded:w-40 2xl:sidebar-expanded:w-56 shrink-0" href="meetups-post.html">
<img class="absolute object-cover object-center w-full h-full" src="./images/meetups-thumb-01.jpg" width="220" height="236" alt="Meetup 01" />
<!-- Like button -->
<button class="absolute top-0 right-0 mt-4 mr-4">
<div class="text-gray-100 bg-gray-900 bg-opacity-60 rounded-full">
<span class="sr-only">Like</span>
<svg class="h-8 w-8 fill-current" viewBox="0 0 32 32">
<path d="M22.682 11.318A4.485 4.485 0 0019.5 10a4.377 4.377 0 00-3.5 1.707A4.383 4.383 0 0012.5 10a4.5 4.5 0 00-3.182 7.682L16 24l6.682-6.318a4.5 4.5 0 000-6.364zm-1.4 4.933L16 21.247l-5.285-5A2.5 2.5 0 0112.5 12c1.437 0 2.312.681 3.5 2.625C17.187 12.681 18.062 12 19.5 12a2.5 2.5 0 011.785 4.251h-.003z" />
</svg>
</div>
</button>
</a>
<!-- Content -->
<div class="grow p-5 flex flex-col">
<div class="grow">
<div class="text-sm font-semibold text-violet-500 uppercase mb-2">Mon 27 Dec, 2024</div>
<a class="inline-flex mb-2" href="meetups-post.html">
<h3 class="text-lg font-bold text-gray-800 dark:text-gray-100">Silicon Valley Bootstrapper Breakfast Online for 2024</h3>
</a>
<div class="text-sm">Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts.</div>
</div>
<!-- Footer -->
<div class="flex justify-between items-center mt-3">
<!-- Tag -->
<div class="text-xs inline-flex items-center font-medium border border-gray-200 dark:border-gray-700/60 text-gray-600 dark:text-gray-400 rounded-full text-center px-2.5 py-1">
<svg class="w-4 h-3 fill-gray-400 dark:fill-gray-500 mr-2" viewBox="0 0 16 12">
<path d="m16 2-4 2.4V2a2 2 0 0 0-2-2H2a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V7.6l4 2.4V2ZM2 10V2h8v8H2Z" />
</svg>
<span>Online Event</span>
</div>
<!-- Avatars -->
<div class="flex items-center space-x-2">
<div class="flex -space-x-3 -ml-0.5">
<img class="rounded-full border-2 border-white dark:border-gray-800 box-content" src="./images/avatar-01.jpg" width="28" height="28" alt="User 01" />
<img class="rounded-full border-2 border-white dark:border-gray-800 box-content" src="./images/avatar-04.jpg" width="28" height="28" alt="User 04" />
<img class="rounded-full border-2 border-white dark:border-gray-800 box-content" src="./images/avatar-05.jpg" width="28" height="28" alt="User 05" />
</div>
<div class="text-xs font-medium text-gray-400 dark:text-gray-500 italic">+22</div>
</div>
</div>
</div>
</article>
</div>
</div>
</div>
</div>
</x-layouts.app>

View File

@@ -1,33 +0,0 @@
<x-layouts.app title="{{ __('Mockup') }}">
<div class="relative" x-data="nostrApp(@this)">
<div class="flex items-center space-x-2 mt-12">
<div>
<x-input wire:model.live.debounce="title" label="Title"/>
</div>
<div>
<x-textarea wire:model.live.debounce="description" label="Description"/>
</div>
<div>
<x-button wire:click="save" label="Save"/>
</div>
</div>
<h1 class="text-2x font-bold py-6">Meetups</h1>
<ul class="border-t border-white space-y-4 divide-y divide-white">
@foreach($events as $event)
<li>
<div class="flex items">
<div class="flex items-center space-x-2">
<div>
Name: {{ collect($event['tags'])->firstWhere(0, 'title')[1] }}
</div>
<div>
Beschreibung: {{ $event['content'] }}
</div>
</div>
</div>
</li>
@endforeach
</ul>
</div>
</x-layouts.app>

View File

@@ -1,5 +0,0 @@
<x-layouts.app title="{{ __('Meetups') }}">
<div>
<livewire:meetup-table />
</div>
</x-layouts.app>

View File

@@ -1,46 +0,0 @@
@push('scripts')
<script src="{{ asset('dist/jquery.js') }}"></script>
<script src="{{ asset('vendor/jvector/jquery-jvectormap-2.0.5.min.js') }}"></script>
<script src="{{ asset('vendor/jvector/maps/world-mill.js') }}"></script>
<link rel="stylesheet" href="{{ asset('vendor/jvector/jquery-jvectormap-2.0.5.css') }}" type="text/css"
media="screen"/>
@endpush
<x-layouts.app title="{{ __('Worldmap') }}">
<div
wire:ignore
class="w-full flex justify-center"
x-data="{
init() {
let markers = {{ Js::from($markers) }};
$('#mapworld').vectorMap({
zoomButtons : true,
zoomOnScroll: true,
map: 'world_mill',
backgroundColor: 'transparent',
markers: markers.map(function(h){ return {name: h.name, latLng: h.coords} }),
onMarkerClick: function(event, index) {
$wire.call('filterByMarker', markers[index].id)
},
markerStyle: {
initial: {
image: '{{ asset('img/btc.png') }}',
}
},
regionStyle: {
initial: {
fill: '#a4a4a4'
},
hover: {
'fill-opacity': 1,
cursor: 'default'
},
}
});
}
}"
>
<div id="mapworld" style="width: 100%;" class="h-[200px] sm:h-[400px]"></div>
</div>
</x-layouts.app>

View File

@@ -1,124 +0,0 @@
@props(['project', 'currentPleb', 'section' => 'all'])
@php
$boardVotes = $project->votes->filter(function ($vote) {
return in_array($vote->einundzwanzigPleb->npub, config('einundzwanzig.config.current_board'));
});
$approveCount = $boardVotes->where('value', 1)->count();
$disapproveCount = $boardVotes->where('value', 0)->count();
$shouldDisplay = match($section) {
'all' => true,
'new' => $approveCount < 3,
'supported' => $project->sats_paid > 0,
'rejected' => $disapproveCount >= 3,
'approved' => ($approveCount === 3 || $disapproveCount !== 3),
default => true,
};
@endphp
@if($shouldDisplay)
<article
wire:key="project_{{ $project->id }}"
class="flex bg-white dark:bg-gray-800 shadow-sm rounded-xl overflow-hidden">
<!-- Image -->
@if(!$project->sats_paid)
<a class="relative block w-24 sm:w-56 xl:sidebar-expanded:w-40 2xl:sidebar-expanded:w-56 shrink-0"
href="{{ route('association.projectSupport.item', ['projectProposal' => $project]) }}">
<img class="absolute object-cover object-center w-full h-full"
src="{{ $project->getFirstMediaUrl('main') }}" alt="Meetup 01">
<button class="absolute top-0 right-0 mt-4 mr-4">
<img class="rounded-full h-8 w-8"
src="{{ $project->einundzwanzigPleb->profile?->picture ?? asset('einundzwanzig-alpha.jpg') }}"
alt="">
</button>
</a>
@else
<div
class="relative block w-24 sm:w-56 xl:sidebar-expanded:w-40 2xl:sidebar-expanded:w-56 shrink-0"
href="{{ route('association.projectSupport.item', ['projectProposal' => $project]) }}">
<img class="absolute object-cover object-center w-full h-full"
src="{{ $project->getFirstMediaUrl('main') }}" alt="Meetup 01">
<button class="absolute top-0 right-0 mt-4 mr-4">
<img class="rounded-full h-8 w-8"
src="{{ $project->einundzwanzigPleb->profile?->picture ?? asset('einundzwanzig-alpha.jpg') }}"
alt="">
</button>
</div>
@endif
<!-- Content -->
<div class="grow p-5 flex flex-col">
<div class="grow">
<div class="text-sm font-semibold text-amber-500 uppercase mb-2">
Eingereicht von: {{ $project->einundzwanzigPleb->profile?->name ?? str($project->einundzwanzigPleb->npub)->limit(32) }}
</div>
<div class="inline-flex mb-2">
<h3 class="text-lg font-bold text-gray-800 dark:text-gray-100">
{{ $project->name }}
</h3>
</div>
<div class="text-sm line-clamp-1 sm:line-clamp-3">
{!! strip_tags($project->description) !!}
</div>
</div>
<!-- Footer -->
<div class="flex justify-between items-center mt-3">
<!-- Tag -->
<div
class="text-xs inline-flex items-center font-bold border border-gray-200 dark:border-gray-700/60 text-gray-600 dark:text-gray-200 rounded-full text-center px-2.5 py-1">
<span>{{ number_format($project->support_in_sats, 0, ',', '.') }} Sats</span>
</div>
<div
class="text-xs inline-flex items-center font-bold border border-gray-200 dark:border-gray-700/60 text-gray-600 dark:text-gray-200 rounded-full text-center px-2.5 py-1">
<a href="{{ $project->website }}" target="_blank">Webseite</a>
</div>
<!-- Avatars -->
@if($project->votes->where('value', true)->count() > 0)
<div class="hidden sm:flex items-center space-x-2">
<div class="text-xs font-medium text-gray-400 dark:text-gray-300 italic">
Anzahl der Unterstützer:
+{{ $project->votes->where('value', true)->count() }}
</div>
</div>
@endif
</div>
<div
class="flex flex-col sm:flex-row justify-between items-center mt-3 space-y-2 sm:space-y-0">
@if(
($currentPleb && $currentPleb->id === $project->einundzwanzig_pleb_id)
|| ($currentPleb && in_array($currentPleb->npub, config('einundzwanzig.config.current_board'), true))
)
<x-button
icon="trash"
xs
negative
wire:click="confirmDelete({{ $project->id }})"
label="Löschen"/>
<x-button
icon="pencil"
xs
secondary
:href="route('association.projectSupport.edit', ['projectProposal' => $project])"
label="Editieren"/>
@endif
@if(($currentPleb && $currentPleb->association_status->value > 2) || $project->accepted)
<x-button
icon="folder-open"
xs
:href="route('association.projectSupport.item', ['projectProposal' => $project])"
label="Öffnen"/>
@endif
</div>
<div class="py-2">
@if($project->sats_paid)
<div
class="text-sm inline-flex font-medium bg-green-500/20 text-green-700 rounded-full text-center px-2.5 py-1">
Wurde mit {{ number_format($project->sats_paid, 0, ',', '.') }} Sats
unterstützt
</div>
@endif
</div>
</div>
</article>
@endif

View File

@@ -1,67 +0,0 @@
<x-layouts.app title="{{ __('Changelog') }}">
<div>
<div
class="sm:flex sm:justify-between sm:items-center px-4 sm:px-6 py-8 border-b border-gray-200 dark:border-gray-700/60">
<!-- Left: Title -->
<div class="mb-4 sm:mb-0">
<h1 class="text-2xl md:text-3xl text-gray-800 dark:text-gray-100 font-bold">Changelog</h1>
</div>
<!-- Right: Actions -->
<div class="grid grid-flow-col sm:auto-cols-max justify-start sm:justify-end gap-2">
{{--<!-- Add entry button -->
<button
class="btn bg-gray-900 text-gray-100 hover:bg-gray-800 dark:bg-gray-100 dark:text-gray-800 dark:hover:bg-white">
Add Entry
</button>--}}
</div>
</div>
<div class="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
<div class="max-w-3xl m-auto">
<!-- Posts -->
<div class="xl:-translate-x-16">
@foreach($entries as $entry)
<article class="pt-6">
<div class="xl:flex">
<div class="w-32 shrink-0">
<div
class="text-xs font-semibold uppercase text-gray-400 dark:text-gray-500 xl:leading-8">
{{ $entry['date'] }}
</div>
</div>
<div class="grow pb-6 border-b border-gray-200 dark:border-gray-700/60">
<header>
<div class="flex flex-nowrap items-center space-x-2 mb-4">
<div class="flex items-center">
<a class="block text-sm font-semibold text-gray-800 dark:text-gray-100"
href="#0">
{{ $entry['author'] }}
</a>
</div>
<div class="text-gray-400 dark:text-gray-600">·</div>
<div>
<div
class="text-xs inline-flex font-medium bg-green-500/20 text-green-700 rounded-full text-center px-2.5 py-1">
{{ $entry['hash'] }}
</div>
</div>
</div>
</header>
<div class="space-y-3 font-mono">
{!! $entry['message'] !!}
</div>
</div>
</div>
</article>
@endforeach
</div>
</div>
</div>
</div>
</x-layouts.app>

View File

@@ -1,5 +0,0 @@
<x-layouts.app title="Welcome">
<div>
TEST
</div>
</x-layouts.app>