Various AT Protocol integrations with obsidian
20
fork

Configure Feed

Select the types of activity you want to include in your feed.

enable using H1 header as title via settings (#20)

* publishing: Pull title from H1

Allows the title to be sourced from the published document's first H1
header. The order of precedence for determining the document's title is
now:

- `title` frontmatter field
- First present H1 header
- Filename

* refactor header extracting

* enable via settings

* fix lint

---------

Co-authored-by: Isaac Corbrey <isaac@isaaccorbrey.com>

authored by

treethought
Isaac Corbrey
and committed by
GitHub
35bee34b a585c9f3

+34 -1
+5
src/commands/publishDocument.ts
··· 6 6 import { SiteStandardDocument, SiteStandardPublication } from "@atcute/standard-site"; 7 7 import { PubLeafletContent } from "@atcute/leaflet"; 8 8 import { BlogPcktContent } from "@atcute/pckt"; 9 + import { extractFirstH1 } from "lib/markdown"; 9 10 10 11 export async function publishFileAsDocument(plugin: AtmospherePlugin) { 11 12 const file = plugin.app.workspace.getActiveFile(); ··· 112 113 path = normalizePath(fm["path"]); 113 114 tags = fm["tags"] && Array.isArray(fm["tags"]) ? fm["tags"] : undefined; 114 115 publishedAt = fm["publishedAt"]; // Preserve existing if updating 116 + } 117 + 118 + if (!title && plugin.settings.publish.useFirstHeaderAsTitle) { 119 + title = extractFirstH1(content); 115 120 } 116 121 117 122 if (!title) {
+10 -1
src/lib/markdown/index.ts
··· 1 1 import { unified } from "unified"; 2 2 import remarkParse from "remark-parse"; 3 - import type { Root, RootContent } from "mdast"; 3 + import type { Root, RootContent, Heading } from "mdast"; 4 4 5 5 export function parseMarkdown(markdown: string): Root { 6 6 return unified().use(remarkParse).parse(markdown); ··· 24 24 } 25 25 26 26 return ""; 27 + } 28 + 29 + export function extractFirstH1(markdown: string): string | undefined { 30 + const tree = parseMarkdown(markdown); 31 + const first = tree.children.find( 32 + node => node.type === "heading" && node.depth === 1 33 + ) as Heading | undefined; 34 + 35 + return first ? extractText(first) : undefined; 27 36 } 28 37 29 38 /**
+19
src/settings.ts
··· 5 5 identifier: string; 6 6 appPassword: string; 7 7 clipDir: string; 8 + publish: { 9 + useFirstHeaderAsTitle: boolean; 10 + }; 8 11 } 9 12 10 13 export const DEFAULT_SETTINGS: AtProtoSettings = { 11 14 identifier: "", 12 15 appPassword: "", 13 16 clipDir: "AtmosphereClips", 17 + publish: { 18 + useFirstHeaderAsTitle: false, 19 + } 14 20 }; 15 21 16 22 export class SettingTab extends PluginSettingTab { ··· 50 56 await this.plugin.saveSettings(); 51 57 }); 52 58 }); 59 + 53 60 new Setting(containerEl) 54 61 .setName("Clip directory") 55 62 .setDesc("Directory in your vault to save clips (will be created if it doesn't exist)") ··· 58 65 .setValue(this.plugin.settings.clipDir) 59 66 .onChange(async (value) => { 60 67 this.plugin.settings.clipDir = value; 68 + await this.plugin.saveSettings(); 69 + }) 70 + ); 71 + 72 + new Setting(containerEl) 73 + .setName("Use first header as publish title") 74 + .setDesc('Use the first level one header instead of filename when no title property is set') 75 + .addToggle((toggle) => 76 + toggle 77 + .setValue(this.plugin.settings.publish.useFirstHeaderAsTitle) 78 + .onChange(async (value) => { 79 + this.plugin.settings.publish.useFirstHeaderAsTitle = value; 61 80 await this.plugin.saveSettings(); 62 81 }) 63 82 );