mirror of
https://github.com/gapmiss/inline-callouts.git
synced 2026-07-22 12:30:25 +00:00
feat: add hex color support
Support hex colors (#RGB, #RRGGBB) in addition to RGB values and CSS variables. Color picker in modals now preserves hex format instead of converting to RGB. Closes #2 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
663e6b83f0
commit
cf52f94f29
4 changed files with 64 additions and 41 deletions
10
README.md
10
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]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<HTMLSelectElement>(".modify-inline-callout-modal .inline-callouts-color-dropdown .dropdown");
|
||||
if (dropdown) dropdown.value = '';
|
||||
this.buildPreview();
|
||||
|
|
|
|||
|
|
@ -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<HTMLSelectElement>(".new-inline-callout-modal .inline-callouts-color-dropdown .dropdown");
|
||||
if (dropdown) dropdown.value = '';
|
||||
this.buildPreview();
|
||||
|
|
|
|||
Loading…
Reference in a new issue