329 lines
7.5 KiB
Plaintext
329 lines
7.5 KiB
Plaintext
---
|
|
import BaseLayout from './BaseLayout.astro'
|
|
import { Icon } from 'astro-icon/components'
|
|
|
|
interface Props {
|
|
title?: string
|
|
withGap?: boolean
|
|
}
|
|
|
|
const { title = '小帕的小窝', withGap = false } = Astro.props
|
|
---
|
|
|
|
<BaseLayout title={title}>
|
|
<div class="nav-mobile" aria-hidden="true" transition:persist>
|
|
<button
|
|
id="nav-mobile-button"
|
|
onclick="document.getElementById('nav-main').classList.remove('nav-container-hidden')"
|
|
><Icon name="mdi:menu-close" /></button
|
|
>
|
|
<a href="/">小帕的小窝</a>
|
|
</div>
|
|
<div
|
|
id="nav-main"
|
|
class="nav-container nav-container-hidden"
|
|
transition:persist
|
|
>
|
|
<nav>
|
|
<ul class="left">
|
|
<li class="website-logo">
|
|
<a href="/">小帕的小窝</a>
|
|
</li>
|
|
<li>
|
|
<a href="/blogs"><Icon name="mdi:invoice-text-outline" />文章</a>
|
|
</li>
|
|
<li>
|
|
<a href="/about"
|
|
><Icon name="mdi:information-slab-circle-outline" />关于</a
|
|
>
|
|
</li>
|
|
</ul>
|
|
<ul class="right">
|
|
<li>
|
|
<a href="https://legacy.passthem.top"
|
|
><Icon name="mdi:history" /> 旧博客系统*</a
|
|
>
|
|
</li>
|
|
<li>
|
|
<a href="/rss.xml">
|
|
<Icon name="material-symbols:rss-feed" /> 博客 RSS
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
<div
|
|
class="loading-indicator hidden"
|
|
id="loading-indicator"
|
|
aria-hidden="true"
|
|
transition:persist
|
|
>
|
|
</div>
|
|
<main>
|
|
{withGap && <div aria-hidden="true" class="layout-gap" />}
|
|
<slot />
|
|
</main>
|
|
</BaseLayout>
|
|
|
|
<script>
|
|
const navClose = () => {
|
|
const navMain = document.getElementById('nav-main')
|
|
navMain?.classList.add('nav-container-hidden')
|
|
}
|
|
|
|
const navOpen = () => {
|
|
const navMain = document.getElementById('nav-main')
|
|
navMain?.classList.remove('nav-container-hidden')
|
|
}
|
|
|
|
document.getElementById('nav-main')?.addEventListener('click', (e) => {
|
|
const target = e.target as HTMLElement
|
|
if (target.id == 'nav-main') {
|
|
document.getElementById('nav-main')?.classList.add('nav-container-hidden')
|
|
}
|
|
})
|
|
|
|
document.getElementById('nav-main')?.addEventListener('focusin', navOpen)
|
|
document.getElementById('nav-main')?.addEventListener('focusout', (e) => {
|
|
if (
|
|
e.relatedTarget &&
|
|
!document
|
|
.getElementById('nav-main')
|
|
?.contains(e.relatedTarget as HTMLElement)
|
|
) {
|
|
navClose()
|
|
}
|
|
})
|
|
|
|
document.addEventListener('astro:before-preparation', () => {
|
|
document.getElementById('loading-indicator')?.classList.remove('hidden')
|
|
})
|
|
|
|
document.addEventListener('astro:after-swap', () => {
|
|
requestAnimationFrame(navClose)
|
|
document.getElementById('loading-indicator')?.classList.add('hidden')
|
|
})
|
|
|
|
document.addEventListener('astro:page-load', () => {
|
|
document.querySelectorAll('#nav-main li:has(a)').forEach((li) => {
|
|
const child = li.querySelector('a')
|
|
if (!child) {
|
|
li.classList.add('url-here')
|
|
return
|
|
}
|
|
if (
|
|
window.location.href.replace(/\/$/, '') == child.href.replace(/\/$/, '')
|
|
) {
|
|
li.classList.add('url-here')
|
|
} else {
|
|
li.classList.remove('url-here')
|
|
}
|
|
})
|
|
})
|
|
</script>
|
|
|
|
<style>
|
|
.nav-container {
|
|
inline-size: 100dvi;
|
|
block-size: 3rem;
|
|
position: fixed;
|
|
z-index: 10000;
|
|
backdrop-filter: blur(4px);
|
|
background-color: rgb(from var(--color-bg-n) r g b / 0.5);
|
|
|
|
@media (width < 768px) {
|
|
block-size: 100dvh;
|
|
background-color: #00000033;
|
|
transition:
|
|
background-color ease 0.2s,
|
|
backdrop-filter ease 0.2s;
|
|
}
|
|
|
|
&.nav-container-hidden {
|
|
@media (width < 768px) {
|
|
backdrop-filter: blur(0px);
|
|
background-color: transparent;
|
|
pointer-events: none;
|
|
}
|
|
}
|
|
|
|
& > nav {
|
|
inline-size: 100%;
|
|
block-size: 100%;
|
|
padding-inline: 40px;
|
|
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
max-inline-size: 1400px;
|
|
margin-inline: auto;
|
|
|
|
font-weight: 400;
|
|
|
|
@media (width < 768px) {
|
|
flex-direction: column;
|
|
padding-block: 5rem;
|
|
padding-inline: 2rem;
|
|
align-items: start;
|
|
inline-size: 70%;
|
|
background-color: var(--color-bg-n);
|
|
margin-inline-start: 0;
|
|
font-size: larger;
|
|
transition: transform cubic-bezier(0.4, 1, 0.4, 1) 0.4s;
|
|
}
|
|
|
|
.nav-container-hidden & {
|
|
@media (width < 768px) {
|
|
transform: translateX(-80dvi);
|
|
}
|
|
}
|
|
|
|
& > ul {
|
|
display: flex;
|
|
flex-direction: row;
|
|
|
|
@media (width < 768px) {
|
|
flex-direction: column;
|
|
gap: 0.25rem;
|
|
inline-size: 100%;
|
|
}
|
|
}
|
|
|
|
& li {
|
|
height: 2rem;
|
|
|
|
@media (width < 768px) {
|
|
height: 3rem;
|
|
inline-size: 100%;
|
|
}
|
|
|
|
&:hover {
|
|
background-color: rgb(from var(--color-fg-0) r g b / 0.1);
|
|
}
|
|
|
|
&.url-here {
|
|
color: var(--color-blue);
|
|
background-color: rgb(from var(--color-blue) r g b / 0.1);
|
|
}
|
|
|
|
& > a {
|
|
padding-inline: 0.75rem;
|
|
inline-size: 100%;
|
|
block-size: 100%;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.25rem;
|
|
|
|
& > svg {
|
|
font-size: 1.5rem;
|
|
}
|
|
}
|
|
}
|
|
|
|
& .website-logo > a {
|
|
gap: 0.5rem;
|
|
font-weight: 600;
|
|
|
|
/* & > .logo { */
|
|
/* --size: 2.5rem; */
|
|
/**/
|
|
/* width: var(--size); */
|
|
/* height: var(--size); */
|
|
/* display: inline-block; */
|
|
/* } */
|
|
}
|
|
}
|
|
}
|
|
|
|
.nav-mobile {
|
|
inline-size: 100dvw;
|
|
block-size: 4rem;
|
|
position: fixed;
|
|
z-index: 100;
|
|
backdrop-filter: blur(4px);
|
|
background-color: rgb(from var(--color-bg-n) r g b / 0.5);
|
|
font-size: larger;
|
|
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
padding-inline: 1rem;
|
|
gap: 0.5rem;
|
|
|
|
& > button {
|
|
inline-size: 3rem;
|
|
aspect-ratio: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 2rem;
|
|
cursor: pointer;
|
|
|
|
&:active,
|
|
&:hover {
|
|
background-color: rgb(from var(--color-fg-0) r g b / 0.1);
|
|
}
|
|
}
|
|
|
|
& > a {
|
|
font-weight: 600;
|
|
|
|
&:active,
|
|
&:hover {
|
|
background-color: rgb(from var(--color-fg-0) r g b / 0.1);
|
|
}
|
|
}
|
|
|
|
@media (width >= 768px) {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
.loading-indicator {
|
|
--color1: oklch(from var(--color-blue) 0.7 0.17 h);
|
|
--color2: oklch(from var(--color-blue) 0.57 0.25 h);
|
|
--loading-x-size: 2rem;
|
|
--loading-height: 0.25rem;
|
|
|
|
position: fixed;
|
|
height: var(--loading-height);
|
|
background-color: var(--color1);
|
|
inset-inline-start: 0;
|
|
inset-inline-end: 0;
|
|
inset-block-start: 0;
|
|
z-index: 10001;
|
|
background-image: linear-gradient(
|
|
-45deg,
|
|
transparent 0%,
|
|
transparent 25%,
|
|
var(--color2) 25%,
|
|
var(--color2) 75%,
|
|
transparent 75%,
|
|
transparent 100%
|
|
);
|
|
background-repeat: repeat;
|
|
background-size: 2rem 100%;
|
|
|
|
animation: loading-animation infinite 0.5s linear;
|
|
transition: inset-block-start cubic-bezier(0.4, 1, 0.4, 1) 0.2s;
|
|
|
|
&.hidden {
|
|
inset-block-start: calc(-1 * var(--loading-height));
|
|
}
|
|
}
|
|
|
|
@keyframes loading-animation {
|
|
0% {
|
|
background-position: 0 0;
|
|
}
|
|
100% {
|
|
background-position: var(--loading-x-size) 0;
|
|
}
|
|
}
|
|
|
|
.layout-gap {
|
|
height: var(--size-nav);
|
|
}
|
|
</style>
|