feat: remove uneeded changes, add delay for loading

This commit is contained in:
luwai 2026-03-25 22:08:01 -04:00
parent d590ccd9d2
commit 8013a63e90
4 changed files with 40 additions and 126 deletions

View file

@ -149,10 +149,8 @@ class EmbedManager {
// Check if we should load all embeds on page load
if (this.plugin.settings.loadAllOnPageLoad) {
// Load immediately without intersection observer
requestAnimationFrame(() => {
this.loadEmbed(embedContainer, file, section, displayAlias, ctx, placeholder, options);
});
await this.loadEmbed(embedContainer, file, section, displayAlias, ctx, placeholder, options);
await new Promise(r => setTimeout(r, 50));
} else {
// Aggressive lazy loading to prevent scrollbar jumps
const observer = new IntersectionObserver((entries) => {

View file

@ -16,8 +16,6 @@ const DEFAULT_SETTINGS = {
loadAllOnPageLoad: false,
showFocusHighlight: true,
showHeaderHints: true, // NEW: Header hints (enforcement is always on)
hideSectionHeaders: false, // NEW: Hide headers in section embeds
showPropertiesToggle: true, // NEW: Show properties collapse toggle button
debugMode: false
};
@ -34,11 +32,11 @@ module.exports = class SyncEmbedPlugin extends Plugin {
async onload() {
await this.loadSettings();
// Initialize managers
this.embedManager = new EmbedManager(this);
this.commandInterceptor = new CommandInterceptor(this);
// Setup command interception with monkey-around
if (this.settings.enableCommandInterception) {
this.setupCommandInterception();
@ -90,26 +88,26 @@ module.exports = class SyncEmbedPlugin extends Plugin {
// Add settings tab
this.addSettingTab(new SyncEmbedsSettingTab(this.app, this));
// Apply focus highlight setting
this.updateFocusHighlight();
// Log successful load
this.log('Sync Embeds plugin loaded successfully');
}
onunload() {
this.log('Unloading Sync Embeds plugin');
// Clean up command interception
this.uninstallers.forEach(uninstall => uninstall());
this.uninstallers = [];
// Clean up managers
if (this.embedManager) {
this.embedManager.cleanup();
}
this.currentFocusedEmbed = null;
}
@ -121,7 +119,7 @@ module.exports = class SyncEmbedPlugin extends Plugin {
{ level: 5, name: 'Heading 5', key: '5' },
{ level: 6, name: 'Heading 6', key: '6' },
];
headerLevels.forEach(({ level, name, key }) => {
this.addCommand({
id: `insert-header-${level}`,
@ -129,13 +127,13 @@ module.exports = class SyncEmbedPlugin extends Plugin {
editorCallback: (editor, view) => {
// Check if we're in a sync embed
const focusedEmbed = this.getFocusedEmbed();
if (focusedEmbed) {
// Use our custom handler
const handler = this.commandInterceptor.insertHeaderCommand(level);
return handler(focusedEmbed);
}
// Fall back to normal behavior for non-embed editing
this.commandInterceptor.insertHeader({ editor }, level);
},
@ -147,7 +145,7 @@ module.exports = class SyncEmbedPlugin extends Plugin {
]
});
});
this.log('Registered header commands with default hotkeys (Alt+2-6)');
}
@ -159,7 +157,7 @@ module.exports = class SyncEmbedPlugin extends Plugin {
const plugin = this;
return function(command, ...args) {
const focusedEmbed = plugin.getFocusedEmbed();
// If embed is focused, check if we should intercept
if (focusedEmbed) {
// Check for our header commands first
@ -170,17 +168,17 @@ module.exports = class SyncEmbedPlugin extends Plugin {
const handler = plugin.commandInterceptor.insertHeaderCommand(level);
return handler(focusedEmbed);
}
// Check if we have a custom handler
if (plugin.commandInterceptor.hasHandler(command.id)) {
plugin.log(`Intercepting command: ${command.id}`);
return plugin.commandInterceptor.handle(command.id, focusedEmbed, ...args);
}
// For commands we don't handle, let them execute on the embed's editor
// This ensures ALL hotkeys work, including custom user-defined ones
plugin.log(`Passing through command to embed: ${command.id}`);
// Check if command has a callback that expects an editor
if (command.editorCallback && focusedEmbed.editor) {
try {
@ -191,7 +189,7 @@ module.exports = class SyncEmbedPlugin extends Plugin {
}
}
}
return old.call(this, command, ...args);
};
}
@ -213,7 +211,7 @@ module.exports = class SyncEmbedPlugin extends Plugin {
}
});
this.uninstallers.push(getActiveViewUninstall);
// Patch getActiveViewOfType on workspace.activeLeaf as well
const getActiveLeafUninstall = around(this.app.workspace, {
activeLeaf: {
@ -231,7 +229,7 @@ module.exports = class SyncEmbedPlugin extends Plugin {
}
});
this.uninstallers.push(getActiveLeafUninstall);
this.log('Command interception setup complete');
} catch (error) {
console.error('Sync Embeds: Failed to setup command interception:', error);
@ -285,12 +283,7 @@ module.exports = class SyncEmbedPlugin extends Plugin {
container.style.setProperty('--sync-max-height', this.settings.maxEmbedHeight);
container.style.setProperty('--sync-gap', this.settings.gapBetweenEmbeds);
});
// Update viewport CSS for section embeds (header visibility)
if (this.embedManager) {
this.embedManager.refreshViewportCSS();
}
this.log('Refreshed all embeds with new settings');
}

View file

@ -14,7 +14,7 @@ class SyncEmbedsSettingTab extends PluginSettingTab {
// === APPEARANCE SECTION ===
containerEl.createEl('h3', { text: 'Appearance' });
new Setting(containerEl)
.setName('Render as callout')
.setDesc('Render embeds as callouts with sticky headers and collapse functionality')
@ -148,16 +148,6 @@ class SyncEmbedsSettingTab extends PluginSettingTab {
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName('Show properties toggle button')
.setDesc('Display a toggle button to collapse/expand properties in embeds')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.showPropertiesToggle)
.onChange(async (value) => {
this.plugin.settings.showPropertiesToggle = value;
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName('Show inline title')
.setDesc('Display note title at the top of whole-note embeds (not applicable to section embeds or embeds with aliases)')
@ -179,17 +169,7 @@ class SyncEmbedsSettingTab extends PluginSettingTab {
}));
// === HEADER MANAGEMENT SECTION ===
containerEl.createEl('h3', { text: 'Header Management' });
new Setting(containerEl)
.setName('Hide section headers')
.setDesc('Hide the header when embedding a section under a header')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.hideSectionHeaders)
.onChange(async (value) => {
this.plugin.settings.hideSectionHeaders = value;
await this.plugin.saveSettings();
}));
containerEl.createEl('h3', { text: 'Header Management' });
new Setting(containerEl)
.setName('Show header hints')
@ -265,7 +245,7 @@ class SyncEmbedsSettingTab extends PluginSettingTab {
<li><code>![[Note Name|Custom Title]]</code> - Display with custom title</li>
<li><code>![[Note Name#Section|Custom Title]]</code> - Section with custom title</li>
</ul>
<p><strong>Per-Embed Custom Options:</strong></p>
<ul>
<li><code>![[Note|Alias{height:500px}]]</code> - Custom height for this embed</li>
@ -276,7 +256,7 @@ class SyncEmbedsSettingTab extends PluginSettingTab {
<li><code>![[Note|Alias{height:400px,title:false}]]</code> - Multiple options</li>
</ul>
<p><em>Note: Options go inside curly braces before the closing ]]</em></p>
<p><strong>Dynamic Patterns:</strong></p>
<ul>
<li><code>![[Daily/{{date:YYYY-MM-DD}}|Today]]</code> - Current date with display name</li>
@ -287,7 +267,7 @@ class SyncEmbedsSettingTab extends PluginSettingTab {
<li><code>{{time:HH:mm}}</code> - Current time</li>
<li><code>{{title}}</code> - Current note's title</li>
</ul>
<p><strong>Header Management:</strong></p>
<ul>
<li>Use <code>Alt+2</code> through <code>Alt+6</code> to insert headers (H2-H6)</li>
@ -298,7 +278,7 @@ class SyncEmbedsSettingTab extends PluginSettingTab {
<li>Whole-note embeds allow H1-H6 freely</li>
<li>These hotkeys can be customized in Obsidian's Hotkeys settings</li>
</ul>
<p><strong>Date Format Examples:</strong></p>
<ul>
<li><code>YYYY-MM-DD</code> - 2024-03-15</li>
@ -306,7 +286,7 @@ class SyncEmbedsSettingTab extends PluginSettingTab {
<li><code>DD MMM YYYY</code> - 15 Mar 2024</li>
<li><code>dddd, MMMM Do YYYY</code> - Friday, March 15th 2024</li>
</ul>
<p><strong>Complete Example:</strong></p>
<pre><code>\`\`\`sync
![[Daily Notes/{{date:YYYY-MM-DD}}|Today's Note]]
@ -314,7 +294,7 @@ class SyncEmbedsSettingTab extends PluginSettingTab {
![[Tasks#Inbox|My Tasks{height:300px}]]
![[Projects/{{title}}#Notes|Project Notes{title:false}]]
\`\`\`</code></pre>
<p><strong>Tips:</strong></p>
<ul>
<li>Use aliases (text after <code>|</code>) with dynamic patterns for better display</li>
@ -327,7 +307,7 @@ class SyncEmbedsSettingTab extends PluginSettingTab {
<li>Multiple embeds of the same note/section are allowed</li>
<li>Header hierarchy enforcement maintains document structure in section embeds</li>
</ul>
<p><em>Note: Dynamic patterns are cached for 1 second to improve performance.</em></p>
`;
@ -377,15 +357,15 @@ class SyncEmbedsSettingTab extends PluginSettingTab {
validateCSSValue(value) {
// Basic validation for CSS length values
if (!value || value.trim() === '') return false;
// Allow common CSS units
const validPattern = /^(auto|none|\d+(\.\d+)?(px|em|rem|vh|vw|%))$/;
const isValid = validPattern.test(value.trim());
if (!isValid) {
new Notice('Invalid CSS value. Use units like: px, em, rem, vh, vw, %, or "auto"/"none"');
}
return isValid;
}
}

View file

@ -33,7 +33,7 @@ class ViewportController {
applyViewportRestriction(embedData) {
const { view } = embedData;
const style = document.createElement('style');
style.className = 'sync-viewport-style';
@ -47,7 +47,7 @@ class ViewportController {
}
updateViewportCSS(embedData, style) {
const { sectionInfo, embedId, propertiesLineCount = 0, file } = embedData;
const { sectionInfo, embedId, file } = embedData;
const { startLine, endLine } = sectionInfo;
// Frontmatter DOM Offset compensation
@ -62,22 +62,14 @@ class ViewportController {
const domStartLine = Math.max(0, startLine - domOffset);
const domEndLine = Math.max(0, endLine - domOffset);
let adjustedStartLine = domStartLine - propertiesLineCount;
let adjustedEndLine = domEndLine - propertiesLineCount;
if (hideHeader) {
adjustedStartLine += 1;
}
const css = `
/* Hide all lines BEFORE and INCLUDING the section header */
[data-embed-id="${embedId}"] .cm-line:nth-child(-n+${adjustedStartLine + 1}) {
[data-embed-id="${embedId}"] .cm-line:nth-child(-n+${domStartLine + 1}) {
display: none !important;
}
/* Hide all lines AFTER the section */
[data-embed-id="${embedId}"] .cm-line:nth-child(n+${adjustedEndLine + 1}) {
[data-embed-id="${embedId}"] .cm-line:nth-child(n+${domEndLine + 1}) {
display: none !important;
}
@ -247,27 +239,7 @@ class ViewportController {
setupContentConstraints(embedData) {
const { view, editor, component } = embedData;
let isProgrammaticUpdate = false;
// CRITICAL FIX: Update viewport IMMEDIATELY before visible changes
const updateViewportImmediately = () => {
if (!embedData.viewportActive) return;
const currentContent = editor.getValue();
const newSectionInfo = this.findSectionBounds(currentContent, embedData.section);
if (newSectionInfo.startLine !== -1) {
embedData.sectionInfo = newSectionInfo;
// recalculate properties line count on content change
embedData.propertiesLineCount = this.countPropertiesLines(currentContent);
// Update CSS synchronously to prevent flashing
if (embedData.viewportStyle) {
this.updateViewportCSS(embedData, embedData.viewportStyle);
}
}
};
// Force cursor strictly inside bounds (preventing up/down arrow drifting)
const enforceCursorBounds = () => {
if (isProgrammaticUpdate || !embedData.viewportActive || !embedData.sectionInfo) return;
@ -330,14 +302,14 @@ class ViewportController {
const scrollTop = cmScroller.scrollTop;
const lineHeight = editor.defaultTextHeight || 20;
const firstVisibleLine = Math.floor(scrollTop / lineHeight);
// Frontmatter DOM Offset compensation for scrolling bounds
let domOffset = 0;
const fileCache = this.plugin.app.metadataCache.getFileCache(embedData.file);
if (fileCache && fileCache.frontmatterPosition) {
domOffset = fileCache.frontmatterPosition.end.line;
}
const domStartLine = Math.max(0, embedData.sectionInfo.startLine - domOffset);
const domEndLine = Math.max(0, embedData.sectionInfo.endLine - domOffset);
@ -416,35 +388,6 @@ class ViewportController {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
countPropertiesLines(content) {
// Count the number of lines used by frontmatter/properties
// Properties are wrapped in --- markers at the start of the file
const lines = content.split('\n');
// Check if file starts with properties
if (lines.length === 0 || lines[0] !== '---') {
return 0;
}
// Find the closing --- marker
let propertiesEndLine = -1;
for (let i = 1; i < lines.length; i++) {
if (lines[i] === '---') {
propertiesEndLine = i;
break;
}
}
if (propertiesEndLine === -1) {
// Invalid frontmatter, no closing marker
return 0;
}
// Return the number of lines including both --- markers
// These lines are NOT rendered as .cm-line elements
return propertiesEndLine + 1;
}
cleanupViewport(embedData) {
if (embedData.viewportStyle) {
embedData.viewportStyle.remove();