Files
suivicpt/resources/views/components/bottom-tab-bar.blade.php
T
jeremy bayseandClaude Sonnet 5 6a776b0042 Hide top nav on mobile, add "Plus" sheet to bottom tab bar
The top nav (logo + hamburger) was still sm:hidden-only on its inner
sections but the <nav> element itself had no breakpoint class, so it
kept rendering as an empty-looking bar above the new bottom tab bar.
Hide the whole element below sm and drop the now-dead hamburger/Alpine
toggle and its responsive menu, since nothing renders it anymore.

Account/settings links (Profile, Foyer, Catégories, Récurrences,
Log Out) that used to live in that hamburger now live in a "Plus"
slide-up sheet on the bottom tab bar. Logging out needed a real route
since the sheet isn't a Livewire component and can't call the
Volt navigation component's method directly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-02 11:23:24 +02:00

122 lines
6.4 KiB
PHP

@php
$tabs = [
['route' => 'dashboard', 'label' => 'Accueil', 'icon' => 'home'],
['route' => 'plan', 'label' => 'Plan', 'icon' => 'grid'],
['route' => 'suivi', 'label' => 'Suivi', 'icon' => 'list'],
['route' => 'sankey', 'label' => 'Flux', 'icon' => 'chart'],
];
@endphp
<div x-data="{ more: false }" class="sm:hidden">
<nav aria-label="Navigation principale" class="fixed inset-x-0 bottom-0 z-40 pb-[max(env(safe-area-inset-bottom),8px)] pt-2 px-4 bg-surface/90 backdrop-blur border-t border-border">
<div class="flex justify-around">
@foreach ($tabs as $tab)
@continue (! Route::has($tab['route']))
@php $active = request()->routeIs($tab['route']); @endphp
<a
href="{{ route($tab['route']) }}"
wire:navigate
aria-current="{{ $active ? 'page' : 'false' }}"
class="flex flex-col items-center gap-0.5 px-3 py-1 rounded-xl focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring {{ $active ? 'text-brand' : 'text-text-muted' }}"
>
<span class="w-6 h-6 flex items-center justify-center rounded-lg {{ $active ? 'bg-brand text-surface' : '' }}">
@switch($tab['icon'])
@case('home')
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4" aria-hidden="true"><path d="M3 11l9-8 9 8" /><path d="M5 10v10h14V10" /></svg>
@break
@case('grid')
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4" aria-hidden="true"><rect x="3" y="3" width="7" height="7" rx="1.5" /><rect x="14" y="3" width="7" height="7" rx="1.5" /><rect x="3" y="14" width="7" height="7" rx="1.5" /><rect x="14" y="14" width="7" height="7" rx="1.5" /></svg>
@break
@case('list')
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4" aria-hidden="true"><path d="M8 6h13M8 12h13M8 18h13" /><path d="M3 6h.01M3 12h.01M3 18h.01" /></svg>
@break
@case('chart')
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4" aria-hidden="true"><path d="M3 3v18h18" /><path d="M7 15l4-6 4 3 5-8" /></svg>
@break
@endswitch
</span>
<span class="text-[10px] font-semibold leading-none">{{ $tab['label'] }}</span>
</a>
@endforeach
<button
type="button"
@click="more = true"
aria-haspopup="true"
:aria-expanded="more.toString()"
class="flex flex-col items-center gap-0.5 px-3 py-1 rounded-xl focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring text-text-muted"
>
<span class="w-6 h-6 flex items-center justify-center rounded-lg">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4" aria-hidden="true"><circle cx="12" cy="5" r="1.5" /><circle cx="12" cy="12" r="1.5" /><circle cx="12" cy="19" r="1.5" /></svg>
</span>
<span class="text-[10px] font-semibold leading-none">Plus</span>
</button>
</div>
</nav>
<div
x-show="more"
x-cloak
x-transition.opacity
class="fixed inset-0 z-50 bg-text/40"
@click="more = false"
role="presentation"
></div>
<div
x-show="more"
x-cloak
x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="translate-y-full"
x-transition:enter-end="translate-y-0"
x-transition:leave="transition ease-in duration-150"
x-transition:leave-start="translate-y-0"
x-transition:leave-end="translate-y-full"
class="fixed inset-x-0 bottom-0 z-50 pb-[max(env(safe-area-inset-bottom),16px)] pt-2 px-4 bg-surface rounded-t-3xl shadow-lg"
role="dialog"
aria-modal="true"
aria-label="Menu"
@keydown.escape.window="more = false"
>
<div class="w-10 h-1 rounded-full bg-border mx-auto mb-4"></div>
<div class="px-2 pb-2">
<div class="font-medium text-base text-text" x-data="{{ json_encode(['name' => auth()->user()->name]) }}" x-text="name" x-on:profile-updated.window="name = $event.detail.name"></div>
<div class="font-medium text-sm text-text-muted">{{ auth()->user()->email }}</div>
</div>
<div class="px-2 py-2">
<x-theme-toggle />
</div>
<div class="pb-2 space-y-1">
<x-responsive-nav-link :href="route('profile')" wire:navigate>
{{ __('Profile') }}
</x-responsive-nav-link>
<x-responsive-nav-link :href="route('household.settings')" wire:navigate>
{{ __('Foyer') }}
</x-responsive-nav-link>
@if (Route::has('categories'))
<x-responsive-nav-link :href="route('categories')" wire:navigate>
{{ __('Catégories') }}
</x-responsive-nav-link>
@endif
@if (Route::has('recurring'))
<x-responsive-nav-link :href="route('recurring')" wire:navigate>
{{ __('Récurrences') }}
</x-responsive-nav-link>
@endif
<form method="POST" action="{{ route('logout') }}">
@csrf
<button type="submit" class="block w-full ps-3 pe-4 py-2 border-l-4 border-transparent text-start text-base font-medium text-text-muted hover:text-text hover:bg-surface-alt hover:border-border-strong focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-inset transition duration-150 ease-in-out">
{{ __('Log Out') }}
</button>
</form>
</div>
</div>
</div>