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 <noreply@anthropic.com>
This commit is contained in:
svemagie
2026-03-04 21:35:13 +01:00
parent 4941b9184e
commit d11976e0ca
4 changed files with 57 additions and 16 deletions
+24 -6
View File
@@ -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) => {
+17 -3
View File
@@ -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 {
+12
View File
@@ -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" });
+4 -7
View File
@@ -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 {