got dark/light mode working for color preference I think just need to add toggle

This commit is contained in:
Pagwin 2024-10-24 19:07:18 -04:00
parent 294925c926
commit 131f2e2d0f
No known key found for this signature in database
GPG key ID: 81137023740CA260
7 changed files with 461 additions and 23 deletions

14
TODO
View file

@ -1,15 +1,17 @@
get RSS feed up and running position code blocks in a way I like
handle dark/light theming correctly (https://www.joshwcomeau.com/react/dark-mode/) seems useful for that handle dark/light theming correctly (https://www.joshwcomeau.com/react/dark-mode/) seems useful for that
~~get code blocks working properly, namely get them colored (probably with https://highlightjs.org/), maybe add a red border, consider https://github.com/highlightjs/highlight.js?tab=readme-ov-file#using-web-workers~~ get RSS feed up and running
get highlight js theme set to my preference, make sure to add nesting in CSS so it'll be active when the light/dark class is active
https://highlightjs.org/examples
https://github.com/highlightjs/base16-highlightjs/blob/main/themes/google-light.css
ico? ico?
analytics
~~get code blocks working properly, namely get them colored (probably with https://highlightjs.org/), maybe add a red border, consider https://github.com/highlightjs/highlight.js?tab=readme-ov-file#using-web-workers~~
~~get highlight js theme set to my preference, make sure to add nesting in CSS so it'll be active when the light/dark class is active~~
~~add CSS styling rule(s) so headers don't get link colors~~ ~~add CSS styling rule(s) so headers don't get link colors~~
~~center titles properly~~ ~~center titles properly~~

182
static/css/dark-code.css Normal file
View file

@ -0,0 +1,182 @@
/*
* wrapping Google Light so it fits my purposes
* */
body.dark{
/*!
Theme: Google Dark
Author: Seth Wright (http://sethawright.com)
License: ~ MIT (or more permissive) [via base16-schemes-source]
Maintainer: @highlightjs/core-team
Version: 2021.09.0
*/
/*
WARNING: DO NOT EDIT THIS FILE DIRECTLY.
This theme file was auto-generated from the Base16 scheme google-dark
by the Highlight.js Base16 template builder.
- https://github.com/highlightjs/base16-highlightjs
*/
/*
base00 #1d1f21 Default Background
base01 #282a2e Lighter Background (Used for status bars, line number and folding marks)
base02 #373b41 Selection Background
base03 #969896 Comments, Invisibles, Line Highlighting
base04 #b4b7b4 Dark Foreground (Used for status bars)
base05 #c5c8c6 Default Foreground, Caret, Delimiters, Operators
base06 #e0e0e0 Light Foreground (Not often used)
base07 #ffffff Light Background (Not often used)
base08 #CC342B Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted
base09 #F96A38 Integers, Boolean, Constants, XML Attributes, Markup Link Url
base0A #FBA922 Classes, Markup Bold, Search Text Background
base0B #198844 Strings, Inherited Class, Markup Code, Diff Inserted
base0C #3971ED Support, Regular Expressions, Escape Characters, Markup Quotes
base0D #3971ED Functions, Methods, Attribute IDs, Headings
base0E #A36AC7 Keywords, Storage, Selector, Markup Italic, Diff Changed
base0F #3971ED Deprecated, Opening/Closing Embedded Language Tags, e.g. <?php ?>
*/
pre code.hljs {
display: block;
overflow-x: auto;
padding: 1em;
}
code.hljs {
padding: 3px 5px;
}
.hljs {
color: #c5c8c6;
background: #1d1f21;
}
.hljs::selection,
.hljs ::selection {
background-color: #373b41;
color: #c5c8c6;
}
/* purposely do not highlight these things */
.hljs-formula,
.hljs-params,
.hljs-property
{}
/* base03 - #969896 - Comments, Invisibles, Line Highlighting */
.hljs-comment {
color: #969896;
}
/* base04 - #b4b7b4 - Dark Foreground (Used for status bars) */
.hljs-tag {
color: #b4b7b4;
}
/* base05 - #c5c8c6 - Default Foreground, Caret, Delimiters, Operators */
.hljs-subst,
.hljs-punctuation,
.hljs-operator {
color: #c5c8c6;
}
.hljs-operator {
opacity: 0.7;
}
/* base08 - Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted */
.hljs-bullet,
.hljs-variable,
.hljs-template-variable,
.hljs-selector-tag,
.hljs-name,
.hljs-deletion {
color: #CC342B;
}
/* base09 - Integers, Boolean, Constants, XML Attributes, Markup Link Url */
.hljs-symbol,
.hljs-number,
.hljs-link,
.hljs-attr,
.hljs-variable.constant_,
.hljs-literal {
color: #F96A38;
}
/* base0A - Classes, Markup Bold, Search Text Background */
.hljs-title,
.hljs-class .hljs-title,
.hljs-title.class_
{
color: #FBA922;
}
.hljs-strong {
font-weight:bold;
color: #FBA922;
}
/* base0B - Strings, Inherited Class, Markup Code, Diff Inserted */
.hljs-code,
.hljs-addition,
.hljs-title.class_.inherited__,
.hljs-string {
color: #198844;
}
/* base0C - Support, Regular Expressions, Escape Characters, Markup Quotes */
.hljs-built_in,
.hljs-doctag, /* guessing */
.hljs-quote,
.hljs-keyword.hljs-atrule,
.hljs-regexp {
color: #3971ED;
}
/* base0D - Functions, Methods, Attribute IDs, Headings */
.hljs-function .hljs-title,
.hljs-attribute,
.ruby .hljs-property,
.hljs-title.function_,
.hljs-section {
color: #3971ED;
}
/* base0E - Keywords, Storage, Selector, Markup Italic, Diff Changed */
.hljs-type,
/* .hljs-selector-id, */
/* .hljs-selector-class, */
/* .hljs-selector-attr, */
/* .hljs-selector-pseudo, */
.hljs-template-tag,
.diff .hljs-meta,
.hljs-keyword {
color: #A36AC7;
}
.hljs-emphasis {
color: #A36AC7;
font-style: italic;
}
/* base0F - Deprecated, Opening/Closing Embedded Language Tags, e.g. <?php ?> */
.hljs-meta,
/*
prevent top level .keyword and .string scopes
from leaking into meta by accident
*/
.hljs-meta .hljs-keyword,
.hljs-meta .hljs-string
{
color: #3971ED;
}
.hljs-meta .hljs-keyword,
/* for v10 compatible themes */
.hljs-meta-keyword {
font-weight: bold;
}
}

View file

@ -99,7 +99,8 @@ pre {
max-width: calc(100% - 2em); max-width: calc(100% - 2em);
width: fit-content; width: fit-content;
overflow:scroll; overflow:scroll;
background: #444; /*background: #444;*/
border-radius: 0.5em; border-radius: 0.5em;
padding: 1em; /*border: 0.2em solid red;*/
padding: 0.5em;
} }

182
static/css/light-code.css Normal file
View file

@ -0,0 +1,182 @@
/*
* wrapping Google Light so it fits my purposes
* */
body.light{
/*!
Theme: Google Light
Author: Seth Wright (http://sethawright.com)
License: ~ MIT (or more permissive) [via base16-schemes-source]
Maintainer: @highlightjs/core-team
Version: 2021.09.0
*/
/*
WARNING: DO NOT EDIT THIS FILE DIRECTLY.
This theme file was auto-generated from the Base16 scheme google-light
by the Highlight.js Base16 template builder.
- https://github.com/highlightjs/base16-highlightjs
*/
/*
base00 #ffffff Default Background
base01 #e0e0e0 Lighter Background (Used for status bars, line number and folding marks)
base02 #c5c8c6 Selection Background
base03 #b4b7b4 Comments, Invisibles, Line Highlighting
base04 #969896 Dark Foreground (Used for status bars)
base05 #373b41 Default Foreground, Caret, Delimiters, Operators
base06 #282a2e Light Foreground (Not often used)
base07 #1d1f21 Light Background (Not often used)
base08 #CC342B Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted
base09 #F96A38 Integers, Boolean, Constants, XML Attributes, Markup Link Url
base0A #FBA922 Classes, Markup Bold, Search Text Background
base0B #198844 Strings, Inherited Class, Markup Code, Diff Inserted
base0C #3971ED Support, Regular Expressions, Escape Characters, Markup Quotes
base0D #3971ED Functions, Methods, Attribute IDs, Headings
base0E #A36AC7 Keywords, Storage, Selector, Markup Italic, Diff Changed
base0F #3971ED Deprecated, Opening/Closing Embedded Language Tags, e.g. <?php ?>
*/
pre code.hljs {
display: block;
overflow-x: auto;
padding: 1em;
}
code.hljs {
padding: 3px 5px;
}
.hljs {
color: #373b41;
background: #ffffff;
}
.hljs::selection,
.hljs ::selection {
background-color: #c5c8c6;
color: #373b41;
}
/* purposely do not highlight these things */
.hljs-formula,
.hljs-params,
.hljs-property
{}
/* base03 - #b4b7b4 - Comments, Invisibles, Line Highlighting */
.hljs-comment {
color: #b4b7b4;
}
/* base04 - #969896 - Dark Foreground (Used for status bars) */
.hljs-tag {
color: #969896;
}
/* base05 - #373b41 - Default Foreground, Caret, Delimiters, Operators */
.hljs-subst,
.hljs-punctuation,
.hljs-operator {
color: #373b41;
}
.hljs-operator {
opacity: 0.7;
}
/* base08 - Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted */
.hljs-bullet,
.hljs-variable,
.hljs-template-variable,
.hljs-selector-tag,
.hljs-name,
.hljs-deletion {
color: #CC342B;
}
/* base09 - Integers, Boolean, Constants, XML Attributes, Markup Link Url */
.hljs-symbol,
.hljs-number,
.hljs-link,
.hljs-attr,
.hljs-variable.constant_,
.hljs-literal {
color: #F96A38;
}
/* base0A - Classes, Markup Bold, Search Text Background */
.hljs-title,
.hljs-class .hljs-title,
.hljs-title.class_
{
color: #FBA922;
}
.hljs-strong {
font-weight:bold;
color: #FBA922;
}
/* base0B - Strings, Inherited Class, Markup Code, Diff Inserted */
.hljs-code,
.hljs-addition,
.hljs-title.class_.inherited__,
.hljs-string {
color: #198844;
}
/* base0C - Support, Regular Expressions, Escape Characters, Markup Quotes */
.hljs-built_in,
.hljs-doctag, /* guessing */
.hljs-quote,
.hljs-keyword.hljs-atrule,
.hljs-regexp {
color: #3971ED;
}
/* base0D - Functions, Methods, Attribute IDs, Headings */
.hljs-function .hljs-title,
.hljs-attribute,
.ruby .hljs-property,
.hljs-title.function_,
.hljs-section {
color: #3971ED;
}
/* base0E - Keywords, Storage, Selector, Markup Italic, Diff Changed */
.hljs-type,
/* .hljs-selector-id, */
/* .hljs-selector-class, */
/* .hljs-selector-attr, */
/* .hljs-selector-pseudo, */
.hljs-template-tag,
.diff .hljs-meta,
.hljs-keyword {
color: #A36AC7;
}
.hljs-emphasis {
color: #A36AC7;
font-style: italic;
}
/* base0F - Deprecated, Opening/Closing Embedded Language Tags, e.g. <?php ?> */
.hljs-meta,
/*
prevent top level .keyword and .string scopes
from leaking into meta by accident
*/
.hljs-meta .hljs-keyword,
.hljs-meta .hljs-string
{
color: #3971ED;
}
.hljs-meta .hljs-keyword,
/* for v10 compatible themes */
.hljs-meta-keyword {
font-weight: bold;
}
}

View file

@ -2,37 +2,36 @@
async function setup(){ async function setup(){
// start fetching css sooner rather than latter // start fetching css sooner rather than latter
const baseCssProm = fetch("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css").then(res=>res.text()); const baseCssProm = fetch("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css").then(res=>res.text());
// TODO: pick light and dark themes and specify their fetch location const lightCssProm = fetch("/static/css/light-code.css").then(res=>res.text());
//const lightCssProm = fetch("").then(res=>res.text()); const darkCssProm = fetch("/static/css/dark-code.css").then(res=>res.text());
//const darkCssProm = fetch("").then(res=>res.text());
const code = document.querySelectorAll("pre.sourceCode code"); const code = document.querySelectorAll("pre.sourceCode");
const worker = new Worker('/static/js/code_highlighting_worker.mjs'); const worker = new Worker('/static/js/code_highlighting_worker.mjs');
worker.onmessage = (event) => { worker.onmessage = (event) => {
const [index, newTxt] = event.data; const [index, newTxt] = event.data;
code[index].innerHTML = newTxt; code[index].innerHTML = newTxt;
//for(let c of code){
// c.innerHTML = event.data;
//}
} }
for(let i = 0;i<code.length;i++){ for(let i = 0;i<code.length;i++){
worker.postMessage([i, code[i].textContent]); worker.postMessage([i, code[i].textContent]);
} }
for(const c of code){
c.classList.add("hljs");
}
// setting up the css for highlighting with previously fetched css // setting up the css for highlighting with previously fetched css
const baseStylesheet = new CSSStyleSheet(); const baseStylesheet = new CSSStyleSheet();
//const lightThemeSheet = new CSSStyleSheet(); const lightThemeSheet = new CSSStyleSheet();
//const darkThemeSheet = new CSSStyleSheet(); const darkThemeSheet = new CSSStyleSheet();
//shenanigans done to avoid awaiting each promise sequentially //shenanigans done to avoid awaiting each promise sequentially
await Promise.all([ await Promise.all([
(async()=>{return await baseStylesheet.replace(await baseCssProm)})(), (async()=>{return await baseStylesheet.replace(await baseCssProm)})(),
//(async()=>{return await lightThemeSheet.replace(await lightCssProm)})(), (async()=>{return await lightThemeSheet.replace(await lightCssProm)})(),
//(async()=>{return await darkThemeSheet.replace(await darkCssProm)})(), (async()=>{return await darkThemeSheet.replace(await darkCssProm)})(),
]); ]);
document.adoptedStyleSheets.push(baseStylesheet); document.adoptedStyleSheets.push(baseStylesheet);
//document.adoptedStyleSheets.push(lightThemeSheet); document.adoptedStyleSheets.push(lightThemeSheet);
//document.adoptedStyleSheets.push(darkThemeSheet); document.adoptedStyleSheets.push(darkThemeSheet);
} }
addEventListener('load', setup); addEventListener('load', setup);

70
static/js/color-mode.mjs Normal file
View file

@ -0,0 +1,70 @@
// this script is intentionally not a module so it'll block loading the document until we set color mode
// shamelessly stolen from https://www.joshwcomeau.com/react/dark-mode/
function getInitialColorMode() {
const persistedColorPreference =
window.localStorage.getItem('color-mode');
const hasPersistedPreference =
typeof persistedColorPreference === 'string';
// If the user has explicitly chosen light or dark,
// let's use it. Otherwise, this value will be null.
if (hasPersistedPreference) {
return persistedColorPreference;
}
// If they haven't been explicit, let's check the media query
const mql = window.matchMedia('(prefers-color-scheme: dark)');
const hasMediaQueryPreference = typeof mql.matches === 'boolean';
if (hasMediaQueryPreference) {
return mql.matches ? 'dark' : 'light';
}
// If they are using a browser/OS that doesn't support
// color themes, let's default to 'light'.
return 'light';
}
function setMode(mode){
if(document.body.classList.contains("light")){
document.body.classList.replace("light", mode);
}
else if (document.body.classList.contains("dark")){
document.body.classList.replace("dark", mode);
}
else {
document.body.classList.add(color_mode);
}
localStorage.setItem("color-mode", mode);
}
// repeats set code but who cares, the logic is different
function toggleMode(){
let mode;
if(document.body.classList.contains("light")){
document.body.classList.replace("light", "dark");
mode = "dark";
}
else if (document.body.classList.contains("dark")){
document.body.classList.replace("dark", "light");
mode = "light";
}
else {
throw new Error("cannot toggle theme it isn't set yet");
}
localStorage.setItem("color-mode", mode);
}
// start grabbing the css in the background
const bg_css = (async ()=>{
const css_txt = fetch("/static/css/default.css").then(res=>res.text());
const css = new CSSStyleSheet();
await css.replace(await css_txt);
return css;
})();
// set color mode
const color_mode = getInitialColorMode();
setMode(color_mode);
// now that color mode is set lets go actually set the css
document.adoptedStyleSheets.push(await bg_css);

View file

@ -5,12 +5,14 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{{title}}} · Pagwin's website</title> <title>{{{title}}} · Pagwin's website</title>
<link rel="stylesheet" type="text/css" href="/static/css/default.css" /> <link rel="preload" type="text/css" href="/static/css/default.css" />
<link rel="alternate" type="application/rss+xml" title="RSS" href="https://pagwin.xyz/index.xml"> <link rel="alternate" type="application/rss+xml" title="RSS" href="https://pagwin.xyz/index.xml">
<script type="module" src="/static/js/code_highlighting.mjs"></script> <script type="module" src="/static/js/code_highlighting.mjs"></script>
</head> </head>
<body class="dark"> <body class="light">
<!--script is at the top of body, it needs body defined but we want to start work on downloading and loading it asap, we can have it block by having it not be a module but that has performance problems for slower internet that makes me prefer having it as a module even if users get a flicker of unstylized page-->
<script type="module" src="/static/js/color-mode.mjs"></script>
<div id="header"> <div id="header">
<a class="nav-link" href="/">Home</a> <a class="nav-link" href="/">Home</a>
<a class="nav-link" href="/posts/">Blog Posts</a> <a class="nav-link" href="/posts/">Blog Posts</a>