mirror of
https://github.com/jackyzha0/quartz.git
synced 2025-05-19 06:54:18 +02:00
Compare commits
No commits in common. "c238dd16d9923aac404a16b8551d93e5b91a4c5a" and "bfd72347cf719a7500dd98484d037c2b2320729c" have entirely different histories.
c238dd16d9
...
bfd72347cf
@ -1,44 +0,0 @@
|
|||||||
---
|
|
||||||
title: Reader Mode
|
|
||||||
tags:
|
|
||||||
- component
|
|
||||||
---
|
|
||||||
|
|
||||||
Reader Mode is a feature that allows users to focus on the content by hiding the sidebars and other UI elements. When enabled, it provides a clean, distraction-free reading experience.
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
Reader Mode is enabled by default. To disable it, you can remove the component from your layout configuration in `quartz.layout.ts`:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
// Remove or comment out this line
|
|
||||||
Component.ReaderMode(),
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
The Reader Mode toggle appears as a button with a book icon. When clicked:
|
|
||||||
|
|
||||||
- Sidebars are hidden
|
|
||||||
- Hovering over the content area reveals the sidebars temporarily
|
|
||||||
|
|
||||||
Unlike Dark Mode, Reader Mode state is not persisted between page reloads but is maintained during SPA navigation within the site.
|
|
||||||
|
|
||||||
## Customization
|
|
||||||
|
|
||||||
You can customize the appearance of Reader Mode through CSS variables and styles. The component uses the following classes:
|
|
||||||
|
|
||||||
- `.readermode`: The toggle button
|
|
||||||
- `.readerIcon`: The book icon
|
|
||||||
- `[reader-mode="on"]`: Applied to the root element when Reader Mode is active
|
|
||||||
|
|
||||||
Example customization in your custom CSS:
|
|
||||||
|
|
||||||
```scss
|
|
||||||
.readermode {
|
|
||||||
// Customize the button
|
|
||||||
svg {
|
|
||||||
stroke: var(--custom-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
1
index.d.ts
vendored
1
index.d.ts
vendored
@ -8,7 +8,6 @@ interface CustomEventMap {
|
|||||||
prenav: CustomEvent<{}>
|
prenav: CustomEvent<{}>
|
||||||
nav: CustomEvent<{ url: FullSlug }>
|
nav: CustomEvent<{ url: FullSlug }>
|
||||||
themechange: CustomEvent<{ theme: "light" | "dark" }>
|
themechange: CustomEvent<{ theme: "light" | "dark" }>
|
||||||
readermodechange: CustomEvent<{ mode: "on" | "off" }>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContentIndex = Record<FullSlug, ContentDetails>
|
type ContentIndex = Record<FullSlug, ContentDetails>
|
||||||
|
31
package-lock.json
generated
31
package-lock.json
generated
@ -9,7 +9,7 @@
|
|||||||
"version": "4.5.0",
|
"version": "4.5.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@clack/prompts": "^0.10.1",
|
"@clack/prompts": "^0.10.0",
|
||||||
"@floating-ui/dom": "^1.6.13",
|
"@floating-ui/dom": "^1.6.13",
|
||||||
"@myriaddreamin/rehype-typst": "^0.5.4",
|
"@myriaddreamin/rehype-typst": "^0.5.4",
|
||||||
"@napi-rs/simple-git": "0.1.19",
|
"@napi-rs/simple-git": "0.1.19",
|
||||||
@ -80,7 +80,7 @@
|
|||||||
"@types/d3": "^7.4.3",
|
"@types/d3": "^7.4.3",
|
||||||
"@types/hast": "^3.0.4",
|
"@types/hast": "^3.0.4",
|
||||||
"@types/js-yaml": "^4.0.9",
|
"@types/js-yaml": "^4.0.9",
|
||||||
"@types/node": "^22.14.1",
|
"@types/node": "^22.14.0",
|
||||||
"@types/pretty-time": "^1.1.5",
|
"@types/pretty-time": "^1.1.5",
|
||||||
"@types/source-map-support": "^0.5.10",
|
"@types/source-map-support": "^0.5.10",
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
@ -178,22 +178,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@clack/core": {
|
"node_modules/@clack/core": {
|
||||||
"version": "0.4.2",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/@clack/core/-/core-0.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@clack/core/-/core-0.4.1.tgz",
|
||||||
"integrity": "sha512-NYQfcEy8MWIxrT5Fj8nIVchfRFA26yYKJcvBS7WlUIlw2OmQOY9DhGGXMovyI5J5PpxrCPGkgUi207EBrjpBvg==",
|
"integrity": "sha512-Pxhij4UXg8KSr7rPek6Zowm+5M22rbd2g1nfojHJkxp5YkFqiZ2+YLEM/XGVIzvGOcM0nqjIFxrpDwWRZYWYjA==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
"sisteransi": "^1.0.5"
|
"sisteransi": "^1.0.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@clack/prompts": {
|
"node_modules/@clack/prompts": {
|
||||||
"version": "0.10.1",
|
"version": "0.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-0.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-0.10.0.tgz",
|
||||||
"integrity": "sha512-Q0T02vx8ZM9XSv9/Yde0jTmmBQufZhPJfYAg2XrrrxWWaZgq1rr8nU8Hv710BQ1dhoP8rtY7YUdpGej2Qza/cw==",
|
"integrity": "sha512-H3rCl6CwW1NdQt9rE3n373t7o5cthPv7yUoxF2ytZvyvlJv89C5RYMJu83Hed8ODgys5vpBU0GKxIRG83jd8NQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@clack/core": "0.4.2",
|
"@clack/core": "0.4.1",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
"sisteransi": "^1.0.5"
|
"sisteransi": "^1.0.5"
|
||||||
}
|
}
|
||||||
@ -1941,9 +1940,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "22.14.1",
|
"version": "22.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.0.tgz",
|
||||||
"integrity": "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==",
|
"integrity": "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -5504,8 +5503,7 @@
|
|||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
|
||||||
"license": "ISC"
|
|
||||||
},
|
},
|
||||||
"node_modules/picomatch": {
|
"node_modules/picomatch": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
@ -6704,8 +6702,7 @@
|
|||||||
"node_modules/sisteransi": {
|
"node_modules/sisteransi": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
||||||
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
|
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/slash": {
|
"node_modules/slash": {
|
||||||
"version": "5.1.0",
|
"version": "5.1.0",
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
"quartz": "./quartz/bootstrap-cli.mjs"
|
"quartz": "./quartz/bootstrap-cli.mjs"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@clack/prompts": "^0.10.1",
|
"@clack/prompts": "^0.10.0",
|
||||||
"@floating-ui/dom": "^1.6.13",
|
"@floating-ui/dom": "^1.6.13",
|
||||||
"@myriaddreamin/rehype-typst": "^0.5.4",
|
"@myriaddreamin/rehype-typst": "^0.5.4",
|
||||||
"@napi-rs/simple-git": "0.1.19",
|
"@napi-rs/simple-git": "0.1.19",
|
||||||
@ -103,7 +103,7 @@
|
|||||||
"@types/d3": "^7.4.3",
|
"@types/d3": "^7.4.3",
|
||||||
"@types/hast": "^3.0.4",
|
"@types/hast": "^3.0.4",
|
||||||
"@types/js-yaml": "^4.0.9",
|
"@types/js-yaml": "^4.0.9",
|
||||||
"@types/node": "^22.14.1",
|
"@types/node": "^22.14.0",
|
||||||
"@types/pretty-time": "^1.1.5",
|
"@types/pretty-time": "^1.1.5",
|
||||||
"@types/source-map-support": "^0.5.10",
|
"@types/source-map-support": "^0.5.10",
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
|
@ -35,7 +35,6 @@ export const defaultContentPageLayout: PageLayout = {
|
|||||||
grow: true,
|
grow: true,
|
||||||
},
|
},
|
||||||
{ Component: Component.Darkmode() },
|
{ Component: Component.Darkmode() },
|
||||||
{ Component: Component.ReaderMode() },
|
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
Component.Explorer(),
|
Component.Explorer(),
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
// @ts-ignore
|
|
||||||
import readerModeScript from "./scripts/readermode.inline"
|
|
||||||
import styles from "./styles/readermode.scss"
|
|
||||||
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
|
|
||||||
import { classNames } from "../util/lang"
|
|
||||||
|
|
||||||
const ReaderMode: QuartzComponent = ({ displayClass }: QuartzComponentProps) => {
|
|
||||||
return (
|
|
||||||
<button class={classNames(displayClass, "readermode")}>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
class="readerIcon"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
>
|
|
||||||
<rect x="6" y="4" width="12" height="16" rx="1"></rect>
|
|
||||||
<line x1="9" y1="8" x2="15" y2="8"></line>
|
|
||||||
<line x1="9" y1="12" x2="15" y2="12"></line>
|
|
||||||
<line x1="9" y1="16" x2="13" y2="16"></line>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
ReaderMode.beforeDOMLoaded = readerModeScript
|
|
||||||
ReaderMode.css = styles
|
|
||||||
|
|
||||||
export default (() => ReaderMode) satisfies QuartzComponentConstructor
|
|
@ -4,7 +4,6 @@ import FolderContent from "./pages/FolderContent"
|
|||||||
import NotFound from "./pages/404"
|
import NotFound from "./pages/404"
|
||||||
import ArticleTitle from "./ArticleTitle"
|
import ArticleTitle from "./ArticleTitle"
|
||||||
import Darkmode from "./Darkmode"
|
import Darkmode from "./Darkmode"
|
||||||
import ReaderMode from "./ReaderMode"
|
|
||||||
import Head from "./Head"
|
import Head from "./Head"
|
||||||
import PageTitle from "./PageTitle"
|
import PageTitle from "./PageTitle"
|
||||||
import ContentMeta from "./ContentMeta"
|
import ContentMeta from "./ContentMeta"
|
||||||
@ -30,7 +29,6 @@ export {
|
|||||||
TagContent,
|
TagContent,
|
||||||
FolderContent,
|
FolderContent,
|
||||||
Darkmode,
|
Darkmode,
|
||||||
ReaderMode,
|
|
||||||
Head,
|
Head,
|
||||||
PageTitle,
|
PageTitle,
|
||||||
ContentMeta,
|
ContentMeta,
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
let isReaderMode = false
|
|
||||||
|
|
||||||
const emitReaderModeChangeEvent = (mode: "on" | "off") => {
|
|
||||||
const event: CustomEventMap["readermodechange"] = new CustomEvent("readermodechange", {
|
|
||||||
detail: { mode },
|
|
||||||
})
|
|
||||||
document.dispatchEvent(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("nav", () => {
|
|
||||||
const switchReaderMode = () => {
|
|
||||||
isReaderMode = !isReaderMode
|
|
||||||
const newMode = isReaderMode ? "on" : "off"
|
|
||||||
document.documentElement.setAttribute("reader-mode", newMode)
|
|
||||||
emitReaderModeChangeEvent(newMode)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const readerModeButton of document.getElementsByClassName("readermode")) {
|
|
||||||
readerModeButton.addEventListener("click", switchReaderMode)
|
|
||||||
window.addCleanup(() => readerModeButton.removeEventListener("click", switchReaderMode))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set initial state
|
|
||||||
document.documentElement.setAttribute("reader-mode", isReaderMode ? "on" : "off")
|
|
||||||
})
|
|
@ -6,7 +6,7 @@
|
|||||||
border: none;
|
border: none;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
margin: 0;
|
margin: 0 10px;
|
||||||
text-align: inherit;
|
text-align: inherit;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
.readermode {
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0;
|
|
||||||
position: relative;
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
margin: 0;
|
|
||||||
text-align: inherit;
|
|
||||||
flex-shrink: 0;
|
|
||||||
|
|
||||||
& svg {
|
|
||||||
position: absolute;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
top: calc(50% - 10px);
|
|
||||||
stroke: var(--darkgray);
|
|
||||||
transition: opacity 0.1s ease;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:root[reader-mode="on"] {
|
|
||||||
& .sidebar.left,
|
|
||||||
& .sidebar.right {
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.2s ease;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user