Add groups page. Update landing Add toastmagic

This commit is contained in:
joeplikestocode
2026-02-28 21:46:08 +01:00
parent 09b2b988f7
commit e405fec5c2
24 changed files with 2000 additions and 17 deletions

View File

@@ -0,0 +1,125 @@
<?php
use Livewire\Component;
use Illuminate\Support\Facades\Auth;
new class extends Component
{
public bool $isOpen = false;
public string $name = '';
public string $email = '';
public function openModal(): void
{
$user = Auth::user();
$this->name = (string) ($user?->name ?? '');
$this->email = (string) ($user?->email ?? '');
$this->isOpen = true;
}
public function closeModal(): void
{
$this->isOpen = false;
}
public function save(): void
{
$user = Auth::user();
$this->validate([
'name' => ['required', 'string', 'min:2', 'max:60'],
]);
$user->forceFill([
'name' => $this->name,
])->save();
$this->dispatch('toastMagic',
status: 'success',
title: 'Profile updated',
message: 'Your profile has been saved.'
);
$this->isOpen = false;
}
};
?>
<div class="relative">
<button type="button" wire:click="openModal" class="btn-primary w-full text-base">
Edit profile
</button>
@if($isOpen)
<div class="fixed inset-0 z-[9999]" role="dialog" aria-modal="true" wire:keydown.escape.window="closeModal">
<button
type="button"
class="absolute inset-0 bg-black/50"
wire:click="closeModal"
aria-label="Close modal"
></button>
<div class="absolute inset-0 bg-card">
<div class="mx-auto flex h-full w-full max-w-[420px] flex-col px-6 pt-6 pb-8">
<div class="flex items-center justify-between">
<div>
<h3 class="text-lg font-semibold">Edit profile</h3>
<p class="mt-1 text-xs text-muted-foreground">Update your display name.</p>
</div>
<button
type="button"
wire:click="closeModal"
class="grid h-10 w-10 place-items-center rounded-xl bg-background ring-1 ring-border"
aria-label="Close"
>
<svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M6 6l12 12M18 6L6 18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
</button>
</div>
<div class="mt-6 flex flex-col gap-3">
<label class="rounded-2xl bg-background p-4 ring-1 ring-border">
<p class="text-xs text-muted-foreground">Name</p>
<input
type="text"
wire:model.defer="name"
autocomplete="name"
class="mt-2 w-full rounded bg-transparent text-sm outline-none"
placeholder="Your name"
/>
@error('name')
<p class="mt-2 text-xs text-red-500">{{ $message }}</p>
@enderror
</label>
<label class="rounded-2xl bg-background p-4 ring-1 ring-border opacity-70">
<p class="text-xs text-muted-foreground">Email</p>
<input
type="email"
value="{{ auth()->user()->email }}"
disabled
class="mt-2 w-full rounded bg-transparent text-sm outline-none"
/>
</label>
</div>
<div class="mt-auto pt-6 flex flex-col gap-3">
<button type="button" wire:click="save" wire:loading.attr="disabled" class="btn-primary w-full text-base">
<span wire:loading.remove wire:target="save">Save</span>
<span wire:loading wire:target="save">Saving...</span>
</button>
<button type="button" wire:click="closeModal" class="btn-outline w-full text-base">
Cancel
</button>
</div>
</div>
</div>
</div>
@endif
</div>

View File

@@ -8,6 +8,7 @@
@vite(['resources/css/app.css', 'resources/js/app.js'])
@livewireStyles
{!! ToastMagic::styles() !!}
</head>
<body class="min-h-dvh bg-background text-foreground">
@@ -22,5 +23,6 @@
</div>
@livewireScripts
{!! ToastMagic::scripts() !!}
</body>
</html>

View File

