Add Live Preview support and reorder counter elements
- Move buttons to right side of number (number, -, +, label) - Add CodeMirror ViewPlugin for Live Preview rendering - Counter now works in edit mode (Live Preview) - Create CounterWidget for editor decorations - Use Decoration.replace to render counters in editor 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
62
main.ts
62
main.ts
@@ -1,4 +1,42 @@
|
||||
import { Plugin, MarkdownPostProcessorContext, MarkdownView } from 'obsidian';
|
||||
import { Decoration, DecorationSet, EditorView, WidgetType, ViewPlugin, ViewUpdate } from '@codemirror/view';
|
||||
import { RangeSetBuilder } from '@codemirror/state';
|
||||
|
||||
class CounterWidget extends WidgetType {
|
||||
constructor(private value: number, private label: string, private plugin: CounterPlugin) {
|
||||
super();
|
||||
}
|
||||
|
||||
toDOM(view: EditorView): HTMLElement {
|
||||
return this.plugin.createCounterElement(this.value, this.label, {} as MarkdownPostProcessorContext);
|
||||
}
|
||||
}
|
||||
|
||||
function buildCounterDecorations(view: EditorView, plugin: CounterPlugin): DecorationSet {
|
||||
const builder = new RangeSetBuilder<Decoration>();
|
||||
const counterRegex = /~\s*\(\s*(\d*)\s*\)\s*(.+)/g;
|
||||
|
||||
for (let { from, to } of view.visibleRanges) {
|
||||
const text = view.state.doc.sliceString(from, to);
|
||||
let match;
|
||||
counterRegex.lastIndex = 0;
|
||||
|
||||
while ((match = counterRegex.exec(text)) !== null) {
|
||||
const startPos = from + match.index;
|
||||
const endPos = startPos + match[0].length;
|
||||
const value = match[1] === '' ? 0 : parseInt(match[1], 10);
|
||||
const label = match[2].trim();
|
||||
|
||||
const widget = Decoration.replace({
|
||||
widget: new CounterWidget(value, label, plugin),
|
||||
});
|
||||
|
||||
builder.add(startPos, endPos, widget);
|
||||
}
|
||||
}
|
||||
|
||||
return builder.finish();
|
||||
}
|
||||
|
||||
export default class CounterPlugin extends Plugin {
|
||||
async onload() {
|
||||
@@ -7,6 +45,28 @@ export default class CounterPlugin extends Plugin {
|
||||
this.registerMarkdownPostProcessor((element, context) => {
|
||||
this.processCounters(element, context);
|
||||
});
|
||||
|
||||
const plugin = this;
|
||||
this.registerEditorExtension(
|
||||
ViewPlugin.fromClass(
|
||||
class {
|
||||
decorations: DecorationSet;
|
||||
|
||||
constructor(view: EditorView) {
|
||||
this.decorations = buildCounterDecorations(view, plugin);
|
||||
}
|
||||
|
||||
update(update: ViewUpdate) {
|
||||
if (update.docChanged || update.viewportChanged) {
|
||||
this.decorations = buildCounterDecorations(update.view, plugin);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
decorations: (v) => v.decorations,
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
onunload() {
|
||||
@@ -147,8 +207,8 @@ export default class CounterPlugin extends Plugin {
|
||||
updateSource(currentValue);
|
||||
});
|
||||
|
||||
container.appendChild(minusButton);
|
||||
container.appendChild(counterDisplay);
|
||||
container.appendChild(minusButton);
|
||||
container.appendChild(plusButton);
|
||||
if (label) {
|
||||
container.appendChild(labelSpan);
|
||||
|
||||
Reference in New Issue
Block a user