starlight-obsidian 0.8.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,39 @@
1
1
  # starlight-obsidian
2
2
 
3
+ ## 0.9.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#53](https://github.com/HiDeoo/starlight-obsidian/pull/53) [`be89246`](https://github.com/HiDeoo/starlight-obsidian/commit/be8924661655c041a7339d040c4518e74e39defb) Thanks [@HiDeoo](https://github.com/HiDeoo)! - ⚠️ **BREAKING CHANGE:** The minimum supported version of Starlight is now version `0.34.0`.
8
+
9
+ Please use the `@astrojs/upgrade` command to upgrade your project:
10
+
11
+ ```sh
12
+ npx @astrojs/upgrade
13
+ ```
14
+
15
+ - [#53](https://github.com/HiDeoo/starlight-obsidian/pull/53) [`be89246`](https://github.com/HiDeoo/starlight-obsidian/commit/be8924661655c041a7339d040c4518e74e39defb) Thanks [@HiDeoo](https://github.com/HiDeoo)! - Removes the `autoLinkHeadings` option.
16
+
17
+ ⚠️ **BREAKING CHANGE:** The `autoLinkHeadings` option has been removed and this feature is now built-in to Starlight and configurable using the Starlight [`markdown.headingLinks` configuration option](https://starlight.astro.build/reference/configuration/#headinglinks) which is enabled by default.
18
+
19
+ To conserve the previous default behavior of the plugin, set `markdown.headingLinks` to `false` in your Starlight configuration.
20
+
21
+ ```js
22
+ // astro.config.mjs
23
+ starlight({
24
+ markdown: {
25
+ // Disable Starlight’s clickable heading anchor links.
26
+ headingLinks: false,
27
+ },
28
+ }),
29
+ ```
30
+
31
+ ## 0.8.2
32
+
33
+ ### Patch Changes
34
+
35
+ - [#51](https://github.com/HiDeoo/starlight-obsidian/pull/51) [`b067e02`](https://github.com/HiDeoo/starlight-obsidian/commit/b067e026613abe8aaed9b3de673a5ae93e70525e) Thanks [@HiDeoo](https://github.com/HiDeoo)! - Fixes an issue with embedded note sections not being rendered correctly.
36
+
3
37
  ## 0.8.1
4
38
 
5
39
  ### Patch Changes
package/index.ts CHANGED
@@ -10,12 +10,6 @@ import { throwUserError } from './libs/plugin'
10
10
  import { addObsidianFiles, getSidebarFromConfig, getSidebarGroupPlaceholder, type SidebarGroup } from './libs/starlight'
11
11
 
12
12
  const starlightObsidianConfigSchema = z.object({
13
- /**
14
- * Add links to Starlight headings to make it easier to share a link to a specific section of a page.
15
- *
16
- * @default false
17
- */
18
- autoLinkHeadings: z.boolean().default(false),
19
13
  /**
20
14
  * The name of the Obsidian vault configuration folder if different from the default one.
21
15
  *
@@ -165,18 +159,12 @@ function makeStarlightObsidianPlugin(
165
159
  addRouteMiddleware({ entrypoint: 'starlight-obsidian/middleware' })
166
160
  }
167
161
 
168
- const customCss = [...(starlightConfig.customCss ?? []), 'starlight-obsidian/styles/common']
169
-
170
- if (config.autoLinkHeadings) {
171
- customCss.push('starlight-obsidian/styles/autolinks-headings')
172
- }
173
-
174
162
  const updatedStarlightConfig: Partial<StarlightUserConfig> = {
175
163
  components: {
176
164
  ...starlightConfig.components,
177
165
  ...overrideStarlightComponent(starlightConfig.components, logger, 'PageTitle'),
178
166
  },
179
- customCss,
167
+ customCss: [...(starlightConfig.customCss ?? []), 'starlight-obsidian/styles/common'],
180
168
  sidebar: getSidebarFromConfig(config, starlightConfig.sidebar, sidebarGroup),
181
169
  }
182
170
 
@@ -1,12 +1,10 @@
1
- import { rehypeHeadingIds } from '@astrojs/markdown-remark'
2
1
  import type { AstroIntegration } from 'astro'
3
- import rehypeAutolinkHeadings from 'rehype-autolink-headings'
4
2
  import rehypeKatex from 'rehype-katex'
5
3
  import remarkMath from 'remark-math'
6
4
 
7
5
  import type { StarlightObsidianConfig } from '..'
8
6
 
9
- import { getRehypeAutolinkHeadingsOptions, rehypeStarlightObsidian } from './rehype'
7
+ import { rehypeStarlightObsidian } from './rehype'
10
8
  import { vitePluginStarlightObsidianConfig } from './vite'
11
9
 
12
10
  export function starlightObsidianIntegration(config: StarlightObsidianConfig): AstroIntegration {
@@ -16,13 +14,7 @@ export function starlightObsidianIntegration(config: StarlightObsidianConfig): A
16
14
  'astro:config:setup': ({ updateConfig }) => {
17
15
  updateConfig({
18
16
  markdown: {
19
- rehypePlugins: [
20
- ...(config.autoLinkHeadings
21
- ? [rehypeHeadingIds, [rehypeAutolinkHeadings, getRehypeAutolinkHeadingsOptions()]]
22
- : []),
23
- rehypeStarlightObsidian,
24
- rehypeKatex,
25
- ],
17
+ rehypePlugins: [rehypeStarlightObsidian, rehypeKatex],
26
18
  remarkPlugins: [remarkMath],
27
19
  },
28
20
  vite: {
package/libs/rehype.ts CHANGED
@@ -1,9 +1,5 @@
1
1
  import type { Element, ElementContent, Root } from 'hast'
2
- import { toString } from 'hast-util-to-string'
3
- import { h } from 'hastscript'
4
- import { escape } from 'html-escaper'
5
2
  import type { Literal } from 'mdast'
6
- import type { Options as RehypeAutolinkHeadingsOptions } from 'rehype-autolink-headings'
7
3
  import { CONTINUE, SKIP, visit } from 'unist-util-visit'
8
4
 
9
5
  const blockIdentifierRegex = /(?<identifier> *\^(?<name>[\w-]+))$/
@@ -42,24 +38,6 @@ export function rehypeStarlightObsidian() {
42
38
  }
43
39
  }
44
40
 
45
- // https://hideoo.dev/notes/starlight-heading-links
46
- // https://github.com/withastro/docs/blob/main/plugins/rehype-autolink.ts
47
- // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
48
- export function getRehypeAutolinkHeadingsOptions(): RehypeAutolinkHeadingsOptions {
49
- return {
50
- behavior: 'after',
51
- content: (heading) => {
52
- return [
53
- h('span', { ariaHidden: 'true' }, '§'),
54
- h('span', { class: 'sr-only' }, `Section titled ${escape(toString(heading))}`),
55
- ]
56
- },
57
- group: ({ tagName }) =>
58
- h('div', { class: `sl-obs-section sl-obs-section-level-${tagName.slice(1)}`, tabIndex: -1 }),
59
- properties: { class: 'sl-obs-heading-link' },
60
- }
61
- }
62
-
63
41
  function transformBlockIdentifier(reference: Element, node: ElementContent | undefined) {
64
42
  if (!isNodeWithValue(node)) {
65
43
  return CONTINUE
package/libs/remark.ts CHANGED
@@ -20,7 +20,7 @@ import type {
20
20
  import { findAndReplace } from 'mdast-util-find-and-replace'
21
21
  import { toHast } from 'mdast-util-to-hast'
22
22
  import { customAlphabet } from 'nanoid'
23
- import { CONTINUE, SKIP, visit } from 'unist-util-visit'
23
+ import { CONTINUE, EXIT, SKIP, visit } from 'unist-util-visit'
24
24
  import type { VFile } from 'vfile'
25
25
  import yaml from 'yaml'
26
26
 
@@ -669,9 +669,13 @@ function getCustomFileNode(filePath: string): RootContent {
669
669
  async function getMarkdownFileNode(file: VFile, fileUrl: string): Promise<RootContent> {
670
670
  ensureTransformContext(file)
671
671
 
672
+ const [fileName, ...anchorSegments] = fileUrl.split('#')
673
+ const fileAnchor = anchorSegments.join('#')
672
674
  const fileExt = file.data.vault.options.linkSyntax === 'wikilink' ? '.md' : ''
673
675
  const filePath = decodeURIComponent(
674
- file.data.vault.options.linkFormat === 'relative' ? getRelativeFilePath(file, fileUrl) : fileUrl,
676
+ file.data.vault.options.linkFormat === 'relative'
677
+ ? getRelativeFilePath(file, fileName ?? fileUrl)
678
+ : (fileName ?? fileUrl),
675
679
  )
676
680
  const url = path.posix.join(path.posix.sep, `${filePath}${fileExt}`)
677
681
  const matchingFile = file.data.files.find(
@@ -685,6 +689,10 @@ async function getMarkdownFileNode(file: VFile, fileUrl: string): Promise<RootCo
685
689
  const content = fs.readFileSync(matchingFile.fsPath, 'utf8')
686
690
  const root = await transformMarkdownToAST(matchingFile.fsPath, content, { ...file.data, embedded: true })
687
691
 
692
+ if (fileAnchor) {
693
+ root.children = extractMarkdownSection(root, fileAnchor)
694
+ }
695
+
688
696
  return {
689
697
  type: 'blockquote',
690
698
  children: [
@@ -705,6 +713,35 @@ function replaceNode({ index, parent }: VisitorContext, replacement: RootContent
705
713
  parent.children.splice(index, 1, ...(Array.isArray(replacement) ? replacement : [replacement]))
706
714
  }
707
715
 
716
+ function extractMarkdownSection(root: Root, sectionAnchor: string) {
717
+ const children: Root['children'] = []
718
+
719
+ visit(root, (node, index, parent) => {
720
+ switch (node.type) {
721
+ case 'heading': {
722
+ if (!parent || index === undefined) return CONTINUE
723
+ const headingText = node.children.find((child) => child.type === 'text')?.value
724
+ if (headingText !== sectionAnchor) return CONTINUE
725
+
726
+ children.push(node)
727
+
728
+ let nextNode = parent.children[index + 1]
729
+ while (nextNode && (nextNode.type !== 'heading' || nextNode.depth > node.depth)) {
730
+ children.push(nextNode)
731
+ nextNode = parent.children[index + children.length]
732
+ }
733
+
734
+ return EXIT
735
+ }
736
+ default: {
737
+ return CONTINUE
738
+ }
739
+ }
740
+ })
741
+
742
+ return children
743
+ }
744
+
708
745
  // We are using `Html` node instead of real MDX nodes because we are not using `remark-mdx` due to the fact that it
709
746
  // makes the parsing step way more strict. During our inital testing round, we found out that a few users had pretty
710
747
  // poorly formatted Markdown files (usually the result of various Obisidian migration tools) and we wanted to make sure
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "starlight-obsidian",
3
- "version": "0.8.1",
3
+ "version": "0.9.0",
4
4
  "license": "MIT",
5
5
  "description": "Starlight plugin to publish Obsidian vaults.",
6
6
  "author": "HiDeoo <github@hideoo.dev> (https://hideoo.dev)",
@@ -14,27 +14,21 @@
14
14
  "./overrides/PageTitle.astro": "./overrides/PageTitle.astro",
15
15
  "./schema": "./schema.ts",
16
16
  "./styles/common": "./styles/common.css",
17
- "./styles/autolinks-headings": "./styles/autolinks-headings.css",
18
17
  "./package.json": "./package.json"
19
18
  },
20
19
  "dependencies": {
21
20
  "@astro-community/astro-embed-twitter": "^0.5.8",
22
21
  "@astro-community/astro-embed-youtube": "^0.5.6",
23
- "@astrojs/markdown-remark": "^6.0.0",
24
22
  "decode-uri-component": "^0.4.1",
25
23
  "github-slugger": "^2.0.0",
26
24
  "globby": "^14.0.2",
27
25
  "hast-util-to-html": "^9.0.4",
28
- "hast-util-to-string": "^3.0.1",
29
- "hastscript": "^9.0.0",
30
- "html-escaper": "^3.0.3",
31
26
  "is-absolute-url": "^4.0.1",
32
27
  "mdast-util-find-and-replace": "^3.0.1",
33
28
  "mdast-util-from-markdown": "^2.0.2",
34
29
  "mdast-util-to-hast": "^13.2.0",
35
30
  "nanoid": "^5.0.9",
36
31
  "rehype": "^13.0.2",
37
- "rehype-autolink-headings": "^7.1.0",
38
32
  "rehype-katex": "^7.0.1",
39
33
  "rehype-mermaid": "^2.1.0",
40
34
  "remark": "^15.0.1",
@@ -47,7 +41,6 @@
47
41
  },
48
42
  "devDependencies": {
49
43
  "@types/hast": "^3.0.4",
50
- "@types/html-escaper": "^3.0.2",
51
44
  "@types/mdast": "^4.0.4",
52
45
  "@types/node": "^18.19.68",
53
46
  "@types/unist": "^3.0.3",
@@ -55,7 +48,7 @@
55
48
  "vitest": "2.1.6"
56
49
  },
57
50
  "peerDependencies": {
58
- "@astrojs/starlight": ">=0.32.0"
51
+ "@astrojs/starlight": ">=0.34.0"
59
52
  },
60
53
  "engines": {
61
54
  "node": ">=18.17.1"
@@ -1,68 +0,0 @@
1
- .sl-markdown-content :not(.sl-obs-section) + :is(.sl-obs-section):not(:where(.not-content *)) {
2
- margin-top: 1.5em;
3
- }
4
-
5
- .sl-markdown-content .sl-obs-section {
6
- --sl-obs-heading-link-spacing: 0.25em;
7
-
8
- line-height: var(--sl-line-height-headings);
9
- }
10
-
11
- .sl-markdown-content .sl-obs-section.sl-obs-section-level-1 {
12
- font-size: var(--sl-text-h1);
13
- }
14
-
15
- .sl-markdown-content .sl-obs-section.sl-obs-section-level-2 {
16
- font-size: var(--sl-text-h2);
17
- }
18
-
19
- .sl-markdown-content .sl-obs-section.sl-obs-section-level-3 {
20
- font-size: var(--sl-text-h3);
21
- }
22
-
23
- .sl-markdown-content .sl-obs-section.sl-obs-section-level-4 {
24
- font-size: var(--sl-text-h4);
25
- }
26
-
27
- .sl-markdown-content .sl-obs-section.sl-obs-section-level-5 {
28
- font-size: var(--sl-text-h5);
29
- }
30
-
31
- .sl-markdown-content .sl-obs-section.sl-obs-section-level-6 {
32
- font-size: var(--sl-text-h6);
33
- }
34
-
35
- .sl-markdown-content .sl-obs-section > :first-child {
36
- display: inline;
37
- margin-inline-end: var(--sl-obs-heading-link-spacing);
38
- }
39
-
40
- .sl-markdown-content .sl-obs-heading-link {
41
- color: var(--sl-color-gray-3);
42
- text-decoration: none;
43
- }
44
-
45
- .sl-markdown-content .sl-obs-heading-link:is(:hover, :focus) {
46
- color: var(--sl-color-text-accent);
47
- }
48
-
49
- @media (hover: hover) {
50
- .sl-markdown-content .sl-obs-heading-link {
51
- opacity: 0;
52
- }
53
- }
54
-
55
- .sl-markdown-content .sl-obs-section:hover > .sl-obs-heading-link,
56
- .sl-markdown-content .sl-obs-heading-link:focus {
57
- opacity: 1;
58
- }
59
-
60
- @media (min-width: 95em) {
61
- .sl-markdown-content .sl-obs-section {
62
- display: flex;
63
- flex-direction: row-reverse;
64
- gap: var(--sl-obs-heading-link-spacing);
65
- justify-content: flex-end;
66
- margin-inline-start: calc(-1 * (1ch + var(--sl-obs-heading-link-spacing)));
67
- }
68
- }