mirror of
https://github.com/ChenQihan666/MyBlog-Next.git
synced 2026-08-14 11:29:33 +08:00
build!: upgrade to Tailwind CSS v4
This commit is contained in:
+108
-190
@@ -1,149 +1,138 @@
|
||||
---
|
||||
import { LOGO_IMAGE, SITE } from "@config";
|
||||
import Hr from "./Hr.astro";
|
||||
import IconX from "@/assets/icons/IconX.svg";
|
||||
import IconMoon from "@/assets/icons/IconMoon.svg";
|
||||
import IconSearch from "@/assets/icons/IconSearch.svg";
|
||||
import IconArchive from "@/assets/icons/IconArchive.svg";
|
||||
import IconSunHigh from "@/assets/icons/IconSunHigh.svg";
|
||||
import IconMenuDeep from "@/assets/icons/IconMenuDeep.svg";
|
||||
import LinkButton from "./LinkButton.astro";
|
||||
import { SITE } from "@/config";
|
||||
|
||||
export interface Props {
|
||||
activeNav?: "posts" | "archives" | "tags" | "about" | "search";
|
||||
}
|
||||
const { pathname } = Astro.url;
|
||||
|
||||
const { activeNav } = Astro.props;
|
||||
// Remove trailing slash from current pathname if exists
|
||||
const currentPath =
|
||||
pathname.endsWith("/") && pathname !== "/" ? pathname.slice(0, -1) : pathname;
|
||||
|
||||
const isActive = (path: string) => {
|
||||
const currentPathArray = currentPath.split("/").filter(p => p.trim());
|
||||
const pathArray = path.split("/").filter(p => p.trim());
|
||||
|
||||
return currentPath === path || currentPathArray[0] === pathArray[0];
|
||||
};
|
||||
---
|
||||
|
||||
<header>
|
||||
<a id="skip-to-content" href="#main-content">Skip to content</a>
|
||||
<div class="nav-container">
|
||||
<div class="top-nav-wrap">
|
||||
<a href="/" class="logo whitespace-nowrap">
|
||||
{
|
||||
LOGO_IMAGE.enable ? (
|
||||
<img
|
||||
src={`/assets/${LOGO_IMAGE.svg ? "logo.svg" : "logo.png"}`}
|
||||
alt={SITE.title}
|
||||
width={LOGO_IMAGE.width}
|
||||
height={LOGO_IMAGE.height}
|
||||
/>
|
||||
) : (
|
||||
SITE.title
|
||||
)
|
||||
}
|
||||
<a
|
||||
id="skip-to-content"
|
||||
href="#main-content"
|
||||
class="absolute -top-full left-16 z-50 bg-background px-3 py-2 text-accent backdrop-blur-lg transition-all focus:top-4"
|
||||
>
|
||||
Skip to content
|
||||
</a>
|
||||
<div
|
||||
id="nav-container"
|
||||
class="mx-auto flex max-w-3xl flex-col items-center justify-between sm:flex-row"
|
||||
>
|
||||
<div
|
||||
id="top-nav-wrap"
|
||||
class="relative flex w-full items-start justify-between bg-background p-4 sm:py-6"
|
||||
>
|
||||
<a
|
||||
href="/"
|
||||
class="absolute py-1 text-2xl leading-7 font-semibold whitespace-nowrap sm:static"
|
||||
>
|
||||
{SITE.title}
|
||||
</a>
|
||||
<nav id="nav-menu">
|
||||
<nav
|
||||
id="nav-menu"
|
||||
class="flex w-full flex-col items-center sm:ml-2 sm:flex-row sm:justify-end sm:space-x-4 sm:py-0"
|
||||
>
|
||||
<button
|
||||
class="hamburger-menu focus-outline"
|
||||
id="menu-btn"
|
||||
class="focus-outline self-end p-2 sm:hidden"
|
||||
aria-label="Open Menu"
|
||||
aria-expanded="false"
|
||||
aria-controls="menu-items"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="menu-icon"
|
||||
>
|
||||
<line x1="7" y1="12" x2="21" y2="12" class="line"></line>
|
||||
<line x1="3" y1="6" x2="21" y2="6" class="line"></line>
|
||||
<line x1="12" y1="18" x2="21" y2="18" class="line"></line>
|
||||
<line x1="18" y1="6" x2="6" y2="18" class="close"></line>
|
||||
<line x1="6" y1="6" x2="18" y2="18" class="close"></line>
|
||||
</svg>
|
||||
<IconX id="close-icon" class="hidden" />
|
||||
<IconMenuDeep id="menu-icon" />
|
||||
</button>
|
||||
<ul id="menu-items" class="display-none sm:flex">
|
||||
<li>
|
||||
<a href="/posts/" class={activeNav === "posts" ? "active" : ""}>
|
||||
<ul
|
||||
id="menu-items"
|
||||
class:list={[
|
||||
"mt-4 grid w-44 grid-cols-2 place-content-center gap-2",
|
||||
"[&>li>a]:block [&>li>a]:px-4 [&>li>a]:py-3 [&>li>a]:text-center [&>li>a]:font-medium [&>li>a]:hover:text-accent sm:[&>li>a]:px-2 sm:[&>li>a]:py-1",
|
||||
"hidden",
|
||||
"sm:mt-0 sm:ml-0 sm:flex sm:w-auto sm:gap-x-5 sm:gap-y-0",
|
||||
]}
|
||||
>
|
||||
<li class="col-span-2">
|
||||
<a href="/posts" class:list={{ "active-nav": isActive("/posts") }}>
|
||||
Posts
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/tags/" class={activeNav === "tags" ? "active" : ""}>
|
||||
<li class="col-span-2">
|
||||
<a href="/tags" class:list={{ "active-nav": isActive("/tags") }}>
|
||||
Tags
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/about/" class={activeNav === "about" ? "active" : ""}>
|
||||
<li class="col-span-2">
|
||||
<a href="/about" class:list={{ "active-nav": isActive("/about") }}>
|
||||
About
|
||||
</a>
|
||||
</li>
|
||||
{
|
||||
SITE.showArchives && (
|
||||
<li>
|
||||
<li class="col-span-2">
|
||||
<LinkButton
|
||||
href="/archives/"
|
||||
className={`focus-outline flex justify-center p-3 sm:p-1`}
|
||||
href="/archives"
|
||||
class:list={[
|
||||
"focus-outline flex justify-center p-3 sm:p-1",
|
||||
{
|
||||
"active-nav [&>svg]:stroke-accent": isActive("/archives"),
|
||||
},
|
||||
]}
|
||||
ariaLabel="archives"
|
||||
title="Archives"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class:list={[
|
||||
"icon icon-tabler icons-tabler-outline !hidden sm:!inline-block",
|
||||
activeNav === "archives" && "!stroke-skin-accent",
|
||||
]}
|
||||
>
|
||||
<>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M3 4m0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v0a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z" />
|
||||
<path d="M5 8v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-10" />
|
||||
<path d="M10 12l4 0" />
|
||||
</>
|
||||
</svg>
|
||||
<span
|
||||
class:list={[
|
||||
"sm:sr-only",
|
||||
activeNav === "archives" && "active",
|
||||
]}
|
||||
>
|
||||
Archives
|
||||
</span>
|
||||
<IconArchive class="hidden sm:inline-block" />
|
||||
<span class="sm:sr-only">Archives</span>
|
||||
</LinkButton>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
<li>
|
||||
<li class="col-span-1 flex items-center justify-center">
|
||||
<LinkButton
|
||||
href="/search/"
|
||||
className={`focus-outline p-3 sm:p-1 ${
|
||||
activeNav === "search" ? "active" : ""
|
||||
} flex`}
|
||||
href="/search"
|
||||
class:list={[
|
||||
"focus-outline flex p-3 sm:p-1",
|
||||
{ "[&>svg]:stroke-accent": isActive("/search") },
|
||||
]}
|
||||
ariaLabel="search"
|
||||
title="Search"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="scale-125 sm:scale-100"
|
||||
><path
|
||||
d="M19.023 16.977a35.13 35.13 0 0 1-1.367-1.384c-.372-.378-.596-.653-.596-.653l-2.8-1.337A6.962 6.962 0 0 0 16 9c0-3.859-3.14-7-7-7S2 5.141 2 9s3.14 7 7 7c1.763 0 3.37-.66 4.603-1.739l1.337 2.8s.275.224.653.596c.387.363.896.854 1.384 1.367l1.358 1.392.604.646 2.121-2.121-.646-.604c-.379-.372-.885-.866-1.391-1.36zM9 14c-2.757 0-5-2.243-5-5s2.243-5 5-5 5 2.243 5 5-2.243 5-5 5z"
|
||||
></path>
|
||||
</svg>
|
||||
<IconSearch />
|
||||
<span class="sr-only">Search</span>
|
||||
</LinkButton>
|
||||
</li>
|
||||
{
|
||||
SITE.lightAndDarkMode && (
|
||||
<li>
|
||||
<button
|
||||
id="theme-btn"
|
||||
class="focus-outline"
|
||||
title="Toggles light & dark"
|
||||
aria-label="auto"
|
||||
aria-live="polite"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="moon-svg">
|
||||
<path d="M20.742 13.045a8.088 8.088 0 0 1-2.077.271c-2.135 0-4.14-.83-5.646-2.336a8.025 8.025 0 0 1-2.064-7.723A1 1 0 0 0 9.73 2.034a10.014 10.014 0 0 0-4.489 2.582c-3.898 3.898-3.898 10.243 0 14.143a9.937 9.937 0 0 0 7.072 2.93 9.93 9.93 0 0 0 7.07-2.929 10.007 10.007 0 0 0 2.583-4.491 1.001 1.001 0 0 0-1.224-1.224zm-2.772 4.301a7.947 7.947 0 0 1-5.656 2.343 7.953 7.953 0 0 1-5.658-2.344c-3.118-3.119-3.118-8.195 0-11.314a7.923 7.923 0 0 1 2.06-1.483 10.027 10.027 0 0 0 2.89 7.848 9.972 9.972 0 0 0 7.848 2.891 8.036 8.036 0 0 1-1.484 2.059z" />
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="sun-svg">
|
||||
<path d="M6.993 12c0 2.761 2.246 5.007 5.007 5.007s5.007-2.246 5.007-5.007S14.761 6.993 12 6.993 6.993 9.239 6.993 12zM12 8.993c1.658 0 3.007 1.349 3.007 3.007S13.658 15.007 12 15.007 8.993 13.658 8.993 12 10.342 8.993 12 8.993zM10.998 19h2v3h-2zm0-17h2v3h-2zm-9 9h3v2h-3zm17 0h3v2h-3zM4.219 18.363l2.12-2.122 1.415 1.414-2.12 2.122zM16.24 6.344l2.122-2.122 1.414 1.414-2.122 2.122zM6.342 7.759 4.22 5.637l1.415-1.414 2.12 2.122zm13.434 10.605-1.414 1.414-2.122-2.122 1.414-1.414z" />
|
||||
</svg>
|
||||
</button>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
<li class="col-span-1 flex items-center justify-center">
|
||||
<button
|
||||
id="theme-btn"
|
||||
class="focus-outline relative size-12 p-4 sm:size-8 hover:[&>svg]:stroke-accent"
|
||||
title="Toggles light & dark"
|
||||
aria-label="auto"
|
||||
aria-live="polite"
|
||||
>
|
||||
<IconMoon
|
||||
class="absolute top-[50%] left-[50%] -translate-[50%] scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90"
|
||||
/>
|
||||
<IconSunHigh
|
||||
class="absolute top-[50%] left-[50%] -translate-[50%] scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0"
|
||||
/>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
@@ -151,95 +140,24 @@ const { activeNav } = Astro.props;
|
||||
<Hr />
|
||||
</header>
|
||||
|
||||
<style>
|
||||
#skip-to-content {
|
||||
@apply absolute -top-full left-16 z-50 bg-skin-accent px-3 py-2 text-skin-inverted transition-all focus:top-4;
|
||||
}
|
||||
.nav-container {
|
||||
@apply mx-auto flex max-w-3xl flex-col items-center justify-between sm:flex-row;
|
||||
}
|
||||
.top-nav-wrap {
|
||||
@apply relative flex w-full items-start justify-between p-4 sm:items-center sm:py-8;
|
||||
}
|
||||
.logo {
|
||||
@apply absolute py-1 text-xl font-semibold sm:static sm:text-2xl;
|
||||
}
|
||||
.hamburger-menu {
|
||||
@apply self-end p-2 sm:hidden;
|
||||
}
|
||||
.hamburger-menu svg {
|
||||
@apply h-6 w-6 scale-125 fill-skin-base;
|
||||
}
|
||||
|
||||
nav {
|
||||
@apply flex w-full flex-col items-center sm:ml-2 sm:flex-row sm:justify-end sm:space-x-4 sm:py-0;
|
||||
}
|
||||
nav ul {
|
||||
@apply mt-4 grid w-44 grid-cols-2 grid-rows-4 gap-x-2 gap-y-2 sm:ml-0 sm:mt-0 sm:w-auto sm:gap-x-5 sm:gap-y-0;
|
||||
}
|
||||
nav ul li {
|
||||
@apply col-span-2 flex items-center justify-center;
|
||||
}
|
||||
nav ul li a {
|
||||
@apply w-full px-4 py-3 text-center font-medium hover:text-skin-accent sm:my-0 sm:px-2 sm:py-1;
|
||||
}
|
||||
nav ul li:nth-last-child(2) a {
|
||||
@apply w-auto;
|
||||
}
|
||||
nav ul li:nth-last-child(1),
|
||||
nav ul li:nth-last-child(2) {
|
||||
@apply col-span-1;
|
||||
}
|
||||
nav .active {
|
||||
@apply underline decoration-wavy decoration-2 underline-offset-4;
|
||||
}
|
||||
nav a.active svg {
|
||||
@apply fill-skin-accent;
|
||||
}
|
||||
|
||||
nav button {
|
||||
@apply p-1;
|
||||
}
|
||||
nav button svg {
|
||||
@apply h-6 w-6 fill-skin-base hover:fill-skin-accent;
|
||||
}
|
||||
#theme-btn {
|
||||
@apply p-3 sm:p-1;
|
||||
}
|
||||
#theme-btn svg {
|
||||
@apply scale-125 hover:rotate-12 sm:scale-100;
|
||||
}
|
||||
|
||||
.menu-icon line {
|
||||
@apply transition-opacity duration-75 ease-in-out;
|
||||
}
|
||||
.menu-icon .close {
|
||||
opacity: 0;
|
||||
}
|
||||
.menu-icon.is-active .line {
|
||||
@apply opacity-0;
|
||||
}
|
||||
.menu-icon.is-active .close {
|
||||
@apply opacity-100;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function toggleNav() {
|
||||
// Toggle menu
|
||||
const menuBtn = document.querySelector(".hamburger-menu");
|
||||
const menuIcon = document.querySelector(".menu-icon");
|
||||
const menuBtn = document.querySelector("#menu-btn");
|
||||
const menuItems = document.querySelector("#menu-items");
|
||||
const menuIcon = document.querySelector("#menu-icon");
|
||||
const closeIcon = document.querySelector("#close-icon");
|
||||
|
||||
menuBtn?.addEventListener("click", () => {
|
||||
const menuExpanded = menuBtn.getAttribute("aria-expanded") === "true";
|
||||
menuIcon?.classList.toggle("is-active");
|
||||
menuBtn.setAttribute("aria-expanded", menuExpanded ? "false" : "true");
|
||||
menuBtn.setAttribute(
|
||||
"aria-label",
|
||||
menuExpanded ? "Open Menu" : "Close Menu"
|
||||
);
|
||||
menuItems?.classList.toggle("display-none");
|
||||
if (!menuBtn || !menuItems || !menuIcon || !closeIcon) return;
|
||||
|
||||
menuBtn.addEventListener("click", () => {
|
||||
const openMenu = menuBtn.getAttribute("aria-expanded") === "true";
|
||||
|
||||
menuBtn.setAttribute("aria-expanded", openMenu ? "false" : "true");
|
||||
menuBtn.setAttribute("aria-label", openMenu ? "Open Menu" : "Close Menu");
|
||||
|
||||
menuItems.classList.toggle("hidden");
|
||||
menuIcon.classList.toggle("hidden");
|
||||
closeIcon.classList.toggle("hidden");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user