From d11976e0ca33f243f081f3b4e7985ad222a21bae Mon Sep 17 00:00:00 2001 From: svemagie <869694+svemagie@users.noreply.github.com> Date: Wed, 4 Mar 2026 21:35:13 +0100 Subject: [PATCH] Fix @ autocomplete visibility + configurable Enter key @ autocomplete: dropdown was clipped by overflow:hidden ancestors. Fix by appending it to the root element and using position:fixed with getBoundingClientRect() for viewport-relative placement. Enter key: add sendOnEnter setting (default: off = Cmd+Enter sends). When on, plain Enter sends and Shift+Enter inserts a newline. Co-Authored-By: Claude Sonnet 4.6 --- main.js | 30 ++++++++++++++++++++++++------ src/ChatView.ts | 20 +++++++++++++++++--- src/SettingsTab.ts | 12 ++++++++++++ styles.css | 11 ++++------- 4 files changed, 57 insertions(+), 16 deletions(-) diff --git a/main.js b/main.js index 1c3f4b5..2390e07 100644 --- a/main.js +++ b/main.js @@ -96,7 +96,7 @@ var ChatView = class extends import_obsidian.ItemView { this.contextPreviewEl.style.display = "none"; const inputArea = chatArea.createDiv("vc-input-area"); const inputWrapper = inputArea.createDiv("vc-input-wrapper"); - this.mentionDropdownEl = inputWrapper.createDiv("vc-mention-dropdown"); + this.mentionDropdownEl = root.createDiv("vc-mention-dropdown"); this.mentionDropdownEl.style.display = "none"; this.inputEl = inputWrapper.createEl("textarea", { cls: "vc-input", @@ -133,7 +133,11 @@ var ChatView = class extends import_obsidian.ItemView { return; } } - if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) { + const sendOnEnter = this.plugin.settings.sendOnEnter; + if (sendOnEnter && e.key === "Enter" && !e.shiftKey && !e.metaKey && !e.ctrlKey) { + e.preventDefault(); + this.handleSend(); + } else if (!sendOnEnter && e.key === "Enter" && (e.metaKey || e.ctrlKey)) { e.preventDefault(); this.handleSend(); } @@ -466,7 +470,14 @@ ${content}`; } this.mentionSelectedIdx = 0; this.renderMentionDropdown(); - this.mentionDropdownEl.style.display = "block"; + const rect = this.inputEl.getBoundingClientRect(); + const el = this.mentionDropdownEl; + el.style.position = "fixed"; + el.style.left = rect.left + "px"; + el.style.width = rect.width + "px"; + el.style.top = "auto"; + el.style.bottom = window.innerHeight - rect.top + 4 + "px"; + el.style.display = "block"; } renderMentionDropdown() { this.mentionDropdownEl.empty(); @@ -723,8 +734,8 @@ var VaultSearch = class { let bestPos = 0; let bestScore = 0; for (let i = 0; i < content.length - maxLen; i += 50) { - const window = lower.slice(i, i + maxLen); - const score = queryWords.filter((w) => window.includes(w)).length; + const window2 = lower.slice(i, i + maxLen); + const score = queryWords.filter((w) => window2.includes(w)).length; if (score > bestScore) { bestScore = score; bestPos = i; @@ -819,7 +830,8 @@ Wenn du Fragen beantwortest: autoRetrieveContext: true, showContextPreview: true, saveThreadsToVault: true, - threadsFolder: "Calendar/Chat" + threadsFolder: "Calendar/Chat", + sendOnEnter: false }; var MODELS = [ { id: "claude-opus-4-5-20251101", name: "Claude Opus 4.5 (St\xE4rkst)" }, @@ -851,6 +863,12 @@ var MemexChatSettingsTab = class extends import_obsidian3.PluginSettingTab { await this.plugin.saveSettings(); }); }); + new import_obsidian3.Setting(containerEl).setName("Senden mit Enter").setDesc("Ein: Enter sendet. Aus: Cmd+Enter sendet (Enter = neue Zeile)").addToggle( + (toggle) => toggle.setValue(this.plugin.settings.sendOnEnter).onChange(async (value) => { + this.plugin.settings.sendOnEnter = value; + await this.plugin.saveSettings(); + }) + ); containerEl.createEl("h3", { text: "Kontext-Einstellungen" }); new import_obsidian3.Setting(containerEl).setName("Max. Kontext-Notizen").setDesc("Wie viele Notizen werden automatisch als Kontext hinzugef\xFCgt? (1\u201315)").addSlider( (slider) => slider.setLimits(1, 15, 1).setValue(this.plugin.settings.maxContextNotes).setDynamicTooltip().onChange(async (value) => { diff --git a/src/ChatView.ts b/src/ChatView.ts index 628b604..bf1b94b 100644 --- a/src/ChatView.ts +++ b/src/ChatView.ts @@ -128,7 +128,8 @@ export class ChatView extends ItemView { const inputArea = chatArea.createDiv("vc-input-area"); const inputWrapper = inputArea.createDiv("vc-input-wrapper"); - this.mentionDropdownEl = inputWrapper.createDiv("vc-mention-dropdown"); + // Dropdown appended to root to escape overflow:hidden ancestors + this.mentionDropdownEl = root.createDiv("vc-mention-dropdown"); this.mentionDropdownEl.style.display = "none"; this.inputEl = inputWrapper.createEl("textarea", { cls: "vc-input", @@ -170,7 +171,11 @@ export class ChatView extends ItemView { return; } } - if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) { + const sendOnEnter = this.plugin.settings.sendOnEnter; + if (sendOnEnter && e.key === "Enter" && !e.shiftKey && !e.metaKey && !e.ctrlKey) { + e.preventDefault(); + this.handleSend(); + } else if (!sendOnEnter && e.key === "Enter" && (e.metaKey || e.ctrlKey)) { e.preventDefault(); this.handleSend(); } @@ -570,7 +575,16 @@ export class ChatView extends ItemView { this.mentionSelectedIdx = 0; this.renderMentionDropdown(); - this.mentionDropdownEl.style.display = "block"; + + // Position using fixed coords to escape overflow:hidden ancestors + const rect = this.inputEl.getBoundingClientRect(); + const el = this.mentionDropdownEl; + el.style.position = "fixed"; + el.style.left = rect.left + "px"; + el.style.width = rect.width + "px"; + el.style.top = "auto"; + el.style.bottom = (window.innerHeight - rect.top + 4) + "px"; + el.style.display = "block"; } private renderMentionDropdown(): void { diff --git a/src/SettingsTab.ts b/src/SettingsTab.ts index 2da5e60..90e0c09 100644 --- a/src/SettingsTab.ts +++ b/src/SettingsTab.ts @@ -11,6 +11,7 @@ export interface MemexChatSettings { showContextPreview: boolean; saveThreadsToVault: boolean; threadsFolder: string; + sendOnEnter: boolean; } export const DEFAULT_SETTINGS: MemexChatSettings = { @@ -30,6 +31,7 @@ Wenn du Fragen beantwortest: showContextPreview: true, saveThreadsToVault: true, threadsFolder: "Calendar/Chat", + sendOnEnter: false, }; export const MODELS = [ @@ -80,6 +82,16 @@ export class MemexChatSettingsTab extends PluginSettingTab { }); }); + new Setting(containerEl) + .setName("Senden mit Enter") + .setDesc("Ein: Enter sendet. Aus: Cmd+Enter sendet (Enter = neue Zeile)") + .addToggle((toggle) => + toggle.setValue(this.plugin.settings.sendOnEnter).onChange(async (value) => { + this.plugin.settings.sendOnEnter = value; + await this.plugin.saveSettings(); + }) + ); + // --- Context --- containerEl.createEl("h3", { text: "Kontext-Einstellungen" }); diff --git a/styles.css b/styles.css index 886cefd..e7874f4 100644 --- a/styles.css +++ b/styles.css @@ -405,16 +405,13 @@ } .vc-mention-dropdown { - position: absolute; - bottom: calc(100% + 4px); - left: 0; - right: 0; background: var(--background-primary); border: 1px solid var(--background-modifier-border); border-radius: 8px; - box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15); - overflow: hidden; - z-index: 100; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2); + max-height: 220px; + overflow-y: auto; + z-index: 9999; } .vc-mention-item {