Merge pull request 'feat: Sticky navbar' (#30) from component/navbar into main

Reviewed-on: #30
This commit is contained in:
Leni Aniva 2025-01-25 16:09:00 -08:00
commit c2362e26ef
2 changed files with 94 additions and 25 deletions

View File

@ -1,6 +1,7 @@
<script lang="ts"> <script lang="ts">
import '../app.css'; import '../app.css';
import { page } from '$app/stores'; import { page } from '$app/stores';
import { name } from '$content/metadata.json';
import Footer from "./Footer.svelte"; import Footer from "./Footer.svelte";
import Navbar from "./Navbar.svelte"; import Navbar from "./Navbar.svelte";
import PageTransition from "./PageTransition.svelte"; import PageTransition from "./PageTransition.svelte";
@ -11,7 +12,8 @@
<!-- Homepage has its own navbar with animations --> <!-- Homepage has its own navbar with animations -->
{#if $page.url.pathname != "/"} {#if $page.url.pathname != "/"}
<div id="layout"> <div id="layout">
<div id="navbar"> <div id="nav">
<p id="bio-name">{name}</p>
<Navbar /> <Navbar />
<slot name="header" /> <slot name="header" />
</div> </div>
@ -31,6 +33,12 @@
{/if} {/if}
<style> <style>
#bio-name {
font-family: serif;
font-size: 3rem;
font-weight: normal;
color: var(--name);
}
#layout { #layout {
max-width: max(80vw, 100vh); max-width: max(80vw, 100vh);
margin-left: auto; margin-left: auto;
@ -58,7 +66,7 @@
width: min(100vw, max(50vw, 100vh)); width: min(100vw, max(50vw, 100vh));
grid-area: content; grid-area: content;
} }
#navbar { #nav {
align-self: right; align-self: right;
padding-left: 10px; padding-left: 10px;
grid-area: nav; grid-area: nav;

View File

@ -1,43 +1,95 @@
<script lang="ts"> <script lang="ts">
import { page } from '$app/stores'; import { page } from '$app/stores';
import { routes } from "$lib/sitemap.ts" import { routes } from "$lib/sitemap.ts"
import { name } from '$content/metadata.json';
import ThemeSwitch from "$lib/components/ThemeSwitch.svelte" import ThemeSwitch from "$lib/components/ThemeSwitch.svelte"
import { Rss } from "lucide-svelte"; import { Rss, Menu } from "lucide-svelte";
function isCurrentLink(pathname, route) { function isCurrentLink(pathname, route) {
return route != "/" && pathname.startsWith(route) return route != "/" && pathname.startsWith(route)
|| route == "/post" && pathname.startsWith("/page"); || route == "/post" && pathname.startsWith("/page");
} }
import { onMount } from 'svelte';
let showDropdown = false;
function onDropdownToggle(event) {
showDropdown = !showDropdown;
}
function onKeyDown(event) {
if (event.key == "Escape") {
showDropdown = !showDropdown;
}
}
</script> </script>
<div id="navbar" class="h-5 space-x-4"> <nav
<p id="bio-name">{name}</p> id="navbar"
class="h-5 space-x-4"
class:dropdown-opened={showDropdown}>
<div
class="link-container"
role="button"
tabindex={0}
on:keydown={onKeyDown}
on:click={() => { showDropdown = false; }}
>
{#each routes as item} {#each routes as item}
<a <a
class="nav-link" class="nav-link"
class:disabled-link={item.disabled} class:disabled-link={item.disabled}
class:current-link={isCurrentLink($page.url.pathname, item.route)} class:current-link={isCurrentLink($page.url.pathname, item.route)}
href={item.route}>{item.name}</a> on:click={() => { showDropdown = false; }}
href={item.route}>
{item.name}
</a>
{/each} {/each}
<a class="nav-link icon" href="/rss.xml"><Rss /></a> <a class="nav-link icon" href="/rss.xml"><Rss /></a>
<div><ThemeSwitch /></div> <div><ThemeSwitch /></div>
</div> </div>
<button
id="dropdown-toggle"
aria-hidden="true"
on:click={onDropdownToggle}>
<Menu />
</button>
</nav>
<svelte:window on:keydown={onKeyDown} />
<style> <style>
#bio-name { .link-container {
font-family: serif;
font-size: 3rem;
font-weight: normal;
color: var(--name);
}
#navbar {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: flex-end; align-items: flex-end;
justify-content: between; position: sticky;
top: 0;
}
#dropdown-toggle {
display: none;
}
/* mobile mode */
@media (max-width: 768px) {
.link-container {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 100vh;
justify-content: center;
margin: 0;
padding-left: 5vw;
padding-right: 5vw;
background: hsl(var(--background) / .8);
/* Initial hidden state */
opacity: 0;
transform: translateY(-100%);
transition: transform 0.2s, opacity 0.2s;
} }
@media (max-width: 700px) {
#navbar { #navbar {
display: inline-block; display: inline-block;
white-space: pre-wrap; white-space: pre-wrap;
@ -45,5 +97,14 @@
#navbar .nav-link { #navbar .nav-link {
display: inline-block; display: inline-block;
} }
#dropdown-toggle {
display: initial;
z-index: 5;
}
.dropdown-opened > .link-container {
opacity: 1;
z-index: 1;
transform: translateY(0);
}
} }
</style> </style>