mirror of
https://github.com/uthvah/sync-embeds.git
synced 2026-07-22 06:43:40 +00:00
v1
This commit is contained in:
parent
b00f0fdc02
commit
51ec340a75
3 changed files with 195 additions and 0 deletions
101
main.js
Normal file
101
main.js
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
const { Plugin, MarkdownView, WorkspaceLeaf, Component } = require('obsidian');
|
||||
|
||||
module.exports = class SyncEmbedPlugin extends Plugin {
|
||||
async onload() {
|
||||
console.log('Loading Sync Embeds Plugin');
|
||||
|
||||
// Add the command to insert a sync block.
|
||||
this.addCommand({
|
||||
id: 'insert-synced-embed',
|
||||
name: 'Insert synced embed',
|
||||
editorCallback: (editor, view) => {
|
||||
const selection = editor.getSelection();
|
||||
// If the user has selected text, use it as the note name.
|
||||
const noteName = selection || ' ';
|
||||
const textToInsert = `\`\`\`sync\n![[${noteName}]]\n\`\`\``;
|
||||
editor.replaceSelection(textToInsert);
|
||||
}
|
||||
});
|
||||
|
||||
// Register the main code block processor.
|
||||
this.registerMarkdownCodeBlockProcessor('sync', (source, el, ctx) => {
|
||||
this.processSyncBlock(source, el, ctx);
|
||||
});
|
||||
}
|
||||
|
||||
onunload() {
|
||||
console.log('Unloading Sync Embeds Plugin');
|
||||
}
|
||||
|
||||
async processSyncBlock(source, el, ctx) {
|
||||
el.empty();
|
||||
const syncContainer = el.createDiv('sync-container');
|
||||
|
||||
const embedLines = source.split('\n')
|
||||
.map(line => line.trim())
|
||||
.filter(line => line.startsWith('![[') && line.endsWith(']]'));
|
||||
|
||||
if (embedLines.length === 0) {
|
||||
syncContainer.createDiv('sync-empty').setText('No embeds found in sync block');
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < embedLines.length; i++) {
|
||||
const embedLine = embedLines[i];
|
||||
await this.processEmbed(embedLine, syncContainer, ctx, i > 0);
|
||||
}
|
||||
}
|
||||
|
||||
async processEmbed(embedLine, container, ctx, addGap = false) {
|
||||
try {
|
||||
const match = embedLine.match(/!\[\[([^\]]+)\]\]/);
|
||||
if (!match) return;
|
||||
|
||||
const linkText = match[1];
|
||||
const notePath = linkText.split('#')[0];
|
||||
|
||||
const file = this.app.metadataCache.getFirstLinkpathDest(notePath, ctx.sourcePath);
|
||||
if (!file) {
|
||||
this.renderError(container, `Note not found: ${notePath}`, addGap);
|
||||
return;
|
||||
}
|
||||
|
||||
const embedContainer = container.createDiv('sync-embed');
|
||||
if (addGap) embedContainer.addClass('sync-embed-gap');
|
||||
|
||||
const component = new Component();
|
||||
const leaf = new WorkspaceLeaf(this.app);
|
||||
|
||||
component.load();
|
||||
component.addChild(new (class extends Component {
|
||||
async onunload() {
|
||||
leaf.detach();
|
||||
}
|
||||
})());
|
||||
|
||||
await leaf.openFile(file, { state: { mode: "source" } });
|
||||
|
||||
const view = leaf.view;
|
||||
if (!(view instanceof MarkdownView)) {
|
||||
this.renderError(embedContainer, 'Failed to load a markdown view.', addGap);
|
||||
leaf.detach();
|
||||
return;
|
||||
}
|
||||
|
||||
embedContainer.appendChild(view.containerEl);
|
||||
embedContainer.style.height = 'auto';
|
||||
|
||||
ctx.addChild(component);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Sync Embeds: Error processing embed:', error);
|
||||
this.renderError(container, `Error loading: ${error.message}`, addGap);
|
||||
}
|
||||
}
|
||||
|
||||
renderError(container, message, addGap) {
|
||||
const errorDiv = container.createDiv('sync-embed-error');
|
||||
if (addGap) errorDiv.addClass('sync-embed-gap');
|
||||
errorDiv.setText(message);
|
||||
}
|
||||
};
|
||||
10
manifest.json
Normal file
10
manifest.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"id": "sync-embeds",
|
||||
"name": "Sync Embeds",
|
||||
"version": "1.0.0",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "Create fully editable, live-synced note embeds.",
|
||||
"author": "uthvah",
|
||||
"authorUrl": "https://github.com/uthvah",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
84
styles.css
Normal file
84
styles.css
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/* Main container for the sync block */
|
||||
.sync-container {
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
background: var(--background-primary);
|
||||
margin: 12px 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
/* Individual embed container */
|
||||
.sync-embed {
|
||||
border: none !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
background: transparent !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
/* --- SEAMLESS STYLING FOR EMBEDDED EDITOR --- */
|
||||
|
||||
/* Hide the view's header (title bar, icons) completely */
|
||||
.sync-embed .view-header {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Make the main content area and editor background transparent */
|
||||
.sync-embed .view-content,
|
||||
.sync-embed .markdown-source-view,
|
||||
.sync-embed .cm-editor,
|
||||
.sync-embed .cm-scroller {
|
||||
background-color: transparent !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
/* Ensure the editor itself takes up the full width */
|
||||
.sync-embed .markdown-source-view.mod-cm6 .cm-editor {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Remove padding from the view content area */
|
||||
.sync-embed .view-content {
|
||||
padding: 0 var(--file-margins) !important;
|
||||
}
|
||||
|
||||
/* Remove extra vertical padding from CodeMirror */
|
||||
.sync-embed .cm-s-obsidian .cm-gutters,
|
||||
.sync-embed .cm-s-obsidian .cm-content {
|
||||
padding-top: 0 !important;
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
/* Optional: remove line numbers */
|
||||
.sync-embed .cm-gutters {
|
||||
display: none;
|
||||
}
|
||||
.sync-embed .cm-content {
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
|
||||
/* --- UTILITY & ERROR STYLING --- */
|
||||
|
||||
.sync-embed-gap {
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid var(--background-modifier-border-hover);
|
||||
}
|
||||
|
||||
.sync-empty {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
color: var(--text-muted);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.sync-embed-error {
|
||||
padding: 8px 12px;
|
||||
background: var(--background-modifier-error);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 4px;
|
||||
color: var(--text-error);
|
||||
}
|
||||
Loading…
Reference in a new issue