diff --git a/assets/css/torchlight.css b/assets/css/torchlight.css index 5def64b..a864f1a 100644 --- a/assets/css/torchlight.css +++ b/assets/css/torchlight.css @@ -126,17 +126,17 @@ opacity: 1; Insert prompt indicators on interactive shells. */ .cmd::before { - color: var(--base07); + color: var(--user-prompt); content: "$ "; } .cmd_root::before { - color: var(--base08); + color: var(--root-prompt); content: "# "; } .cmd_pwsh::before { - color: var(--base07); + color: var(--user-prompt); content: "PS> "; } diff --git a/assets/js/set-theme.js b/assets/js/set-theme.js new file mode 100644 index 0000000..5ee4ac4 --- /dev/null +++ b/assets/js/set-theme.js @@ -0,0 +1,40 @@ +const toggleButton = document.getElementById('themeToggle'); +const htmlElement = document.documentElement; + +function setTheme(theme) { + htmlElement.setAttribute('data-theme', theme); + localStorage.setItem('theme', theme); + updateToggleButton(theme); +} + +function updateToggleButton(theme) { + toggleButton.setAttribute('aria-checked', theme === 'dark'); +} + +function getPreferredTheme() { + const storedTheme = localStorage.getItem('theme'); + if (storedTheme) { + return storedTheme; + } + return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; +} + +// Ensure the toggle button state is correct on load +document.addEventListener('DOMContentLoaded', () => { + updateToggleButton(getPreferredTheme()); +}); + +// Listen for toggle button clicks +toggleButton.addEventListener('click', () => { + const currentTheme = htmlElement.getAttribute('data-theme') || getPreferredTheme(); + const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; + setTheme(newTheme); +}); + +// Listen for system preference changes +window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => { + if (!localStorage.getItem('theme')) { + const newTheme = e.matches ? 'dark' : 'light'; + setTheme(newTheme); + } +}); \ No newline at end of file diff --git a/layouts/partials/about.html b/layouts/partials/about.html index f78bae7..d0e4a3e 100644 --- a/layouts/partials/about.html +++ b/layouts/partials/about.html @@ -1,7 +1,7 @@ {{ with .Site.Params.about }}
{{ with .logo }}{{ end }} -

{{ .title }}  

+

{{ .title }} 

