# Blog Content Bridge The public Obsidian vault is the writing source of truth. The Astro sites are deployable targets that receive copied Markdown and assets. ## Folder Map | Vault folder | Astro content folder | Public domain | | ---------------------- | ------------------------------------------- | ------------------------------------ | | `blogs/01-research` | `sites/research/src/content/research` | `https://research.neeldhara.blog` | | `blogs/02-vibes` | `sites/vibes/src/content/vibes` | `https://vibes.neeldhara.blog` | | `blogs/03-puzzles` | `sites/puzzles/src/content/puzzles` | `https://puzzles.neeldhara.blog` | | `blogs/04-reflections` | `sites/reflections/src/content/reflections` | `https://reflections.neeldhara.blog` | | `blogs/05-poetry` | `sites/poetry/src/content/poetry` | `https://poetry.neeldhara.blog` | | `blogs/06-reviews` | `sites/reviews/src/content/reviews` | `https://reviews.neeldhara.blog` | | `blogs/07-art` | `sites/art/src/content/art` | `https://art.neeldhara.blog` | | `blogs/micro` | `../micro/src/content/blog` | `https://micro.neeldhara.blog` | The installed Obsidian plugin lives at: ```text /Users/neeldhara/obsidian/public/.obsidian/plugins/microblog-sync ``` The versioned copy lives in this repo at: ```text obsidian-plugin/microblog-sync ``` The plugin id remains `microblog-sync`, but Obsidian shows it as **Blog Family Sync**. ## Post Layout Use one folder per post: ```text blogs/01-research/example-post/index.md blogs/01-research/example-post/diagram.png ``` The folder path becomes the public URL: ```text blogs/01-research/example-post/index.md https://research.neeldhara.blog/example-post/ ``` Nested folders are supported: ```text blogs/04-reflections/exportober/2021/index.md https://reflections.neeldhara.blog/exportober/2021/ ``` ## Frontmatter Every public post needs the fields required by the Astro content schema: ```yaml --- title: "Post title" description: "One or two sentence summary for cards and RSS." pubDate: "2024-05-10" authorName: "Neeldhara" --- ``` Optional fields currently understood by the sites include `updatedDate`, `image`, and `authorImage`. Prefer colocated images in the body over remote stock images. Use `main-feature: true` on at most one post per blog to pin a fixed featured post on the `neeldhara.blog` homepage. The homepage still shows the two newest non-featured posts for that blog, sorted by `pubDate`. The Quarto import also preserved `sourceCategories` and `sourcePath`. Astro strips unknown schema fields, but they are useful in Obsidian for provenance. ## Markdown Conventions Standard Markdown headings, lists, links, tables, code fences, footnotes, and raw HTML are preserved. Use colocated relative assets: ```markdown ![Caption](image.png) ``` Quarto image attributes such as `{width=70%}` were removed during import. Going forward, use normal Markdown and let Astro CSS handle presentation. Quarto callouts were converted to portable blockquotes: ```markdown > **Note** > > Text of the callout. ``` Use the same convention for new notes: ```markdown > **Warning** > > This point needs attention. ``` Quarto margin notes such as `[text]{.aside}` were converted to: ```markdown > **Aside:** text ``` ## Semantic Blocks Use Pandoc-style fenced attributes for blocks that need to render differently in HTML and PDF. This is the preferred form because it works cleanly with both Astro and Pandoc/LuaLaTeX. ### Interactive Blocks An interactive block reserves a place in the post for a React component and also supplies fallback text for PDF or non-JavaScript rendering: ````markdown ```{.interactive #int:tape-layout caption="Tape layout explorer"} Drag files along a tape and compare the access cost of each arrangement. ``` ```` The id after `#` is the semantic label. For interactives, use the `int:` prefix. The component id is inferred by removing that prefix, so the example above mounts this component when it exists: ```text sites//src/interactives/tape-layout/index.tsx ``` The component receives: ```ts { id: "tape-layout", label: "int:tape-layout", caption: "Tape layout explorer", description: "Drag files along a tape...", fallback: "Drag files along a tape...", attrs: { caption: "Tape layout explorer" } } ``` If the component is not present, Astro renders the fallback text in the interactive frame. For a different PDF fallback, add `pdf="..."`: ````markdown ```{.interactive #int:tape-layout caption="Tape layout explorer" pdf="The HTML version contains an interactive tape layout explorer."} Implementation notes for the interactive can go here. ``` ```` Astro also accepts the shorter Obsidian-friendly form: ````markdown ```interactive id="tape-layout" caption="Tape layout explorer" Drag files along a tape and compare the access cost. ``` ```` Use the Pandoc-style form for posts that should export to PDF. ### LaTeX-Style Environments Use `.env` plus the environment class and a label: ````markdown ```{.env .theorem #thm:hall title="Hall's theorem" html="callout"} Every bipartite graph satisfying Hall's condition has a matching that covers the left side. ``` ```` Supported environment types are: ```text theorem, lemma, proposition, corollary, definition, example, remark, proof ``` In Astro, `html="callout"` renders the block like a callout. `html="plain"` renders it as a quieter left-rule block. If `html` is omitted, theorem-like blocks default to `callout`, and `proof` defaults to `plain`. In PDF, the same block becomes a real LuaLaTeX environment: ```tex \begin{theorem}[Hall's theorem] \label{thm:hall} ... \end{theorem} ``` Astro also accepts shorter forms when PDF export is not needed: ````markdown ```theorem id="thm:hall" title="Hall's theorem" Every bipartite graph satisfying Hall's condition has a matching... ``` ```` ### Linking To Semantic Blocks Use ordinary Markdown links to semantic ids: ```markdown The proof of [Hall's theorem](#thm:hall) is constructive. See the [tape explorer](#int:tape-layout) for an interactive version. ``` Astro renders these as normal HTML links. The PDF pipeline converts internal links whose target starts with `#` into `\cref{...}`, so the first link above becomes `\cref{thm:hall}`. Use these label prefixes consistently: ```text thm: theorem lem: lemma prop: proposition cor: corollary def: definition ex: example rem: remark prf: proof int: interactive fig: figure ``` ## Import Rules The import script is: ```text scripts/import-quarto-blog.mjs ``` It reads the Quarto archive, skips `draft: true`, converts `index.qmd` to `index.md`, copies colocated assets, and writes a temporary tree under `/private/tmp/quarto-blog-import`. The first import made these category choices: | Blog | Rule of thumb | | ------------- | ------------------------------------------------------------------ | | `research` | CS/math exposition, lecture notes, and academic explainers. | | `vibes` | LLM-assisted making, interactives, and generated-tool experiments. | | `puzzles` | Puzzle/game/problem posts. | | `reflections` | Essays, speeches, teaching/career notes, and Exportober context. | | `poetry` | Poems. | | `reviews` | Tool, workflow, software, website, book-list, and tutorial posts. | | `art` | Visual/sketchnote/design/communications-oriented posts. | See `IMPORT_REPORT.md` for the specific source-to-destination mapping. ## Sync Rules - Obsidian is the source of truth for day-to-day writing. - Auto-sync copies changes from the matching `blogs/...` folder into the matching local Astro content folder. - The plugin includes Markdown plus common web assets: images, PDFs, JSON/YAML, JS, CSS, HTML, and text files. - One-way sync does not delete target files unless **Delete orphaned target files** is enabled. - The initial Quarto import used replace-style sync to clear placeholder Astro posts. Day-to-day editing should use the plugin. ## Preview And Publish Use these Obsidian commands: - `Blog Family Sync: Sync and preview current note` - `Blog Family Sync: Publish current note` - `Blog Family Sync: Publish all changes for current blog` Preview detects the current note's folder, starts the matching Astro dev server on its configured local port, and opens the post URL. Publish does three things: 1. Sync vault content into the local repo. 2. Run the configured Astro build command. 3. Commit and push to Forgejo, where Dokploy picks up the change. ## PDF Export PDF export uses Pandoc plus LuaLaTeX: ```bash npm run pdf:post -- sites/research/src/content/research/example/index.md --out /tmp/example.pdf ``` The command runs: - `scripts/pandoc-filters/semantic-blocks.lua` to convert interactive and environment fences. - `scripts/pandoc-templates/semantic-preamble.tex` to load `amsthm`, `cleveref`, and the shared theorem definitions. The PDF route is intentionally separate from Astro. Astro owns HTML rendering; Pandoc owns PDF rendering. The Markdown conventions above are the shared contract between both outputs and can be reused for future site families such as `neeldhara.courses` and `books.neeldhara.com`.