devonthesofa_obsidian-note-.../integrations/settings/settings-tab.ts
2025-05-21 12:37:30 +02:00

352 lines
11 KiB
TypeScript

import { App, PluginSettingTab, Setting, Notice } from 'obsidian';
import { Status } from '../../models/types';
import { PREDEFINED_TEMPLATES } from '../../constants/status-templates';
import NoteStatus from 'main';
import { StatusService } from 'services/status-service';
/**
* Settings tab for the Note Status plugin
*/
export class NoteStatusSettingTab extends PluginSettingTab {
plugin: NoteStatus;
statusService: StatusService
constructor(app: App, plugin: any, statusService: StatusService) {
super(app, plugin);
this.plugin = plugin;
this.statusService = statusService;
}
display(): void {
const { containerEl } = this;
containerEl.empty();
// Status Template section
this.displayTemplateSettings(containerEl.createDiv());
// UI section
new Setting(containerEl).setName('User interface').setHeading();
// Status bar settings
new Setting(containerEl)
.setName('Show status bar')
.setDesc('Display the status bar')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.showStatusBar)
.onChange(async (value) => {
this.plugin.settings.showStatusBar = value;
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName('Auto-hide status bar')
.setDesc('Hide the status bar when status is unknown')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.autoHideStatusBar)
.onChange(async (value) => {
this.plugin.settings.autoHideStatusBar = value;
await this.plugin.saveSettings();
}));
// File explorer settings
new Setting(containerEl)
.setName('Show status icons in file explorer')
.setDesc('Display status icons in the file explorer')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.showStatusIconsInExplorer)
.onChange(async (value) => {
this.plugin.settings.showStatusIconsInExplorer = value;
await this.plugin.saveSettings();
// Explicitly refresh explorer icons
if (value) {
this.plugin.explorerIntegration.updateAllFileExplorerIcons();
} else {
this.plugin.explorerIntegration.removeAllFileExplorerIcons();
}
}));
// NEW SETTING: Hide unknown status in explorer
new Setting(containerEl)
.setName('Hide unknown status in file explorer')
.setDesc('Hide status icons for files with unknown status in the file explorer')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.hideUnknownStatusInExplorer || false)
.onChange(async (value) => {
this.plugin.settings.hideUnknownStatusInExplorer = value;
await this.plugin.saveSettings();
// Refresh explorer icons when this setting changes
this.plugin.explorerIntegration.updateAllFileExplorerIcons();
}));
// Compact view setting
new Setting(containerEl)
.setName('Default to compact view')
.setDesc('Start the status pane in compact view by default')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.compactView || false)
.onChange(async (value) => {
this.plugin.settings.compactView = value;
await this.plugin.saveSettings();
}));
// Add option to exclude unknown status in pane view for performance
new Setting(containerEl)
.setName('Exclude unassigned notes from status pane')
.setDesc('Improves performance by excluding notes with no assigned status from the status pane. Recommended for large vaults.')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.excludeUnknownStatus || false)
.onChange(async (value) => {
this.plugin.settings.excludeUnknownStatus = value;
await this.plugin.saveSettings();
// Refresh the status pane if open
const statusPane = this.app.workspace.getLeavesOfType('status-pane')[0];
if (statusPane && statusPane.view) {
this.statusService.refreshUI([]);
}
}));
new Setting(containerEl).setName('Status tag').setHeading();
// Option to use multiple statuses
new Setting(containerEl)
.setName('Enable multiple statuses')
.setDesc('Allow notes to have multiple statuses at the same time')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.useMultipleStatuses)
.onChange(async (value) => {
this.plugin.settings.useMultipleStatuses = value;
await this.plugin.saveSettings();
// Refresh UI to show multi-select or single-select options
this.statusService.refreshUI([]);
}));
// Status tag prefix
new Setting(containerEl)
.setName('Status tag prefix')
.setDesc('The YAML frontmatter tag name used for status (default: obsidian-note-status)')
.addText(text => text
.setValue(this.plugin.settings.tagPrefix)
.onChange(async (value) => {
// Don't allow empty tag prefix
if (!value.trim()) {
return;
}
this.plugin.settings.tagPrefix = value.trim();
await this.plugin.saveSettings();
this.statusService.refreshUI([]);
}));
// Status management section
new Setting(containerEl).setName('Custom statuses').setHeading();
// Option to use only custom statuses
new Setting(containerEl)
.setName('Use only custom statuses')
.setDesc('Ignore template statuses and use only the custom statuses defined below')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.useCustomStatusesOnly || false)
.onChange(async (value) => {
this.plugin.settings.useCustomStatusesOnly = value;
await this.plugin.saveSettings();
// Refresh the UI to show/hide template statuses
this.statusService.refreshUI([]);
this.display();
}));
// Custom statuses list
const statusList = containerEl.createDiv({ cls: 'custom-status-list' });
const renderStatuses = () => {
statusList.empty();
this.plugin.settings.customStatuses.forEach((status: Status, index: number) => {
const setting = new Setting(statusList)
.setName(status.name)
.setClass('status-item');
// Name field - now properly implemented
setting.addText(text => text
.setPlaceholder('Name')
.setValue(status.name)
.onChange(async (value) => {
const oldName = status.name;
status.name = value || 'unnamed';
// Update color mapping when name changes
if (oldName !== status.name) {
this.plugin.settings.statusColors[status.name] =
this.plugin.settings.statusColors[oldName];
delete this.plugin.settings.statusColors[oldName];
}
await this.plugin.saveSettings();
}));
// Icon field
setting.addText(text => text
.setPlaceholder('Icon')
.setValue(status.icon)
.onChange(async (value) => {
status.icon = value || '❓';
await this.plugin.saveSettings();
}));
// Color picker
setting.addColorPicker(colorPicker => colorPicker
.setValue(this.plugin.settings.statusColors[status.name] || '#ffffff')
.onChange(async (value) => {
this.plugin.settings.statusColors[status.name] = value;
await this.plugin.saveSettings();
}));
// Description field
setting.addText(text => text
.setPlaceholder('Description')
.setValue(status.description || '')
.onChange(async (value) => {
status.description = value;
await this.plugin.saveSettings();
}));
// Remove button
setting.addButton(button => button
.setButtonText('Remove')
.setClass('status-remove-button')
.setWarning()
.onClick(async () => {
this.plugin.settings.customStatuses.splice(index, 1);
delete this.plugin.settings.statusColors[status.name];
await this.plugin.saveSettings();
renderStatuses();
}));
});
};
renderStatuses();
// Add new status
new Setting(containerEl)
.setName('Add new status')
.setDesc('Add a custom status with a name, icon, and color')
.addButton(button => button
.setButtonText('Add Status')
.setCta()
.onClick(async () => {
const newStatus = {
name: `status${this.plugin.settings.customStatuses.length + 1}`,
icon: '⭐'
};
this.plugin.settings.customStatuses.push(newStatus);
this.plugin.settings.statusColors[newStatus.name] = '#ffffff'; // Initial white color
await this.plugin.saveSettings();
renderStatuses();
}));
}
/**
* Display template settings section
*/
private displayTemplateSettings(containerEl: HTMLElement): void {
new Setting(containerEl).setName('Status templates').setHeading();
containerEl.createEl('p', {
text: 'Enable predefined templates to quickly add common status workflows',
cls: 'setting-item-description'
});
// Create templates container
const templatesContainer = containerEl.createDiv({ cls: 'templates-container' });
// List each template with checkbox and preview
PREDEFINED_TEMPLATES.forEach(template => {
const templateEl = templatesContainer.createDiv({ cls: 'template-item' });
// Template header with checkbox and name
const headerEl = templateEl.createDiv({ cls: 'template-header' });
// Checkbox for enabling/disabling template
const isEnabled = this.plugin.settings.enabledTemplates.includes(template.id);
const checkbox = headerEl.createEl('input', {
type: 'checkbox',
cls: 'template-checkbox'
});
checkbox.checked = isEnabled;
checkbox.addEventListener('change', async () => {
if (checkbox.checked) {
// Enable template
if (!this.plugin.settings.enabledTemplates.includes(template.id)) {
this.plugin.settings.enabledTemplates.push(template.id);
}
} else {
// Disable template
this.plugin.settings.enabledTemplates = this.plugin.settings.enabledTemplates.filter(
(id: string) => id !== template.id
);
}
await this.plugin.saveSettings();
this.statusService.refreshUI([]);
});
// Template name
headerEl.createEl('span', {
text: template.name,
cls: 'template-name'
});
// Template description
templateEl.createEl('div', {
text: template.description,
cls: 'template-description'
});
// Preview statuses
const statusesEl = templateEl.createDiv({ cls: 'template-statuses' });
template.statuses.forEach(status => {
const statusEl = statusesEl.createEl('div', { cls: 'template-status-chip' });
const colorDot = statusEl.createEl('span', { cls: 'status-color-dot' });
colorDot.style.setProperty('--dot-color', status.color || '#ffffff')
// Status icon and name
statusEl.createSpan({ text: `${status.icon} ${status.name}` });
});
});
// Import/Export buttons for templates
const buttonsContainer = containerEl.createDiv({ cls: 'template-buttons' });
// Import button
const importButton = buttonsContainer.createEl('button', {
text: 'Import template',
cls: 'mod-cta'
});
importButton.addEventListener('click', () => {
// Show notification about upcoming feature
new Notice('Template import functionality coming soon!');
});
// Export button
const exportButton = buttonsContainer.createEl('button', {
text: 'Export templates',
cls: ''
});
exportButton.addEventListener('click', () => {
// Show notification about upcoming feature
new Notice('Template export functionality coming soon!');
});
}
}