diff --git a/README.md b/README.md index 0e072a4..0a1c991 100644 --- a/README.md +++ b/README.md @@ -9,56 +9,67 @@ Forked and generalised from [svemagie/obsidian-microblog](https://github.com/sve ## Features - **Any Micropub endpoint** — not locked to Micro.blog; works with Indiekit and other servers +- **IndieAuth sign-in** — browser-based PKCE login, no token copy-paste required - **Auto-discovery** — reads `` from your site to find the endpoint automatically -- **Digital Garden stage mapping** — Obsidian tags `#garden/plant`, `#garden/cultivate`, etc. become a `gardenStage` property on the published post, matching the Eleventy blog's garden system -- **Create + Update** — if the note has a `mp-url` frontmatter key, Publish will update the existing post instead of creating a new one -- **Image upload** — local images (wiki-embeds and markdown) are uploaded to the media endpoint and URLs rewritten +- **Article vs. note** — auto-detected from frontmatter; override with `postType` +- **Digital Garden stage mapping** — Obsidian tags `#garden/plant`, `#garden/cultivate`, etc. become a `gardenStage` property on the published post +- **Create + Update** — if the note has an `mp-url` frontmatter key, Publish updates the existing post instead of creating a new one +- **Image upload** — local images (`![[file.png]]` and `![alt](path)`) are uploaded to the media endpoint and rewritten to remote URLs in the post content +- **WikiLink resolution** — `[[Note Name]]` links in the body are resolved to their published blog URLs via `mp-url` frontmatter +- **Interaction posts** — bookmark, like, reply, repost using standard Micropub properties +- **AI disclosure** — `ai-text-level`, `ai-tools`, etc. pass through as Micropub properties - **URL write-back** — the returned post URL is saved to `mp-url` in the note's frontmatter after publishing --- ## Installation -### From source (development) - -```bash -cd /path/to/your/obsidian/vault/.obsidian/plugins -git clone https://github.com/yourname/obsidian-micropub -cd obsidian-micropub -npm install -npm run dev -``` - -Then enable the plugin in Obsidian → Settings → Community plugins. - ### Manual -1. Download the latest release (main.js + manifest.json) +1. Download the latest release (`main.js` + `manifest.json`) 2. Create a folder `.obsidian/plugins/obsidian-micropub/` in your vault 3. Copy both files there 4. Enable in Obsidian → Settings → Community plugins +### From source + +```bash +cd /path/to/your/obsidian/vault/.obsidian/plugins +git clone https://github.com/svemagie/obsidian-micropub +cd obsidian-micropub +npm install +npm run build +``` + --- ## Configuration Open **Settings → Micropub Publisher**. -| Setting | Description | -|---|---| -| **Site URL** | Your site's home page — used for endpoint auto-discovery | -| **Micropub endpoint** | e.g. `https://example.com/micropub` | -| **Media endpoint** | For image uploads; auto-discovered if blank | -| **Access token** | Bearer token from your IndieAuth token endpoint | -| **Default visibility** | `public` / `unlisted` / `private` | -| **Write URL to note** | Save the published post URL as `mp-url` in frontmatter | -| **Map #garden/* tags** | Convert `#garden/plant` → `garden-stage: plant` property | +### Sign in with IndieAuth (recommended) -### Getting a token from Indiekit +1. Enter your **Site URL** (e.g. `https://blog.example.com`). +2. Click **Sign in** — your browser opens your site's IndieAuth login page. +3. Log in. The browser redirects back to Obsidian automatically. +4. The plugin stores your access token and fills in the endpoint URLs. -1. Log into your Indiekit admin panel -2. Go to **Tokens** → Create new token with `create update` scope -3. Paste the token into the plugin settings +The flow uses [PKCE](https://oauth.net/2/pkce/) and a GitHub Pages relay page as the redirect URI, so it works without a local HTTP server. + +### Manual token (advanced) + +Expand **Or paste a token manually** and enter a bearer token from your Indiekit admin panel (`create update media` scope). Click **Verify** to confirm it works. + +### Settings reference + +| Setting | Default | Description | +|---|---|---| +| Site URL | — | Your site's homepage; used for IndieAuth endpoint discovery | +| Micropub endpoint | — | e.g. `https://example.com/micropub` | +| Media endpoint | — | For image uploads; auto-discovered from Micropub config if blank | +| Default visibility | `public` | Applied when the note has no `visibility` field | +| Write URL back to note | on | Saves the published post URL as `mp-url` in frontmatter | +| Map #garden/* tags | on | Converts `#garden/plant` → `gardenStage: plant` Micropub property | --- @@ -102,24 +113,48 @@ mp-url: "https://example.com/articles/2026/on-building-in-public" ## Frontmatter properties recognised -### Standard properties +### Post identity | Property | Effect | |---|---| -| `title` | Sets the post `name` (article mode) | -| `created` / `date` | Sets `published` date (`created` takes priority — matches Obsidian's default date field) | -| `postType` | Force post type: `article` sends a title (uses filename if none set), `note` skips title | -| `tags` + `category` | Both merged into Micropub `category` (excluding `garden/*` and bare `garden` tags, deduplicated) | -| `summary` / `excerpt` | Sets `summary` property | +| `mp-url` / `url` | Existing post URL — triggers an **update** rather than create | +| `postType` | Force post type: `article` (sets `name`), `note` (skips `name`) | +| `title` / `name` | Sets the post `name`; presence auto-detects post type as article | + +If no `postType` is set: a note with a `title` or `name` field publishes as an article; a note without one publishes as a note. + +### Content + +| Property | Effect | +|---|---| +| `created` / `date` | Sets `published` date; `created` takes priority (matches Obsidian's default) | +| `tags` + `category` | Both merged into Micropub `category`; `garden/*` and bare `garden` tags are filtered out | +| `summary` / `excerpt` | Sets the `summary` property | | `visibility` | `public` / `unlisted` / `private` | -| `gardenStage` | Explicit garden stage — see table below | -| `mp-url` | Triggers an **update** rather than create | -| `mp-syndicate-to` / `mpSyndicateTo` | Pre-fills syndication target list | -| `mp-*` | Any other `mp-*` keys passed through verbatim | +| `photo` | Featured photo: a URL string, array of URLs, or `[{url, alt}]` objects | +| `related` | List of `[[WikiLinks]]` or URLs to related posts; WikiLinks are resolved to `mp-url` | -### AI disclosure properties +### Syndication -Use flat kebab-case properties (camelCase fallback supported for backward compatibility): +| Property | Effect | +|---|---| +| `mp-syndicate-to` / `mpSyndicateTo` | Per-note syndication targets, merged with the default targets in settings | +| `mp-*` | Any other `mp-*` key (except `mp-url`) is passed through verbatim | + +### Interaction posts + +Set one of these to publish a bookmark, like, reply, or repost. Adding body text to an interaction note includes it as a comment or quote; bare likes and reposts omit `content` entirely. + +| Property | Effect | +|---|---| +| `bookmarkOf` / `bookmark-of` | URL being bookmarked | +| `likeOf` / `like-of` | URL being liked | +| `inReplyTo` / `in-reply-to` | URL being replied to | +| `repostOf` / `repost-of` | URL being reposted | + +### AI disclosure + +Flat kebab-case keys are recommended; camelCase and a nested `ai:` object are also supported. | Property | Values | Meaning | |---|---|---| @@ -128,27 +163,6 @@ Use flat kebab-case properties (camelCase fallback supported for backward compat | `ai-tools` | string | Tools used, e.g. `"Claude"` | | `ai-description` | string | Free-text disclosure note | -Nested `ai:` objects (e.g. `ai: {textLevel: "1"}`) also work but flat keys are recommended. - -**Example article template:** - -```yaml ---- -title: "My Post" -created: 2026-03-15T10:00:00 -postType: article -tags: - - garden/evergreen -category: - - indieweb - - lang/en -ai-text-level: "1" -ai-code-level: "0" -ai-tools: "Claude" -ai-description: "AI helped refine the structure" ---- -``` - ### Digital Garden stages Set via `gardenStage` frontmatter or a `#garden/` tag: @@ -163,6 +177,25 @@ Set via `gardenStage` frontmatter or a `#garden/` tag: | `revitalize` | ✨ Revitalizing | Being refreshed | | `revisit` | 🔄 Revisit | Flagged to come back to | +When a note is first published with `gardenStage: evergreen`, an `evergreen-since` date is stamped automatically. + +**Example article template:** + +```yaml +--- +title: "My Post" +created: 2026-03-15T10:00:00 +postType: article +tags: + - garden/evergreen +category: + - indieweb + - lang/en +ai-text-level: "1" +ai-tools: "Claude" +--- +``` + --- ## Development @@ -176,11 +209,12 @@ npm run build # production bundle (minified) ``` src/ - main.ts Plugin entry point, command/ribbon registration - types.ts Shared interfaces and constants - MicropubClient.ts Low-level HTTP (create, update, upload, discover) - Publisher.ts Orchestrates publish flow (parse → upload → send → write-back) - SettingsTab.ts Obsidian settings UI + main.ts Plugin entry point, commands, ribbon, protocol handler + types.ts Shared interfaces and constants + MicropubClient.ts Low-level HTTP (create, update, upload, discover) + Publisher.ts Orchestrates publish flow (parse → upload → send → write-back) + IndieAuth.ts PKCE IndieAuth sign-in via GitHub Pages relay + SettingsTab.ts Obsidian settings UI ``` ---