168 lines
5.6 KiB
TypeScript
168 lines
5.6 KiB
TypeScript
import { App, Plugin, PluginSettingTab, Setting, Notice } from 'obsidian';
|
|
import { FormStore } from '../core/form-store';
|
|
import { FormBuilderModal } from './form-builder';
|
|
import { exportForms, importForms } from '../utils/form-io';
|
|
|
|
/**
|
|
* Interface for the subset of FormfirePlugin that the settings tab needs.
|
|
* Avoids circular dependency with main.ts.
|
|
*/
|
|
export interface SettingsPluginRef extends Plugin {
|
|
store: FormStore;
|
|
saveSettings: () => Promise<void>;
|
|
refreshSidebar: () => void;
|
|
}
|
|
|
|
/**
|
|
* Formfire settings tab — lists all forms with Edit / Duplicate / Delete,
|
|
* plus a button to create new forms.
|
|
*/
|
|
export class FormfireSettingTab extends PluginSettingTab {
|
|
private pluginRef: SettingsPluginRef;
|
|
|
|
constructor(app: App, plugin: SettingsPluginRef) {
|
|
super(app, plugin);
|
|
this.pluginRef = plugin;
|
|
}
|
|
|
|
display(): void {
|
|
const { containerEl } = this;
|
|
containerEl.empty();
|
|
|
|
containerEl.createEl('h2', { text: 'Formfire' });
|
|
|
|
// New form button
|
|
new Setting(containerEl)
|
|
.setName('Create a new form')
|
|
.setDesc('Add a new form definition to your collection.')
|
|
.addButton((btn) => {
|
|
btn.setButtonText('+ New Form').setCta().onClick(() => {
|
|
const blank = this.pluginRef.store.createBlank();
|
|
new FormBuilderModal(this.app, blank, async (saved) => {
|
|
this.pluginRef.store.add(saved);
|
|
await this.pluginRef.saveSettings();
|
|
this.pluginRef.refreshSidebar();
|
|
this.display();
|
|
}).open();
|
|
});
|
|
});
|
|
|
|
// Import / Export
|
|
new Setting(containerEl)
|
|
.setName('Import / Export')
|
|
.setDesc('Share forms as JSON files.')
|
|
.addButton((btn) => {
|
|
btn.setButtonText('Export All').onClick(() => {
|
|
const forms = this.pluginRef.store.getAll();
|
|
if (forms.length === 0) {
|
|
new Notice('No forms to export.');
|
|
return;
|
|
}
|
|
const json = exportForms(forms);
|
|
const blob = new Blob([json], { type: 'application/json' });
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = 'formfire-export.json';
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
});
|
|
})
|
|
.addButton((btn) => {
|
|
btn.setButtonText('Import').onClick(() => {
|
|
const input = document.createElement('input');
|
|
input.type = 'file';
|
|
input.accept = '.json';
|
|
input.addEventListener('change', async () => {
|
|
const file = input.files?.[0];
|
|
if (!file) return;
|
|
try {
|
|
const text = await file.text();
|
|
const forms = importForms(text);
|
|
for (const form of forms) {
|
|
this.pluginRef.store.add(form);
|
|
}
|
|
await this.pluginRef.saveSettings();
|
|
this.pluginRef.refreshSidebar();
|
|
this.display();
|
|
new Notice(`Imported ${forms.length} form(s).`);
|
|
} catch (err) {
|
|
new Notice(
|
|
err instanceof Error ? err.message : 'Import failed.',
|
|
);
|
|
}
|
|
});
|
|
input.click();
|
|
});
|
|
});
|
|
|
|
// Form list
|
|
const forms = this.pluginRef.store.getAll();
|
|
|
|
if (forms.length === 0) {
|
|
containerEl.createDiv({
|
|
cls: 'ff-settings-empty',
|
|
text: 'No forms defined yet. Click the button above to create your first form.',
|
|
});
|
|
return;
|
|
}
|
|
|
|
containerEl.createEl('h3', { text: 'Your Forms' });
|
|
|
|
for (const form of forms) {
|
|
const modeDesc =
|
|
form.mode === 'create'
|
|
? `Creates notes in ${form.targetFolder ?? '/'}`
|
|
: `Updates ${form.targetFile === 'active' ? 'active file' : 'prompted file'}`;
|
|
const fieldCount = form.fields.length;
|
|
const desc = `${modeDesc} \u2022 ${fieldCount} field${fieldCount !== 1 ? 's' : ''}`;
|
|
|
|
new Setting(containerEl)
|
|
.setName(form.name)
|
|
.setDesc(desc)
|
|
.addButton((btn) => {
|
|
btn.setButtonText('Export').onClick(() => {
|
|
const json = exportForms([form]);
|
|
const blob = new Blob([json], { type: 'application/json' });
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = `formfire-${form.name.toLowerCase().replace(/\s+/g, '-')}.json`;
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
});
|
|
})
|
|
.addButton((btn) => {
|
|
btn.setButtonText('Edit').onClick(() => {
|
|
new FormBuilderModal(this.app, form, async (saved) => {
|
|
this.pluginRef.store.update(form.id, saved);
|
|
await this.pluginRef.saveSettings();
|
|
this.pluginRef.refreshSidebar();
|
|
this.display();
|
|
}).open();
|
|
});
|
|
})
|
|
.addButton((btn) => {
|
|
btn.setButtonText('Duplicate').onClick(async () => {
|
|
this.pluginRef.store.duplicate(form.id);
|
|
await this.pluginRef.saveSettings();
|
|
this.pluginRef.refreshSidebar();
|
|
this.display();
|
|
new Notice(`Duplicated "${form.name}".`);
|
|
});
|
|
})
|
|
.addButton((btn) => {
|
|
btn
|
|
.setButtonText('Delete')
|
|
.setWarning()
|
|
.onClick(async () => {
|
|
this.pluginRef.store.remove(form.id);
|
|
await this.pluginRef.saveSettings();
|
|
this.pluginRef.refreshSidebar();
|
|
this.display();
|
|
new Notice(`Deleted "${form.name}".`);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
}
|