feat: added optional text description for event

This commit is contained in:
Aleksey Korolev 2026-01-22 13:34:44 +03:00
parent e6f00b51ae
commit bb9ff01bba
2 changed files with 103 additions and 19 deletions

76
main.ts
View file

@ -1,4 +1,4 @@
import { Plugin, moment, setIcon, setTooltip } from 'obsidian';
import { MarkdownRenderer, Plugin, moment, setIcon, setTooltip } from 'obsidian';
import { SettingsTab } from 'settings-tab';
interface PluginSettings {
@ -40,27 +40,33 @@ export default class EventHighlightPlugin extends Plugin {
this.addSettingTab(new SettingsTab(this.app, this));
this.registerMarkdownCodeBlockProcessor('event-highlight', (source, el, ctx) => {
this.renderElement(el, source.trim());
this.registerMarkdownCodeBlockProcessor(
'event-highlight',
async (source, el, ctx) => {
await this.renderElement(el, source.trim(), undefined, ctx.sourcePath);
el.addEventListener('click', () => {
el.addEventListener('click', async () => {
const { swapped } = this.loadState(el);
this.renderElement(el, source.trim(), {
swapped: !swapped,
});
});
await this.renderElement(
el,
source.trim(),
{ swapped: !swapped },
ctx.sourcePath,
);
});
},
);
this.registerEvent(
this.app.workspace.on('active-leaf-change', () => {
this.updateAllPage();
void this.updateAllPage();
}),
);
this.registerInterval(
window.setInterval(() => {
this.updateAllPage();
void this.updateAllPage();
}, 10_000),
);
}
@ -115,10 +121,17 @@ export default class EventHighlightPlugin extends Plugin {
return JSON.stringify(oldState) === JSON.stringify(newState);
}
private renderElement(el: Element, source: string, overrideState?: Partial<State>) {
const parsedDate = moment(source, ['YYYY-MM-DD', 'DD.MM.YYYY'], true);
private async renderElement(
el: Element,
source: string,
overrideState?: Partial<State>,
sourcePath = '',
) {
const { dateSource, extraText } = this.parseSource(source);
const parsedDate = moment(dateSource, ['YYYY-MM-DD', 'DD.MM.YYYY'], true);
const parsedDateTime = moment(
source,
dateSource,
['YYYY-MM-DD HH:mm', 'DD.MM.YYYY HH:mm'],
true,
);
@ -214,14 +227,27 @@ export default class EventHighlightPlugin extends Plugin {
el.empty();
const dateSpan = el.createEl('div', { cls: 'event-highlight-badge' });
const container = el.createEl('div', { cls: 'event-highlight-container' });
if (extraText) {
const textEl = container.createEl('div', { cls: 'event-highlight-text' });
await MarkdownRenderer.render(this.app, extraText, textEl, sourcePath, this);
}
const dateSpan = container.createEl('div', { cls: 'event-highlight-badge' });
const iconSpan = dateSpan.createEl('div', { cls: 'icon' });
if (extraText) {
dateSpan.classList.add('with-text');
}
dateSpan.createEl('div', { text });
switch (true) {
case isError:
dateSpan.classList.add('error');
container.classList.add('error');
setIcon(iconSpan, 'ban');
setTooltip(dateSpan, 'Invalid date');
@ -229,6 +255,7 @@ export default class EventHighlightPlugin extends Plugin {
break;
case isAfter:
dateSpan.classList.add('after');
container.classList.add('after');
setIcon(iconSpan, 'calendar-check-2');
setTooltip(dateSpan, 'Past event');
@ -236,6 +263,7 @@ export default class EventHighlightPlugin extends Plugin {
break;
case isBefore:
dateSpan.classList.add('before');
container.classList.add('before');
setIcon(iconSpan, 'calendar');
setTooltip(dateSpan, `Event soon (${workFormatted})`);
@ -243,6 +271,7 @@ export default class EventHighlightPlugin extends Plugin {
break;
case isUpcoming:
dateSpan.classList.add('upcoming');
container.classList.add('upcoming');
setIcon(iconSpan, 'calendar-clock');
setTooltip(dateSpan, `Upcoming event (${workFormatted})`);
@ -250,6 +279,7 @@ export default class EventHighlightPlugin extends Plugin {
break;
case isActual:
dateSpan.classList.add('actual');
container.classList.add('actual');
setIcon(iconSpan, 'clock');
setTooltip(dateSpan, `Event started (${workFormatted})`);
@ -258,15 +288,25 @@ export default class EventHighlightPlugin extends Plugin {
}
}
private updateAllPage() {
private async updateAllPage() {
const elements = document.querySelectorAll(`[${this.attributeStateName}]`);
elements.forEach((el) => {
const sourcePath = this.app.workspace.getActiveFile()?.path ?? '';
for (const el of Array.from(elements)) {
const { source } = this.loadState(el);
if (!source) return;
this.renderElement(el, source);
});
await this.renderElement(el, source, undefined, sourcePath);
}
}
private parseSource(source: string) {
const lines = source.split(/\r?\n/);
const dateSource = (lines[0] || '').trim();
const extraText = lines.slice(1).join('\n').trim();
return { dateSource, extraText };
}
}

View file

@ -1,3 +1,21 @@
.event-highlight-container {
display: inline-flex;
flex-direction: column;
align-items: flex-start;
gap: 6px;
border: 1px solid transparent;
border-radius: 4px;
}
.event-highlight-text {
margin: 6px;
margin-bottom: 0;
color: var(--text-normal);
}
.event-highlight-badge {
padding: 2px 4px;
@ -12,21 +30,39 @@
cursor: default;
}
.event-highlight-badge.with-text {
width: 100%;
border-radius: 0 0 4px 4px;
}
.event-highlight-badge.after {
background-color: var(--background-secondary-alt);
color: var(--mono-rgb-255);
}
.event-highlight-container.after {
border-color: var(--background-secondary-alt);
}
.event-highlight-badge.before {
background-color: rgba(var(--color-green-rgb), 0.2);
color: var(--color-green);
}
.event-highlight-container.before {
border-color: rgba(var(--color-green-rgb), 0.2);
}
.event-highlight-badge.upcoming {
background-color: rgba(var(--color-yellow-rgb), 0.2);
color: var(--color-yellow);
}
.event-highlight-container.upcoming {
border-color: rgba(var(--color-yellow-rgb), 0.2);
}
.event-highlight-badge.actual {
background-color: rgba(var(--color-purple-rgb), 0.2);
color: var(--color-purple);
@ -34,6 +70,10 @@
font-weight: bold;
}
.event-highlight-container.actual {
border-color: rgba(var(--color-purple-rgb), 0.2);
}
.event-highlight-badge.error {
background-color: rgba(var(--color-red-rgb), 0.2);
color: var(--color-red);
@ -41,6 +81,10 @@
font-weight: bold;
}
.event-highlight-container.error {
border-color: rgba(var(--color-red-rgb), 0.2);
}
.event-highlight-badge .icon {
display: inline-flex;