Files
Crussell/frontend/src/routes/+layout.svelte
T
popertots f6caaab8a3 feat: redesign homepage, add global footer, fix carousel font
Homepage: restored original v0 design, replaced lorem ipsum with real service descriptions, added BusinessHours (Opening Hours) section, alternating bg-gray-50 section backgrounds. Layout: added global sticky footer (hidden on /admin/schedule, /account, and ?format=pdf pages), wrapped content in min-h-screen flex layout. PortfolioCarousel: set heading to Playfair Display.
2026-08-22 00:34:49 +01:00

110 lines
3.3 KiB
Svelte

<script lang="ts">
import '../app.css';
import favicon from '$lib/assets/favicon.svg';
import NavBar from '$lib/components/layout/NavBar.svelte';
import { Toaster } from '$lib/components/ui/sonner/index.js';
import { toast } from 'svelte-sonner';
import { authStore } from '$lib/stores/auth.svelte';
import { onMount } from 'svelte';
import { page } from '$app/stores';
const { children } = $props();
let hideFooter = $derived(
$page.url.pathname === '/admin/schedule' ||
$page.url.pathname === '/account' ||
$page.url.searchParams.get('format') === 'pdf'
);
// Default to 'top-center' (mobile-first approach)
let toasterPosition = $state<'top-center' | 'bottom-center'>('top-center');
function updateToasterPosition() {
// Use 640px (Tailwind's 'sm' breakpoint) to differentiate desktop and mobile
if (typeof window !== 'undefined' && window.innerWidth >= 768) {
toasterPosition = 'bottom-center';
} else {
toasterPosition = 'top-center';
}
}
onMount(() => {
updateToasterPosition();
window.addEventListener('resize', updateToasterPosition);
return () => {
window.removeEventListener('resize', updateToasterPosition);
};
});
// Verify email address
// TODO: `/api/verify-email` doesn't exist in the backend. The correct endpoints are
// `POST /api/verify/generate` (send verification code) and `POST /api/verify/check` (verify code).
// This call silently 404s. Fix required — either add the missing backend route or refactor
// to use `/api/verify/generate` + `/api/verify/check`.
async function verify_email() {
const loadingToast = toast.loading('Verifying email address...');
const response = await fetch('/api/verify-email', {
method: 'POST'
});
if (response.ok) {
toast.success('Email verified successfully!', { id: loadingToast });
window.location.reload();
} else {
toast.error('Failed to verify email address', { id: loadingToast });
}
}
</script>
<svelte:head>
<link rel="icon" href={favicon} />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous" />
<link
href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400..900;1,400..900&display=swap"
rel="stylesheet"
/>
</svelte:head>
<div class="flex min-h-screen flex-col">
<NavBar />
<Toaster position={toasterPosition} />
<main class="flex-1 pt-16">
{#if authStore.currentUser?.role === 'unverified_email'}
<div class="w-full bg-red-600 py-2 pr-8 pl-8 text-center text-sm font-medium text-white">
Please verify your email address to continue. Didn't recieve the email? Check your spam
folder, or <button
type="button"
onclick={verify_email}
class="cursor-pointer border-0 bg-transparent p-0 text-white underline"
>
click here
</button>
to resend it.
</div>
{/if}
{@render children?.()}
</main>
{#if !hideFooter}
<footer class="border-t py-3 text-center text-xs text-gray-500 md:py-4 md:text-sm">
&copy; {new Date().getFullYear()} Crussell Nails. All rights reserved.
</footer>
{/if}
</div>
<style>
@media print {
:global(nav) {
display: none !important;
}
:global(main > div.bg-red-600) {
display: none !important;
}
:global(main) {
padding-top: 0 !important;
}
}
</style>