Making the navbars into components
This commit is contained in:
0
src/lib/components/util/navbarFoot.svelte
Normal file
0
src/lib/components/util/navbarFoot.svelte
Normal file
73
src/lib/components/util/navbarSide.svelte
Normal file
73
src/lib/components/util/navbarSide.svelte
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<script context="module" lang="ts">
|
||||||
|
export interface NavTab {
|
||||||
|
pathname: string
|
||||||
|
name: string
|
||||||
|
icon: string
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export let navTabs: NavTab[]
|
||||||
|
export let currentPathname: string
|
||||||
|
export let transitionTime: number = 200
|
||||||
|
|
||||||
|
import { fade } from 'svelte/transition'
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
type PageTransitionDirection = 'up' | 'down'
|
||||||
|
let direction: PageTransitionDirection = 'down'
|
||||||
|
|
||||||
|
const calculateDirection = (newPage: string, currentPage: string): void => {
|
||||||
|
const newPageIndex = navTabs.findIndex((tab) => tab.pathname === newPage)
|
||||||
|
const currentPageIndex = navTabs.findIndex((tab) => tab.pathname === currentPage)
|
||||||
|
newPageIndex > currentPageIndex ? (direction = 'down') : (direction = 'up')
|
||||||
|
}
|
||||||
|
|
||||||
|
let activeTab: HTMLButtonElement, indicatorBar: HTMLDivElement, tabList: HTMLDivElement
|
||||||
|
$: calculateBar(activeTab)
|
||||||
|
|
||||||
|
const calculateBar = (activeTab: HTMLButtonElement) => {
|
||||||
|
if (activeTab && indicatorBar && tabList) {
|
||||||
|
const listRect = tabList.getBoundingClientRect()
|
||||||
|
const tabRec = activeTab.getBoundingClientRect()
|
||||||
|
if (direction === 'down') {
|
||||||
|
indicatorBar.style.bottom = `${listRect.bottom - tabRec.bottom}px`
|
||||||
|
setTimeout(() => (indicatorBar.style.top = `${tabRec.top - listRect.top}px`), transitionTime)
|
||||||
|
} else {
|
||||||
|
indicatorBar.style.top = `${tabRec.top - listRect.top}px`
|
||||||
|
setTimeout(() => (indicatorBar.style.bottom = `${listRect.bottom - tabRec.bottom}px`), transitionTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="relative flex h-full flex-col gap-6 rounded-lg px-3 py-12" bind:this={tabList}>
|
||||||
|
{#each navTabs as tabData}
|
||||||
|
{#if currentPathname === tabData.pathname}
|
||||||
|
<button bind:this={activeTab} class="pointer-events-none grid aspect-square w-14 place-items-center text-white transition-colors" disabled>
|
||||||
|
<span class="flex flex-col gap-2 text-xs">
|
||||||
|
<i class="{tabData.icon} text-xl" />
|
||||||
|
{tabData.name}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
{:else}
|
||||||
|
<button
|
||||||
|
class="grid aspect-square w-14 place-items-center text-neutral-400 transition-colors hover:text-lazuli-primary"
|
||||||
|
on:click={() => {
|
||||||
|
calculateDirection(tabData.pathname, currentPathname)
|
||||||
|
dispatch('navigate', { direction, pathname: tabData.pathname })
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span class="flex flex-col gap-2 text-xs">
|
||||||
|
<i class="{tabData.icon} text-xl" />
|
||||||
|
{tabData.name}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
{#if navTabs.some((tab) => tab.pathname === currentPathname)}
|
||||||
|
<div bind:this={indicatorBar} transition:fade class="absolute left-0 w-[0.2rem] rounded-full bg-white transition-all duration-300 ease-in-out" />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
@@ -1,38 +1,143 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { fly, fade } from "svelte/transition";
|
import { fly, fade } from 'svelte/transition'
|
||||||
import { goto } from "$app/navigation";
|
import { goto } from '$app/navigation'
|
||||||
import { pageWidth } from "$lib/stores";
|
import { pageWidth } from '$lib/stores'
|
||||||
import type { LayoutServerData } from "../$types.js";
|
import type { LayoutServerData } from '../$types'
|
||||||
|
import NavbarSide, { type NavTab } from '$lib/components/util/navbarSide.svelte'
|
||||||
|
|
||||||
export let data: LayoutServerData
|
export let data: LayoutServerData
|
||||||
|
|
||||||
const contentTabs = {
|
const contentTabs: NavTab[] = [
|
||||||
'/': {
|
{
|
||||||
header: 'Home',
|
pathname: '/',
|
||||||
|
name: 'Home',
|
||||||
icon: 'fa-solid fa-house',
|
icon: 'fa-solid fa-house',
|
||||||
},
|
},
|
||||||
'/account': {
|
{
|
||||||
header: data.user.username,
|
pathname: '/user',
|
||||||
icon: 'fa-solid fa-user',
|
name: 'User',
|
||||||
|
icon: 'fa-solid fa-user', // This would be a cool spot for a user-uploaded pfp
|
||||||
},
|
},
|
||||||
'/search': {
|
{
|
||||||
header: 'Search',
|
pathname: '/search',
|
||||||
|
name: 'Search',
|
||||||
icon: 'fa-solid fa-search',
|
icon: 'fa-solid fa-search',
|
||||||
},
|
},
|
||||||
'/library': {
|
{
|
||||||
header: 'Libray',
|
pathname: '/library',
|
||||||
|
name: 'Libray',
|
||||||
icon: 'fa-solid fa-bars-staggered',
|
icon: 'fa-solid fa-bars-staggered',
|
||||||
},
|
},
|
||||||
}
|
]
|
||||||
|
|
||||||
const pageTransitionTime: number = 200
|
const pageTransitionTime: number = 200
|
||||||
|
|
||||||
let previousPage = data.urlPathname
|
|
||||||
type PageTransitionDirection = 1 | -1
|
type PageTransitionDirection = 1 | -1
|
||||||
let direction: PageTransitionDirection = 1
|
let direction: PageTransitionDirection = 1
|
||||||
|
// $: calculateDirection(data.urlPathname)
|
||||||
|
|
||||||
const calculateDirection = (newPage: string): void => {
|
// const calculateDirection = (newPage: string): void => {
|
||||||
const contentLinks = Object.keys(contentTabs)
|
// const newPageIndex = contentTabs.findIndex((tab) => tab.pathname === newPage)
|
||||||
const newPageIndex = contentLinks.indexOf(newPage)
|
// const previousPageIndex = contentTabs.findIndex((tab) => tab.pathname === previousPage)
|
||||||
}
|
// newPageIndex > previousPageIndex ? (direction = 1) : (direction = -1)
|
||||||
|
// previousPage = data.urlPathname
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let activeTab: HTMLButtonElement, indicatorBar: HTMLDivElement, tabList: HTMLDivElement
|
||||||
|
// $: calculateBar(activeTab)
|
||||||
|
|
||||||
|
// const calculateBar = (activeTab: HTMLButtonElement) => {
|
||||||
|
// if (activeTab && indicatorBar && tabList) {
|
||||||
|
// if ($pageWidth >= 768) {
|
||||||
|
// const listRect = tabList.getBoundingClientRect()
|
||||||
|
// const tabRec = activeTab.getBoundingClientRect()
|
||||||
|
// if (direction === 1) {
|
||||||
|
// indicatorBar.style.bottom = `${listRect.bottom - tabRec.bottom}px`
|
||||||
|
// setTimeout(() => (indicatorBar.style.top = `${tabRec.top - listRect.top}px`), pageTransitionTime)
|
||||||
|
// } else {
|
||||||
|
// indicatorBar.style.top = `${tabRec.top - listRect.top}px`
|
||||||
|
// setTimeout(() => (indicatorBar.style.bottom = `${listRect.bottom - tabRec.bottom}px`), pageTransitionTime)
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// const listRect = tabList.getBoundingClientRect()
|
||||||
|
// const tabRec = activeTab.getBoundingClientRect()
|
||||||
|
// if (direction === 1) {
|
||||||
|
// indicatorBar.style.right = `${listRect.right - tabRec.right}px`
|
||||||
|
// setTimeout(() => (indicatorBar.style.left = `${tabRec.left - listRect.left}px`), pageTransitionTime)
|
||||||
|
// } else {
|
||||||
|
// indicatorBar.style.left = `${tabRec.left - listRect.left}px`
|
||||||
|
// setTimeout(() => (indicatorBar.style.right = `${listRect.right - tabRec.right}px`), pageTransitionTime)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<!-- {#if $pageWidth >= 768} -->
|
||||||
|
<div id="content-grid" class="h-full overflow-hidden">
|
||||||
|
<NavbarSide
|
||||||
|
navTabs={contentTabs}
|
||||||
|
currentPathname={data.urlPathname}
|
||||||
|
transitionTime={pageTransitionTime}
|
||||||
|
on:navigate={(event) => {
|
||||||
|
event.detail.direction === 'up' ? (direction = 1) : (direction = -1)
|
||||||
|
goto(event.detail.pathname)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<section class="no-scrollbar relative overflow-y-scroll">
|
||||||
|
{#key data.urlPathname}
|
||||||
|
<div in:fly={{ y: -50 * direction, duration: pageTransitionTime, delay: pageTransitionTime }} out:fly={{ y: 50 * direction, duration: pageTransitionTime }} class="absolute w-full pr-[5vw] pt-16">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
{/key}
|
||||||
|
</section>
|
||||||
|
<footer class="fixed bottom-0 flex w-full flex-col items-center justify-center">
|
||||||
|
<!-- <MiniPlayer displayMode={'horizontal'} /> -->
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- {:else}
|
||||||
|
<div class="h-full overflow-hidden">
|
||||||
|
{#key data.urlPathname}
|
||||||
|
<section
|
||||||
|
in:fly={{ x: 200 * direction, duration: pageTransitionTime, delay: pageTransitionTime }}
|
||||||
|
out:fly={{ x: -200 * direction, duration: pageTransitionTime }}
|
||||||
|
class="no-scrollbar h-full overflow-y-scroll px-[5vw] pt-16"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</section>
|
||||||
|
{/key}
|
||||||
|
<footer class="fixed bottom-0 flex w-full flex-col items-center justify-center">
|
||||||
|
<MiniPlayer displayMode={'vertical'} />
|
||||||
|
<div bind:this={tabList} id="bottom-tab-list" class="relative flex w-full items-center justify-around bg-black">
|
||||||
|
{#each contentTabs as tabData}
|
||||||
|
{#if data.urlPathname === tabData.pathname}
|
||||||
|
<button bind:this={activeTab} class="pointer-events-none text-white transition-colors" disabled>
|
||||||
|
<i class={tabData.icon} />
|
||||||
|
</button>
|
||||||
|
{:else}
|
||||||
|
<button class="text-neutral-400 transition-colors hover:text-lazuli-primary" on:click={() => goto(tabData.pathname)}>
|
||||||
|
<i class={tabData.icon} />
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
{#if contentTabs.some((tab) => tab.pathname === data.urlPathname)}
|
||||||
|
<div bind:this={indicatorBar} transition:fade class="absolute bottom-0 h-1 rounded-full bg-white transition-all duration-300 ease-in-out" />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
{/if} -->
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#content-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: max-content auto;
|
||||||
|
grid-template-rows: 100%;
|
||||||
|
}
|
||||||
|
#bottom-tab-list {
|
||||||
|
padding: 16px 0px;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 28px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
1
src/routes/(app)/library/+page.svelte
Normal file
1
src/routes/(app)/library/+page.svelte
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<h1>Welcome to the library page!</h1>
|
||||||
1
src/routes/(app)/search/+page.svelte
Normal file
1
src/routes/(app)/search/+page.svelte
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<h1>Welcome to the Search Page!</h1>
|
||||||
1
src/routes/(app)/user/+page.svelte
Normal file
1
src/routes/(app)/user/+page.svelte
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<h1>Welcome to the User Page!</h1>
|
||||||
Reference in New Issue
Block a user