feat: enable dark theme and theme switcher
Some checks failed
Node.js CI / Lint and Test (push) Successful in 1m26s
Code Analysis / SonarQube (push) Failing after 1m29s

This commit is contained in:
Naomi Carrigan 2025-03-27 14:51:14 -07:00
parent bd47ff2bb3
commit db7a34e975
Signed by: naomi
SSH Key Fingerprint: SHA256:rca1iUI2OhAM6n4FIUaFcZcicmri0jgocqKiTTAfrt8
5 changed files with 475 additions and 3 deletions

View File

@ -2,17 +2,18 @@ import { defineConfig } from 'astro/config';
import starlight from "@astrojs/starlight";
import { ExpressiveCodeTheme } from "@astrojs/starlight/expressive-code"
import themeJson from "./src/styles/theme.json"
import darkThemeJson from "./src/styles/theme-dark.json"
import { navigation } from "./src/components/navigation.ts";
const sakuraDreams = ExpressiveCodeTheme.fromJSONString(JSON.stringify(themeJson));
const sakuraDreamsDark = ExpressiveCodeTheme.fromJSONString(JSON.stringify(darkThemeJson));
export default defineConfig({
site: "https://docs.nhcarrigan.com",
integrations: [starlight({
components: {
Footer: "./src/components/Footer.astro",
ThemeSelect: "./src/components/ThemeSelect.astro",
ThemeProvider: "./src/components/ThemeProvider.astro",
},
title: "NHCarrigan Docs",
@ -69,7 +70,7 @@ export default defineConfig({
"./src/fonts/font-face.css"
],
expressiveCode: {
themes: [sakuraDreams]
themes: [sakuraDreams, sakuraDreamsDark],
}
}),
]

View File

@ -1,6 +1,42 @@
---
import { Icon } from "@astrojs/starlight/components";
---
{/* This is intentionally inlined to avoid FOUC. */}
<script is:inline>
document.documentElement.dataset.theme = "light";
window.StarlightThemeProvider = (() => {
const storedTheme =
typeof localStorage !== 'undefined' && localStorage.getItem('starlight-theme');
const theme =
storedTheme ||
(window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark');
document.documentElement.dataset.theme = theme === 'light' ? 'light' : 'dark';
console.log(document.documentElement)
return {
updatePickers(theme = storedTheme || 'auto') {
document.querySelectorAll('starlight-theme-select').forEach((picker) => {
const select = picker.querySelector('select');
if (select) select.value = theme;
/** @type {HTMLTemplateElement | null} */
const tmpl = document.querySelector(`#theme-icons`);
const newIcon = tmpl && tmpl.content.querySelector('.' + theme);
if (newIcon) {
const oldIcon = picker.querySelector('svg.label-icon');
if (oldIcon) {
oldIcon.replaceChildren(...newIcon.cloneNode(true).childNodes);
}
}
});
},
};
})();
</script>
<template id="theme-icons">
<Icon name="sun" class="light" />
<Icon name="moon" class="dark" />
<Icon name="laptop" class="auto" />
</template>
<video
autoplay={true}
loop={true}

View File

@ -4,6 +4,12 @@
--sl-color-text-accent: #db7093;
}
html[data-theme="dark"] {
--primary-color: #ffefef;
--background-color: #db7093ee;
--sl-color-text-accent: #ffefef;
}
.main-frame::before {
background: url(https://cdn.nhcarrigan.com/background.png);
background-size: cover;
@ -71,6 +77,10 @@ footer > div > p {
color: var(--primary-color) !important;
}
starlight-theme-select, starlight-theme-select > label {
color: var(--primary-color) !important;
}
.social-icons::after {
display: none;
}

425
src/styles/theme-dark.json Normal file
View File

@ -0,0 +1,425 @@
{
"$schema": "vscode://schemas/color-theme",
"type": "dark",
"colors": {
"activityBar.background": "#3a0d22",
"activityBar.foreground": "#ffb6c1",
"activityBarBadge.background": "#ff69b4",
"activityBarBadge.foreground": "#000000",
"button.background": "#ff69b4",
"button.foreground": "#000000",
"dropdown.background": "#4a112a",
"dropdown.foreground": "#ffb6c1",
"editor.background": "#2a0a18",
"editor.foreground": "#ffb6c1",
"editor.lineHighlightBackground": "#1073cf2d",
"editor.lineHighlightBorder": "#9fced11f",
"editor.selectionBackground": "#e35a8f",
"editor.selectionHighlightBackground": "#e35a8f80",
"editor.wordHighlightBackground": "#e35a8f80",
"editorCursor.foreground": "#ff69b4",
"editorGroupHeader.tabsBackground": "#3a0d22",
"editorWhitespace.foreground": "#4a112a",
"focusBorder": "#ff69b4",
"input.background": "#3a0d22",
"input.foreground": "#ffb6c1",
"input.placeholderForeground": "#e35a8f",
"list.activeSelectionBackground": "#4a112a",
"list.activeSelectionForeground": "#ffb6c1",
"list.hoverBackground": "#3a0d22",
"list.hoverForeground": "#ffb6c1",
"sideBar.background": "#3a0d22",
"sideBar.foreground": "#ffb6c1",
"sideBarTitle.foreground": "#ff69b4",
"statusBar.background": "#4a112a",
"statusBar.foreground": "#ffb6c1",
"statusBar.noFolderBackground": "#2a0a18",
"tab.activeBackground": "#3a0d22",
"tab.activeForeground": "#ffb6c1",
"tab.inactiveBackground": "#4a112a",
"tab.inactiveForeground": "#e35a8f",
"terminal.ansiBlack": "#4a112a",
"terminal.ansiBlue": "#c96385",
"terminal.ansiBrightBlack": "#3a0d22",
"terminal.ansiBrightBlue": "#d87093",
"terminal.ansiBrightCyan": "#ffafc5",
"terminal.ansiBrightGreen": "#ff77a8",
"terminal.ansiBrightMagenta": "#ff85a2",
"terminal.ansiBrightRed": "#ff1493",
"terminal.ansiBrightWhite": "#fff5f7",
"terminal.ansiBrightYellow": "#ffb6c1",
"terminal.ansiCyan": "#ff9aac",
"terminal.ansiGreen": "#e35a8f",
"terminal.ansiMagenta": "#e35a8f",
"terminal.ansiRed": "#ff69b4",
"terminal.ansiWhite": "#ffd1dc",
"terminal.ansiYellow": "#d45a88",
"terminal.background": "#2a0a18",
"terminal.foreground": "#ffb6c1",
"titleBar.activeBackground": "#4a112a",
"titleBar.activeForeground": "#ffb6c1"
},
"tokenColors": [
{
"scope": [
"comment",
"punctuation.definition.comment"
],
"settings": {
"foreground": "#E5A3B5",
"fontStyle": "italic"
}
},
{
"scope": [
"string",
"string.quoted.single",
"string.quoted.double",
"string.quoted.triple",
"string.template",
"constant.character",
"constant.other.symbol"
],
"settings": {
"foreground": "#FF69B4"
}
},
{
"scope": [
"constant.numeric",
"constant.language",
"constant.character.escape",
"constant.other",
"support.constant"
],
"settings": {
"foreground": "#C96385"
}
},
{
"scope": [
"variable",
"variable.other",
"variable.parameter",
"variable.language",
"variable.object.property"
],
"settings": {
"foreground": "#D87093"
}
},
{
"scope": [
"keyword",
"keyword.control",
"keyword.operator",
"keyword.other",
"storage.type",
"storage.modifier",
"punctuation.decorator"
],
"settings": {
"foreground": "#E35A8F"
}
},
{
"scope": [
"entity.name.function",
"entity.name.method",
"support.function",
"meta.function-call",
"meta.method-call",
"meta.function.dart"
],
"settings": {
"foreground": "#D45A88"
}
},
{
"scope": [
"entity.name.type",
"entity.name.class",
"entity.name.struct",
"entity.name.enum",
"entity.name.union",
"entity.name.trait",
"entity.name.interface",
"support.class",
"support.type",
"meta.return-type"
],
"settings": {
"foreground": "#FF77A8",
"fontStyle": "bold"
}
},
{
"scope": [
"meta.decorator",
"meta.annotation",
"punctuation.definition.annotation"
],
"settings": {
"foreground": "#C96385"
}
},
{
"scope": [
"entity.name.tag",
"punctuation.definition.tag"
],
"settings": {
"foreground": "#E35A8F"
}
},
{
"scope": [
"entity.other.attribute-name",
"entity.other.attribute-name.html",
"entity.other.attribute-name.css",
"support.type.property-name.css",
"entity.other.attribute-name.class"
],
"settings": {
"foreground": "#FF77A8"
}
},
{
"scope": [
"support.type.primitive",
"support.type.builtin",
"keyword.type",
"storage.type.primitive",
"storage.type.built-in",
"support.type.primitive.dart"
],
"settings": {
"foreground": "#FF77A8"
}
},
{
"scope": [
"string.regexp",
"constant.character.escape.regex"
],
"settings": {
"foreground": "#FF69B4"
}
},
{
"scope": [
"markup.heading",
"entity.name.section"
],
"settings": {
"foreground": "#D45A88",
"fontStyle": "bold"
}
},
{
"scope": [
"markup.bold"
],
"settings": {
"fontStyle": "bold"
}
},
{
"scope": [
"markup.italic"
],
"settings": {
"fontStyle": "italic"
}
},
{
"scope": [
"markup.inline.raw",
"markup.fenced_code",
"markup.raw"
],
"settings": {
"foreground": "#FF69B4"
}
},
{
"scope": [
"support.type.property-name.json",
"support.type.property-name.jsonc"
],
"settings": {
"foreground": "#FF77A8"
}
},
{
"scope": [
"keyword.operator.expression",
"keyword.operator.new",
"keyword.operator.optional",
"keyword.operator.comparison",
"keyword.operator.arithmetic",
"keyword.operator.assignment",
"keyword.operator.logical"
],
"settings": {
"foreground": "#E35A8F"
}
},
{
"scope": [
"meta.embedded",
"source.groovy.embedded",
"meta.template.expression"
],
"settings": {
"foreground": "#D87093"
}
},
{
"scope": [
"meta.object-literal.key",
"variable.object.property",
"variable.other.property",
"variable.other.object.property"
],
"settings": {
"foreground": "#FF77A8"
}
},
{
"scope": [
"support.variable.property",
"support.variable.object.process",
"support.variable.object.node"
],
"settings": {
"foreground": "#FF77A8"
}
},
{
"scope": [
"source.rust storage.type.rust",
"source.rust entity.name.type.rust",
"source.rust entity.name.type.struct.rust"
],
"settings": {
"foreground": "#FF77A8"
}
},
{
"scope": [
"source.rust keyword.operator",
"source.rust keyword.operator.arithmetic",
"source.rust keyword.operator.logical"
],
"settings": {
"foreground": "#E35A8F"
}
},
{
"scope": [
"source.python support.type.python",
"source.python support.function.builtin.python"
],
"settings": {
"foreground": "#D45A88"
}
},
{
"scope": [
"source.cs entity.name.type.class.cs",
"source.cs storage.type.cs"
],
"settings": {
"foreground": "#FF77A8"
}
},
{
"scope": [
"source.dart support.class.dart",
"source.dart support.type.dart"
],
"settings": {
"foreground": "#FF77A8"
}
},
{
"scope": [
"source.prisma keyword.operator",
"source.prisma constant.language",
"source.prisma keyword.type"
],
"settings": {
"foreground": "#E35A8F"
}
},
{
"scope": [
"source.graphql support.type",
"source.graphql constant.character"
],
"settings": {
"foreground": "#FF77A8"
}
},
{
"scope": [
"source.sql keyword.other",
"source.sql storage.type"
],
"settings": {
"foreground": "#E35A8F"
}
},
{
"scope": [
"meta.jsx.children",
"meta.embedded.block.tsx",
"meta.embedded.block.jsx"
],
"settings": {
"foreground": "#D87093"
}
},
{
"scope": [
"meta.decorator.ts",
"meta.decorator.tsx",
"meta.decorator.angular"
],
"settings": {
"foreground": "#C96385"
}
},
{
"scope": "ref.matchtext",
"settings": {
"foreground": "#FFFFFF"
}
},
{
"scope": "token.info-token",
"settings": {
"foreground": "#6796E6"
}
},
{
"scope": "token.warn-token",
"settings": {
"foreground": "#CD9731"
}
},
{
"scope": "token.error-token",
"settings": {
"foreground": "#F44747"
}
},
{
"scope": "token.debug-token",
"settings": {
"foreground": "#B267E6"
}
}
]
}