feat(links): added ofm option to style unresolved or broken links differently (#1992)
* feat: add option to disable broken wikilinks * fix(style): update hover color for broken links and introduce new class * feat: add "disableBrokenWikilinks" option to ObsidianFlavoredMarkdown
This commit is contained in:
		@@ -23,6 +23,7 @@ This plugin accepts the following configuration options:
 | 
				
			|||||||
- `enableYouTubeEmbed`: If `true` (default), enables the embedding of YouTube videos and playlists using external image Markdown syntax.
 | 
					- `enableYouTubeEmbed`: If `true` (default), enables the embedding of YouTube videos and playlists using external image Markdown syntax.
 | 
				
			||||||
- `enableVideoEmbed`: If `true` (default), enables the embedding of video files.
 | 
					- `enableVideoEmbed`: If `true` (default), enables the embedding of video files.
 | 
				
			||||||
- `enableCheckbox`: If `true`, adds support for interactive checkboxes in content. Defaults to `false`.
 | 
					- `enableCheckbox`: If `true`, adds support for interactive checkboxes in content. Defaults to `false`.
 | 
				
			||||||
 | 
					- `disableBrokenWikilinks`: If `true`, replaces links to non-existent notes with a dimmed, disabled link. Defaults to `false`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> [!warning]
 | 
					> [!warning]
 | 
				
			||||||
> Don't remove this plugin if you're using [[Obsidian compatibility|Obsidian]] to author the content!
 | 
					> Don't remove this plugin if you're using [[Obsidian compatibility|Obsidian]] to author the content!
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,6 +41,7 @@ export interface Options {
 | 
				
			|||||||
  enableYouTubeEmbed: boolean
 | 
					  enableYouTubeEmbed: boolean
 | 
				
			||||||
  enableVideoEmbed: boolean
 | 
					  enableVideoEmbed: boolean
 | 
				
			||||||
  enableCheckbox: boolean
 | 
					  enableCheckbox: boolean
 | 
				
			||||||
 | 
					  disableBrokenWikilinks: boolean
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const defaultOptions: Options = {
 | 
					const defaultOptions: Options = {
 | 
				
			||||||
@@ -56,6 +57,7 @@ const defaultOptions: Options = {
 | 
				
			|||||||
  enableYouTubeEmbed: true,
 | 
					  enableYouTubeEmbed: true,
 | 
				
			||||||
  enableVideoEmbed: true,
 | 
					  enableVideoEmbed: true,
 | 
				
			||||||
  enableCheckbox: false,
 | 
					  enableCheckbox: false,
 | 
				
			||||||
 | 
					  disableBrokenWikilinks: false,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const calloutMapping = {
 | 
					const calloutMapping = {
 | 
				
			||||||
@@ -206,7 +208,7 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>>
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      return src
 | 
					      return src
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    markdownPlugins(_ctx) {
 | 
					    markdownPlugins(ctx) {
 | 
				
			||||||
      const plugins: PluggableList = []
 | 
					      const plugins: PluggableList = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // regex replacements
 | 
					      // regex replacements
 | 
				
			||||||
@@ -275,6 +277,18 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>>
 | 
				
			|||||||
                  // otherwise, fall through to regular link
 | 
					                  // otherwise, fall through to regular link
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // treat as broken link if slug not in ctx.allSlugs
 | 
				
			||||||
 | 
					                if (opts.disableBrokenWikilinks) {
 | 
				
			||||||
 | 
					                  const slug = slugifyFilePath(fp as FilePath)
 | 
				
			||||||
 | 
					                  const exists = ctx.allSlugs && ctx.allSlugs.includes(slug)
 | 
				
			||||||
 | 
					                  if (!exists) {
 | 
				
			||||||
 | 
					                    return {
 | 
				
			||||||
 | 
					                      type: "html",
 | 
				
			||||||
 | 
					                      value: `<a class=\"internal broken\">${alias ?? fp}</a>`,
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // internal link
 | 
					                // internal link
 | 
				
			||||||
                const url = fp + anchor
 | 
					                const url = fp + anchor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -91,7 +91,7 @@ a {
 | 
				
			|||||||
  color: var(--secondary);
 | 
					  color: var(--secondary);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &:hover {
 | 
					  &:hover {
 | 
				
			||||||
    color: var(--tertiary) !important;
 | 
					    color: var(--tertiary);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &.internal {
 | 
					  &.internal {
 | 
				
			||||||
@@ -101,6 +101,15 @@ a {
 | 
				
			|||||||
    border-radius: 5px;
 | 
					    border-radius: 5px;
 | 
				
			||||||
    line-height: 1.4rem;
 | 
					    line-height: 1.4rem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.broken {
 | 
				
			||||||
 | 
					      color: var(--secondary);
 | 
				
			||||||
 | 
					      opacity: 0.5;
 | 
				
			||||||
 | 
					      transition: opacity 0.2s ease;
 | 
				
			||||||
 | 
					      &:hover {
 | 
				
			||||||
 | 
					        opacity: 0.8;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    &:has(> img) {
 | 
					    &:has(> img) {
 | 
				
			||||||
      background-color: transparent;
 | 
					      background-color: transparent;
 | 
				
			||||||
      border-radius: 0;
 | 
					      border-radius: 0;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user