mirror of
https://github.com/jackyzha0/quartz.git
synced 2026-01-15 08:08:43 +01:00
Compare commits
16 Commits
v4.5.1
...
sidebar-du
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0560711ed | ||
|
|
6b05c6ba64 | ||
|
|
50b6c217c6 | ||
|
|
b31acc6f0f | ||
|
|
08b2228a43 | ||
|
|
52a5196f38 | ||
|
|
cdd0be2aa8 | ||
|
|
9de370ae14 | ||
|
|
ae0466eedb | ||
|
|
499adf4a4e | ||
|
|
cd13ce3c47 | ||
|
|
b48aa91728 | ||
|
|
7b052e8844 | ||
|
|
1cfc87652c | ||
|
|
096ef220dc | ||
|
|
bc16822d14 |
@@ -27,7 +27,7 @@ This part of the configuration concerns anything that can affect the whole site.
|
||||
- `analytics`: what to use for analytics on your site. Values can be
|
||||
- `null`: don't use analytics;
|
||||
- `{ provider: 'google', tagId: '<your-google-tag>' }`: use Google Analytics;
|
||||
- `{ provider: 'plausible' }` (managed) or `{ provider: 'plausible', host: '<your-plausible-host>' }` (self-hosted): use [Plausible](https://plausible.io/);
|
||||
- `{ provider: 'plausible' }` (managed) or `{ provider: 'plausible', host: 'https://<your-plausible-host>' }` (self-hosted, make sure to include the `https://` protocol prefix): use [Plausible](https://plausible.io/);
|
||||
- `{ provider: 'umami', host: '<your-umami-host>', websiteId: '<your-umami-website-id>' }`: use [Umami](https://umami.is/);
|
||||
- `{ provider: 'goatcounter', websiteId: 'my-goatcounter-id' }` (managed) or `{ provider: 'goatcounter', websiteId: 'my-goatcounter-id', host: 'my-goatcounter-domain.com', scriptSrc: 'https://my-url.to/counter.js' }` (self-hosted) use [GoatCounter](https://goatcounter.com);
|
||||
- `{ provider: 'posthog', apiKey: '<your-posthog-project-apiKey>', host: '<your-posthog-host>' }`: use [Posthog](https://posthog.com/);
|
||||
|
||||
@@ -45,6 +45,8 @@ afterBody: [
|
||||
category: 'Announcements',
|
||||
// from data-category-id
|
||||
categoryId: 'DIC_kwDOFxRnmM4B-Xg6',
|
||||
// from data-lang
|
||||
lang: 'en'
|
||||
}
|
||||
}),
|
||||
],
|
||||
@@ -90,6 +92,10 @@ type Options = {
|
||||
// where to put the comment input box relative to the comments
|
||||
// defaults to 'bottom'
|
||||
inputPosition?: "top" | "bottom"
|
||||
|
||||
// set your preference language here
|
||||
// defaults to 'en'
|
||||
lang?: string
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -43,9 +43,7 @@ Want to customize it even more?
|
||||
- Removing explorer: remove `Component.Explorer()` from `quartz.layout.ts`
|
||||
- (optional): After removing the explorer component, you can move the [[table of contents | Table of Contents]] component back to the `left` part of the layout
|
||||
- Changing `sort`, `filter` and `map` behavior: explained in [[#Advanced customization]]
|
||||
- Component:
|
||||
- Wrapper (Outer component, generates file tree, etc): `quartz/components/Explorer.tsx`
|
||||
- Explorer node (recursive, either a folder or a file): `quartz/components/ExplorerNode.tsx`
|
||||
- Component: `quartz/components/Explorer.tsx`
|
||||
- Style: `quartz/components/styles/explorer.scss`
|
||||
- Script: `quartz/components/scripts/explorer.inline.ts`
|
||||
|
||||
@@ -188,7 +186,7 @@ Component.Explorer({
|
||||
> and passing it in.
|
||||
>
|
||||
> ```ts title="quartz.layout.ts"
|
||||
> import { Options } from "./quartz/components/ExplorerNode"
|
||||
> import { Options } from "./quartz/components/Explorer"
|
||||
>
|
||||
> export const mapFn: Options["mapFn"] = (node) => {
|
||||
> // implement your function here
|
||||
|
||||
@@ -13,9 +13,7 @@ There may be some notes you want to avoid publishing as a website. Quartz suppor
|
||||
If you'd like to only publish a select number of notes, you can instead use [[ExplicitPublish]] which will filter out all notes except for any that have `publish: true` in the frontmatter.
|
||||
|
||||
> [!warning]
|
||||
> Regardless of the filter plugin used, **all non-markdown files will be emitted and available publically in the final build.** This includes files such as images, voice recordings, PDFs, etc. One way to prevent this and still be able to embed local images is to create a folder specifically for public media and add the following two patterns to the ignorePatterns array.
|
||||
>
|
||||
> `"!(PublicMedia)**/!(*.md)", "!(*.md)"`
|
||||
> Regardless of the filter plugin used, **all non-markdown files will be emitted and available publically in the final build.** This includes files such as images, voice recordings, PDFs, etc.
|
||||
|
||||
## `ignorePatterns`
|
||||
|
||||
@@ -28,7 +26,7 @@ Common examples include:
|
||||
|
||||
- `some/folder`: exclude the entire of `some/folder`
|
||||
- `*.md`: exclude all files with a `.md` extension
|
||||
- `!*.md` exclude all files that _don't_ have a `.md` extension
|
||||
- `!(*.md)` exclude all files that _don't_ have a `.md` extension. Note that negations _must_ parenthesize the rest of the pattern!
|
||||
- `**/private`: exclude any files or folders named `private` at any level of nesting
|
||||
|
||||
> [!warning]
|
||||
|
||||
@@ -41,6 +41,15 @@ Component.Flex({
|
||||
})
|
||||
```
|
||||
|
||||
> [!note] Overriding behavior
|
||||
> Components inside `Flex` get an additional CSS class `flex-component` that add the `display: flex` property. If you want to override this behavior, you can add a `display` property to the component's CSS class in your custom CSS file.
|
||||
>
|
||||
> ```scss
|
||||
> .flex-component {
|
||||
> display: block; // or any other display type
|
||||
> }
|
||||
> ```
|
||||
|
||||
## `MobileOnly` Component
|
||||
|
||||
The `MobileOnly` component is a wrapper that makes its child component only visible on mobile devices. This is useful for creating responsive layouts where certain components should only appear on smaller screens.
|
||||
|
||||
@@ -6,29 +6,18 @@ Want to see what Quartz can do? Here are some cool community gardens:
|
||||
|
||||
- [Quartz Documentation (this site!)](https://quartz.jzhao.xyz/)
|
||||
- [Jacky Zhao's Garden](https://jzhao.xyz/)
|
||||
- [Socratica Toolbox](https://toolbox.socratica.info/)
|
||||
- [Morrowind Modding Wiki](https://morrowind-modding.github.io/)
|
||||
- [Aaron Pham's Garden](https://aarnphm.xyz/)
|
||||
- [The Pond](https://turntrout.com/welcome)
|
||||
- [Pelayo Arbues' Notes](https://pelayoarbues.com/)
|
||||
- [Stanford CME 302 Numerical Linear Algebra](https://ericdarve.github.io/NLA/)
|
||||
- [A Pattern Language - Christopher Alexander (Architecture)](https://patternlanguage.cc/)
|
||||
- [oldwinter の数字花园](https://garden.oldwinter.top/)
|
||||
- [Eilleen's Everything Notebook](https://quartz.eilleeenz.com/)
|
||||
- [🧠🌳 Chad's Mind Garden](https://www.chadly.net/)
|
||||
- [Pedro MC Fernandes's Topo da Mente](https://www.pmcf.xyz/topo-da-mente/)
|
||||
- [Mau Camargo's Notkesto](https://notes.camargomau.com/)
|
||||
- [Morrowind Modding Wiki](https://morrowind-modding.github.io/)
|
||||
- [Stanford CME 302 Numerical Linear Algebra](https://ericdarve.github.io/NLA/)
|
||||
- [Socratica Toolbox](https://toolbox.socratica.info/)
|
||||
- [A Pattern Language - Christopher Alexander (Architecture)](https://patternlanguage.cc/)
|
||||
- [Sideny's 3D Artist's Handbook](https://sidney-eliot.github.io/3d-artists-handbook/)
|
||||
- [Brandon Boswell's Garden](https://brandonkboswell.com)
|
||||
- [Scaling Synthesis - A hypertext research notebook](https://scalingsynthesis.com/)
|
||||
- [Simon's Second Brain: Crafted, Curated, Connected, Compounded](https://brain.ssp.sh/)
|
||||
- [Data Engineering Vault: A Second Brain Knowledge Network](https://vault.ssp.sh/)
|
||||
- [Data Dictionary 🧠](https://glossary.airbyte.com/)
|
||||
- [🪴Aster's notebook](https://notes.asterhu.com)
|
||||
- [Gatekeeper Wiki](https://www.gatekeeper.wiki)
|
||||
- [Ellie's Notes](https://ellie.wtf)
|
||||
- [🥷🏻🌳🍃 Computer Science & Thinkering Garden](https://notes.yxy.ninja)
|
||||
- [Eledah's Crystalline](https://blog.eledah.ir/)
|
||||
- [🌓 Projects & Privacy - FOSS, tech, law](https://be-far.com)
|
||||
- [Zen Browser Docs](https://docs.zen-browser.app)
|
||||
- [🪴8cat life](https://8cat.life)
|
||||
|
||||
@@ -125,9 +125,10 @@ async function startWatching(
|
||||
ctx,
|
||||
mut,
|
||||
contentMap,
|
||||
ignored: (path) => {
|
||||
if (gitIgnoredMatcher(path)) return true
|
||||
const pathStr = path.toString()
|
||||
ignored: (fp) => {
|
||||
const pathStr = toPosixPath(fp.toString())
|
||||
if (pathStr.startsWith(".git/")) return true
|
||||
if (gitIgnoredMatcher(pathStr)) return true
|
||||
for (const pattern of cfg.configuration.ignorePatterns) {
|
||||
if (minimatch(pathStr, pattern)) {
|
||||
return true
|
||||
|
||||
@@ -17,6 +17,7 @@ type Options = {
|
||||
strict?: boolean
|
||||
reactionsEnabled?: boolean
|
||||
inputPosition?: "top" | "bottom"
|
||||
lang?: string
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +51,7 @@ export default ((opts: Options) => {
|
||||
data-theme-url={
|
||||
opts.options.themeUrl ?? `https://${cfg.baseUrl ?? "example.com"}/static/giscus`
|
||||
}
|
||||
data-lang={opts.options.lang ?? "en"}
|
||||
></div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { concatenateResources } from "../util/resources"
|
||||
import { classNames } from "../util/lang"
|
||||
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
|
||||
|
||||
type FlexConfig = {
|
||||
@@ -23,7 +24,10 @@ export default ((config: FlexConfig) => {
|
||||
const gap = config.gap ?? "1rem"
|
||||
|
||||
return (
|
||||
<div style={`display: flex; flex-direction: ${direction}; flex-wrap: ${wrap}; gap: ${gap};`}>
|
||||
<div
|
||||
class={classNames(props.displayClass, "flex-component")}
|
||||
style={`flex-direction: ${direction}; flex-wrap: ${wrap}; gap: ${gap};`}
|
||||
>
|
||||
{config.components.map((c) => {
|
||||
const grow = c.grow ? 1 : 0
|
||||
const shrink = (c.shrink ?? true) ? 1 : 0
|
||||
|
||||
@@ -55,6 +55,7 @@ type GiscusElement = Omit<HTMLElement, "dataset"> & {
|
||||
strict: string
|
||||
reactionsEnabled: string
|
||||
inputPosition: "top" | "bottom"
|
||||
lang: string
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +79,7 @@ document.addEventListener("nav", () => {
|
||||
giscusScript.setAttribute("data-strict", giscusContainer.dataset.strict)
|
||||
giscusScript.setAttribute("data-reactions-enabled", giscusContainer.dataset.reactionsEnabled)
|
||||
giscusScript.setAttribute("data-input-position", giscusContainer.dataset.inputPosition)
|
||||
|
||||
giscusScript.setAttribute("data-lang", giscusContainer.dataset.lang)
|
||||
const theme = document.documentElement.getAttribute("saved-theme")
|
||||
if (theme) {
|
||||
giscusScript.setAttribute("data-theme", getThemeUrl(getThemeName(theme)))
|
||||
|
||||
@@ -74,9 +74,6 @@ function toggleFolder(evt: MouseEvent) {
|
||||
collapsed: isCollapsed,
|
||||
})
|
||||
}
|
||||
|
||||
const stringifiedFileTree = JSON.stringify(currentExplorerState)
|
||||
localStorage.setItem("fileTree", stringifiedFileTree)
|
||||
}
|
||||
|
||||
function createFileNode(currentSlug: FullSlug, node: FileTrieNode): HTMLLIElement {
|
||||
@@ -165,8 +162,8 @@ async function setupExplorer(currentSlug: FullSlug) {
|
||||
mapFn: new Function("return " + (dataFns.mapFn || "undefined"))(),
|
||||
}
|
||||
|
||||
// Get folder state from local storage
|
||||
const storageTree = localStorage.getItem("fileTree")
|
||||
// Get folder state from session storage
|
||||
const storageTree = sessionStorage.getItem("fileTree")
|
||||
const serializedExplorerState = storageTree && opts.useSavedState ? JSON.parse(storageTree) : []
|
||||
const oldIndex = new Map<string, boolean>(
|
||||
serializedExplorerState.map((entry: FolderState) => [entry.path, entry.collapsed]),
|
||||
@@ -263,6 +260,9 @@ document.addEventListener("prenav", async () => {
|
||||
const explorer = document.querySelector(".explorer-ul")
|
||||
if (!explorer) return
|
||||
sessionStorage.setItem("explorerScrollTop", explorer.scrollTop.toString())
|
||||
if (!currentExplorerState) return
|
||||
const stringifiedFileTree = JSON.stringify(currentExplorerState)
|
||||
sessionStorage.setItem("fileTree", stringifiedFileTree)
|
||||
})
|
||||
|
||||
document.addEventListener("nav", async (e: CustomEventMap["nav"]) => {
|
||||
|
||||
@@ -239,7 +239,7 @@ li:has(> .folder-outer:not(.open)) > .folder-container > svg {
|
||||
margin-top: 0;
|
||||
background-color: var(--light);
|
||||
max-width: 100vw;
|
||||
width: 100%;
|
||||
width: 100vw;
|
||||
transform: translateX(-100vw);
|
||||
transition:
|
||||
transform 200ms ease,
|
||||
@@ -265,6 +265,6 @@ li:has(> .folder-outer:not(.open)) > .folder-container > svg {
|
||||
|
||||
.mobile-no-scroll {
|
||||
@media all and ($mobile) {
|
||||
overflow: hidden;
|
||||
overscroll-behavior: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +101,11 @@ export const FrontMatter: QuartzTransformerPlugin<Partial<Options>> = (userOpts)
|
||||
const socialImage = coalesceAliases(data, ["socialImage", "image", "cover"])
|
||||
|
||||
const created = coalesceAliases(data, ["created", "date"])
|
||||
if (created) data.created = created
|
||||
if (created) {
|
||||
data.created = created
|
||||
data.modified ||= created // if modified is not set, use created
|
||||
}
|
||||
|
||||
const modified = coalesceAliases(data, [
|
||||
"modified",
|
||||
"lastmod",
|
||||
|
||||
@@ -12,7 +12,17 @@ const defaultOptions: Options = {
|
||||
priority: ["frontmatter", "git", "filesystem"],
|
||||
}
|
||||
|
||||
// YYYY-MM-DD
|
||||
const iso8601DateOnlyRegex = /^\d{4}-\d{2}-\d{2}$/
|
||||
|
||||
function coerceDate(fp: string, d: any): Date {
|
||||
// check ISO8601 date-only format
|
||||
// we treat this one as local midnight as the normal
|
||||
// js date ctor treats YYYY-MM-DD as UTC midnight
|
||||
if (typeof d === "string" && iso8601DateOnlyRegex.test(d)) {
|
||||
d = `${d}T00:00:00`
|
||||
}
|
||||
|
||||
const dt = new Date(d)
|
||||
const invalidDate = isNaN(dt.getTime()) || dt.getTime() === 0
|
||||
if (invalidDate && d !== undefined) {
|
||||
|
||||
@@ -11,8 +11,7 @@ html {
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
body,
|
||||
section {
|
||||
body {
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
background-color: var(--light);
|
||||
@@ -132,16 +131,32 @@ a {
|
||||
}
|
||||
}
|
||||
|
||||
.flex-component {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.desktop-only {
|
||||
display: initial;
|
||||
&.flex-component {
|
||||
display: flex;
|
||||
}
|
||||
@media all and ($mobile) {
|
||||
&.flex-component {
|
||||
display: none;
|
||||
}
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.mobile-only {
|
||||
display: none;
|
||||
&.flex-component {
|
||||
display: none;
|
||||
}
|
||||
@media all and ($mobile) {
|
||||
&.flex-component {
|
||||
display: flex;
|
||||
}
|
||||
display: initial;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user