style: fix no-navigation-without-resolve — add resolve() for SPA links, rel=external for target=_blank, suppress in event handlers and effects
This commit is contained in:
@@ -788,7 +788,7 @@
|
||||
<p class="font-medium text-amber-900">Cannot Reschedule Online</p>
|
||||
<p class="mt-1">{noticeBlockedMessage}</p>
|
||||
<p class="mt-1">
|
||||
<a href="/contact" target="_blank" class="underline">Contact us</a> to discuss
|
||||
<a href="/contact" target="_blank" rel="external" class="underline">Contact us</a> to discuss
|
||||
options, or
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -330,7 +330,7 @@
|
||||
<a
|
||||
href={settings.website_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
rel="noopener noreferrer external"
|
||||
class="text-primary hover:underline"
|
||||
>
|
||||
{settings.website_url}
|
||||
|
||||
@@ -837,7 +837,7 @@
|
||||
<a
|
||||
href={result.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
rel="noopener noreferrer external"
|
||||
class="mt-1 inline-block text-xs text-green-700 underline hover:text-green-900"
|
||||
>
|
||||
View uploaded image →
|
||||
|
||||
@@ -1646,7 +1646,7 @@
|
||||
<p>
|
||||
We are currently asking for deposits on upcoming bookings. While this is active,
|
||||
only one online booking can be made at a time. If you need another appointment
|
||||
please <a href="/contact" target="_blank" class="font-medium underline"
|
||||
please <a href="/contact" target="_blank" rel="external" class="font-medium underline"
|
||||
>contact us</a
|
||||
>.
|
||||
</p>
|
||||
@@ -1670,7 +1670,7 @@
|
||||
a bespoke treatment.
|
||||
</p>
|
||||
<a
|
||||
href="/contact"
|
||||
href={resolve("/contact")}
|
||||
class="mt-1 inline-block text-sm font-medium text-blue-600 hover:underline"
|
||||
>
|
||||
Arrange a custom booking →
|
||||
@@ -1911,13 +1911,13 @@
|
||||
{#if emailSuggestion === 'login'}
|
||||
<p class="text-xs font-medium text-red-500">
|
||||
This email belongs to a registered user. Please
|
||||
<a href="/login" class="underline hover:text-red-800">log in</a>
|
||||
<a href={resolve("/login")} class="underline hover:text-red-800">log in</a>
|
||||
instead to access your bookings and rewards.
|
||||
</p>
|
||||
{:else if emailSuggestion === 'check'}
|
||||
<p class="text-xs font-medium text-amber-600">
|
||||
This email might belong to an existing account. Please double-check or
|
||||
<a href="/login" class="underline hover:text-amber-800">log in</a>.
|
||||
<a href={resolve("/login")} class="underline hover:text-amber-800">log in</a>.
|
||||
</p>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
{#if isLoading}
|
||||
<Skeleton class={`h-4 ${link.width} rounded`} />
|
||||
{:else}
|
||||
<a href={link.href} class="font-medium text-gray-800 hover:text-primary"
|
||||
<a href={resolve(link.href)} class="font-medium text-gray-800 hover:text-primary"
|
||||
>{link.label}</a
|
||||
>
|
||||
{/if}
|
||||
@@ -230,7 +230,7 @@
|
||||
<Skeleton class="h-4 w-full rounded" />
|
||||
{:else}
|
||||
<a
|
||||
href={link.href}
|
||||
href={resolve(link.href)}
|
||||
class="block rounded px-3 py-2 text-center text-primary hover:text-gray-800"
|
||||
>
|
||||
{link.label}
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
<a
|
||||
href="/cancellation-policy"
|
||||
target="_blank"
|
||||
rel="external"
|
||||
class="block w-full rounded px-3 py-2 text-left text-sm hover:bg-gray-100"
|
||||
onclick={() => (open = false)}
|
||||
>
|
||||
|
||||
@@ -166,6 +166,7 @@ class AuthStore {
|
||||
}
|
||||
}
|
||||
this.clearAuth();
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
goto('/', { invalidateAll: true });
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
// Redirect admins to /today (their homepage)
|
||||
$effect(() => {
|
||||
if (!authStore.isLoading && authStore.currentUser?.role === 'admin') {
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
goto('/today', { replaceState: true });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
|
||||
if (!authStore.isAuthenticated) {
|
||||
pageState = 'unauthorized';
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
goto('/login', { replaceState: true });
|
||||
return;
|
||||
}
|
||||
@@ -1232,6 +1233,7 @@
|
||||
|
||||
if (response.ok) {
|
||||
toast.success('Account deleted successfully', { id: loadingToast });
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
authStore.logout();
|
||||
goto('/');
|
||||
} else {
|
||||
@@ -2593,6 +2595,7 @@
|
||||
<div>
|
||||
<h3 class="mb-2 text-sm font-semibold">Data Privacy</h3>
|
||||
<p class="mb-3 text-sm text-gray-600">
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
View and export all personal data we hold about you
|
||||
</p>
|
||||
<Button onclick={() => goto('/gdpr')} variant="outline">
|
||||
|
||||
@@ -34,12 +34,14 @@
|
||||
|
||||
if (!authStore.isAuthenticated) {
|
||||
pageState = 'unauthorized';
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
goto('/login', { replaceState: true });
|
||||
return;
|
||||
}
|
||||
|
||||
if (authStore.currentUser?.role !== 'admin') {
|
||||
pageState = 'unauthorized';
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
goto('/', { replaceState: true });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
}
|
||||
if (!authStore.isAuthenticated || authStore.currentUser?.role !== 'admin') {
|
||||
pageState = 'unauthorized';
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
goto(authStore.isAuthenticated ? '/' : '/login', { replaceState: true });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { resolve } from '$app/paths';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let format = $state('html');
|
||||
@@ -262,7 +263,7 @@
|
||||
<p class="text-xs text-gray-500">
|
||||
If you need to request an adjustment due to exceptional circumstances or have questions
|
||||
regarding your upcoming appointments, please use our official <a
|
||||
href="/contact"
|
||||
href={resolve("/contact")}
|
||||
class="font-medium text-blue-600 underline hover:text-blue-800">Contact Channels</a
|
||||
> to get in touch.
|
||||
</p>
|
||||
|
||||
@@ -208,6 +208,7 @@ import { SvelteMap } from 'svelte/reactivity';
|
||||
}
|
||||
if (!authStore.isAuthenticated) {
|
||||
pageState = 'unauthorized';
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
goto('/login', { replaceState: true });
|
||||
return;
|
||||
}
|
||||
@@ -507,6 +508,7 @@ import { SvelteMap } from 'svelte/reactivity';
|
||||
<p class="mb-6 text-sm text-gray-500">{errorMessage}</p>
|
||||
<div class="flex gap-3">
|
||||
<Button onclick={fetchGdprData}>Try Again</Button>
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
<Button onclick={() => goto('/account')} variant="outline">Back to Account</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -514,6 +516,7 @@ import { SvelteMap } from 'svelte/reactivity';
|
||||
<div class="print-area">
|
||||
<div class="mb-6 flex flex-col items-start justify-between gap-4 sm:flex-row sm:items-center">
|
||||
<div>
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
<button
|
||||
onclick={() => goto('/account')}
|
||||
class="mb-2 inline-flex items-center gap-1 text-sm text-gray-500 hover:text-gray-900"
|
||||
|
||||
@@ -562,14 +562,14 @@
|
||||
href="/terms"
|
||||
class="font-semibold text-primary hover:underline"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">Terms & Conditions</a
|
||||
rel="noopener noreferrer external">Terms & Conditions</a
|
||||
>
|
||||
and
|
||||
<a
|
||||
href="/privacy"
|
||||
class="font-semibold text-primary hover:underline"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">Privacy Policy</a
|
||||
rel="noopener noreferrer external">Privacy Policy</a
|
||||
>
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
@@ -206,12 +206,14 @@
|
||||
|
||||
if (!authStore.isAuthenticated) {
|
||||
pageState = 'unauthorized';
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
goto('/login', { replaceState: true });
|
||||
return;
|
||||
}
|
||||
|
||||
if (authStore.currentUser?.role === 'admin') {
|
||||
pageState = 'admin';
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
goto('/admin', { replaceState: true });
|
||||
return;
|
||||
}
|
||||
@@ -248,6 +250,7 @@
|
||||
<Card.Content>
|
||||
<p class="text-gray-600">{error}</p>
|
||||
<div class="mt-4 flex flex-col gap-2 sm:flex-row">
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
<Button class="w-full sm:w-auto" onclick={() => goto('/')}>Go Home</Button>
|
||||
<Button variant="outline" class="w-full sm:w-auto" onclick={fetchBookingData}>
|
||||
Try Again
|
||||
@@ -279,6 +282,7 @@
|
||||
</div>
|
||||
<h2 class="text-xl font-semibold text-gray-900">Thank you!</h2>
|
||||
<p class="mt-2 text-gray-600">Your generosity is greatly appreciated.</p>
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
<Button class="mt-6" onclick={() => goto('/')}>Go Home</Button>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
|
||||
@@ -482,6 +482,7 @@
|
||||
const timestamp = filename.replace(/_full|_thumb|\.[^.]+$/g, '') || images[index].id;
|
||||
const url = new URL(page.url);
|
||||
url.searchParams.set('img', timestamp);
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
goto(url.pathname + url.search, { replaceState: true, noScroll: true });
|
||||
}
|
||||
|
||||
@@ -588,6 +589,7 @@
|
||||
|
||||
const url = new URL(page.url);
|
||||
url.searchParams.set('img', timestamp);
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
goto(url.pathname + url.search, { replaceState: true, noScroll: true });
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
@@ -677,6 +679,7 @@
|
||||
// Remove img param from URL
|
||||
const url = new URL(page.url);
|
||||
url.searchParams.delete('img');
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
goto(url.pathname + url.search, { replaceState: true, noScroll: true });
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
}
|
||||
if (!authStore.isAuthenticated) {
|
||||
pageState = 'unauthorized';
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
goto('/login', { replaceState: true });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -170,12 +170,14 @@
|
||||
|
||||
if (!authStore.isAuthenticated) {
|
||||
pageState = 'unauthorized';
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
goto('/login', { replaceState: true });
|
||||
return;
|
||||
}
|
||||
|
||||
if (authStore.currentUser?.role === 'admin') {
|
||||
pageState = 'admin';
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
goto('/admin', { replaceState: true });
|
||||
return;
|
||||
}
|
||||
@@ -274,6 +276,7 @@
|
||||
<Card.Content>
|
||||
<p class="text-gray-600">{error}</p>
|
||||
<div class="mt-4 flex flex-col gap-2 sm:flex-row">
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
<Button class="w-full sm:w-auto" onclick={() => goto('/')}>Go Home</Button>
|
||||
<Button variant="outline" class="w-full sm:w-auto" onclick={fetchMostRecentBooking}>
|
||||
Try Again
|
||||
@@ -305,6 +308,7 @@
|
||||
</div>
|
||||
<h2 class="text-xl font-semibold text-gray-900">Thank you!</h2>
|
||||
<p class="mt-2 text-gray-600">Your generosity is greatly appreciated.</p>
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
<Button class="mt-6" onclick={() => goto('/')}>Go Home</Button>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
|
||||
@@ -30,12 +30,14 @@
|
||||
|
||||
if (!authStore.isAuthenticated) {
|
||||
pageState = 'unauthorized';
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
goto('/login', { replaceState: true });
|
||||
return;
|
||||
}
|
||||
|
||||
if (authStore.currentUser?.role !== 'admin') {
|
||||
pageState = 'unauthorized';
|
||||
<!-- svelte-ignore no-navigation-without-resolve -->
|
||||
goto('/', { replaceState: true });
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user