Files
obsidian-micropub/docs/superpowers/specs/2026-03-30-syndication-dialog-design.md
svemagie f5af7ff1e2 fresh
2026-03-31 14:23:33 +02:00

6.5 KiB

Syndication Dialog Design

Date: 2026-03-30 Status: Approved Scope: obsidian-micropub plugin feature


1. Overview

Add a dialog that appears when publishing to Micropub, allowing users to select which syndication targets (e.g., Twitter, Mastodon) to cross-post to. The dialog integrates with the existing ?q=config Micropub endpoint to fetch available targets.


2. User Flow

  1. User clicks "Publish to Micropub"
  2. Plugin fetches ?q=config to get available syndication targets
  3. Plugin checks frontmatter for mp-syndicate-to:
    • Has values → use those, skip dialog, publish
    • Empty array [] → force dialog
    • Absent → show dialog with defaults pre-checked
  4. Dialog displays checkboxes for each target from server
  5. User confirms → publish with selected targets
  6. Successful publish writes mp-syndicate-to to frontmatter

3. Configuration

New Settings

Setting Type Default Description
showSyndicationDialog enum "when-needed" When to show the dialog
defaultSyndicateTo string[] [] Targets checked by default

showSyndicationDialog Options

  • "when-needed" — Show only if mp-syndicate-to is absent from frontmatter
  • "always" — Show every time user publishes
  • "never" — Use defaults, never show dialog

Frontmatter Support

Users can bypass the dialog per-note using frontmatter:

---
# Skip dialog, auto-syndicate to these targets
mp-syndicate-to: [twitter, mastodon]

# Force dialog even with defaults set
mp-syndicate-to: []
---

4. Components

4.1 SyndicationDialog (New)

Location: src/SyndicationDialog.ts

Responsibilities:

  • Render modal with checkbox list of targets
  • Pre-check targets from defaultSyndicateTo setting
  • Handle OK/Cancel actions
  • Return selected target UIDs via promise

Interface:

export class SyndicationDialog extends Modal {
  constructor(
    app: App,
    targets: SyndicationTarget[],
    defaultSelected: string[]
  );

  /**
   * Opens the dialog and waits for user selection.
   * @returns Selected target UIDs, or null if cancelled.
   */
  async awaitSelection(): Promise<string[] | null>;
}

4.2 Publisher (Modified)

Changes:

  • Accept optional syndicateToOverride?: string[] parameter
  • Merge override with frontmatter values (override wins)
  • Write mp-syndicate-to to frontmatter on successful publish

4.3 SettingsTab (Modified)

Changes:

  • Add dropdown for showSyndicationDialog behavior
  • Display currently configured default targets (read-only list)
  • Add button to clear defaults

4.4 main.ts (Modified)

Changes:

  • Before calling publishActiveNote:
    1. Fetch ?q=config for syndication targets
    2. Check frontmatter for mp-syndicate-to
    3. Decide whether to show dialog based on setting + frontmatter
    4. If showing dialog, wait for user selection
    5. Call publisher.publish() with selected targets

5. Data Flow

User clicks "Publish"
       │
       ▼
Fetch ?q=config ──► Check frontmatter mp-syndicate-to
       │                      │
       │         ┌─────────────┼─────────────┐
       │         │             │             │
       │    Has values     Absent         Empty []
       │    (skip dialog)  (show dialog)  (show dialog)
       │         │             │             │
       │         └─────────────┴─────────────┘
       │                       │
       ▼                       ▼
SyndicationDialog (if needed)
       │
       ▼
Publisher.publish(selectedTargets?)
       │
       ▼
Write mp-syndicate-to to frontmatter

6. Error Handling

Scenario Behavior
?q=config fails Warn user, offer to publish without syndication or cancel
Dialog canceled Abort publish, no changes
Micropub POST fails Don't write mp-syndicate-to to frontmatter
No targets returned from server Skip dialog, publish normally (backward compatible)

7. UI/UX Details

Dialog Layout

┌─────────────────────────────────────────┐
│  Publish to Syndication Targets         │
├─────────────────────────────────────────┤
│                                         │
│  [✓] Twitter (@username)                │
│  [✓] Mastodon (@user@instance)          │
│  [ ] LinkedIn                           │
│                                         │
├─────────────────────────────────────────┤
│  [Cancel]              [Publish]      │
└─────────────────────────────────────────┘

Settings UI Addition

Publish Behaviour
├── Default visibility: [public ▼]
├── Write URL back to note: [✓]
├── Syndication dialog: [when-needed ▼]
│   └── when-needed: Show only if no mp-syndicate-to
├── Default syndication targets:
│   └── twitter, mastodon [Clear defaults]
└── ...

8. Edge Cases

  1. User has no syndication targets configured on server — Skip dialog, publish normally
  2. User cancels dialog — Abort publish entirely, no state changes
  3. Micropub server returns targets but some are invalid — Show all, let server reject invalid ones
  4. User changes targets in settings after publishing — Affects future publishes only, doesn't retroactively change existing mp-syndicate-to frontmatter

9. Backward Compatibility

  • Default showSyndicationDialog: "when-needed" means existing behavior unchanged for notes without frontmatter
  • Existing mp-syndicate-to frontmatter values continue to work
  • Plugin remains compatible with servers that don't return syndication targets

10. Testing Considerations

  • Unit test: SyndicationDialog renders checkboxes correctly
  • Unit test: Frontmatter parsing handles mp-syndicate-to array
  • Unit test: Setting "never" skips dialog
  • Integration test: Full flow from click to publish with targets
  • Edge case: Server returns empty targets array
  • Edge case: User cancels dialog

Approval

Approved by: @svemagie Date: 2026-03-30