{{ partial "tagline.html" . }}
 {{ site.Params.Author.name }} diff --git a/layouts/partials/footer.html b/layouts/partials/footer.html index 9f713ba..d1ba2ac 100644 --- a/layouts/partials/footer.html +++ b/layouts/partials/footer.html @@ -15,3 +15,7 @@ {{ $jsCopy := resources.Get "js/code-copy-button.js" | minify }} {{ end }} + + +{{ $themeToggle := resources.Get "js/set-theme.js" | minify }} + diff --git a/layouts/partials/head.html b/layouts/partials/head.html index 113b5ee..4691e45 100644 --- a/layouts/partials/head.html +++ b/layouts/partials/head.html @@ -21,8 +21,20 @@ {{ partialCached "favicon" . }} {{ partial "opengraph" . }} + + + - + diff --git a/layouts/partials/header.html b/layouts/partials/header.html index 45c46ce..c3435de 100644 --- a/layouts/partials/header.html +++ b/layouts/partials/header.html @@ -7,4 +7,8 @@ {{ end }} - + \ No newline at end of file diff --git a/static/css/custom.css b/static/css/custom.css index c7c6ddf..0398121 100644 --- a/static/css/custom.css +++ b/static/css/custom.css @@ -1,9 +1,113 @@ -/* color and font overrides */ +/* define fonts */ :root { - --code: var(--base06); --font-monospace: 'Berkeley Mono', 'IBM Plex Mono', 'Cascadia Mono', 'Roboto Mono', 'Source Code Pro', 'Fira Mono', 'Courier New', monospace; } +/* dark/light theming */ +:root{ + /* Default dark theme */ + --bg: var(--dark-base00); + --code: var(--dark-base06); + --fg: var(--dark-base05); + --highlight: var(--dark-base0A); + --hover: var(--dark-base0C); + --inner-bg: var(--dark-base02); + --link: var(--dark-base0D); + --logo-text: var(--dark-base09); + --logo: var(--dark-base0B); + --muted: var(--dark-base03); + --off-bg: var(--dark-base01); + --off-fg: var(--dark-base04); + --root-prompt: var(--dark-base08); + --user-prompt: var(--dark-base07); +} + +:root[data-theme="light"] { + --bg: var(--light-base00); + --off-bg: var(--light-base01); + --inner-bg: var(--light-base02); + --muted: var(--light-base03); + --off-fg: var(--light-base04); + --fg: var(--light-base05); + --code: var(--light-base06); + --user-prompt: var(--light-base07); + --root-prompt: var(--light-base08); + --logo-text: var(--light-base09); + --highlight: var(--light-base0A); + --logo: var(--light-base0B); + --hover: var(--light-base0C); + --link: var(--light-base0D); +} + +@media (prefers-color-scheme: light) { + :root:not([data-theme="dark"]) { + --bg: var(--light-base00); + --off-bg: var(--light-base01); + --inner-bg: var(--light-base02); + --muted: var(--light-base03); + --off-fg: var(--light-base04); + --fg: var(--light-base05); + --code: var(--light-base06); + --user-prompt: var(--light-base07); + --root-prompt: var(--light-base08); + --logo-text: var(--light-base09); + --highlight: var(--light-base0A); + --logo: var(--light-base0B); + --hover: var(--light-base0C); + --link: var(--light-base0D); + } +} + +body { + transition: background-color 0.3s ease, color 0.3s ease; +} + +.theme-toggle { + position: absolute; + top: 1rem; + right: 1rem; + background: none; + border: none; + cursor: pointer; + padding: 0; + width: 2rem; + height: 2rem; + z-index: 1000; + transition: opacity 0.3s ease; +} + +.theme-toggle:hover { + opacity: 0.7; +} + +.theme-toggle:focus { + outline: none; +} + +.theme-toggle:focus-visible { + outline: 2px solid var(--hover); + outline-offset: 2px; +} + +.theme-toggle__icon { + width: 100%; + height: 100%; + transition: transform 0.3s ease, fill 0.3s ease; + fill: var(--off-fg); +} + +.theme-toggle:hover .theme-toggle__icon { + fill: var(--hover); +} + +[data-theme="dark"] .theme-toggle__icon { + transform: rotate(180deg); +} + +.page__nav ul { + padding-right: 3rem; +} + /* load preferred font */ @font-face { font-family: 'Berkeley Mono'; @@ -30,7 +134,7 @@ /* logo tweaks */ .page__logo { - color: var(--off-fg); + color: var(--logo-text); } .page__logo-inner { diff --git a/static/css/palettes/runtimeterror.css b/static/css/palettes/runtimeterror.css index 76e566e..5d6b2a9 100644 --- a/static/css/palettes/runtimeterror.css +++ b/static/css/palettes/runtimeterror.css @@ -2,20 +2,35 @@ */ :root { - --base00: #090909; /* bg */ - --base01: #1c1c1c; /* off-bg */ - --base02: #292929; /* inner-bg */ - --base03: #6d6c6c; /* muted */ - --base04: #abaaaa; /* off-fg */ - --base05: #d8d8d8; /* fg */ - --base06: #75f558; /* code */ - --base07: #5f8700; /* user prompt */ - --base08: #ab4642; /* root prompt */ - --base09: #dc9656; - --base0A: #f7ca88; /* highlight */ - --base0B: #682523; /* logo */ - --base0C: #ab2321; /* hover */ - --base0D: #d36060; /* link */ - --base0E: #ba8baf; - --base0F: #a16946; + /* dark theme colors */ + --dark-base00: #090909; /* bg */ + --dark-base01: #1c1c1c; /* off-bg */ + --dark-base02: #292929; /* inner-bg */ + --dark-base03: #6d6c6c; /* muted */ + --dark-base04: #abaaaa; /* off-fg */ + --dark-base05: #d8d8d8; /* fg */ + --dark-base06: #75f558; /* code */ + --dark-base07: #5f8700; /* user prompt */ + --dark-base08: #ab4642; /* root prompt */ + --dark-base09: #abaaaa; /* logo text */ + --dark-base0A: #f7ca88; /* highlight */ + --dark-base0B: #682523; /* logo */ + --dark-base0C: #ab2321; /* hover */ + --dark-base0D: #d36060; /* link */ + + /* light theme colors */ + --light-base00: #ffffff; /* bg */ + --light-base01: #f0f0f0; /* off-bg */ + --light-base02: #dbdbdb; /* inner-bg */ + --light-base03: #909090; /* muted */ + --light-base04: #707070; /* off-fg */ + --light-base05: #303030; /* fg */ + --light-base06: #2a8f1f; /* code */ + --light-base07: #3f5900; /* user prompt */ + --light-base08: #c23d3d; /* root prompt */ + --light-base09: #f0f0f0; /* logo-text */ + --light-base0A: #d4a960; /* highlight */ + --light-base0B: #af3a37; /* logo */ + --light-base0C: #c62a28; /* hover */ + --light-base0D: #a04545; /* link */ } diff --git a/torchlight.config.js b/torchlight.config.js index bc799f9..8c44c81 100644 --- a/torchlight.config.js +++ b/torchlight.config.js @@ -11,7 +11,7 @@ module.exports = { // Which theme you want to use. You can find all of the themes at // https://torchlight.dev/docs/themes. - theme: 'synthwave-84', + theme: 'material-theme-lighter', // The Host of the API. host: 'https://api.torchlight.dev',