@@ -0,0 +1,41 @@
<?php
use Livewire\Component;
new class extends Component
{
//
};
?>
<div class="flex flex-col gap-6 px-4 pt-6 pb-4">
<div>
<p class="text-sm text-muted-foreground">Welcome back,</p>
<h1 class="text-2xl font-bold text-foreground">Alex Rivera</h1>
</div>
<div class="grid grid-cols-3 gap-3">
<div class="flex flex-col items-center gap-1 rounded-xl border border-border bg-card p-3">
<div class="grid h-10 w-10 place-items-center rounded-xl bg-primary/15 text-primary-foreground mb-2">
<x-bi-people class="h-6 w-6 text-primary" />
</div>
<span class="font-bold text-xl">2</span>
<span class="text-muted-foreground text-sm">Groups</span>
</div>
<div class="flex flex-col items-center gap-1 rounded-xl border border-border bg-card p-3">
<div class="grid h-10 w-10 place-items-center rounded-xl bg-accent/15 text-primary-foreground mb-2">
<x-solar-medal-ribbon-linear class="h-6 w-6 text-accent" />
</div>
<span class="font-bold text-xl">2</span>
<span class="text-muted-foreground text-sm">Groups</span>
</div>
<div class="flex flex-col items-center gap-1 rounded-xl border border-border bg-card p-3">
<div class="grid h-10 w-10 place-items-center rounded-xl bg-card-foreground/15 text-primary-foreground mb-2">
<x-phosphor-trend-up class="h-6 w-6 text-card-foreground" />
</div>
<span class="font-bold text-xl">2</span>
<span class="text-muted-foreground text-sm">Groups</span>
</div>
</div>
</div>

View File

@@ -0,0 +1,13 @@
<?php
use Livewire\Component;
new class extends Component
{
//
};
?>
<div>
{{-- Order your soul. Reduce your wants. - Augustine --}}
</div>

View File

@@ -0,0 +1,13 @@
<?php
use Livewire\Component;
new class extends Component
{
//
};
?>
<div>
{{-- Knowing is not enough; we must apply. Being willing is not enough; we must do. - Leonardo da Vinci --}}
</div>

View File

@@ -31,13 +31,6 @@ new class extends Component
<a href="{{ route('register') }}" wire:navigate class="btn-primary w-full text-base">
Get Started
</a>
<form method="POST" action="{{ route('logout') }}">
@csrf
<button type="submit" class="btn-primary w-full text-base">
Logout
</button>
</form>
<a href="{{ route('login') }}" wire:navigate class="btn-outline w-full text-base">
I already have an account
</a>
@@ -109,24 +102,24 @@ new class extends Component
</div>
<div class="aspect-square rounded-2xl bg-card ring-1 ring-border p-4 text-sm">
<div class="grid h-10 w-10 place-items-center rounded-xl bg-primary/15 text-primary-foreground shadow-sm mb-2">
<x-bi-people class="h-6 w-6 text-primary" />
<x-solar-medal-ribbon-linear class="h-6 w-6 text-primary" />
</div>
<b>Patches</b>
<p class="text-muted-foreground">Private crews with invite codes</p>
<p class="text-muted-foreground">Custom badges with requirements</p>
</div>
<div class="aspect-square rounded-2xl bg-card ring-1 ring-border p-4 text-sm">
<div class="grid h-10 w-10 place-items-center rounded-xl bg-primary/15 text-primary-foreground shadow-sm mb-2">
<x-bi-people class="h-6 w-6 text-primary" />
<x-bi-shield class="h-6 w-6 text-primary" />
</div>
<b>Your sash</b>
<p class="text-muted-foreground">Private crews with invite codes</p>
<p class="text-muted-foreground">Show off everything you earned</p>
</div>
<div class="aspect-square rounded-2xl bg-card ring-1 ring-border p-4 text-sm">
<div class="grid h-10 w-10 place-items-center rounded-xl bg-primary/15 text-primary-foreground shadow-sm mb-2">
<x-feathericon-target class="h-6 w-6 text-primary" />
</div>
<b>Progress</b>
<p class="text-muted-foreground">Private crews with invite codes</p>
<p class="text-muted-foreground">Track steps toward each patch</p>
</div>
</div>

View File

