mirror of
https://github.com/liyunze-coding/coworking-website.git
synced 2026-11-06 13:13:34 +00:00
added theme toggle
This commit is contained in:
parent
21ddf2d621
commit
a42899e522
7 changed files with 256 additions and 17 deletions
|
|
@ -1,10 +1,11 @@
|
|||
---
|
||||
import VerticalNav from "./verticalNav.astro";
|
||||
import SearchModal from "../ui/SearchModal.astro";
|
||||
import ThemeToggle from "../ui/ThemeToggle.astro";
|
||||
---
|
||||
|
||||
<div
|
||||
class="w-full backdrop-blur fixed top-0 text-white bg-secondary/75 z-[60] text-lg py-3 h-[var(--header-height)]"
|
||||
class="site-nav w-full backdrop-blur fixed top-0 z-[60] text-lg py-3 h-[var(--header-height)]"
|
||||
data-pagefind-ignore
|
||||
>
|
||||
<div
|
||||
|
|
@ -21,7 +22,7 @@ import SearchModal from "../ui/SearchModal.astro";
|
|||
<!-- Vertical Navbar -->
|
||||
<aside
|
||||
id="vertical-navbar"
|
||||
class="sidebar fixed block overflow-y-auto duration-300 z-[60] lg:hidden bg-[#151515] py-8 px-8 h-[calc(100vh-var(--header-height))] top-[--header-height] left-0 w-full"
|
||||
class="sidebar fixed block overflow-y-auto duration-300 z-[60] lg:hidden py-8 px-8 h-[calc(100vh-var(--header-height))] top-[--header-height] left-0 w-full"
|
||||
transition:persist="vertical-nav-from-left"
|
||||
>
|
||||
<VerticalNav showHome={true} />
|
||||
|
|
@ -47,30 +48,33 @@ import SearchModal from "../ui/SearchModal.astro";
|
|||
transition:name="navbar"
|
||||
>
|
||||
<a
|
||||
class="no-target-blank hover:text-black hover:bg-white rounded-md transition-colors duration-300 px-2 py-1 text-white hover:no-underline"
|
||||
class="no-target-blank nav-link rounded-md transition-colors duration-300 px-2 py-1 hover:no-underline"
|
||||
href="/get-started/introduction">Get started</a
|
||||
>
|
||||
<a
|
||||
class="no-target-blank hover:text-black hover:bg-white rounded-md transition-colors duration-300 px-2 py-1 text-white hover:no-underline"
|
||||
class="no-target-blank nav-link rounded-md transition-colors duration-300 px-2 py-1 hover:no-underline"
|
||||
href="/guide/general-tips">Guide</a
|
||||
>
|
||||
<a
|
||||
class="no-target-blank hover:text-black hover:bg-white rounded-md transition-colors duration-300 px-2 py-1 text-white hover:no-underline"
|
||||
class="no-target-blank nav-link rounded-md transition-colors duration-300 px-2 py-1 hover:no-underline"
|
||||
href="/games">Games</a
|
||||
>
|
||||
<a
|
||||
class="no-target-blank hover:text-black hover:bg-white rounded-md transition-colors duration-300 px-2 py-1 text-white hover:no-underline"
|
||||
class="no-target-blank nav-link rounded-md transition-colors duration-300 px-2 py-1 hover:no-underline"
|
||||
href="/groups">Groups</a
|
||||
>
|
||||
<a
|
||||
class="no-target-blank hover:text-black hover:bg-white rounded-md transition-colors duration-300 px-2 py-1 text-white hover:no-underline"
|
||||
class="no-target-blank nav-link rounded-md transition-colors duration-300 px-2 py-1 hover:no-underline"
|
||||
href="/credits">Credits</a
|
||||
>
|
||||
</div>
|
||||
<!-- Search bar -->
|
||||
<div class="hidden lg:flex lg:flex-1 justify-end relative">
|
||||
<div class="flex lg:flex-1 justify-end items-center gap-3 relative">
|
||||
<div class="hidden lg:block">
|
||||
<SearchModal id="searchModal" open="Open modal" />
|
||||
</div>
|
||||
<ThemeToggle />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -99,6 +103,34 @@ import SearchModal from "../ui/SearchModal.astro";
|
|||
);
|
||||
}
|
||||
|
||||
.site-nav {
|
||||
background: var(--nav-background);
|
||||
color: var(--text-color);
|
||||
border-bottom: 1px solid color-mix(in srgb, var(--border-color) 55%, transparent);
|
||||
}
|
||||
|
||||
.site-nav .sidebar {
|
||||
background: var(--sidebar-background);
|
||||
}
|
||||
|
||||
.site-nav a {
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.site-nav .nav-link:hover {
|
||||
background: var(--control-hover);
|
||||
}
|
||||
|
||||
html[data-theme="light"] {
|
||||
--pagefind-ui-primary: #171717;
|
||||
--pagefind-ui-text: #171717;
|
||||
--pagefind-ui-background: #ffffff;
|
||||
--pagefind-ui-border: #cbd5e1;
|
||||
--pagefind-ui-tag: #171717;
|
||||
--foreground: #171717;
|
||||
--background: #171717;
|
||||
}
|
||||
|
||||
.hamburger-menu {
|
||||
--x-width: calc(var(--hamburger-height) * 1.41421356237);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<div class="flex flex-col">
|
||||
<div class="text-center text-4xl lg:text-6xl font-bold">
|
||||
<span class="text-slate-200">Getting started with</span>
|
||||
<span class="text-[var(--text-color)]">Getting started with</span>
|
||||
<div
|
||||
id="coworking-streams"
|
||||
class="text-transparent animate-gradient py-1 lg:py-3 bg-[length:300%]"
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ const { id } = Astro.props;
|
|||
|
||||
<button
|
||||
onclick={`window.${id}.showModal()`}
|
||||
class="text-sm flex bg-[#101010] w-60 px-2 py-2 border border-gray-600 border-solid text-left rounded-lg group"
|
||||
class="search-trigger text-sm flex w-60 px-2 py-2 border border-solid text-left rounded-lg group"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
|
@ -33,7 +33,7 @@ const { id } = Astro.props;
|
|||
|
||||
<dialog
|
||||
id=`${id}`
|
||||
class="fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 bg-[#202020] border-2 border-solid border-[#505050] text-white rounded-lg w-4/5 lg:w-1/2 h-5/6 px-10 py-10 animate-fadeIn"
|
||||
class="search-dialog fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 border-2 border-solid rounded-lg w-4/5 lg:w-1/2 h-5/6 px-10 py-10 animate-fadeIn"
|
||||
>
|
||||
<form method="dialog">
|
||||
<button class="absolute top-3 right-3"
|
||||
|
|
@ -52,3 +52,17 @@ const { id } = Astro.props;
|
|||
</form>
|
||||
<div id=`${id}-search` class="mt-2"></div>
|
||||
</dialog>
|
||||
|
||||
<style>
|
||||
.search-trigger {
|
||||
background: var(--control-background);
|
||||
border-color: var(--border-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.search-dialog {
|
||||
background: var(--surface-color);
|
||||
border-color: var(--border-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
115
src/components/ui/ThemeToggle.astro
Normal file
115
src/components/ui/ThemeToggle.astro
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
<button
|
||||
type="button"
|
||||
class="theme-toggle"
|
||||
aria-label="Switch to light theme"
|
||||
title="Switch to light theme"
|
||||
>
|
||||
<svg
|
||||
class="sun-icon"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<circle cx="12" cy="12" r="4"></circle>
|
||||
<path d="M12 2v2M12 20v2M4.93 4.93l1.42 1.42M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.42-1.42M17.66 6.34l1.41-1.41"></path>
|
||||
</svg>
|
||||
<svg
|
||||
class="moon-icon"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79Z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<script is:inline>
|
||||
(() => {
|
||||
const updateThemeToggle = () => {
|
||||
const button = document.querySelector(".theme-toggle");
|
||||
if (!button) return;
|
||||
|
||||
const isDark = document.documentElement.dataset.theme === "dark";
|
||||
const nextTheme = isDark ? "light" : "dark";
|
||||
button.setAttribute("aria-label", `Switch to ${nextTheme} theme`);
|
||||
button.setAttribute("title", `Switch to ${nextTheme} theme`);
|
||||
};
|
||||
|
||||
if (!window.__themeToggleReady) {
|
||||
document.addEventListener("click", (event) => {
|
||||
const button = event.target.closest(".theme-toggle");
|
||||
if (!button) return;
|
||||
|
||||
const theme =
|
||||
document.documentElement.dataset.theme === "dark"
|
||||
? "light"
|
||||
: "dark";
|
||||
document.documentElement.dataset.theme = theme;
|
||||
document.documentElement.style.colorScheme = theme;
|
||||
localStorage.setItem("theme", theme);
|
||||
updateThemeToggle();
|
||||
});
|
||||
window.__themeToggleReady = true;
|
||||
}
|
||||
|
||||
document.addEventListener("astro:page-load", updateThemeToggle);
|
||||
updateThemeToggle();
|
||||
})();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.theme-toggle {
|
||||
display: grid;
|
||||
width: 2.25rem;
|
||||
height: 2.25rem;
|
||||
flex: 0 0 auto;
|
||||
place-items: center;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 0.5rem;
|
||||
background: var(--control-background);
|
||||
color: var(--text-color);
|
||||
cursor: pointer;
|
||||
transition:
|
||||
background-color 150ms ease,
|
||||
border-color 150ms ease,
|
||||
transform 150ms ease;
|
||||
}
|
||||
|
||||
.theme-toggle:hover {
|
||||
background: var(--control-hover);
|
||||
}
|
||||
|
||||
.theme-toggle:active {
|
||||
transform: scale(0.94);
|
||||
}
|
||||
|
||||
.theme-toggle:focus-visible {
|
||||
outline: 2px solid #3f84d8;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.theme-toggle svg {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
grid-area: 1 / 1;
|
||||
}
|
||||
|
||||
.sun-icon,
|
||||
:global(html[data-theme="light"]) .moon-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:global(html[data-theme="light"]) .sun-icon {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -67,7 +67,7 @@ export const Card = ({
|
|||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"relative z-20 h-full w-full overflow-hidden rounded-2xl border border-transparent bg-[#232323] p-4 group-hover:border-slate-700 dark:border-white/[0.2]",
|
||||
"relative z-20 h-full w-full overflow-hidden rounded-2xl border border-[var(--card-border)] bg-[var(--card-background)] p-4 shadow-sm group-hover:border-[var(--card-border-hover)]",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
|
@ -87,7 +87,7 @@ export const CardTitle = ({
|
|||
return (
|
||||
<h4
|
||||
className={cn(
|
||||
"mt-4 font-bold tracking-wide text-zinc-100 text-xl",
|
||||
"mt-4 font-bold tracking-wide text-[var(--text-color)] text-xl",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
|
@ -105,7 +105,7 @@ export const CardDescription = ({
|
|||
return (
|
||||
<p
|
||||
className={cn(
|
||||
"mt-5 text-sm leading-relaxed tracking-wide text-zinc-400",
|
||||
"mt-5 text-sm leading-relaxed tracking-wide text-[var(--muted-text)]",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ const { title, description } = Astro.props;
|
|||
---
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="description" content={description} />
|
||||
|
|
@ -48,6 +48,34 @@ const { title, description } = Astro.props;
|
|||
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
<link href="/pagefind/pagefind-ui.css" rel="stylesheet" />
|
||||
<script is:inline>
|
||||
(() => {
|
||||
const applyTheme = (root) => {
|
||||
const savedTheme = localStorage.getItem("theme");
|
||||
const theme =
|
||||
savedTheme === "light" || savedTheme === "dark"
|
||||
? savedTheme
|
||||
: window.matchMedia("(prefers-color-scheme: dark)")
|
||||
.matches
|
||||
? "dark"
|
||||
: "light";
|
||||
root.dataset.theme = theme;
|
||||
root.style.colorScheme = theme;
|
||||
};
|
||||
|
||||
applyTheme(document.documentElement);
|
||||
|
||||
if (!window.__themePersistenceReady) {
|
||||
document.addEventListener("astro:before-swap", (event) => {
|
||||
applyTheme(event.newDocument.documentElement);
|
||||
});
|
||||
document.addEventListener("astro:after-swap", () => {
|
||||
applyTheme(document.documentElement);
|
||||
});
|
||||
window.__themePersistenceReady = true;
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<script src="/pagefind/pagefind-ui.js" is:inline></script>
|
||||
<script is:inline src="/_vercel/insights/script.js"></script>
|
||||
<ClientRouter />
|
||||
|
|
@ -74,8 +102,8 @@ const { title, description } = Astro.props;
|
|||
|
||||
html {
|
||||
font-family: system-ui, sans-serif;
|
||||
background-color: #171717;
|
||||
color: rgb(255 255 255);
|
||||
background-color: var(--background-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
html,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,55 @@
|
|||
@import "tailwindcss";
|
||||
|
||||
:root,
|
||||
html[data-theme="dark"] {
|
||||
--background-color: #171717;
|
||||
--surface-color: #202020;
|
||||
--nav-background: rgb(23 23 23 / 0.82);
|
||||
--sidebar-background: #151515;
|
||||
--control-background: #101010;
|
||||
--control-hover: #2f2f2f;
|
||||
--text-color: #ffffff;
|
||||
--muted-text: #9ca3af;
|
||||
--border-color: #505050;
|
||||
--card-background: #232323;
|
||||
--card-border: rgb(255 255 255 / 0.2);
|
||||
--card-border-hover: #334155;
|
||||
}
|
||||
|
||||
html[data-theme="light"] {
|
||||
--background-color: #f8fafc;
|
||||
--surface-color: #ffffff;
|
||||
--nav-background: rgb(255 255 255 / 0.86);
|
||||
--sidebar-background: #f8fafc;
|
||||
--control-background: #ffffff;
|
||||
--control-hover: #e2e8f0;
|
||||
--text-color: #171717;
|
||||
--muted-text: #4b5563;
|
||||
--border-color: #cbd5e1;
|
||||
--card-background: #ffffff;
|
||||
--card-border: #cbd5e1;
|
||||
--card-border-hover: #94a3b8;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
transition:
|
||||
background-color 180ms ease,
|
||||
color 180ms ease;
|
||||
}
|
||||
|
||||
html[data-theme="light"] .text-white {
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
html[data-theme="light"] .text-gray-400 {
|
||||
color: var(--muted-text);
|
||||
}
|
||||
|
||||
html[data-theme="light"] .guide-content code {
|
||||
background-color: #e2e8f0;
|
||||
}
|
||||
|
||||
@theme {
|
||||
--color-primary: #fafafa;
|
||||
--color-secondary: #171717;
|
||||
|
|
|
|||
Loading…
Reference in a new issue