feat: Enhance inline date calculation with improved Live Preview support, type normalization, and plugin cleanup.
This commit is contained in:
@@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
An Obsidian plugin that adds dynamic date calculations to your notes using `date-calc` fenced code blocks and inline code.
|
An Obsidian plugin that adds dynamic date calculations to your notes using `date-calc` fenced code blocks and inline code.
|
||||||
|
|
||||||
|
|
||||||
|
## Todo
|
||||||
|
- [x] Make inline work
|
||||||
|
- [ ] Add a non-verbose birthday type? Just show the age, with decimals, maybe? Like "3.7 years old"
|
||||||
|
- [ ]
|
||||||
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
### Fenced Code Blocks
|
### Fenced Code Blocks
|
||||||
|
|||||||
101
main.ts
101
main.ts
@@ -110,6 +110,11 @@ function processInlineDateCalc(raw: string, app: App, sourcePath: string): strin
|
|||||||
else if ((cfg as any).since) type = 'since';
|
else if ((cfg as any).since) type = 'since';
|
||||||
else if ((cfg as any).from && (cfg as any).to) type = 'diff';
|
else if ((cfg as any).from && (cfg as any).to) type = 'diff';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Normalize type aliases to match fenced code block processor
|
||||||
|
if (type === 'bday') type = 'birthday';
|
||||||
|
if (type === 'until') type = 'countdown';
|
||||||
|
if (type === 'difference') type = 'diff';
|
||||||
if (!type) return '';
|
if (!type) return '';
|
||||||
|
|
||||||
// Render result similarly to the block processor
|
// Render result similarly to the block processor
|
||||||
@@ -235,6 +240,7 @@ const dateCalcLivePreviewPlugin = (app: App) => ViewPlugin.fromClass(class {
|
|||||||
const text = view.state.doc.toString();
|
const text = view.state.doc.toString();
|
||||||
|
|
||||||
// Find inline code spans that start with date-calc:
|
// Find inline code spans that start with date-calc:
|
||||||
|
// This regex looks for inline code between backticks
|
||||||
const inlineCodeRegex = /`([^`]+)`/g;
|
const inlineCodeRegex = /`([^`]+)`/g;
|
||||||
let match;
|
let match;
|
||||||
|
|
||||||
@@ -258,6 +264,9 @@ const dateCalcLivePreviewPlugin = (app: App) => ViewPlugin.fromClass(class {
|
|||||||
side: 1
|
side: 1
|
||||||
});
|
});
|
||||||
builder.add(to, to, widget);
|
builder.add(to, to, widget);
|
||||||
|
|
||||||
|
// Add a debug log to verify when a widget is being created
|
||||||
|
console.log(`Live Preview widget created for: ${codeContent} with result: ${result}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -287,11 +296,25 @@ class DateCalcInlineRenderer extends MarkdownRenderChild {
|
|||||||
async render() {
|
async render() {
|
||||||
const result = processInlineDateCalc(this.raw, this.app, this.sourcePath);
|
const result = processInlineDateCalc(this.raw, this.app, this.sourcePath);
|
||||||
if (result) {
|
if (result) {
|
||||||
|
console.log(`Rendering inline date-calc: ${this.raw} -> ${result}`);
|
||||||
|
|
||||||
|
// In Live Preview, just replace the code element directly
|
||||||
const span = document.createElement('span');
|
const span = document.createElement('span');
|
||||||
span.classList.add('date-calc-inline');
|
span.classList.add('date-calc-inline');
|
||||||
span.setAttribute('contenteditable', 'false');
|
span.setAttribute('contenteditable', 'false');
|
||||||
span.textContent = result;
|
span.textContent = result;
|
||||||
this.target.replaceWith(span);
|
|
||||||
|
// Ensure we properly replace the target element
|
||||||
|
try {
|
||||||
|
this.target.parentNode?.replaceChild(span, this.target);
|
||||||
|
console.log('Successfully replaced code element with result');
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to replace code element:', e);
|
||||||
|
// Fallback: try the original method
|
||||||
|
this.target.replaceWith(span);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log(`No result for inline date-calc: ${this.raw}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -305,69 +328,44 @@ export default class MyPlugin extends Plugin {
|
|||||||
async onload() {
|
async onload() {
|
||||||
await this.loadSettings();
|
await this.loadSettings();
|
||||||
|
|
||||||
// This creates an icon in the left ribbon.
|
// Add a status bar item showing the plugin is enabled
|
||||||
const ribbonIconEl = this.addRibbonIcon('dice', 'Sample Plugin', (_evt: MouseEvent) => {
|
|
||||||
// Called when the user clicks the icon.
|
|
||||||
new Notice('This is a notice!');
|
|
||||||
});
|
|
||||||
// Perform additional things with the ribbon
|
|
||||||
ribbonIconEl.addClass('my-plugin-ribbon-class');
|
|
||||||
|
|
||||||
// This adds a status bar item to the bottom of the app. Does not work on mobile apps.
|
|
||||||
const statusBarItemEl = this.addStatusBarItem();
|
const statusBarItemEl = this.addStatusBarItem();
|
||||||
statusBarItemEl.setText('Status Bar Text');
|
statusBarItemEl.setText('Date Calculator Enabled');
|
||||||
|
|
||||||
// This adds a simple command that can be triggered anywhere
|
// Debugging command to test plugin functionality
|
||||||
this.addCommand({
|
this.addCommand({
|
||||||
id: 'open-sample-modal-simple',
|
id: 'date-calc-debug',
|
||||||
name: 'Open sample modal (simple)',
|
name: 'Debug Date Calculator',
|
||||||
callback: () => {
|
callback: () => {
|
||||||
new SampleModal(this.app).open();
|
new Notice('Date Calculator plugin is working! Check console for more details.');
|
||||||
|
console.log('Date Calculator plugin debug info:');
|
||||||
|
console.log('Plugin version: 1.0.0');
|
||||||
|
console.log('Plugin enabled: true');
|
||||||
|
console.log('Current file:', this.app.workspace.getActiveFile()?.path);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// This adds an editor command that can perform some operation on the current editor instance
|
|
||||||
this.addCommand({
|
|
||||||
id: 'sample-editor-command',
|
|
||||||
name: 'Sample editor command',
|
|
||||||
editorCallback: (editor: Editor, _view: MarkdownView) => {
|
|
||||||
console.log(editor.getSelection());
|
|
||||||
editor.replaceSelection('Sample Editor Command');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// This adds a complex command that can check whether the current state of the app allows execution of the command
|
|
||||||
this.addCommand({
|
|
||||||
id: 'open-sample-modal-complex',
|
|
||||||
name: 'Open sample modal (complex)',
|
|
||||||
checkCallback: (checking: boolean) => {
|
|
||||||
// Conditions to check
|
|
||||||
const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);
|
|
||||||
if (markdownView) {
|
|
||||||
// If checking is true, we're simply "checking" if the command can be run.
|
|
||||||
// If checking is false, then we want to actually perform the operation.
|
|
||||||
if (!checking) {
|
|
||||||
new SampleModal(this.app).open();
|
|
||||||
}
|
|
||||||
|
|
||||||
// This command will only show up in Command Palette when the check function returns true
|
// Command to refresh inline calculations (useful for troubleshooting)
|
||||||
return true;
|
this.addCommand({
|
||||||
}
|
id: 'refresh-date-calc-inline',
|
||||||
|
name: 'Refresh Date Calculations',
|
||||||
|
callback: () => {
|
||||||
|
// Force refresh by triggering layout
|
||||||
|
this.app.workspace.trigger('layout-change');
|
||||||
|
new Notice('Date calculations refreshed!');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// This adds a settings tab so the user can configure various aspects of the plugin
|
// This adds a settings tab so the user can configure various aspects of the plugin
|
||||||
this.addSettingTab(new SampleSettingTab(this.app, this));
|
this.addSettingTab(new SampleSettingTab(this.app, this));
|
||||||
|
|
||||||
// If the plugin hooks up any global DOM events (on parts of the app that doesn't belong to this plugin)
|
// CRITICAL: Register Live Preview extension FIRST and ensure it's properly loaded
|
||||||
// Using this function will automatically remove the event listener when this plugin is disabled.
|
console.log('Registering Live Preview editor extension for date-calc...');
|
||||||
this.registerDomEvent(document, 'click', (evt: MouseEvent) => {
|
|
||||||
console.log('click', evt);
|
|
||||||
});
|
|
||||||
|
|
||||||
// When registering intervals, this function will automatically clear the interval when the plugin is disabled.
|
|
||||||
this.registerInterval(window.setInterval(() => console.log('setInterval'), 5 * 60 * 1000));
|
|
||||||
|
|
||||||
// Register the Live Preview editor extension for inline date-calc processing
|
|
||||||
this.registerEditorExtension(dateCalcLivePreviewPlugin(this.app));
|
this.registerEditorExtension(dateCalcLivePreviewPlugin(this.app));
|
||||||
|
console.log('Date Calculator Live Preview extension registered successfully!');
|
||||||
|
|
||||||
|
// Add more comprehensive debugging
|
||||||
|
new Notice('Date Calculator loaded with Live Preview support!');
|
||||||
|
|
||||||
// Register the `date-calc` code block processor
|
// Register the `date-calc` code block processor
|
||||||
this.registerMarkdownCodeBlockProcessor('date-calc', (source, el, ctx) => {
|
this.registerMarkdownCodeBlockProcessor('date-calc', (source, el, ctx) => {
|
||||||
@@ -384,6 +382,7 @@ export default class MyPlugin extends Plugin {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case 'bday':
|
||||||
case 'birthday': {
|
case 'birthday': {
|
||||||
// Accept from config or frontmatter fallback
|
// Accept from config or frontmatter fallback
|
||||||
const fileCache = this.app.metadataCache.getCache(ctx.sourcePath);
|
const fileCache = this.app.metadataCache.getCache(ctx.sourcePath);
|
||||||
@@ -445,7 +444,7 @@ export default class MyPlugin extends Plugin {
|
|||||||
|
|
||||||
msg = `next one is in ${monthsUntil} months.`;
|
msg = `next one is in ${monthsUntil} months.`;
|
||||||
} else if (daysUntil === 0) {
|
} else if (daysUntil === 0) {
|
||||||
msg = `Today! Wish ${pronoun} Happy Birthday!`;
|
msg = `today! Wish ${pronoun} Happy Birthday!`;
|
||||||
} else if (daysUntil === 1) {
|
} else if (daysUntil === 1) {
|
||||||
msg = `that's tomorrow!`;
|
msg = `that's tomorrow!`;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
18
styles.css
18
styles.css
@@ -2,7 +2,7 @@
|
|||||||
Date Calc Plugin Styles
|
Date Calc Plugin Styles
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Inline date-calc styling for live preview - now styles actual span elements */
|
/* Inline date-calc styling for reading view and live preview */
|
||||||
.date-calc-inline {
|
.date-calc-inline {
|
||||||
background-color: var(--background-modifier-accent);
|
background-color: var(--background-modifier-accent);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
@@ -12,6 +12,22 @@ Date Calc Plugin Styles
|
|||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 0 2px;
|
margin: 0 2px;
|
||||||
|
font-family: var(--font-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Specific styles for CodeMirror Live Preview widgets */
|
||||||
|
.cm-line .date-calc-inline {
|
||||||
|
background-color: var(--background-modifier-accent);
|
||||||
|
color: var(--text-accent);
|
||||||
|
padding: 2px 6px;
|
||||||
|
margin-left: 4px;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 0.9em;
|
||||||
|
display: inline;
|
||||||
|
user-select: none;
|
||||||
|
cursor: default;
|
||||||
|
vertical-align: baseline;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Additional styling for fenced code blocks */
|
/* Additional styling for fenced code blocks */
|
||||||
|
|||||||
Reference in New Issue
Block a user