@@ -0,0 +1,132 @@
<?php
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
use App\Models\Setting;
new class extends Component
{
public bool $notifications = false;
public bool $public = false;
public function saveSettings()
{
Setting::updateOrCreate(['user_id' => Auth::id(), 'key' => 'notifications'], ['value' => $this->notifications]);
Setting::updateOrCreate(['user_id' => Auth::id(), 'key' => 'public'], ['value' => $this->public]);
$this->dispatch('toastMagic',
status: 'success',
title: 'Settings saved',
message: 'The settings have succesfully been saved.'
);
}
};
?>
<div class="px-6 pt-16 pb-10">
<div class="mx-auto max-w-[420px]">
<div class="text-center">
<div class="mx-auto flex items-center justify-center gap-2">
<div class="grid h-12 w-12 place-items-center rounded-xl bg-primary text-primary-foreground shadow-sm">
<svg class="h-7 w-7" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M12 2l7 4v6c0 5-3 9-7 10-4-1-7-5-7-10V6l7-4Z" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
</svg>
</div>
<span class="text-2xl font-bold tracking-tight">PatchBook</span>
</div>
<h1 class="mt-6 text-3xl font-bold leading-tight tracking-tight text-balance">
Account
</h1>
<p class="mx-auto mt-2 max-w-[320px] text-sm leading-relaxed text-muted-foreground">
Your profile and security settings.
</p>
</div>
<div class="mt-8 rounded-2xl bg-card p-5 ring-1 ring-border">
<div class="flex items-center gap-4">
<div class="grid h-14 w-14 place-items-center rounded-2xl bg-primary/15 ring-1 ring-border">
<span class="text-lg font-bold text-primary">
{{ strtoupper(substr(auth()->user()->name ?? 'U', 0, 1)) }}
</span>
</div>
<div class="min-w-0 flex-1">
<h2 class="truncate text-lg font-semibold leading-tight">
{{ auth()->user()->name }}
</h2>
<p class="truncate text-sm text-muted-foreground">
{{ auth()->user()->email }}
</p>
</div>
</div>
<div class="mt-5">
<div class="rounded-2xl bg-background p-4 ring-1 ring-border text-center">
<p class="text-xs text-muted-foreground">Member since</p>
<p class="mt-1 text-sm font-semibold">
{{ optional(auth()->user()->created_at)->format('d M Y') ?? 'Unknown' }}
</p>
</div>
</div>
<div class="mt-5 flex flex-col gap-3">
<livewire:profile.edit />
@if(Auth::user()->password)
<button type="button" class="btn-outline w-full text-base">
Change password
</button>
@endif
<form action="{{ route('logout') }}" method="post">
@csrf
<button type="submit" class="btn-outline w-full text-base">
Logout
</button>
</form>
</div>
</div>
<hr class="mt-6 mb-6 border-t border-muted-foreground opacity-20">
<div class="rounded-2xl bg-card p-5 ring-1 ring-border">
<h3 class="text-base font-semibold">Preferences</h3>
<div class="mt-4 flex flex-col gap-3">
<label class="flex items-center justify-between rounded-2xl bg-background px-4 py-3 ring-1 ring-border">
<div class="flex items-center gap-3">
<div class="grid h-10 w-10 place-items-center rounded-xl bg-primary/15">
<svg class="h-5 w-5 text-primary" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M12 22a2 2 0 0 0 2-2H10a2 2 0 0 0 2 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<path d="M18 16v-5a6 6 0 1 0-12 0v5l-2 2h16l-2-2Z" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
</svg>
</div>
<div>
<p class="text-sm font-semibold leading-tight">Notifications</p>
<p class="text-xs text-muted-foreground">Email updates and reminders</p>
</div>
</div>
<input wire:change.debounce="saveSettings()" wire:model="notifications" type="checkbox" class="h-5 w-5 rounded border-muted-foreground/30" />
</label>
<label class="flex items-center justify-between rounded-2xl bg-background px-4 py-3 ring-1 ring-border">
<div class="flex items-center gap-3">
<div class="grid h-10 w-10 place-items-center rounded-xl bg-primary/15">
<svg class="h-5 w-5 text-primary" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M12 3v18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<path d="M3 12h18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
</div>
<div>
<p class="text-sm font-semibold leading-tight">Public profile</p>
<p class="text-xs text-muted-foreground">Let others see your name</p>
</div>
</div>
<input wire:change.debounce="saveSettings()" wire:model="public" type="checkbox" class="h-5 w-5 rounded border-muted-foreground/30" />
</label>
</div>
</div>
</div>
</div>