From 4d3579ca9876d3ca6612589d116c3a300a60b446 Mon Sep 17 00:00:00 2001 From: Jacky Zhao <j.zhao2k19@gmail.com> Date: Tue, 6 Jun 2023 19:48:37 -0700 Subject: [PATCH] darkmode scripts --- quartz.config.ts | 4 +- quartz/bootstrap-cli.mjs | 1 + quartz/build.ts | 2 +- quartz/components/Darkmode.tsx | 47 ++++++++++++++++++++ quartz/components/Head.tsx | 2 +- quartz/components/Header.tsx | 8 +++- quartz/components/scripts/darkmode.inline.ts | 26 ++++++++++- quartz/components/types.ts | 3 +- quartz/plugins/emitters/contentPage.tsx | 4 +- quartz/styles/base.scss | 6 +-- quartz/styles/callouts.scss | 2 +- quartz/styles/darkmode.scss | 45 +++++++++++++++++++ quartz/styles/header.scss | 10 +++++ 13 files changed, 145 insertions(+), 15 deletions(-) create mode 100644 quartz/components/Darkmode.tsx create mode 100644 quartz/styles/darkmode.scss create mode 100644 quartz/styles/header.scss diff --git a/quartz.config.ts b/quartz.config.ts index 6808d93..25518d5 100644 --- a/quartz.config.ts +++ b/quartz.config.ts @@ -1,6 +1,6 @@ import { QuartzConfig } from "./quartz/cfg" -import * as Head from "./quartz/components/Head" -import * as Header from "./quartz/components/Header" +import Head from "./quartz/components/Head" +import Header from "./quartz/components/Header" import { ContentPage, CreatedModifiedDate, diff --git a/quartz/bootstrap-cli.mjs b/quartz/bootstrap-cli.mjs index be6270e..f9b5304 100755 --- a/quartz/bootstrap-cli.mjs +++ b/quartz/bootstrap-cli.mjs @@ -74,6 +74,7 @@ yargs(hideBin(process.argv)) const transpiled = await esbuild.build({ stdin: { contents: text, + loader: 'ts', sourcefile: path.relative(path.resolve('.'), args.path), }, write: false, diff --git a/quartz/build.ts b/quartz/build.ts index 26e354c..60a1a51 100644 --- a/quartz/build.ts +++ b/quartz/build.ts @@ -59,7 +59,7 @@ export default async function buildQuartz(argv: Argv, version: string) { const server = http.createServer(async (req, res) => { return serveHandler(req, res, { public: output, - directoryListing: false + directoryListing: false, }) }) server.listen(argv.port) diff --git a/quartz/components/Darkmode.tsx b/quartz/components/Darkmode.tsx new file mode 100644 index 0000000..0161e0a --- /dev/null +++ b/quartz/components/Darkmode.tsx @@ -0,0 +1,47 @@ +import darkmodeScript from "./scripts/darkmode.inline" +import styles from '../styles/darkmode.scss' + +export default function Darkmode() { + return <div class="darkmode"> + <input class="toggle" id="darkmode-toggle" type="checkbox" tabIndex={-1} /> + <label id="toggle-label-light" for="darkmode-toggle" tabIndex={-1}> + <svg + xmlns="http://www.w3.org/2000/svg" + xmlnsXlink="http://www.w3.org/1999/xlink" + version="1.1" + id="dayIcon" + x="0px" + y="0px" + viewBox="0 0 35 35" + style="enable-background:new 0 0 35 35;" + xmlSpace="preserve" + > + <title>Light mode</title> + <path + d="M6,17.5C6,16.672,5.328,16,4.5,16h-3C0.672,16,0,16.672,0,17.5 S0.672,19,1.5,19h3C5.328,19,6,18.328,6,17.5z M7.5,26c-0.414,0-0.789,0.168-1.061,0.439l-2,2C4.168,28.711,4,29.086,4,29.5 C4,30.328,4.671,31,5.5,31c0.414,0,0.789-0.168,1.06-0.44l2-2C8.832,28.289,9,27.914,9,27.5C9,26.672,8.329,26,7.5,26z M17.5,6 C18.329,6,19,5.328,19,4.5v-3C19,0.672,18.329,0,17.5,0S16,0.672,16,1.5v3C16,5.328,16.671,6,17.5,6z M27.5,9 c0.414,0,0.789-0.168,1.06-0.439l2-2C30.832,6.289,31,5.914,31,5.5C31,4.672,30.329,4,29.5,4c-0.414,0-0.789,0.168-1.061,0.44 l-2,2C26.168,6.711,26,7.086,26,7.5C26,8.328,26.671,9,27.5,9z M6.439,8.561C6.711,8.832,7.086,9,7.5,9C8.328,9,9,8.328,9,7.5 c0-0.414-0.168-0.789-0.439-1.061l-2-2C6.289,4.168,5.914,4,5.5,4C4.672,4,4,4.672,4,5.5c0,0.414,0.168,0.789,0.439,1.06 L6.439,8.561z M33.5,16h-3c-0.828,0-1.5,0.672-1.5,1.5s0.672,1.5,1.5,1.5h3c0.828,0,1.5-0.672,1.5-1.5S34.328,16,33.5,16z M28.561,26.439C28.289,26.168,27.914,26,27.5,26c-0.828,0-1.5,0.672-1.5,1.5c0,0.414,0.168,0.789,0.439,1.06l2,2 C28.711,30.832,29.086,31,29.5,31c0.828,0,1.5-0.672,1.5-1.5c0-0.414-0.168-0.789-0.439-1.061L28.561,26.439z M17.5,29 c-0.829,0-1.5,0.672-1.5,1.5v3c0,0.828,0.671,1.5,1.5,1.5s1.5-0.672,1.5-1.5v-3C19,29.672,18.329,29,17.5,29z M17.5,7 C11.71,7,7,11.71,7,17.5S11.71,28,17.5,28S28,23.29,28,17.5S23.29,7,17.5,7z M17.5,25c-4.136,0-7.5-3.364-7.5-7.5 c0-4.136,3.364-7.5,7.5-7.5c4.136,0,7.5,3.364,7.5,7.5C25,21.636,21.636,25,17.5,25z" + ></path> + </svg> + </label> + <label id="toggle-label-dark" for="darkmode-toggle" tabIndex={-1}> + <svg + xmlns="http://www.w3.org/2000/svg" + xmlnsXlink="http://www.w3.org/1999/xlink" + version="1.1" + id="nightIcon" + x="0px" + y="0px" + viewBox="0 0 100 100" + style="enable-background='new 0 0 100 100'" + xmlSpace="preserve" + > + <title>Dark mode</title> + <path + d="M96.76,66.458c-0.853-0.852-2.15-1.064-3.23-0.534c-6.063,2.991-12.858,4.571-19.655,4.571 C62.022,70.495,50.88,65.88,42.5,57.5C29.043,44.043,25.658,23.536,34.076,6.47c0.532-1.08,0.318-2.379-0.534-3.23 c-0.851-0.852-2.15-1.064-3.23-0.534c-4.918,2.427-9.375,5.619-13.246,9.491c-9.447,9.447-14.65,22.008-14.65,35.369 c0,13.36,5.203,25.921,14.65,35.368s22.008,14.65,35.368,14.65c13.361,0,25.921-5.203,35.369-14.65 c3.872-3.871,7.064-8.328,9.491-13.246C97.826,68.608,97.611,67.309,96.76,66.458z" + ></path> + </svg> + </label> + </div> +} + +Darkmode.beforeDOMLoaded = darkmodeScript +Darkmode.css = styles diff --git a/quartz/components/Head.tsx b/quartz/components/Head.tsx index 29050a7..9e182c7 100644 --- a/quartz/components/Head.tsx +++ b/quartz/components/Head.tsx @@ -8,7 +8,7 @@ export interface HeadProps { externalResources: StaticResources } -export function Component({ title, description, slug, externalResources }: HeadProps) { +export default function Head({ title, description, slug, externalResources }: HeadProps) { const { css, js } = externalResources const baseDir = resolveToRoot(slug) const iconPath = baseDir + "/static/icon.png" diff --git a/quartz/components/Header.tsx b/quartz/components/Header.tsx index 229e210..cb2fae8 100644 --- a/quartz/components/Header.tsx +++ b/quartz/components/Header.tsx @@ -1,14 +1,20 @@ import { resolveToRoot } from "../path" +import Darkmode from "./Darkmode" +import style from '../styles/header.scss' export interface HeaderProps { title: string slug: string } -export function Component({ title, slug }: HeaderProps) { +export default function Header({ title, slug }: HeaderProps) { const baseDir = resolveToRoot(slug) return <header> <h1><a href={baseDir}>{title}</a></h1> + <div class="spacer"></div> + <Darkmode /> </header> } +Header.beforeDOMLoaded = Darkmode.beforeDOMLoaded +Header.css = style + Darkmode.css diff --git a/quartz/components/scripts/darkmode.inline.ts b/quartz/components/scripts/darkmode.inline.ts index c17013a..d2b6e06 100644 --- a/quartz/components/scripts/darkmode.inline.ts +++ b/quartz/components/scripts/darkmode.inline.ts @@ -1,3 +1,25 @@ -export default "Darkmode" +export default "Darkmode" -console.log("HELLOOOO FROM CONSOLE") +const currentTheme = localStorage.getItem("theme") +const theme = + currentTheme ?? + (window.matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark") + +document.documentElement.setAttribute("saved-theme", theme) + +window.addEventListener("DOMContentLoaded", () => { + const toggleSwitch = document.querySelector("#darkmode-toggle") as HTMLInputElement + toggleSwitch.addEventListener("change", (e: any) => { + if (e.target.checked) { + document.documentElement.setAttribute("saved-theme", "dark") + localStorage.setItem("theme", "dark") + } else { + document.documentElement.setAttribute("saved-theme", "light") + localStorage.setItem("theme", "light") + } + }) + + if (theme === "dark") { + toggleSwitch.checked = true + } +}) diff --git a/quartz/components/types.ts b/quartz/components/types.ts index e1bdebc..96ead5f 100644 --- a/quartz/components/types.ts +++ b/quartz/components/types.ts @@ -1,7 +1,6 @@ import { ComponentType } from "preact" -export type QuartzComponent<Props> = { - Component: ComponentType<Props> +export type QuartzComponent<Props> = ComponentType<Props> & { css?: string, beforeDOMLoaded?: string, afterDOMLoaded?: string, diff --git a/quartz/plugins/emitters/contentPage.tsx b/quartz/plugins/emitters/contentPage.tsx index 05c4c4b..9cca0af 100644 --- a/quartz/plugins/emitters/contentPage.tsx +++ b/quartz/plugins/emitters/contentPage.tsx @@ -48,14 +48,14 @@ export class ContentPage extends QuartzEmitterPlugin { const title = file.data.frontmatter?.title const doc = <html> - <Head.Component + <Head title={title ?? "Untitled"} description={file.data.description ?? "No description provided"} slug={file.data.slug!} externalResources={pageResources} /> <body> <div id="quartz-root" class="page"> - <Header.Component title={cfg.siteTitle} slug={file.data.slug!} /> + <Header title={cfg.siteTitle} slug={file.data.slug!} /> <article> {file.data.slug !== "index" && <h1>{title}</h1>} {content} diff --git a/quartz/styles/base.scss b/quartz/styles/base.scss index f039035..d7a1891 100644 --- a/quartz/styles/base.scss +++ b/quartz/styles/base.scss @@ -24,7 +24,7 @@ body { border-radius: 5px; } -p, ul, text, a, tr, td, li, ol, ul { +p, ul, text, a, tr, td, li, ol, ul, .katex { color: var(--darkgray); fill: var(--darkgray); } @@ -67,7 +67,7 @@ a { } blockquote { - margin-left: 0; + margin: 1rem 0; border-left: 3px solid var(--secondary); padding-left: 1rem; transition: border-color 0.2s ease; @@ -134,7 +134,7 @@ pre { & > code { background: none; padding: 0; - font-size: 0.9rem; + font-size: 0.85rem; counter-reset: line; counter-increment: line 0; display: grid; diff --git a/quartz/styles/callouts.scss b/quartz/styles/callouts.scss index 9e2ff2d..26cb0ba 100644 --- a/quartz/styles/callouts.scss +++ b/quartz/styles/callouts.scss @@ -4,7 +4,7 @@ border: 1px solid var(--border); background-color: var(--bg); border-radius: 5px; - padding: 0 0.7rem; + padding: 0 1rem; &[data-callout="note"] { --color: #448aff; diff --git a/quartz/styles/darkmode.scss b/quartz/styles/darkmode.scss new file mode 100644 index 0000000..561a83c --- /dev/null +++ b/quartz/styles/darkmode.scss @@ -0,0 +1,45 @@ +.darkmode { + float: right; + padding: 1rem; + min-width: 30px; + position: relative; + + @media all and (max-width: 450px) { + padding: 1rem; + } + + & > .toggle { + display: none; + box-sizing: border-box; + } + + & svg { + cursor: pointer; + opacity: 0; + position: absolute; + width: 20px; + height: 20px; + top: calc(50% - 10px); + margin: 0 7px; + fill: var(--darkgray); + transition: opacity 0.1s ease; + } +} + +:root[saved-theme="dark"] .toggle ~ label { + & > #dayIcon { + opacity: 0; + } + & > #nightIcon { + opacity: 1; + } +} + +:root .toggle ~ label { + & > #dayIcon { + opacity: 1; + } + & > #nightIcon { + opacity: 0; + } +} diff --git a/quartz/styles/header.scss b/quartz/styles/header.scss new file mode 100644 index 0000000..c3ea487 --- /dev/null +++ b/quartz/styles/header.scss @@ -0,0 +1,10 @@ +header { + display: flex; + flex-direction: row; + align-items: center; + margin: 1em 0 2em 0; + & > h1 { + margin: 0; + flex: auto; + } +}