relative position the modal attempt 1

This commit is contained in:
kunalja 2025-06-07 15:17:12 -04:00
parent 83bce6b663
commit 19864160e9
3 changed files with 122 additions and 40 deletions

View file

@ -268,32 +268,38 @@ export default class VariantEditor extends Plugin {
this.app.workspace.updateOptions();
// Open the text input modal after highlighting with the original text
new TextInputModal(this.app, selectedWord, (variantText: string, activeIndex?: number, commitVariant?: boolean) => {
if (variantText && variantText.trim()) {
if (commitVariant) {
// If committing, just replace with the selected variant text directly
editor.replaceRange(variantText, from, to);
new Notice(`Committed variant: "${variantText}"`);
} else {
// Create the variant syntax: {{original | variant1 | variant2}}^n
const variants = variantText.split('|').map(v => v.trim()).filter(v => v);
// Ensure we have at least one variant (the original text)
if (variants.length > 0) {
// Use the provided activeIndex or default to 0
const activeIdx = typeof activeIndex === 'number' ? activeIndex : 0;
const variantSyntax = `{{${variants.join(' | ')}}}^${activeIdx}`;
new TextInputModal(
this.app,
selectedWord,
(variantText: string, activeIndex?: number, commitVariant?: boolean) => {
if (variantText && variantText.trim()) {
if (commitVariant) {
// If committing, just replace with the selected variant text directly
editor.replaceRange(variantText, from, to);
new Notice(`Committed variant: "${variantText}"`);
} else {
// Create the variant syntax: {{original | variant1 | variant2}}^n
const variants = variantText.split('|').map(v => v.trim()).filter(v => v);
// Replace the selected text with the variant syntax
editor.replaceRange(variantSyntax, from, to);
new Notice(`Created variant with ${variants.length} options (${variants[activeIdx]} active)`);
// Ensure we have at least one variant (the original text)
if (variants.length > 0) {
// Use the provided activeIndex or default to 0
const activeIdx = typeof activeIndex === 'number' ? activeIndex : 0;
const variantSyntax = `{{${variants.join(' | ')}}}^${activeIdx}`;
// Replace the selected text with the variant syntax
editor.replaceRange(variantSyntax, from, to);
new Notice(`Created variant with ${variants.length} options (${variants[activeIdx]} active)`);
}
}
// Clear highlighting after creating variant
this.clearHighlight();
}
// Clear highlighting after creating variant
this.clearHighlight();
}
}).open();
},
// Pass the cursor position to position the modal relative to the highlighted text
from
).open();
} catch (e) {
console.error('Error in highlightSelection:', e);

View file

@ -1,4 +1,4 @@
import { App, Modal, Setting, ButtonComponent } from 'obsidian';
import { App, Modal, Setting, ButtonComponent, EditorPosition } from 'obsidian';
/**
* Modal for text input that appears after highlighting
@ -10,17 +10,34 @@ export class TextInputModal extends Modal {
private onSubmit: (result: string, activeIndex?: number, commitVariant?: boolean) => void;
private originalText: string;
private variantContainer: HTMLElement;
private cursorPosition: EditorPosition | null;
constructor(app: App, originalText: string, onSubmit: (result: string, activeIndex?: number, commitVariant?: boolean) => void) {
constructor(
app: App,
originalText: string,
onSubmit: (result: string, activeIndex?: number, commitVariant?: boolean) => void,
cursorPosition: EditorPosition | null = null
) {
super(app);
this.originalText = originalText;
this.onSubmit = onSubmit;
// Initialize with the original text as the first variant
this.variants = [originalText];
this.cursorPosition = cursorPosition;
}
onOpen() {
const {contentEl} = this;
const {contentEl, modalEl} = this;
// Add a class for styling
modalEl.addClass('variant-editor-modal');
// Position the modal relative to the cursor if we have cursor position
if (this.cursorPosition) {
// We need to position the modal after it's rendered
setTimeout(() => {
this.positionModalRelativeToCursor(modalEl);
}, 0);
}
contentEl.createEl('h2', {text: 'Create Variants'});
@ -100,25 +117,73 @@ export class TextInputModal extends Modal {
.map((v, i) => ({ text: v.trim(), originalIndex: i }))
.filter(v => v.text.length > 0);
if (nonEmptyVariantsWithIndices.length > 0) {
// Find the new index of the active variant after filtering
let newActiveIndex = 0;
for (let i = 0; i < nonEmptyVariantsWithIndices.length; i++) {
if (nonEmptyVariantsWithIndices[i].originalIndex === this.activeVariantIndex) {
newActiveIndex = i;
break;
if (nonEmptyVariantsWithIndices.length >= 2) {
// Find the new index of the active variant after filtering
let newActiveIndex = 0;
for (let i = 0; i < nonEmptyVariantsWithIndices.length; i++) {
if (nonEmptyVariantsWithIndices[i].originalIndex === this.activeVariantIndex) {
newActiveIndex = i;
break;
}
}
// Join variants with pipe character for the expected format and pass the corrected active index
const nonEmptyVariants = nonEmptyVariantsWithIndices.map(v => v.text);
this.onSubmit(nonEmptyVariants.join('|'), newActiveIndex);
}
this.close();
// Join variants with pipe character for the expected format and pass the corrected active index
const nonEmptyVariants = nonEmptyVariantsWithIndices.map(v => v.text);
this.onSubmit(nonEmptyVariants.join('|'), newActiveIndex);
}
})
.buttonEl.addClass('variant-editor-button');
}
/**
* Positions the modal relative to the cursor position
*/
private positionModalRelativeToCursor(modalEl: HTMLElement) {
if (!this.cursorPosition) return;
// Get the active editor view
const activeLeaf = this.app.workspace.activeLeaf;
if (!activeLeaf || !activeLeaf.view) return;
// Get the editor element
const editorEl = activeLeaf.view.containerEl.querySelector('.cm-editor');
if (!editorEl) return;
// Find the line element for the cursor position
const lineElements = editorEl.querySelectorAll('.cm-line');
if (!lineElements || lineElements.length <= this.cursorPosition.line) return;
const lineEl = lineElements[this.cursorPosition.line];
if (!lineEl) return;
// Get the position of the line element
const lineRect = lineEl.getBoundingClientRect();
// Get the modal dimensions
const modalRect = modalEl.getBoundingClientRect();
// Position the modal below the line with some padding
const padding = 10;
let top = lineRect.bottom + padding;
// Make sure the modal doesn't go off the bottom of the screen
const viewportHeight = window.innerHeight;
if (top + modalRect.height > viewportHeight) {
// Position above the line instead
top = lineRect.top - modalRect.height - padding;
}
// Center horizontally relative to the line
const left = lineRect.left + (lineRect.width / 2) - (modalRect.width / 2);
// Apply the position
modalEl.style.position = 'fixed';
modalEl.style.top = `${Math.max(0, top)}px`;
modalEl.style.left = `${Math.max(0, left)}px`;
modalEl.style.transform = 'none';
}
private renderVariantInputs() {
// Clear existing inputs
this.variantContainer.empty();

View file

@ -163,11 +163,22 @@
}
.variant-editor-hint {
margin-bottom: 15px;
margin-top: 10px;
margin-bottom: 10px;
color: var(--text-muted);
font-size: 0.9em;
}
/* Style the variant editor modal */
.variant-editor-modal {
width: 400px !important;
max-width: 90vw !important;
max-height: 80vh !important;
overflow-y: auto !important;
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.15) !important;
border: 1px solid var(--background-modifier-border) !important;
}
.variant-editor-textarea:focus {
outline: none;
border-color: var(--interactive-accent);