Spaces:
Sleeping
Sleeping
<script lang="ts"> | |
import { page } from "$app/stores"; | |
import { goto } from "$app/navigation"; | |
import { browser } from "$app/environment"; | |
import { defaultNavPage } from "$lib/subnav"; | |
import { t } from "$lib/i18n/translations"; | |
import IconArrowLeft from "@tabler/icons-svelte/IconArrowLeft.svelte"; | |
export let pageName: "settings" | "about"; | |
export let homeNavPath: string; | |
export let homeTitle: string; | |
export let pageSubtitle = ""; | |
export let contentPadding = false; | |
export let wideContent = false; | |
let screenWidth: number; | |
$: currentPageTitle = $page.url.pathname.split("/").at(-1); | |
$: stringPageTitle = | |
currentPageTitle !== pageName | |
? ` / ${$t(`${pageName}.page.${currentPageTitle}`)}` | |
: ""; | |
$: isMobile = screenWidth <= 750; | |
$: isHome = $page.url.pathname === homeNavPath; | |
$: { | |
if (browser && !isMobile && isHome) { | |
goto(defaultNavPage(pageName), { replaceState: true }); | |
} | |
} | |
</script> | |
<svelte:head> | |
<title> | |
{homeTitle}{stringPageTitle} ~ {$t("general.cobalt")} | |
</title> | |
<meta | |
property="og:title" | |
content="{homeTitle}{stringPageTitle} ~ {$t('general.cobalt')}" | |
/> | |
</svelte:head> | |
<svelte:window bind:innerWidth={screenWidth} /> | |
<div id="{pageName}-page" class="subnav-page"> | |
<div class="subnav-sidebar" class:back-visible={!isHome && isMobile}> | |
<div class="subnav-header"> | |
{#if isMobile} | |
{#if !isHome} | |
<a | |
class="back-button" | |
href={homeNavPath} | |
role="button" | |
aria-label={$t("a11y.general.back")} | |
> | |
<IconArrowLeft /> | |
</a> | |
{/if} | |
<h3 | |
class="subnav-page-title" | |
aria-level="1" | |
tabindex="-1" | |
data-first-focus | |
data-focus-ring-hidden | |
> | |
{#if !isHome} | |
{$t(`${pageName}.page.${currentPageTitle}`)} | |
{:else} | |
{homeTitle} | |
{/if} | |
</h3> | |
{:else} | |
{#if pageSubtitle} | |
<div | |
class="subtext subnav-subtitle" | |
class:hidden={pageSubtitle === "\xa0"} | |
> | |
{pageSubtitle} | |
</div> | |
{/if} | |
<h2 class="subnav-page-title" aria-level="1"> | |
{homeTitle} | |
</h2> | |
{/if} | |
</div> | |
<nav | |
class="subnav-navigation" | |
class:visible-mobile={isMobile && isHome} | |
> | |
<slot name="navigation"></slot> | |
{#if isMobile && isHome && pageSubtitle} | |
<div | |
class="subtext subnav-subtitle center" | |
class:hidden={pageSubtitle === "\xa0"} | |
> | |
{pageSubtitle} | |
</div> | |
{/if} | |
</nav> | |
</div> | |
{#if !isMobile || !isHome} | |
<main | |
id="{pageName}-page-content" | |
class="subnav-page-content" | |
class:padding={contentPadding} | |
class:wide={wideContent} | |
tabindex="-1" | |
data-first-focus | |
data-focus-ring-hidden | |
> | |
<slot name="content"></slot> | |
</main> | |
{/if} | |
</div> | |
<style> | |
.subnav-page { | |
--subnav-nav-width: 250px; | |
--subnav-padding: 30px; | |
--subnav-padding-small: calc(var(--subnav-padding) - var(--padding)); | |
display: grid; | |
width: 100%; | |
grid-template-columns: var(--subnav-nav-width) 1fr; | |
overflow: hidden; | |
padding-left: var(--subnav-padding); | |
} | |
.subnav-page:dir(rtl) { | |
padding-left: 0; | |
padding-right: var(--subnav-padding); | |
} | |
.subnav-page-content { | |
display: flex; | |
flex-direction: column; | |
max-width: 600px; | |
padding: calc(var(--subnav-padding) / 2); | |
overflow-y: scroll; | |
} | |
.subnav-page-content.wide { | |
max-width: 700px; | |
} | |
.subnav-page-content.padding { | |
padding: var(--subnav-padding); | |
} | |
.subnav-sidebar, | |
.subnav-navigation { | |
display: flex; | |
flex-direction: column; | |
overflow-y: scroll; | |
} | |
.subnav-sidebar { | |
width: var(--subnav-nav-width); | |
padding-top: var(--subnav-padding); | |
} | |
.subnav-sidebar.back-visible { | |
overflow: visible; | |
} | |
.subnav-sidebar { | |
gap: var(--padding); | |
} | |
.subnav-navigation { | |
gap: var(--padding); | |
padding-bottom: var(--padding); | |
} | |
.subnav-header { | |
--back-padding: calc(var(--padding) / 2); | |
} | |
.subnav-subtitle { | |
padding: 0; | |
transition: opacity 0.1s; | |
} | |
.subnav-subtitle.hidden { | |
opacity: 0; | |
} | |
.subnav-subtitle.center { | |
text-align: center; | |
} | |
.back-button { | |
display: flex; | |
align-items: center; | |
color: var(--secondary); | |
gap: var(--back-padding); | |
padding: var(--back-padding); | |
position: absolute; | |
left: var(--back-padding); | |
} | |
.back-button:active { | |
background: var(--button-hover-transparent); | |
border-radius: var(--border-radius); | |
} | |
.back-button :global(svg) { | |
stroke-width: 1.8px; | |
height: 22px; | |
width: 22px; | |
will-change: transform; | |
} | |
@media screen and (max-width: 750px) { | |
.subnav-page, | |
.subnav-page:dir(rtl) { | |
--subnav-nav-width: 100%; | |
display: flex; | |
flex-direction: column; | |
grid-template-columns: 1fr; | |
padding: 0; | |
} | |
.subnav-navigation { | |
padding: var(--padding); | |
padding-bottom: calc(var(--padding) * 2); | |
display: none; | |
} | |
.subnav-navigation.visible-mobile { | |
display: flex; | |
} | |
.subnav-page-content { | |
padding: var(--padding) 0; | |
padding-top: 0; | |
max-width: unset; | |
} | |
.subnav-page-content.padding { | |
padding: var(--padding); | |
} | |
.subnav-header { | |
display: flex; | |
align-items: center; | |
position: sticky; | |
padding: var(--padding); | |
gap: 4px; | |
justify-content: center; | |
} | |
.subnav-sidebar { | |
gap: 0px; | |
padding: 0; | |
} | |
.subnav-page-title { | |
text-align: center; | |
letter-spacing: -0.3px; | |
font-size: 16.5px; | |
} | |
} | |
</style> | |