Better skeleton use, live services in booking

This commit is contained in:
2025-10-18 21:39:57 +01:00
parent fad47df642
commit 68cf27541a
6 changed files with 408 additions and 212 deletions
@@ -1,11 +1,21 @@
<script lang="ts">
import { Button } from '$lib/components/ui/button';
import { Skeleton } from '$lib/components/ui/skeleton';
import { navigating, page } from '$app/stores';
import { authStore } from '$lib/stores/auth.svelte';
// Mobile menu state
let mobileMenuOpen: boolean = false;
// Centralized link definition
const links = [
{ href: '/', label: 'Home', showWhen: 'always', width: 'w-12' },
{ href: '/prices', label: 'Price List', showWhen: 'guest', width: 'w-20' },
{ href: '/book', label: 'Book your appointment', showWhen: 'auth', width: 'w-36' },
{ href: '/portfolio', label: 'Portfolio', showWhen: 'always', width: 'w-20' },
{ href: '/contact', label: 'Contact', showWhen: 'always', width: 'w-16' },
{ href: '/account', label: 'My Account', showWhen: 'auth', width: 'w-24' },
{ href: '/admin', label: 'Admin Dashboard', showWhen: 'admin', width: 'w-28' }
];
let mobileMenuOpen: boolean = false;
function toggleMenu() {
mobileMenuOpen = !mobileMenuOpen;
}
@@ -14,6 +24,21 @@
$: if ($navigating) {
mobileMenuOpen = false;
}
// Helper to decide visibility
const canShow = (link: { href: string; label: string; showWhen: string; width: string }) => {
if (authStore.isLoading) return true; // keep skeleton placeholders
// hide booking link for admins
if (link.href === '/book' && authStore.currentUser?.role === 'admin') return false;
if (link.href === '/contact' && authStore.currentUser?.role === 'admin') return false;
if (link.showWhen === 'always') return true;
if (link.showWhen === 'guest' && !authStore.isAuthenticated) return true;
if (link.showWhen === 'auth' && authStore.isAuthenticated) return true;
if (link.showWhen === 'admin' && authStore.currentUser?.role === 'admin') return true;
return false;
};
</script>
<nav
@@ -42,36 +67,37 @@
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="feather feather-instagram"
><rect x="2" y="2" width="20" height="20" rx="5" ry="5"></rect><path
d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"
></path><line x1="17.5" y1="6.5" x2="17.51" y2="6.5"></line></svg
>
<rect x="2" y="2" width="20" height="20" rx="5" ry="5"></rect>
<path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"></path>
<line x1="17.5" y1="6.5" x2="17.51" y2="6.5"></line>
</svg>
</a>
<!-- Add more social icons here -->
</div>
<!-- Center: Links -->
<!-- Center: Desktop Links -->
<div class="hidden space-x-8 md:flex">
<a href="/" class="hover:text-primary font-medium text-gray-800">Home</a>
{#if !authStore?.isAuthenticated}
<a href="/prices" class="hover:text-primary font-medium text-gray-800">Price List</a>
{:else}
<a href="/book" class="hover:text-primary font-medium text-gray-800"
>Book your appointment</a
>
{/if}
<a href="/portfolio" class="hover:text-primary font-medium text-gray-800">Portfolio</a>
<a href="/contact" class="hover:text-primary font-medium text-gray-800">Contact</a>
{#if authStore?.isAuthenticated}
<a href="/account" class="hover:text-primary font-medium text-gray-800">My Account</a>
{/if}
{#each links as link}
{#if canShow(link)}
{#if authStore.isLoading}
<Skeleton class={`h-4 ${link.width} rounded`} />
{:else}
<a href={link.href} class="hover:text-primary font-medium text-gray-800"
>{link.label}</a
>
{/if}
{/if}
{/each}
</div>
<!-- Desktop Login Button -->
<div class="hidden items-center md:flex">
<!-- if not logged in and not on login page -->
{#if !authStore?.isAuthenticated && $page.url.pathname !== '/login'}
{#if !authStore.isLoading && !authStore.isAuthenticated && $page.url.pathname !== '/login'}
<Button href="/login">Login</Button>
{/if}
{#if authStore.isLoading}
<Skeleton class="h-8 w-16 rounded" />
{/if}
</div>
<!-- Mobile: Burger -->
@@ -94,41 +120,25 @@
{#if mobileMenuOpen}
<div class="bg-background border-b border-gray-200 md:hidden">
<div class="space-y-1 px-2 pb-3 pt-2">
<a href="/" class="text-primary block rounded px-3 py-2 text-center hover:text-gray-800"
>Home</a
>
{#each links as link}
{#if canShow(link)}
{#if authStore.isLoading}
<Skeleton class="h-4 w-full rounded" />
{:else}
<a
href={link.href}
class="text-primary block rounded px-3 py-2 text-center hover:text-gray-800"
>
{link.label}
</a>
{/if}
{/if}
{/each}
{#if !authStore?.isAuthenticated}
<a
href="/prices"
class="text-primary block rounded px-3 py-2 text-center hover:text-gray-800"
>Price list</a
>
{:else}
<a
href="/book"
class="text-primary block rounded px-3 py-2 text-center hover:text-gray-800"
>Book your appointment</a
>
{/if}
<a
href="/portfolio"
class="text-primary block rounded px-3 py-2 text-center hover:text-gray-800">Portfolio</a
>
<a
href="/contact"
class="text-primary block rounded px-3 py-2 text-center hover:text-gray-800">Contact</a
>
{#if !authStore?.isAuthenticated}
{#if authStore.isLoading}
<Skeleton class="mt-2 h-8 w-full rounded" />
{:else if !authStore.isAuthenticated}
<Button href="/login" class="mt-2 w-full text-center">Login</Button>
{:else}
<a
href="/Account"
class="text-primary block rounded px-3 py-2 text-center hover:text-gray-800"
>My Account</a
>
{/if}
</div>
</div>