444 lines
14 KiB
Markdown
444 lines
14 KiB
Markdown
# 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://pieces.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.
|
|
|
|
This section is the short writer-facing version. The reusable implementation
|
|
contract for future site families is documented in
|
|
[`docs/PARSER.md`](./docs/PARSER.md).
|
|
|
|
Use colocated relative assets:
|
|
|
|
```markdown
|
|

|
|
```
|
|
|
|
Quarto image attributes such as `{width=70%}` were removed during import. Going
|
|
forward, use normal Markdown and let Astro CSS handle presentation.
|
|
|
|
### Callouts
|
|
|
|
Write callouts as portable blockquotes. The type controls the visual styling,
|
|
but it does not create a visible heading by itself. This is the canonical form
|
|
for a titleless note:
|
|
|
|
```markdown
|
|
> **Note**
|
|
>
|
|
> Text of the callout.
|
|
```
|
|
|
|
Supported labels are `Note`, `Tip`, `Warning`, `Caution`, and `Aside`:
|
|
|
|
```markdown
|
|
> **Warning**
|
|
>
|
|
> This point needs attention.
|
|
```
|
|
|
|
Obsidian-style bracket labels also work. A plain bracket label is still
|
|
titleless:
|
|
|
|
```markdown
|
|
> [!tip]
|
|
> This is a tip.
|
|
```
|
|
|
|
To show a heading, put it explicitly inside the bracket after `:` or `|`:
|
|
|
|
```markdown
|
|
> [!tip: Useful observation]
|
|
>
|
|
> Text of the callout.
|
|
|
|
> [!warning|Check this assumption]
|
|
>
|
|
> This point needs attention.
|
|
```
|
|
|
|
The text after `:` or `|` is treated as the only callout heading. Do not write
|
|
`> [!tip] Useful observation` for a heading; that form is interpreted as a
|
|
titleless tip whose body begins with “Useful observation”. This keeps the
|
|
Markdown unambiguous across Astro, Pandoc, and LaTeX.
|
|
|
|
For quick writing, a few leading emoji markers are recognized and stripped:
|
|
|
|
```markdown
|
|
> 📝 This becomes a note.
|
|
> 💡 This becomes a tip.
|
|
> ⚡ This also becomes a tip.
|
|
> ⚠️ This becomes a warning.
|
|
```
|
|
|
|
In Astro these render as `<aside class="callout callout-note">`, etc. In the
|
|
PDF pipeline they render as pastel `tcolorbox` blocks:
|
|
|
|
```text
|
|
note -> blognotebox
|
|
tip -> blogtipbox
|
|
warning -> blogwarningbox
|
|
caution -> blogcautionbox
|
|
aside -> blogasidebox
|
|
```
|
|
|
|
The LaTeX boxes use `tcolorbox` with the `breakable` and `enhanced` libraries,
|
|
a light tinted background, a thin frame, a stronger left rule, and a small
|
|
attached title only when the Markdown explicitly provides one. This follows the
|
|
same design vocabulary as the DM book callouts: compact colored boxes that can
|
|
split across pages without becoming visually heavy.
|
|
|
|
Quarto margin notes such as `[text]{.aside}` were converted to:
|
|
|
|
```markdown
|
|
> **Aside:** text
|
|
```
|
|
|
|
### Emoji And Symbol Text
|
|
|
|
Write emoji, chess pieces, and card suits directly in Markdown:
|
|
|
|
```markdown
|
|
I like this move: ♘f3. Hearts and diamonds are red: ♥ ♦. Spades and clubs are black: ♠ ♣.
|
|
This reminder is visible in both outputs: 🎯
|
|
```
|
|
|
|
Astro wraps these glyphs in small semantic spans so they get stable font
|
|
fallbacks and accessible labels:
|
|
|
|
```html
|
|
<span
|
|
class="symbol symbol-chess"
|
|
data-symbol="white-knight"
|
|
aria-label="white knight"
|
|
>♘</span
|
|
>
|
|
<span class="symbol symbol-card" data-symbol="heart" aria-label="heart"
|
|
>♥</span
|
|
>
|
|
<span class="symbol symbol-emoji">🎯</span>
|
|
```
|
|
|
|
The PDF pipeline maps the same characters to LaTeX macros:
|
|
|
|
```text
|
|
emoji and emoji sequences -> \BlogEmojiText{...} using the emoji package
|
|
♔ ♕ ♖ ♗ ♘ ♙ -> \BlogChessWhite{\symking}, etc. using chessfss
|
|
♚ ♛ ♜ ♝ ♞ ♟ -> \BlogChessBlack{\symking}, etc. using chessfss
|
|
♥ ♡ ♦ ♢ -> red \heartsuit / \diamondsuit via amssymb + xcolor
|
|
♠ ♤ ♣ ♧ -> black \spadesuit / \clubsuit via amssymb + xcolor
|
|
playing-card emoji -> \BlogEmojiText{...}
|
|
```
|
|
|
|
Use Unicode characters in the source. Do not write LaTeX-only symbols in posts
|
|
unless the post is PDF-only, because raw LaTeX will not generally survive the
|
|
HTML path.
|
|
|
|
## 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/<blog>/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.
|
|
|
|
### Data Tables
|
|
|
|
Use `.data-table` when a post should keep rows in a colocated YAML or JSON file
|
|
but render as a searchable, sortable table in Astro:
|
|
|
|
````markdown
|
|
```{.data-table #tbl:resources src="resources.yml" columns="type,title,summary" headers="type:Type,title:Resource,summary:Notes" link="title" number="slno" caption="Resources" search-placeholder="Search resources"}
|
|
The HTML version renders this as a searchable, sortable table. In Obsidian,
|
|
edit `resources.yml` to update the rows.
|
|
```
|
|
````
|
|
|
|
The data file should contain either a top-level array or an object with an
|
|
`items` array. The `src` path is resolved relative to the Markdown file. Use
|
|
`columns` to control the visible columns, `headers` to rename table headers,
|
|
`link` to choose the column that should link through the row's `link` field,
|
|
and `number` to prefix and sort that linked column by a row number such as
|
|
`slno`.
|
|
|
|
In Obsidian this remains a readable code fence next to the data file. In Astro
|
|
it becomes static HTML enhanced with local search and sort. In PDF it becomes a
|
|
short callout fallback unless a `pdf="..."` or fence body fallback is provided.
|
|
|
|
### 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, internal links, Markdown callouts, emoji, chess pieces,
|
|
and card suits.
|
|
- `scripts/pandoc-templates/semantic-preamble.tex` to load `amsthm`,
|
|
`cleveref`, `tcolorbox`, `emoji`, `chessfss`, and the shared theorem,
|
|
callout, and symbol definitions.
|
|
|
|
Current smoke-test PDFs live outside the repo:
|
|
|
|
```text
|
|
/private/tmp/blog-pdf-samples/callout-symbol-test.pdf
|
|
/private/tmp/blog-pdf-samples/vibes-building-interactives.pdf
|
|
```
|
|
|
|
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`.
|