feat: add side-by-side live preview to form builder

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Luca Oelfke 2026-02-13 15:47:49 +01:00
parent 8b9140ae6c
commit 33be56dcb1

View file

@ -1,5 +1,6 @@
import { App, Modal, Notice } from 'obsidian'; import { App, Modal, Notice } from 'obsidian';
import { FormDefinition, FormField, FieldType } from '../types'; import { FormDefinition, FormField, FieldType } from '../types';
import { renderField } from './field-renderers';
const FIELD_TYPES: FieldType[] = [ const FIELD_TYPES: FieldType[] = [
'text', 'text',
@ -90,10 +91,15 @@ export class FormBuilderModal extends Modal {
} }
}); });
// --- General settings --- // --- Two-column layout ---
contentEl.createEl('h2', { text: 'Form Settings' }); const layout = contentEl.createDiv({ cls: 'ff-builder-layout' });
const generalEl = contentEl.createDiv({ cls: 'ff-builder-general' }); // === LEFT: Editor ===
const editorEl = layout.createDiv({ cls: 'ff-builder-editor' });
editorEl.createEl('h2', { text: 'Form Settings' });
const generalEl = editorEl.createDiv({ cls: 'ff-builder-general' });
// Name // Name
this.addTextSetting(generalEl, 'Form Name', this.draft.name, (v) => { this.addTextSetting(generalEl, 'Form Name', this.draft.name, (v) => {
@ -109,7 +115,7 @@ export class FormBuilderModal extends Modal {
(v) => { (v) => {
this.pushSnapshot(); this.pushSnapshot();
this.draft.mode = v as 'create' | 'update'; this.draft.mode = v as 'create' | 'update';
this.render(); // Re-render to show mode-specific settings this.render();
}, },
); );
@ -151,14 +157,14 @@ export class FormBuilderModal extends Modal {
); );
} }
// --- Fields section --- // Fields section
contentEl.createEl('h3', { text: 'Fields' }); editorEl.createEl('h3', { text: 'Fields' });
const fieldsContainer = contentEl.createDiv({ cls: 'ff-builder-fields' }); const fieldsContainer = editorEl.createDiv({ cls: 'ff-builder-fields' });
this.renderFields(fieldsContainer); this.renderFields(fieldsContainer);
// Add field button // Add field button
const addBtn = contentEl.createEl('button', { const addBtn = editorEl.createEl('button', {
cls: 'ff-builder-add-btn', cls: 'ff-builder-add-btn',
text: '+ Add Field', text: '+ Add Field',
}); });
@ -174,7 +180,40 @@ export class FormBuilderModal extends Modal {
this.render(); this.render();
}); });
// --- Footer --- // === RIGHT: Preview ===
const previewEl = layout.createDiv({ cls: 'ff-builder-preview' });
previewEl.createEl('h2', { text: 'Preview' });
const previewContent = previewEl.createDiv({ cls: 'ff-builder-preview-content' });
if (this.draft.fields.length === 0) {
previewContent.createDiv({
cls: 'ff-builder-preview-empty',
text: 'Add fields to see a preview.',
});
} else {
// Form title
previewContent.createEl('h3', {
text: this.draft.name || 'Untitled Form',
cls: 'ff-form-title',
});
// Render each field
const previewFields = previewContent.createDiv({ cls: 'ff-fields' });
for (const field of this.draft.fields) {
renderField(this.app, previewFields, field, field.defaultValue);
}
// Disabled submit button
const previewFooter = previewContent.createDiv({ cls: 'ff-form-footer' });
const previewSubmit = previewFooter.createEl('button', {
text: this.draft.mode === 'create' ? 'Create Note' : 'Update Frontmatter',
cls: 'mod-cta ff-submit-btn',
});
previewSubmit.setAttribute('disabled', '');
}
// --- Footer (full width, below grid) ---
const footer = contentEl.createDiv({ cls: 'ff-builder-footer' }); const footer = contentEl.createDiv({ cls: 'ff-builder-footer' });
// Left side: undo/redo // Left side: undo/redo