mirror of
https://github.com/gapmiss/badges.git
synced 2026-07-22 08:00:30 +00:00
Add link support for badges using >> syntax
Badges can now include clickable links with `[!!type:text>>link]` syntax. Supports both wikilinks (`[[Note]]`) and external URLs. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
f672e3492e
commit
02c82a339e
3 changed files with 73 additions and 3 deletions
27
README.md
27
README.md
|
|
@ -8,6 +8,7 @@ A light-weight plugin for displaying inline "badges" in [Obsidian.md](https://gi
|
|||
- [Github styled badges](#Github)
|
||||
- [Plain-text](#Plain-text)
|
||||
- [custom](#custom)
|
||||
- [Links](#links)
|
||||
- [Usage in tables](#usage-in-tables)
|
||||
- [Installation](#Installation)
|
||||
- [CSS styles](#CSS)
|
||||
|
|
@ -190,6 +191,32 @@ For example, `[!!success]` displays as "Success" with a checkmark icon. This wor
|
|||

|
||||

|
||||
|
||||
### Links
|
||||
|
||||
Badges can be made clickable by adding a link using the `>>` syntax.
|
||||
|
||||
###### syntax
|
||||
|
||||
```markdown
|
||||
`[!!KEY:VAL>>LINK]`
|
||||
```
|
||||
|
||||
| syntax | details |
|
||||
| ------ | ------- |
|
||||
| `>>` | link delimiter |
|
||||
| `LINK` | wikilink `[[Note]]` or external URL `https://...` |
|
||||
|
||||
###### examples
|
||||
|
||||
```markdown
|
||||
`[!!info:Documentation>>https://obsidian.md]`
|
||||
`[!!note:See also>>[[My Note]]]`
|
||||
`[!!tip:Jump to section>>[[My Note#Heading]]]`
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Links work with all badge types including custom badges.
|
||||
|
||||
### Usage in tables
|
||||
|
||||
When using badges inside Markdown tables, the `|` pipe character conflicts with the table cell separator. To work around this, use escaped pipes `\|` instead of `|` in your badge syntax.
|
||||
|
|
|
|||
39
src/main.ts
39
src/main.ts
|
|
@ -3,7 +3,7 @@ import { RangeSetBuilder } from "@codemirror/state"
|
|||
import { ViewPlugin, WidgetType, EditorView, ViewUpdate, Decoration, DecorationSet } from '@codemirror/view'
|
||||
import { BADGE_TYPES } from './constants';
|
||||
|
||||
const REGEXP = /(`\[!!([^\]]*)\]`)/gm;
|
||||
const REGEXP = /(`\[!!(.*?)\]`)/gm;
|
||||
const TAGS = 'code'
|
||||
|
||||
export default class BadgesPlugin extends Plugin {
|
||||
|
|
@ -131,7 +131,7 @@ const viewPlugin = ViewPlugin.fromClass(class {
|
|||
decorations: (v) => v.decorations,
|
||||
})
|
||||
|
||||
function buildBadge(text: string): HTMLSpanElement {
|
||||
function buildBadge(text: string): HTMLSpanElement | HTMLAnchorElement {
|
||||
const newEl = createSpan();
|
||||
const iconEl = createSpan();
|
||||
const titleEl = createSpan();
|
||||
|
|
@ -139,11 +139,25 @@ function buildBadge(text: string): HTMLSpanElement {
|
|||
let attrType = "";
|
||||
const part = text.substring(2);
|
||||
// Support escaped pipes (\|) for use inside Markdown tables
|
||||
const content = part.substring(part.length-1,1).trim().replace(/\\\|/g, '|');
|
||||
let content = part.substring(part.length-1,1).trim().replace(/\\\|/g, '|');
|
||||
if (!content.length) {
|
||||
newEl.setText("Badges syntax error");
|
||||
return newEl;
|
||||
}
|
||||
// Parse optional link syntax: >>[[wikilink]] or >>https://...
|
||||
let linkTarget: string | null = null;
|
||||
let isWikilink = false;
|
||||
const linkMatch = content.match(/>>(\[\[.+?\]\]|.+)$/);
|
||||
if (linkMatch) {
|
||||
const rawLink = linkMatch[1].trim();
|
||||
if (rawLink.startsWith('[[') && rawLink.endsWith(']]')) {
|
||||
linkTarget = rawLink.slice(2, -2);
|
||||
isWikilink = true;
|
||||
} else {
|
||||
linkTarget = rawLink;
|
||||
}
|
||||
content = content.slice(0, content.lastIndexOf('>>')).trim();
|
||||
}
|
||||
const parts = content.split(':');
|
||||
let badgeType = parts[0].trim();
|
||||
let badgeContent: string;
|
||||
|
|
@ -225,5 +239,24 @@ function buildBadge(text: string): HTMLSpanElement {
|
|||
}
|
||||
newEl.appendChild(titleEl);
|
||||
}
|
||||
// Wrap in anchor if link was specified
|
||||
if (linkTarget) {
|
||||
const anchor = createEl('a');
|
||||
if (isWikilink) {
|
||||
anchor.addClass('internal-link');
|
||||
anchor.setAttr('data-href', linkTarget);
|
||||
anchor.setAttr('href', linkTarget);
|
||||
anchor.setAttr('data-tooltip-position', 'top');
|
||||
} else {
|
||||
anchor.addClass('external-link');
|
||||
anchor.setAttr('href', linkTarget);
|
||||
anchor.setAttr('target', '_blank');
|
||||
anchor.setAttr('rel', 'noopener');
|
||||
anchor.setAttr('aria-label', linkTarget);
|
||||
anchor.setAttr('data-tooltip-position', 'top');
|
||||
}
|
||||
anchor.appendChild(newEl);
|
||||
return anchor;
|
||||
}
|
||||
return newEl;
|
||||
}
|
||||
|
|
|
|||
10
styles.css
10
styles.css
|
|
@ -416,3 +416,13 @@ body {
|
|||
color: rgba(var(--badge-color), 1);
|
||||
background-color: rgba(var(--badge-color),.123);
|
||||
}
|
||||
a:has(> .inline-badge) {
|
||||
text-decoration: none;
|
||||
}
|
||||
a:has(> .inline-badge),
|
||||
a:has(> .inline-badge) .inline-badge {
|
||||
cursor: pointer;
|
||||
}
|
||||
a:has(> .inline-badge):hover .inline-badge {
|
||||
filter: brightness(1.1);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue