mirror of
https://github.com/jcreek/SvelteKitSaasBoilerplate.git
synced 2026-07-13 02:53:50 +00:00
feat(#35): make basket more prominent in nav
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
import { signOut } from '$lib/utils/supabase/auth';
|
||||||
|
import type { SupabaseClient } from '@supabase/supabase-js';
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
function emitSignedOutEvent() {
|
function emitSignedOutEvent() {
|
||||||
@@ -7,14 +9,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Access the supabase client from the layout data
|
// Access the supabase client from the layout data
|
||||||
export let supabase: any;
|
export let supabase: SupabaseClient | null;
|
||||||
|
|
||||||
async function signOut() {
|
async function signOutClick() {
|
||||||
// TODO use the error from the response
|
if (!supabase) return;
|
||||||
const { error } = await supabase.auth.signOut().then(() => {
|
await signOut(supabase, emitSignedOutEvent);
|
||||||
emitSignedOutEvent();
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<button on:click={signOut}>Sign Out</button>
|
<button on:click={signOutClick}>Sign Out</button>
|
||||||
|
|||||||
@@ -44,17 +44,17 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<!-- Dropdown content -->
|
<!-- Dropdown content -->
|
||||||
<NavLinks isMobile />
|
<NavLinks isMobile {session} {supabase} />
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</div>
|
</div>
|
||||||
<a href="/" class="text-white font-bold text-xl">SvelteKit SaaS Boilerplate</a>
|
<a href="/" class="text-white font-bold text-xl">SvelteKit SaaS Boilerplate</a>
|
||||||
<div class="hidden lg:block">
|
<div class="hidden lg:block">
|
||||||
<NavLinks />
|
<NavLinks {session} />
|
||||||
</div>
|
</div>
|
||||||
<!-- Right Side: Basket & User Account -->
|
<!-- Right Side: Basket & User Account -->
|
||||||
<div class="flex items-center space-x-4">
|
<div class="flex items-center space-x-4">
|
||||||
<!-- Basket/Checkout Icon -->
|
<!-- Basket/Checkout Icon -->
|
||||||
<a href="/checkout" class="btn btn-ghost btn-circle hidden lg:flex">
|
<a href="/checkout" class="btn btn-ghost btn-circle">
|
||||||
<div class="indicator">
|
<div class="indicator">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
<!-- User Account Dropdown -->
|
<!-- User Account Dropdown -->
|
||||||
<Dropdown posRight>
|
<Dropdown posRight>
|
||||||
<div slot="dropdown">
|
<div slot="dropdown">
|
||||||
<div class="btn btn-ghost btn-circle avatar placeholder">
|
<div class="btn btn-ghost btn-circle avatar placeholder hidden md:flex">
|
||||||
<div class="w-10 rounded-full">
|
<div class="w-10 rounded-full">
|
||||||
{#if session?.user}
|
{#if session?.user}
|
||||||
<div class="user-circle text-primary-content border-primary-content">
|
<div class="user-circle text-primary-content border-primary-content">
|
||||||
@@ -100,32 +100,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- Dropdown content -->
|
<!-- Dropdown content -->
|
||||||
{#if session?.user}
|
{#if session?.user}
|
||||||
<li class="lg:hidden">
|
|
||||||
<a href="/checkout">
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
class="h-5 w-5"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke="currentColor"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
Basket
|
|
||||||
{#if localBasket.items.length > 0}
|
|
||||||
<span class="badge badge-md indicator-item bg-primary text-primary-content"
|
|
||||||
>{localBasket.items.length}</span
|
|
||||||
>
|
|
||||||
{/if}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li><a href="/account">Account</a></li>
|
<li><a href="/account">Account</a></li>
|
||||||
<li><a href="/settings">Settings</a></li>
|
|
||||||
<li><SignOut {supabase} /></li>
|
<li><SignOut {supabase} /></li>
|
||||||
{:else}
|
{:else}
|
||||||
<MagicLink {supabase} />
|
<MagicLink {supabase} />
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { NavLinkItem } from "$lib/types/Nav/NavLinkItem";
|
||||||
|
import type { SupabaseClient } from "@supabase/supabase-js";
|
||||||
|
import SignOut from "../SignOut.svelte";
|
||||||
|
|
||||||
|
export let linkItem: NavLinkItem;
|
||||||
|
export let supabase: SupabaseClient | null = null;
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if !linkItem.isSignout}
|
||||||
|
<a href={linkItem.href}>{linkItem.text}</a>
|
||||||
|
{:else if supabase && linkItem.isSignout}
|
||||||
|
<SignOut {supabase} />
|
||||||
|
{/if}
|
||||||
@@ -3,19 +3,22 @@
|
|||||||
import { cubicInOut } from 'svelte/easing';
|
import { cubicInOut } from 'svelte/easing';
|
||||||
import Dropdown from '../Dropdown.svelte';
|
import Dropdown from '../Dropdown.svelte';
|
||||||
import { slide } from 'svelte/transition';
|
import { slide } from 'svelte/transition';
|
||||||
|
import NavLink from './NavLink.svelte';
|
||||||
|
import type { SupabaseClient } from '@supabase/supabase-js';
|
||||||
|
|
||||||
export let text: string;
|
export let linkItem: NavLinkItem;
|
||||||
export let children: NavLinkItem[] | undefined;
|
|
||||||
export let isMobile: boolean;
|
export let isMobile: boolean;
|
||||||
|
export let supabase: SupabaseClient | null;
|
||||||
|
|
||||||
|
|
||||||
let isOpen = false;
|
let isOpen = false;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if !isMobile}
|
{#if !isMobile}
|
||||||
<Dropdown indicator>
|
<Dropdown indicator>
|
||||||
<div slot="dropdown">{text}</div>
|
<div slot="dropdown">{linkItem.text}</div>
|
||||||
{#each children ?? [] as child}
|
{#each linkItem.children ?? [] as child}
|
||||||
<li><a href={child.href}>{child.text}</a></li>
|
<li><NavLink linkItem={child} /></li>
|
||||||
{/each}
|
{/each}
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
{:else}
|
{:else}
|
||||||
@@ -24,15 +27,15 @@
|
|||||||
class="menu-dropdown-toggle"
|
class="menu-dropdown-toggle"
|
||||||
on:click={() => (isOpen = !isOpen)}
|
on:click={() => (isOpen = !isOpen)}
|
||||||
>
|
>
|
||||||
{text}
|
{linkItem.text}
|
||||||
</button>
|
</button>
|
||||||
{#if isOpen}
|
{#if isOpen}
|
||||||
<ul
|
<ul
|
||||||
class="menu-dropdown menu-dropdown-show"
|
class="menu-dropdown menu-dropdown-show"
|
||||||
transition:slide={{ duration: 200, easing: cubicInOut }}
|
transition:slide={{ duration: 200, easing: cubicInOut }}
|
||||||
>
|
>
|
||||||
{#each children ?? [] as child}
|
{#each linkItem.children ?? [] as child}
|
||||||
<li><a href={child.href}>{child.text}</a></li>
|
<li><NavLink linkItem={child} {supabase} /></li>
|
||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</ul>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -1,10 +1,46 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { type NavLinkItem } from '$lib/types/Nav/NavLinkItem';
|
import { type NavLinkItem } from '$lib/types/Nav/NavLinkItem';
|
||||||
|
import type { Session } from '@supabase/supabase-js';
|
||||||
import NavLinkParent from './NavLinkParent.svelte';
|
import NavLinkParent from './NavLinkParent.svelte';
|
||||||
|
import type SupabaseClient from '@supabase/supabase-js/dist/module/SupabaseClient';
|
||||||
|
|
||||||
|
export let session: Session | null;
|
||||||
|
export let supabase: SupabaseClient | null = null;
|
||||||
export let isMobile = false;
|
export let isMobile = false;
|
||||||
|
|
||||||
|
const userAccountLinks: NavLinkItem[] = [];
|
||||||
|
|
||||||
|
if (isMobile) {
|
||||||
|
if (session) {
|
||||||
|
userAccountLinks.push(
|
||||||
|
{
|
||||||
|
text: 'User', // TODO - replace with user's name - will require a database call to get the user's name - suggest setting up a user model to store user data.
|
||||||
|
isParent: true,
|
||||||
|
isUserAccount: true,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: 'Account',
|
||||||
|
href: '/account'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Sign Out',
|
||||||
|
isSignout: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
userAccountLinks.push(
|
||||||
|
{
|
||||||
|
text: 'Log in',
|
||||||
|
href: '/login'
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const links: NavLinkItem[] = [
|
const links: NavLinkItem[] = [
|
||||||
|
...userAccountLinks,
|
||||||
{
|
{
|
||||||
text: 'Products',
|
text: 'Products',
|
||||||
href: '/products'
|
href: '/products'
|
||||||
@@ -32,9 +68,9 @@
|
|||||||
|
|
||||||
<ul class:flex={!isMobile} class:space-x-4={!isMobile}>
|
<ul class:flex={!isMobile} class:space-x-4={!isMobile}>
|
||||||
{#each links as link}
|
{#each links as link}
|
||||||
<li>
|
<li class:md:hidden={link.isUserAccount}>
|
||||||
{#if link.isParent}
|
{#if link.isParent}
|
||||||
<NavLinkParent text={link.text} children={link.children} {isMobile} />
|
<NavLinkParent linkItem={link} {isMobile} {supabase} />
|
||||||
{:else}
|
{:else}
|
||||||
<a href={link.href}>{link.text}</a>
|
<a href={link.href}>{link.text}</a>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -3,4 +3,6 @@ export interface NavLinkItem {
|
|||||||
href?: string;
|
href?: string;
|
||||||
isParent?: boolean;
|
isParent?: boolean;
|
||||||
children?: NavLinkItem[];
|
children?: NavLinkItem[];
|
||||||
|
isSignout?: boolean;
|
||||||
|
isUserAccount?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import type { SupabaseClient } from "@supabase/supabase-js";
|
||||||
|
|
||||||
|
export async function signOut(supabase: SupabaseClient, callback: () => void) {
|
||||||
|
// TODO use the error from the response
|
||||||
|
const { error } = await supabase.auth.signOut().then(callback);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user