diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..6313b56
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+* text=auto eol=lf
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
new file mode 100644
index 0000000..9ec04c6
--- /dev/null
+++ b/.github/workflows/deploy.yml
@@ -0,0 +1,74 @@
+name: Deploy Quartz site to GitHub Pages
+
+on:
+ push:
+ branches:
+ - main
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: "pages"
+ cancel-in-progress: false
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout vault
+ uses: actions/checkout@v6
+ with:
+ fetch-depth: 0
+ - name: Checkout Quartz
+ uses: actions/checkout@v6
+ with:
+ repository: jackyzha0/quartz
+ ref: v5
+ path: site
+ - name: Apply publish overlay
+ run: cp publish/quartz.config.yaml site/quartz.config.yaml
+ - uses: actions/setup-node@v6
+ with:
+ node-version: 24
+ - name: Cache dependencies
+ uses: actions/cache@v5
+ with:
+ path: ~/.npm
+ key: ${{ runner.os }}-node-${{ hashFiles('site/package-lock.json') }}
+ restore-keys: |
+ ${{ runner.os }}-node-
+ - name: Cache Quartz plugins
+ uses: actions/cache@v5
+ with:
+ path: site/.quartz/plugins
+ key: ${{ runner.os }}-plugins-${{ hashFiles('site/package-lock.json') }}
+ restore-keys: |
+ ${{ runner.os }}-plugins-
+ - name: Install Dependencies
+ working-directory: site
+ run: npm ci
+ - name: Install Quartz plugins
+ working-directory: site
+ run: npx quartz plugin install --from-config
+ - name: Build Quartz
+ working-directory: site
+ run: npx quartz build -d ..
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v3
+ with:
+ path: site/public
+
+ deploy:
+ needs: build
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e52e02d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,17 @@
+.DS_Store
+.trash/
+.replit
+replit.nix
+
+site/
+
+private/*
+!private/.gitkeep
+meta/attachments/*
+!meta/attachments/.gitkeep
+
+.obsidian/workspace.json
+.obsidian/workspace-mobile.json
+.obsidian/plugins/
+.obsidian/themes/
+.obsidian/snippets/
diff --git a/.obsidian/app.json b/.obsidian/app.json
new file mode 100644
index 0000000..17002a9
--- /dev/null
+++ b/.obsidian/app.json
@@ -0,0 +1,14 @@
+{
+ "alwaysUpdateLinks": true,
+ "newFileLocation": "folder",
+ "newFileFolderPath": "notes",
+ "attachmentFolderPath": "meta/attachments",
+ "newLinkFormat": "shortest",
+ "useMarkdownLinks": false,
+ "showUnsupportedFiles": true,
+ "promptDelete": true,
+ "userIgnoreFilters": [
+ "site/",
+ ".github/"
+ ]
+}
diff --git a/.obsidian/appearance.json b/.obsidian/appearance.json
new file mode 100644
index 0000000..a86fe94
--- /dev/null
+++ b/.obsidian/appearance.json
@@ -0,0 +1,7 @@
+{
+ "accentColor": "",
+ "baseFontSize": 16,
+ "theme": "obsidian",
+ "cssTheme": "",
+ "nativeMenus": false
+}
diff --git a/.obsidian/community-plugins.json b/.obsidian/community-plugins.json
new file mode 100644
index 0000000..cd96ff0
--- /dev/null
+++ b/.obsidian/community-plugins.json
@@ -0,0 +1,7 @@
+[
+ "templater-obsidian",
+ "dataview",
+ "obsidian-linter",
+ "media-extended",
+ "advanced-canvas"
+]
diff --git a/.obsidian/core-plugins.json b/.obsidian/core-plugins.json
new file mode 100644
index 0000000..ec35f9d
--- /dev/null
+++ b/.obsidian/core-plugins.json
@@ -0,0 +1,29 @@
+{
+ "file-explorer": true,
+ "global-search": true,
+ "switcher": true,
+ "graph": true,
+ "backlink": true,
+ "canvas": true,
+ "outgoing-link": true,
+ "tag-pane": true,
+ "footnotes": true,
+ "properties": true,
+ "page-preview": true,
+ "templates": true,
+ "note-composer": true,
+ "command-palette": true,
+ "markdown-importer": true,
+ "word-count": true,
+ "file-recovery": true,
+ "sync": false,
+ "publish": false,
+ "webviewer": false,
+ "slides": false,
+ "audio-recorder": false,
+ "workspaces": false,
+ "slash-command": false,
+ "editor-status": true,
+ "bookmarks": true,
+ "outline": true
+}
diff --git a/.obsidian/graph.json b/.obsidian/graph.json
new file mode 100644
index 0000000..8e7b5c8
--- /dev/null
+++ b/.obsidian/graph.json
@@ -0,0 +1,32 @@
+{
+ "collapse-filter": false,
+ "search": "",
+ "showTags": true,
+ "showAttachments": false,
+ "hideUnresolved": false,
+ "showOrphans": true,
+ "collapse-color-groups": false,
+ "colorGroups": [
+ {
+ "query": "path:archive",
+ "color": {
+ "a": 1,
+ "rgb": 14701138
+ }
+ },
+ {
+ "query": "path:notes",
+ "color": {
+ "a": 1,
+ "rgb": 5431473
+ }
+ },
+ {
+ "query": "path:canvases",
+ "color": {
+ "a": 1,
+ "rgb": 5431378
+ }
+ }
+ ]
+}
diff --git a/.obsidian/templates.json b/.obsidian/templates.json
new file mode 100644
index 0000000..c50a8f7
--- /dev/null
+++ b/.obsidian/templates.json
@@ -0,0 +1,3 @@
+{
+ "folder": "templates"
+}
diff --git a/.obsidian/types.json b/.obsidian/types.json
new file mode 100644
index 0000000..76a27d8
--- /dev/null
+++ b/.obsidian/types.json
@@ -0,0 +1,16 @@
+{
+ "types": {
+ "aliases": "aliases",
+ "tags": "multitext",
+ "cssclasses": "multitext",
+ "type": "text",
+ "source": "text",
+ "source_url": "text",
+ "author": "text",
+ "date": "date",
+ "archived": "date",
+ "status": "text",
+ "draft": "checkbox",
+ "description": "text"
+ }
+}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..03d753d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,125 @@
+# Threadwell
+
+Recovered threads and submerged records.
+
+An [Obsidian](https://obsidian.md) vault published with [Quartz 5](https://quartz.jzhao.xyz) to GitHub Pages. The site is a convenient host for Twitter/X threads and other material that is not reliably web-indexed.
+
+Live (after Pages is enabled): https://ed94.github.io/Threadwell
+
+## Layout
+
+Open **this repo root** as the Obsidian vault. Quartz is only the publisher; it lives in `site/`.
+
+```
+archive/ # public — primary sources
+ threads/ # Twitter/X and similar
+ sources/ # talks, pages, other records
+canvases/ # public — .canvas maps
+notes/ # public — authored / distilled writing
+templates/ # not published
+meta/ # not published — conventions, local attachments
+private/ # not published, not pushed
+publish/ # tracked overlay: quartz.config.yaml
+site/ # local Quartz clone (gitignored; own remotes)
+.obsidian/
+.github/workflows/deploy.yml
+```
+
+`archive/`, `canvases/`, and `notes/` are public by default. `site/` is a separate git checkout of Quartz (`origin` → `jackyzha0/quartz`). Threadwell's only remote is `Ed94/Threadwell`.
+
+## Frontmatter
+
+| Field | Values |
+| --- | --- |
+| `type` | `archive` \| `canvas` \| `note` |
+| `source` | `twitter` \| `youtube` \| `odysee` \| `article` \| `original` \| `other` |
+| `source_url` | original URL |
+| `author` | original author |
+| `date` | original date `YYYY-MM-DD` |
+| `archived` | capture date |
+| `status` | `draft` \| `review` \| `published` |
+| `draft` | `true` omits the page from the site |
+| `tags`, `description`, `aliases` | as usual |
+
+`draft: true` only hides a page from the **site**. A public GitHub repo still contains the file. Use `private/` for anything that must not be pushed.
+
+Templates: `templates/archive-source.md`, `templates/authored-note.md` (Templater placeholders).
+
+## Images and embeds
+
+Images: absolute HTTPS URLs on your image host. Do not commit local binaries for published notes.
+
+```md
+
+```
+
+YouTube and tweets (Quartz Obsidian-flavored Markdown):
+
+```md
+
+
+```
+
+Odysee (iframe; copy the embed URL from Odysee share):
+
+```html
+
+```
+
+Remote URLs and iframes are left as-is in the static build.
+
+## Obsidian plugins
+
+| Plugin | Why |
+| --- | --- |
+| **Templater** | Fills dates/titles in the starter templates |
+| **Dataview** | Local queries by `type` / `source` / `status` (not rendered on the site) |
+| **Linter** | Consistent YAML |
+| **Media Extended** | Better in-vault YouTube playback |
+| **Advanced Canvas** | Stronger canvas editing; site still uses stock JSON Canvas |
+
+Core: Canvas, Templates (folder `templates`), Backlinks, Graph, Properties, Page preview.
+
+See `meta/obsidian-setup.md` and `meta/conventions.md`.
+
+## Local preview
+
+Needs Node 22+ and npm 10.9.2+.
+
+```powershell
+cd C:\projects\Threadwell
+.\publish\setup.ps1
+cd site
+npx quartz build -d .. --serve
+```
+
+Open http://localhost:8080
+
+`publish/setup.ps1` clones Quartz into `site/` if needed, then copies `publish/quartz.config.yaml` over the stock config.
+
+## GitHub Pages
+
+1. Repo Settings → Pages → Source: **GitHub Actions**
+2. If an old `github-pages` environment blocks the first deploy, delete it under Settings → Environments. The workflow recreates it.
+3. Push `main`. CI clones Quartz into `site/`, applies `publish/quartz.config.yaml`, builds with `-d ..`.
+4. Site: `https://ed94.github.io/Threadwell`
+
+`baseUrl` lives in `publish/quartz.config.yaml`. Change it if you attach a custom domain.
+
+## Add content and republish
+
+1. New thread: Templater → `archive-source` → save under `archive/threads/`
+2. Transcribe posts in order. Host images. Optional YouTube/Odysee/tweet embeds.
+3. Distill in `notes/` with `authored-note`. Wikilink the archive record.
+4. Set `draft: false` and `status: published`
+5. Preview: `cd site; npx quartz build -d .. --serve`
+6. Commit and push `main` (vault + `publish/`, never `site/`)
+
+Threadwell remotes: `origin` → https://github.com/Ed94/Threadwell.git only.
+Quartz remotes live in `site/` (`cd site; git pull`). After a Quartz pull, re-copy `publish/quartz.config.yaml`.
+
+## Quartz notes
+
+Current major is **Quartz 5**. Edit `publish/quartz.config.yaml`, not the clone. Canvas uses `@quartz-community/canvas-page`. Drafts use `@quartz-community/remove-draft`.
+
+Engine license: MIT (Quartz). Vault content: Unlicense (`LICENSE`).
diff --git a/archive/index.md b/archive/index.md
new file mode 100644
index 0000000..96fdd14
--- /dev/null
+++ b/archive/index.md
@@ -0,0 +1,16 @@
+---
+title: Archive
+type: note
+status: published
+draft: false
+description: Primary-source records. Not commentary.
+tags:
+ - archive
+---
+
+Objective references: scrapes, transcripts, and source notes. Distilled writing lives in [[notes/index|Notes]].
+
+- [[archive/threads/index|Threads]] — Twitter/X and similar sequential posts
+- [[archive/sources/index|Sources]] — talks, essays, pages, and other records
+
+Use the `archive-source` template. Keep the source text here; put interpretation in a linked note.
diff --git a/archive/sources/index.md b/archive/sources/index.md
new file mode 100644
index 0000000..03df513
--- /dev/null
+++ b/archive/sources/index.md
@@ -0,0 +1,11 @@
+---
+title: Sources
+type: note
+status: published
+draft: false
+description: Non-thread primary sources — talks, pages, videos, documents.
+tags:
+ - archive
+---
+
+Talks, essays, videos, and other records that are not sequential threads. Same `archive-source` template; set `source` to `youtube`, `odysee`, `article`, or `other`.
diff --git a/archive/threads/How to archive a thread.md b/archive/threads/How to archive a thread.md
new file mode 100644
index 0000000..f36448b
--- /dev/null
+++ b/archive/threads/How to archive a thread.md
@@ -0,0 +1,53 @@
+---
+title: How to archive a thread
+type: archive
+source: twitter
+source_url: https://x.com/
+author: ""
+date: 2026-08-22
+archived: 2026-08-22
+status: published
+draft: false
+tags:
+ - archive
+ - twitter
+ - how-to
+description: Worked example of an archived thread note. Replace this when real threads land.
+aliases:
+ - example-thread
+---
+
+> [!info] Provenance
+> Replace this file with a real thread. The shape is what matters: frontmatter, then posts in order, then optional media.
+
+## Source
+
+- URL:
+- Author:
+- Posted:
+
+## Thread
+
+**1/** First post. Copy the text. Do not summarize here.
+
+**2/** Next post. Keep numbering. Preserve links as written.
+
+**3/** Last post.
+
+## Media
+
+Images use absolute URLs on the image host:
+
+```md
+
+```
+
+Optional live tweet (not a substitute for the transcript):
+
+```md
+
+```
+
+## Related
+
+- Distilled note: [[What this archive is for]]
diff --git a/archive/threads/index.md b/archive/threads/index.md
new file mode 100644
index 0000000..9dfba9e
--- /dev/null
+++ b/archive/threads/index.md
@@ -0,0 +1,13 @@
+---
+title: Threads
+type: note
+status: published
+draft: false
+description: Archived Twitter/X threads and similar sequential posts.
+tags:
+ - archive
+---
+
+One note per thread. Transcribe the posts in order. Do not rely on a live embed as the only copy.
+
+Example: [[How to archive a thread]]
diff --git a/canvases/index.md b/canvases/index.md
new file mode 100644
index 0000000..8bc5efd
--- /dev/null
+++ b/canvases/index.md
@@ -0,0 +1,13 @@
+---
+title: Canvases
+type: note
+status: published
+draft: false
+description: Public JSON Canvas maps.
+tags:
+ - canvas
+---
+
+Obsidian `.canvas` files in this folder render as pannable pages on the site.
+
+Starter map: [[overview.canvas|overview]]
diff --git a/canvases/overview.canvas b/canvases/overview.canvas
new file mode 100644
index 0000000..033b59d
--- /dev/null
+++ b/canvases/overview.canvas
@@ -0,0 +1,24 @@
+{
+ "nodes":[
+ {"id":"title","type":"text","text":"# Threadwell\nRecovered threads and submerged records.","x":-360,"y":-80,"width":320,"height":140,"color":"5"},
+ {"id":"home","type":"file","file":"index.md","x":40,"y":-160,"width":260,"height":80},
+ {"id":"archive","type":"file","file":"archive/index.md","x":400,"y":-280,"width":280,"height":100},
+ {"id":"threads","type":"file","file":"archive/threads/index.md","x":760,"y":-360,"width":260,"height":80},
+ {"id":"sources","type":"file","file":"archive/sources/index.md","x":760,"y":-220,"width":260,"height":80},
+ {"id":"canvases","type":"file","file":"canvases/index.md","x":400,"y":-80,"width":280,"height":80},
+ {"id":"notes","type":"file","file":"notes/index.md","x":400,"y":80,"width":280,"height":100},
+ {"id":"example-thread","type":"file","file":"archive/threads/How to archive a thread.md","x":760,"y":-40,"width":300,"height":80},
+ {"id":"example-note","type":"file","file":"notes/What this archive is for.md","x":760,"y":80,"width":300,"height":80}
+ ],
+ "edges":[
+ {"id":"e1","fromNode":"title","fromSide":"right","toNode":"home","toSide":"left"},
+ {"id":"e2","fromNode":"home","fromSide":"right","toNode":"archive","toSide":"left"},
+ {"id":"e3","fromNode":"home","fromSide":"right","toNode":"canvases","toSide":"left"},
+ {"id":"e4","fromNode":"home","fromSide":"right","toNode":"notes","toSide":"left"},
+ {"id":"e5","fromNode":"archive","fromSide":"right","toNode":"threads","toSide":"left"},
+ {"id":"e6","fromNode":"archive","fromSide":"right","toNode":"sources","toSide":"left"},
+ {"id":"e7","fromNode":"threads","fromSide":"bottom","toNode":"example-thread","toSide":"top"},
+ {"id":"e8","fromNode":"notes","fromSide":"right","toNode":"example-note","toSide":"left"},
+ {"id":"e9","fromNode":"example-thread","fromSide":"bottom","toNode":"example-note","toSide":"top","label":"distills"}
+ ]
+}
diff --git a/index.md b/index.md
new file mode 100644
index 0000000..d6f977f
--- /dev/null
+++ b/index.md
@@ -0,0 +1,16 @@
+---
+title: Threadwell
+type: note
+status: published
+draft: false
+description: Recovered threads and submerged records.
+tags: []
+---
+
+An archive of material that is not reliably web-indexed: Twitter/X threads, talks, and other primary sources, plus the notes distilled from them.
+
+- [[archive/index|Archive]] — objective records of threads and other sources
+- [[canvases/index|Canvases]] — maps and relationship diagrams
+- [[notes/index|Notes]] — authored essays and syntheses
+
+Start a new record from the templates in `templates/`. Public folders publish by default; set `draft: true` to keep a note off the site.
diff --git a/meta/attachments/.gitkeep b/meta/attachments/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/meta/conventions.md b/meta/conventions.md
new file mode 100644
index 0000000..33c8bed
--- /dev/null
+++ b/meta/conventions.md
@@ -0,0 +1,65 @@
+---
+title: Conventions
+type: note
+status: draft
+draft: true
+---
+
+# Frontmatter
+
+| Field | Values | Notes |
+| --- | --- | --- |
+| `type` | `archive` \| `canvas` \| `note` | Required |
+| `source` | `twitter` \| `youtube` \| `odysee` \| `article` \| `original` \| `other` | Archive + media notes |
+| `source_url` | URL | Canonical original |
+| `author` | string | Original author, not you |
+| `date` | `YYYY-MM-DD` | Original publication date |
+| `archived` | `YYYY-MM-DD` | When you captured it |
+| `status` | `draft` \| `review` \| `published` | Human workflow |
+| `draft` | `true` \| `false` | Quartz omit-from-site flag |
+| `tags` | list | Prefer `archive`, `twitter`, `note`, topic slugs |
+| `description` | string | Search / OG preview |
+| `aliases` | list | Extra names |
+
+`draft: true` hides the page from the built site. It does **not** hide the file from a public GitHub repo. Truly private material goes in `private/` (gitignored).
+
+# Folders
+
+| Path | Published | Role |
+| --- | --- | --- |
+| `archive/` | yes | Primary sources |
+| `canvases/` | yes | `.canvas` maps |
+| `notes/` | yes | Authored writing |
+| `templates/` | no | Templater / core templates |
+| `meta/` | no | Vault rules, local attachments |
+| `private/` | no, gitignored | Never publish, never push |
+| `site/` | no, gitignored | Local Quartz clone (own remotes) |
+| `publish/` | no | Tracked Quartz overlay |
+
+# Images
+
+Always absolute HTTPS URLs on the image host. Do not commit local binaries for published notes.
+
+```md
+
+```
+
+Scratch files may sit in `meta/attachments/` (gitignored).
+
+# Video
+
+YouTube / tweet (Quartz OFM):
+
+```md
+
+
+
+```
+
+Odysee (raw iframe; survives the static build):
+
+```html
+
+```
+
+Get the embed URL from Odysee share → embed. Do not use the watch URL as the iframe `src`.
diff --git a/meta/obsidian-setup.md b/meta/obsidian-setup.md
new file mode 100644
index 0000000..197b76e
--- /dev/null
+++ b/meta/obsidian-setup.md
@@ -0,0 +1,40 @@
+---
+title: Obsidian setup
+type: note
+status: draft
+draft: true
+---
+
+Open **`C:\\projects\\Threadwell`** as the vault (the repo root). `site/` is a local Quartz checkout and is hidden from the file explorer.
+
+# Core plugins
+
+Enable: Files, Search, Quick switcher, Graph, Backlinks, Canvas, Outgoing links, Tags, Page preview, Templates, Note composer, Command palette, Properties, Word count, File recovery.
+
+Templates folder: `templates`.
+
+# Community plugins
+
+| Plugin | Why |
+| --- | --- |
+| Templater | Date/title fill-in for the two starter templates |
+| Dataview | Local queries over `type`, `source`, `status` (not rendered by Quartz) |
+| Linter | YAML key order and tag consistency |
+| Media Extended | Better YouTube/timestamp playback inside Obsidian |
+| Advanced Canvas | Groups, presentation, nicer maps; Quartz still reads stock JSON Canvas |
+
+Install from Community Plugins using `.obsidian/community-plugins.json`.
+
+# Templater
+
+Template folder: `templates`. Enable "Trigger Templater on new file creation" if you want folder templates later.
+
+# Linter (suggested)
+
+- YAML: insert `date` as `YYYY-MM-DD`
+- Deduplicate and sort tags
+- Do not rewrite wikilinks to markdown links
+
+# Link settings
+
+Already set in `app.json`: wikilinks, shortest path, update links on rename.
diff --git a/notes/What this archive is for.md b/notes/What this archive is for.md
new file mode 100644
index 0000000..35c655f
--- /dev/null
+++ b/notes/What this archive is for.md
@@ -0,0 +1,26 @@
+---
+title: What this archive is for
+type: note
+source: original
+date: 2026-08-22
+status: published
+draft: false
+tags:
+ - note
+ - how-to
+description: Why Threadwell exists and how archive notes relate to authored notes.
+aliases:
+ - about-threadwell
+---
+
+Threadwell holds material that search engines and platform pages do not keep reliably. The split is strict:
+
+| Folder | Role |
+| --- | --- |
+| `archive/` | Primary source. What was said. |
+| `notes/` | Your writing. What it means. |
+| `canvases/` | Spatial maps between the two. |
+
+An authored note should [[How to archive a thread|link the archive record]] instead of pasting the thread again.
+
+Set `draft: true` until a note is ready. `archive/`, `canvases/`, and `notes/` publish otherwise.
diff --git a/notes/index.md b/notes/index.md
new file mode 100644
index 0000000..c44c4b3
--- /dev/null
+++ b/notes/index.md
@@ -0,0 +1,12 @@
+---
+title: Notes
+type: note
+status: published
+draft: false
+description: Authored and distilled writing.
+tags: []
+---
+
+Essays and syntheses. Link back to [[archive/index|archive]] records instead of restating the primary source.
+
+Use the `authored-note` template. Example: [[What this archive is for]]
diff --git a/private/.gitkeep b/private/.gitkeep
new file mode 100644
index 0000000..603945d
--- /dev/null
+++ b/private/.gitkeep
@@ -0,0 +1 @@
+This folder is gitignored except this file. Put unpublished private notes here.
diff --git a/publish/quartz.config.yaml b/publish/quartz.config.yaml
new file mode 100644
index 0000000..13f8a81
--- /dev/null
+++ b/publish/quartz.config.yaml
@@ -0,0 +1,319 @@
+# yaml-language-server: $schema=./quartz/plugins/quartz-plugins.schema.json
+configuration:
+ pageTitle: Threadwell
+ pageTitleSuffix: " · recovered threads"
+ enableSPA: true
+ enablePopovers: true
+ analytics: null
+ locale: en-US
+ baseUrl: ed94.github.io/Threadwell
+ ignorePatterns:
+ - site
+ - .github
+ - .git
+ - private
+ - templates
+ - meta
+ - .obsidian
+ - publish
+ - README.md
+ - LICENSE
+ - .gitignore
+ - .gitattributes
+ theme:
+ fontOrigin: googleFonts
+ cdnCaching: true
+ typography:
+ header: Schibsted Grotesk
+ body: Source Sans Pro
+ code: IBM Plex Mono
+ colors:
+ lightMode:
+ light: "#faf8f8"
+ lightgray: "#e5e5e5"
+ gray: "#b8b8b8"
+ darkgray: "#4e4e4e"
+ dark: "#2b2b2b"
+ secondary: "#284b63"
+ tertiary: "#84a59d"
+ highlight: rgba(143, 159, 169, 0.15)
+ textHighlight: "#fff23688"
+ darkMode:
+ light: "#161618"
+ lightgray: "#393639"
+ gray: "#646464"
+ darkgray: "#d4d4d4"
+ dark: "#ebebec"
+ secondary: "#7b97aa"
+ tertiary: "#84a59d"
+ highlight: rgba(143, 159, 169, 0.15)
+ textHighlight: "#b3aa0288"
+plugins:
+ - source: "@quartz-community/created-modified-date"
+ enabled: true
+ options:
+ defaultDateType: modified
+ priority:
+ - frontmatter
+ - git
+ - filesystem
+ order: 10
+ - source: "@quartz-community/syntax-highlighting"
+ enabled: true
+ options:
+ theme:
+ light: github-light
+ dark: github-dark
+ keepBackground: false
+ order: 20
+ - source: "@quartz-community/obsidian-flavored-markdown"
+ enabled: true
+ options:
+ comments: true
+ highlight: true
+ wikilinks: true
+ callouts: true
+ mermaid: true
+ parseTags: true
+ parseArrows: true
+ parseBlockReferences: true
+ enableInHtmlEmbed: false
+ enableYouTubeEmbed: true
+ enableTweetEmbed: true
+ enableVideoEmbed: true
+ enableCheckbox: true
+ order: 30
+ - source: "@quartz-community/github-flavored-markdown"
+ enabled: true
+ order: 40
+ - source: "@quartz-community/table-of-contents"
+ enabled: true
+ order: 50
+ layout:
+ position: right
+ priority: 30
+ - source: "@quartz-community/crawl-links"
+ enabled: true
+ options:
+ markdownLinkResolution: shortest
+ order: 60
+ - source: "@quartz-community/description"
+ enabled: true
+ order: 70
+ - source: "@quartz-community/latex"
+ enabled: true
+ options:
+ renderEngine: katex
+ order: 80
+ - source: "@quartz-community/citations"
+ enabled: false
+ order: 85
+ - source: "@quartz-community/hard-line-breaks"
+ enabled: true
+ order: 90
+ - source: "@quartz-community/ox-hugo"
+ enabled: false
+ order: 91
+ - source: "@quartz-community/roam"
+ enabled: false
+ order: 92
+ - source: "@quartz-community/quartz-fonts"
+ enabled: true
+ - source: "@quartz-themes/core"
+ enabled: false
+ options:
+ theme: default
+ mode: both
+ - source: "@quartz-community/remove-draft"
+ enabled: true
+ - source: "@quartz-community/explicit-publish"
+ enabled: false
+ - source: "@quartz-community/unlisted-pages"
+ enabled: true
+ options: {}
+ order: 45
+ - source: "@quartz-community/encrypted-pages"
+ enabled: true
+ options:
+ iterations: 600000
+ passwordField: password
+ unlistWhenEncrypted: false
+ outputPath: static/encryptedContentIndex.json
+ - source: "@quartz-community/stacked-pages"
+ enabled: false
+ layout:
+ position: afterBody
+ priority: 50
+ display: all
+ - source: "@quartz-community/alias-redirects"
+ enabled: true
+ - source: "@quartz-community/content-index"
+ enabled: true
+ options:
+ enableSiteMap: true
+ enableRSS: true
+ - source: "@quartz-community/favicon"
+ enabled: true
+ - source: "@quartz-community/og-image"
+ enabled: true
+ - source: "@quartz-community/cname"
+ enabled: true
+ - source: "@quartz-community/canvas-page"
+ enabled: true
+ options:
+ enableInteraction: true
+ initialZoom: 1
+ defaultFullscreen: false
+ - source: "@quartz-community/content-page"
+ enabled: true
+ - source: "@quartz-community/folder-page"
+ enabled: true
+ - source: "@quartz-community/tag-page"
+ enabled: true
+ - source: "@quartz-community/explorer"
+ enabled: true
+ layout:
+ position: left
+ priority: 50
+ - source: "@quartz-community/graph"
+ enabled: true
+ layout:
+ position: right
+ priority: 10
+ - source: "@quartz-community/search"
+ enabled: true
+ layout:
+ position: left
+ priority: 20
+ group: toolbar
+ groupOptions:
+ grow: true
+ - source: "@quartz-community/backlinks"
+ enabled: true
+ layout:
+ position: right
+ priority: 50
+ - source: "@quartz-community/article-title"
+ enabled: true
+ layout:
+ position: beforeBody
+ priority: 10
+ - source: "@quartz-community/content-meta"
+ enabled: true
+ layout:
+ position: beforeBody
+ priority: 20
+ - source: "@quartz-community/tag-list"
+ enabled: true
+ layout:
+ position: beforeBody
+ priority: 30
+ - source: "@quartz-community/page-title"
+ enabled: true
+ layout:
+ position: left
+ priority: 10
+ - source: "@quartz-community/darkmode"
+ enabled: true
+ layout:
+ position: left
+ priority: 30
+ group: toolbar
+ - source: "@quartz-community/reader-mode"
+ enabled: true
+ layout:
+ position: left
+ priority: 35
+ group: toolbar
+ - source: "@quartz-community/breadcrumbs"
+ enabled: true
+ layout:
+ position: beforeBody
+ priority: 5
+ condition: not-index
+ - source: "@quartz-community/comments"
+ enabled: false
+ options:
+ provider: giscus
+ options: {}
+ layout:
+ position: afterBody
+ priority: 10
+ - source: "@quartz-community/footer"
+ enabled: true
+ options:
+ links:
+ GitHub: https://github.com/Ed94/Threadwell
+ layout:
+ position: footer
+ priority: 50
+ - source: "@quartz-community/recent-notes"
+ enabled: true
+ layout:
+ position: left
+ priority: 60
+ - source: "@quartz-community/spacer"
+ enabled: true
+ options: {}
+ order: 25
+ layout:
+ position: left
+ priority: 25
+ display: mobile-only
+ - source: "@quartz-community/bases-page"
+ enabled: true
+ options: {}
+ order: 50
+ - source: "@quartz-community/note-properties"
+ enabled: true
+ options:
+ includeAll: false
+ includedProperties:
+ - type
+ - source
+ - status
+ - date
+ - tags
+ - description
+ - aliases
+ excludedProperties: []
+ hidePropertiesView: false
+ delimiters: ---
+ language: yaml
+ order: 5
+ layout:
+ position: beforeBody
+ priority: 15
+ display: all
+ - source: "@quartz-community/obsidian-plugin-excalidraw"
+ enabled: false
+ options:
+ enableInteraction: true
+ darkMode: auto
+ exportPadding: 20
+ order: 50
+layout:
+ groups:
+ toolbar:
+ priority: 35
+ direction: row
+ gap: 0.5rem
+ byPageType:
+ "404":
+ positions:
+ beforeBody: []
+ left: []
+ right: []
+ content: {}
+ folder:
+ exclude:
+ - reader-mode
+ positions:
+ right: []
+ tag:
+ exclude:
+ - reader-mode
+ positions:
+ right: []
+ canvas: {}
+ bases: {}
diff --git a/publish/setup.ps1 b/publish/setup.ps1
new file mode 100644
index 0000000..ab8a1a2
--- /dev/null
+++ b/publish/setup.ps1
@@ -0,0 +1,12 @@
+$root = Split-Path -Parent $PSScriptRoot
+$site = Join-Path $root "site"
+$config = Join-Path $PSScriptRoot "quartz.config.yaml"
+
+if (-not (Test-Path -LiteralPath (Join-Path $site ".git"))) {
+ git clone --branch v5 --single-branch https://github.com/jackyzha0/quartz.git $site
+}
+
+Copy-Item -LiteralPath $config -Destination (Join-Path $site "quartz.config.yaml") -Force
+Set-Location -LiteralPath $site
+npm ci
+npx quartz plugin install --from-config
diff --git a/templates/archive-source.md b/templates/archive-source.md
new file mode 100644
index 0000000..4acd213
--- /dev/null
+++ b/templates/archive-source.md
@@ -0,0 +1,48 @@
+---
+title: <% tp.file.title %>
+type: archive
+source: twitter
+source_url:
+author:
+date: <% tp.date.now("YYYY-MM-DD") %>
+archived: <% tp.date.now("YYYY-MM-DD") %>
+status: draft
+draft: true
+tags:
+ - archive
+description:
+aliases: []
+---
+
+> [!info] Provenance
+> Primary source record. Do not editorialize here. Interpretation goes in a `notes/` page.
+
+## Source
+
+- URL: <% tp.file.cursor() %>
+- Author:
+- Posted:
+
+## Record
+
+**1/**
+
+## Media
+
+```md
+
+```
+
+YouTube:
+
+```md
+
+```
+
+Odysee:
+
+```html
+
+```
+
+## Related
diff --git a/templates/authored-note.md b/templates/authored-note.md
new file mode 100644
index 0000000..57f43f3
--- /dev/null
+++ b/templates/authored-note.md
@@ -0,0 +1,18 @@
+---
+title: <% tp.file.title %>
+type: note
+source: original
+date: <% tp.date.now("YYYY-MM-DD") %>
+status: draft
+draft: true
+tags:
+ - note
+description:
+aliases: []
+---
+
+<% tp.file.cursor() %>
+
+## Sources
+
+-