mirror of
https://github.com/thiloho/aurora.git
synced 2025-11-22 03:21:35 +01:00
Add ThemeToggle component
This commit is contained in:
26
flake.lock
generated
Normal file
26
flake.lock
generated
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1684428141,
|
||||||
|
"narHash": "sha256-yaMyF02+Wr4H9NQc0HDxQTUon8yqU0GrSzeDlnc1N3M=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "edcd3d30564ca6d4c1f2442c4149fa908228243e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
31
flake.nix
Normal file
31
flake.nix
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
description = "JavaScript development environment";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs }:
|
||||||
|
let
|
||||||
|
# Systems supported
|
||||||
|
allSystems = [
|
||||||
|
"x86_64-linux"
|
||||||
|
"aarch64-linux"
|
||||||
|
"x86_64-darwin"
|
||||||
|
"aarch64-darwin"
|
||||||
|
];
|
||||||
|
|
||||||
|
forAllSystems = f: nixpkgs.lib.genAttrs allSystems (system: f {
|
||||||
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
});
|
||||||
|
in
|
||||||
|
{
|
||||||
|
devShells = forAllSystems ({ pkgs }: {
|
||||||
|
default = pkgs.mkShell {
|
||||||
|
packages = with pkgs; [
|
||||||
|
nodejs # Node.js, plus npm, npx, and corepack
|
||||||
|
];
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -7,4 +7,4 @@ const articles = (await getCollection("blog")).sort(
|
|||||||
);
|
);
|
||||||
---
|
---
|
||||||
|
|
||||||
<ArticleSearch client:load {articles} />
|
<ArticleSearch client:only="svelte" {articles} />
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export let shortcut: string;
|
export let shortcut: string;
|
||||||
|
|
||||||
const possibleShortcuts = ["S", "T"];
|
const possibleShortcuts = ["S", "C", "T"];
|
||||||
|
|
||||||
let detailsElement: HTMLDetailsElement;
|
let detailsElement: HTMLDetailsElement;
|
||||||
let summaryElement: HTMLElement;
|
let summaryElement: HTMLElement;
|
||||||
|
|||||||
@@ -11,4 +11,8 @@ const { title, description } = Astro.props;
|
|||||||
<title>{title}</title>
|
<title>{title}</title>
|
||||||
<meta name="author" content="Your Name" />
|
<meta name="author" content="Your Name" />
|
||||||
<meta name="description" content={description} />
|
<meta name="description" content={description} />
|
||||||
|
<script is:inline>
|
||||||
|
const storedTheme = localStorage.getItem("theme");
|
||||||
|
document.documentElement.classList = storedTheme;
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
import ArticleSearchWrapper from "../components/ArticleSearchWrapper.astro";
|
import ArticleSearchWrapper from "../components/ArticleSearchWrapper.astro";
|
||||||
|
import ThemeToggle from "../components/ThemeToggle.svelte";
|
||||||
---
|
---
|
||||||
|
|
||||||
<nav>
|
<nav>
|
||||||
@@ -9,6 +10,7 @@ import ArticleSearchWrapper from "../components/ArticleSearchWrapper.astro";
|
|||||||
</a>
|
</a>
|
||||||
<slot />
|
<slot />
|
||||||
<ArticleSearchWrapper />
|
<ArticleSearchWrapper />
|
||||||
|
<ThemeToggle client:only="svelte" />
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|||||||
@@ -4,19 +4,17 @@
|
|||||||
export let headings: MarkdownHeading[] = [];
|
export let headings: MarkdownHeading[] = [];
|
||||||
|
|
||||||
import Dropdown from "./Dropdown.svelte";
|
import Dropdown from "./Dropdown.svelte";
|
||||||
|
|
||||||
let dropdown;
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Dropdown shortcut="T" bind:this={dropdown}>
|
<Dropdown shortcut="C">
|
||||||
<svg slot="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
|
<svg slot="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
|
||||||
<title>Table of contents (Shift + t)</title>
|
<title>Table of contents (Shift + c)</title>
|
||||||
<path fill-rule="evenodd" d="M2.625 6.75a1.125 1.125 0 112.25 0 1.125 1.125 0 01-2.25 0zm4.875 0A.75.75 0 018.25 6h12a.75.75 0 010 1.5h-12a.75.75 0 01-.75-.75zM2.625 12a1.125 1.125 0 112.25 0 1.125 1.125 0 01-2.25 0zM7.5 12a.75.75 0 01.75-.75h12a.75.75 0 010 1.5h-12A.75.75 0 017.5 12zm-4.875 5.25a1.125 1.125 0 112.25 0 1.125 1.125 0 01-2.25 0zm4.875 0a.75.75 0 01.75-.75h12a.75.75 0 010 1.5h-12a.75.75 0 01-.75-.75z" clip-rule="evenodd" />
|
<path fill-rule="evenodd" d="M2.625 6.75a1.125 1.125 0 112.25 0 1.125 1.125 0 01-2.25 0zm4.875 0A.75.75 0 018.25 6h12a.75.75 0 010 1.5h-12a.75.75 0 01-.75-.75zM2.625 12a1.125 1.125 0 112.25 0 1.125 1.125 0 01-2.25 0zM7.5 12a.75.75 0 01.75-.75h12a.75.75 0 010 1.5h-12A.75.75 0 017.5 12zm-4.875 5.25a1.125 1.125 0 112.25 0 1.125 1.125 0 01-2.25 0zm4.875 0a.75.75 0 01.75-.75h12a.75.75 0 010 1.5h-12a.75.75 0 01-.75-.75z" clip-rule="evenodd" />
|
||||||
</svg>
|
</svg>
|
||||||
<ul>
|
<ul>
|
||||||
{#each headings.filter(({ depth }) => depth === 2) as { slug, text }}
|
{#each headings.filter(({ depth }) => depth === 2) as { slug, text }}
|
||||||
<li>
|
<li>
|
||||||
<a href="#{slug}" on:click={dropdown.closeMenu}>{text}</a>
|
<a href="#{slug}">{text}</a>
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
47
src/components/ThemeToggle.svelte
Normal file
47
src/components/ThemeToggle.svelte
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Dropdown from "./Dropdown.svelte";
|
||||||
|
|
||||||
|
let themeOptions = ["System", "Light", "Dark"];
|
||||||
|
|
||||||
|
let theme = "System";
|
||||||
|
|
||||||
|
function loadTheme() {
|
||||||
|
theme = localStorage.getItem("theme");
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveTheme() {
|
||||||
|
localStorage.setItem("theme", theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadTheme();
|
||||||
|
|
||||||
|
$: document.documentElement.classList = theme;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Dropdown shortcut="T">
|
||||||
|
<svg slot="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-6 h-6">
|
||||||
|
<title>Toggle theme (Shift + t)</title>
|
||||||
|
<path fill-rule="evenodd" d="M2.25 5.25a3 3 0 013-3h13.5a3 3 0 013 3V15a3 3 0 01-3 3h-3v.257c0 .597.237 1.17.659 1.591l.621.622a.75.75 0 01-.53 1.28h-9a.75.75 0 01-.53-1.28l.621-.622a2.25 2.25 0 00.659-1.59V18h-3a3 3 0 01-3-3V5.25zm1.5 0v7.5a1.5 1.5 0 001.5 1.5h13.5a1.5 1.5 0 001.5-1.5v-7.5a1.5 1.5 0 00-1.5-1.5H5.25a1.5 1.5 0 00-1.5 1.5z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
<div class="theme-toggle">
|
||||||
|
{#each themeOptions as option, index}
|
||||||
|
<div>
|
||||||
|
<input type="radio" id="theme-{option}" name="theme" value={option} bind:group={theme} on:change={saveTheme} />
|
||||||
|
<label for="theme-{option}">{option}</label>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</Dropdown>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.theme-toggle {
|
||||||
|
position: absolute;
|
||||||
|
inset-inline-end: 0;
|
||||||
|
inset-block-start: var(--nav-height);
|
||||||
|
background-color: var(--background-color);
|
||||||
|
border: var(--standard-border);
|
||||||
|
padding: 1rem;
|
||||||
|
display: grid;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -7,7 +7,7 @@ import PublicationDate from "../components/PublicationDate.astro";
|
|||||||
---
|
---
|
||||||
|
|
||||||
<PageLayout {title} {description}>
|
<PageLayout {title} {description}>
|
||||||
<TableOfContents slot="nav" client:load {headings} />
|
<TableOfContents slot="nav" client:only="svelte" {headings} />
|
||||||
<Fragment slot="header">
|
<Fragment slot="header">
|
||||||
<p>
|
<p>
|
||||||
Published on
|
Published on
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const articles = (await getCollection("blog")).sort(
|
|||||||
---
|
---
|
||||||
|
|
||||||
<PageLayout {...home.data}>
|
<PageLayout {...home.data}>
|
||||||
<TableOfContents slot="nav" client:load {headings} />
|
<TableOfContents slot="nav" client:only="svelte" {headings} />
|
||||||
<Content />
|
<Content />
|
||||||
{
|
{
|
||||||
articles.map((article) => (
|
articles.map((article) => (
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
--tertiary-background-color: hsl(0 0% 90%);
|
--tertiary-background-color: hsl(0 0% 90%);
|
||||||
--text-color: hsl(0 0% 10%);
|
--text-color: hsl(0 0% 10%);
|
||||||
--accent-color: #1e40af;
|
--accent-color: #1e40af;
|
||||||
|
|
||||||
|
color-scheme: light;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
@@ -20,6 +22,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html.Light {
|
||||||
|
--background-color: hsl(0 0% 100%);
|
||||||
|
--secondary-background-color: hsl(0 0% 95%);
|
||||||
|
--tertiary-background-color: hsl(0 0% 90%);
|
||||||
|
--text-color: hsl(0 0% 10%);
|
||||||
|
--accent-color: #1e40af;
|
||||||
|
|
||||||
|
color-scheme: light;
|
||||||
|
}
|
||||||
|
|
||||||
|
html.Dark {
|
||||||
|
--background-color: hsl(0 0% 10%);
|
||||||
|
--secondary-background-color: hsl(0 0% 15%);
|
||||||
|
--tertiary-background-color: hsl(0 0% 20%);
|
||||||
|
--text-color: hsl(0 0% 90%);
|
||||||
|
--accent-color: #93c5fd;
|
||||||
|
|
||||||
|
color-scheme: dark;
|
||||||
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user