diff --git a/README.md b/README.md index 6e4c489..3a1281a 100644 --- a/README.md +++ b/README.md @@ -94,11 +94,11 @@ A plugin for displaying inline "callouts" in [Obsidian.md](https://github.com/ob `[!!ICON|LABEL|COLOR]` ``` -| Syntax | Details | -| ----------------- | ------------------------------ | -| `ICON` | Name of the Lucide icon | -| `LABEL`(optional) | Callout label/title text | -| `COLOR`(optional) | RGB values or Obsidian CSS var | +| Syntax | Details | +| ----------------- | ---------------------------------------- | +| `ICON` | Name of the Lucide icon | +| `LABEL`(optional) | Callout label/title text | +| `COLOR`(optional) | Hex, RGB values, or Obsidian CSS var | > [!IMPORTANT] diff --git a/src/callout/builder.ts b/src/callout/builder.ts index 44cb1e4..d73bfb6 100644 --- a/src/callout/builder.ts +++ b/src/callout/builder.ts @@ -3,6 +3,39 @@ import { setIcon } from 'obsidian'; +function parseColorToRgb(color: string): string | null { + const trimmed = color.trim(); + + // Hex color (3, 4, 6, or 8 digit) + if (trimmed.startsWith('#')) { + let hex = trimmed.slice(1); + + // Expand 3-digit hex to 6-digit + if (hex.length === 3) { + hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; + } + // Expand 4-digit hex (with alpha) to 8-digit + if (hex.length === 4) { + hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2] + hex[3] + hex[3]; + } + + // Parse 6-digit or 8-digit hex + if (hex.length === 6 || hex.length === 8) { + const r = parseInt(hex.slice(0, 2), 16); + const g = parseInt(hex.slice(2, 4), 16); + const b = parseInt(hex.slice(4, 6), 16); + + if (!isNaN(r) && !isNaN(g) && !isNaN(b)) { + return `${r}, ${g}, ${b}`; + } + } + return null; + } + + // Already RGB format (e.g., "255, 0, 0") + return trimmed; +} + export class InlineCallout { newEl: HTMLSpanElement; @@ -60,8 +93,11 @@ export class InlineCallout { // icon and color only if (!calloutLabel && calloutColor) { - calloutColorStyle = "color: rgba(" + calloutColor + ", 1);" - this.iconEl.setAttr("style", calloutColorStyle); + const rgb = parseColorToRgb(calloutColor); + if (rgb) { + calloutColorStyle = "color: rgba(" + rgb + ", 1);" + this.iconEl.setAttr("style", calloutColorStyle); + } this.iconEl.setAttr("aria-label", calloutIcon); setIcon(this.iconEl, calloutIcon); this.newEl.appendChild(this.iconEl); @@ -79,8 +115,11 @@ export class InlineCallout { } // color? if (calloutLabel && calloutColor) { - calloutColorStyle = "color: rgba(" + calloutColor + ", 1); background-color: rgba(" + calloutColor + ", var(--inline-callout-bg-transparency));" - this.newEl.setAttr("style", calloutColorStyle) + const rgb = parseColorToRgb(calloutColor); + if (rgb) { + calloutColorStyle = "color: rgba(" + rgb + ", 1); background-color: rgba(" + rgb + ", var(--inline-callout-bg-transparency));" + this.newEl.setAttr("style", calloutColorStyle) + } } return this.newEl; } diff --git a/src/modal/modify.ts b/src/modal/modify.ts index f2cb083..cea530a 100644 --- a/src/modal/modify.ts +++ b/src/modal/modify.ts @@ -111,18 +111,18 @@ export class ModifyInlineCalloutModal extends Modal { }); }); - const hexToRgb = (hex: string) => { - const r = parseInt(hex.slice(1, 3), 16); - const g = parseInt(hex.slice(3, 5), 16); - const b = parseInt(hex.slice(5, 7), 16); - return `${r}, ${g}, ${b}`; - }; - - function rgbToHex(r: number, g: number, b: number) { - return '#' + ((1 << 24) + (r << 16) + (g << 8) + b) - .toString(16) - .slice(1) - .toUpperCase(); + function colorToHex(color: string | undefined): string { + if (!color) return '#000000'; + if (color.startsWith('#')) return color; + // Convert RGB string to hex + const parts = color.split(',').map(s => parseInt(s.trim(), 10)); + if (parts.length >= 3 && parts.every(n => !isNaN(n))) { + return '#' + ((1 << 24) + (parts[0] << 16) + (parts[1] << 8) + parts[2]) + .toString(16) + .slice(1) + .toUpperCase(); + } + return '#000000'; } new Setting(contentEl) @@ -155,18 +155,9 @@ export class ModifyInlineCalloutModal extends Modal { }) }) .addColorPicker((cb) => { - let r = 0; - let g = 0; - let b = 0; - if (this.calloutColor) { - const colorArr = this.calloutColor.split(","); - r = Number(colorArr[0] ?? 0); - g = Number(colorArr[1] ?? 0); - b = Number(colorArr[2] ?? 0); - } - cb.setValue(rgbToHex(r, g, b)) + cb.setValue(colorToHex(this.calloutColor)) .onChange((value) => { - this.calloutColor = hexToRgb(value); + this.calloutColor = value; const dropdown = this.activeDoc.querySelector(".modify-inline-callout-modal .inline-callouts-color-dropdown .dropdown"); if (dropdown) dropdown.value = ''; this.buildPreview(); diff --git a/src/modal/new.ts b/src/modal/new.ts index eac0c3d..1a56efe 100644 --- a/src/modal/new.ts +++ b/src/modal/new.ts @@ -82,13 +82,6 @@ export class NewInlineCalloutModal extends Modal { }); }); - const hexToRgb = (hex: string) => { - const r = parseInt(hex.slice(1, 3), 16); - const g = parseInt(hex.slice(3, 5), 16); - const b = parseInt(hex.slice(5, 7), 16); - return `${r}, ${g}, ${b}`; - }; - new Setting(contentEl) .setName('Color') .setDesc('Pick a color using the dropdown or color picker. Default: Obsidian\'s base color') @@ -119,9 +112,9 @@ export class NewInlineCalloutModal extends Modal { }) }) .addColorPicker((cb) => { - cb.setValue(this.calloutColor ?? '#000000') + cb.setValue(this.calloutColor?.startsWith('#') ? this.calloutColor : '#000000') .onChange((value) => { - this.calloutColor = hexToRgb(value); + this.calloutColor = value; const dropdown = this.activeDoc.querySelector(".new-inline-callout-modal .inline-callouts-color-dropdown .dropdown"); if (dropdown) dropdown.value = ''; this.buildPreview();