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"; this.contextPreviewEl.style.display = "none";
const inputArea = chatArea.createDiv("vc-input-area"); const inputArea = chatArea.createDiv("vc-input-area");
const inputWrapper = inputArea.createDiv("vc-input-wrapper"); 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.mentionDropdownEl.style.display = "none";
this.inputEl = inputWrapper.createEl("textarea", { this.inputEl = inputWrapper.createEl("textarea", {
cls: "vc-input", cls: "vc-input",
@@ -133,7 +133,11 @@ var ChatView = class extends import_obsidian.ItemView {
return; 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(); e.preventDefault();
this.handleSend(); this.handleSend();
} }
@@ -466,7 +470,14 @@ ${content}`;
} }
this.mentionSelectedIdx = 0; this.mentionSelectedIdx = 0;
this.renderMentionDropdown(); 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() { renderMentionDropdown() {
this.mentionDropdownEl.empty(); this.mentionDropdownEl.empty();
@@ -723,8 +734,8 @@ var VaultSearch = class {
let bestPos = 0; let bestPos = 0;
let bestScore = 0; let bestScore = 0;
for (let i = 0; i < content.length - maxLen; i += 50) { for (let i = 0; i < content.length - maxLen; i += 50) {
const window = lower.slice(i, i + maxLen); const window2 = lower.slice(i, i + maxLen);
const score = queryWords.filter((w) => window.includes(w)).length; const score = queryWords.filter((w) => window2.includes(w)).length;
if (score > bestScore) { if (score > bestScore) {
bestScore = score; bestScore = score;
bestPos = i; bestPos = i;
@@ -819,7 +830,8 @@ Wenn du Fragen beantwortest:
autoRetrieveContext: true, autoRetrieveContext: true,
showContextPreview: true, showContextPreview: true,
saveThreadsToVault: true, saveThreadsToVault: true,
threadsFolder: "Calendar/Chat" threadsFolder: "Calendar/Chat",
sendOnEnter: false
}; };
var MODELS = [ var MODELS = [
{ id: "claude-opus-4-5-20251101", name: "Claude Opus 4.5 (St\xE4rkst)" }, { 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(); 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" }); 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( 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) => { (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 inputArea = chatArea.createDiv("vc-input-area");
const inputWrapper = inputArea.createDiv("vc-input-wrapper"); 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.mentionDropdownEl.style.display = "none";
this.inputEl = inputWrapper.createEl("textarea", { this.inputEl = inputWrapper.createEl("textarea", {
cls: "vc-input", cls: "vc-input",
@@ -170,7 +171,11 @@ export class ChatView extends ItemView {
return; 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(); e.preventDefault();
this.handleSend(); this.handleSend();
} }
@@ -570,7 +575,16 @@ export class ChatView extends ItemView {
this.mentionSelectedIdx = 0; this.mentionSelectedIdx = 0;
this.renderMentionDropdown(); 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 { private renderMentionDropdown(): void {
+12
View File
@@ -11,6 +11,7 @@ export interface MemexChatSettings {
showContextPreview: boolean; showContextPreview: boolean;
saveThreadsToVault: boolean; saveThreadsToVault: boolean;
threadsFolder: string; threadsFolder: string;
sendOnEnter: boolean;
} }
export const DEFAULT_SETTINGS: MemexChatSettings = { export const DEFAULT_SETTINGS: MemexChatSettings = {
@@ -30,6 +31,7 @@ Wenn du Fragen beantwortest:
showContextPreview: true, showContextPreview: true,
saveThreadsToVault: true, saveThreadsToVault: true,
threadsFolder: "Calendar/Chat", threadsFolder: "Calendar/Chat",
sendOnEnter: false,
}; };
export const MODELS = [ 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 --- // --- Context ---
containerEl.createEl("h3", { text: "Kontext-Einstellungen" }); containerEl.createEl("h3", { text: "Kontext-Einstellungen" });
+4 -7
View File
@@ -405,16 +405,13 @@
} }
.vc-mention-dropdown { .vc-mention-dropdown {
position: absolute;
bottom: calc(100% + 4px);
left: 0;
right: 0;
background: var(--background-primary); background: var(--background-primary);
border: 1px solid var(--background-modifier-border); border: 1px solid var(--background-modifier-border);
border-radius: 8px; border-radius: 8px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15); box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
overflow: hidden; max-height: 220px;
z-index: 100; overflow-y: auto;
z-index: 9999;
} }
.vc-mention-item { .vc-mention-item {