diff --git a/src/settings.ts b/src/settings.ts index b648ae3..df0fc81 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -1,4 +1,4 @@ -import { App, Notice, PluginSettingTab, Setting } from 'obsidian'; +import { App, Notice, PluginSettingTab, Setting, TFile, TFolder } from 'obsidian'; import ClaudeContextPlugin from './main'; import { ContextSource, getSourceIcon, SourceRegistry } from './sources'; import { SourceModal } from './source-modal'; @@ -238,19 +238,54 @@ export class ClaudeContextSettingTab extends PluginSettingTab { } } + private setDynamicDesc(setting: Setting, base: string, dynamic: string): void { + setting.descEl.empty(); + setting.descEl.appendText(base); + if (dynamic) { + setting.descEl.createSpan({ text: ` (${dynamic})`, cls: 'cc-dynamic-desc' }); + } + } + + private describeContextFolder(setting: Setting, path: string): void { + const folder = this.app.vault.getAbstractFileByPath(path); + let count = 0; + if (folder instanceof TFolder) { + for (const child of folder.children) { + if (child instanceof TFile && child.extension === 'md') count++; + } + } + this.setDynamicDesc(setting, 'Folder containing your context files', + count > 0 ? `${count} .md file${count !== 1 ? 's' : ''}` : ''); + } + + private describeOutputFolder(setting: Setting, path: string): void { + const exists = this.app.vault.getAbstractFileByPath(path) instanceof TFolder; + this.setDynamicDesc(setting, 'Folder for secondary target files', + exists ? 'folder exists' : ''); + } + + private countHistoryEntries(): number { + const folder = this.app.vault.getAbstractFileByPath(this.plugin.settings.history.storageFolder); + if (folder instanceof TFolder) { + return folder.children.filter(c => c instanceof TFile).length; + } + return 0; + } + // === TAB: General === private renderGeneralTab(el: HTMLElement) { - new Setting(el) + const contextFolderSetting = new Setting(el) .setName('Context folder') - .setDesc('Folder containing your context files') .addText(text => text .setPlaceholder('_claude') .setValue(this.plugin.settings.contextFolder) .onChange(async (value) => { this.plugin.settings.contextFolder = value; await this.plugin.saveSettings(); + this.describeContextFolder(contextFolderSetting, value); })); + this.describeContextFolder(contextFolderSetting, this.plugin.settings.contextFolder); new Setting(el) .setName('Separator') @@ -293,9 +328,8 @@ export class ClaudeContextSettingTab extends PluginSettingTab { await this.plugin.saveSettings(); })); - new Setting(el) + const excludedSetting = new Setting(el) .setName('Excluded files') - .setDesc('Comma-separated filenames to exclude (e.g. "examples.md, drafts.md")') .addText(text => text .setPlaceholder('file1.md, file2.md') .setValue(this.plugin.settings.excludedFiles.join(', ')) @@ -305,7 +339,13 @@ export class ClaudeContextSettingTab extends PluginSettingTab { .map(s => s.trim()) .filter(s => s.length > 0); await this.plugin.saveSettings(); + const n = this.plugin.settings.excludedFiles.length; + this.setDynamicDesc(excludedSetting, 'Comma-separated filenames to exclude', + n > 0 ? `${n} excluded` : ''); })); + const excludedCount = this.plugin.settings.excludedFiles.length; + this.setDynamicDesc(excludedSetting, 'Comma-separated filenames to exclude', + excludedCount > 0 ? `${excludedCount} excluded` : ''); } // === TAB: Sources === @@ -341,15 +381,17 @@ export class ClaudeContextSettingTab extends PluginSettingTab { // Section: Options const optionsSection = new CollapsibleSection(el, 'sources-options', 'Options', this.plugin); - new Setting(optionsSection.contentEl) + const sourceLabelsSetting = new Setting(optionsSection.contentEl) .setName('Show source labels') - .setDesc('Add position and name labels to source output') .addToggle(toggle => toggle .setValue(this.plugin.settings.showSourceLabels) .onChange(async (value) => { this.plugin.settings.showSourceLabels = value; await this.plugin.saveSettings(); })); + const enabledSources = this.plugin.settings.sources.filter(s => s.enabled).length; + this.setDynamicDesc(sourceLabelsSetting, 'Add position and name labels to source output', + `${enabledSources} source${enabledSources !== 1 ? 's' : ''} enabled`); } // === TAB: Templates === @@ -408,9 +450,8 @@ export class ClaudeContextSettingTab extends PluginSettingTab { // Section: Defaults const defaultsSection = new CollapsibleSection(el, 'templates-defaults', 'Defaults', this.plugin); - new Setting(defaultsSection.contentEl) + const defaultTemplateSetting = new Setting(defaultsSection.contentEl) .setName('Default template') - .setDesc('Template to use by default when copying context') .addDropdown(dropdown => { dropdown.addOption('', 'None (plain context)'); for (const template of this.plugin.settings.promptTemplates) { @@ -422,6 +463,8 @@ export class ClaudeContextSettingTab extends PluginSettingTab { await this.plugin.saveSettings(); }); }); + this.setDynamicDesc(defaultTemplateSetting, 'Template to use by default when copying context', + `${this.plugin.settings.promptTemplates.length} available`); } // === TAB: Output === @@ -463,9 +506,8 @@ export class ClaudeContextSettingTab extends PluginSettingTab { const settingsSection = new CollapsibleSection(el, 'output-settings', 'Output settings', this.plugin); const oc = settingsSection.contentEl; - new Setting(oc) + const primaryTargetSetting = new Setting(oc) .setName('Primary target') - .setDesc('This target\'s output is copied to clipboard') .addDropdown(dropdown => { dropdown.addOption('', 'First enabled target'); for (const target of this.plugin.settings.targets) { @@ -477,17 +519,22 @@ export class ClaudeContextSettingTab extends PluginSettingTab { await this.plugin.saveSettings(); }); }); + const enabledTargets = this.plugin.settings.targets.filter(t => t.enabled).length; + const totalTargets = this.plugin.settings.targets.length; + this.setDynamicDesc(primaryTargetSetting, 'This target\'s output is copied to clipboard', + totalTargets > 0 ? `${enabledTargets} of ${totalTargets} enabled` : ''); - new Setting(oc) + const outputFolderSetting = new Setting(oc) .setName('Output folder') - .setDesc('Folder for secondary target files') .addText(text => text .setPlaceholder('_claude/outputs') .setValue(this.plugin.settings.targetOutputFolder) .onChange(async (value) => { this.plugin.settings.targetOutputFolder = value || '_claude/outputs'; await this.plugin.saveSettings(); + this.describeOutputFolder(outputFolderSetting, this.plugin.settings.targetOutputFolder); })); + this.describeOutputFolder(outputFolderSetting, this.plugin.settings.targetOutputFolder); } // === TAB: History === @@ -499,9 +546,8 @@ export class ClaudeContextSettingTab extends PluginSettingTab { }); desc.style.marginBottom = '10px'; - new Setting(el) + const enableHistorySetting = new Setting(el) .setName('Enable history') - .setDesc('Save generated contexts for later review and comparison') .addToggle(toggle => toggle .setValue(this.plugin.settings.history.enabled) .onChange(async (value) => { @@ -509,6 +555,9 @@ export class ClaudeContextSettingTab extends PluginSettingTab { await this.plugin.saveSettings(); this.display(); })); + const entryCount = this.countHistoryEntries(); + this.setDynamicDesc(enableHistorySetting, 'Save generated contexts for later review and comparison', + this.plugin.settings.history.enabled && entryCount > 0 ? `${entryCount} entries stored` : ''); if (this.plugin.settings.history.enabled) { new Setting(el) @@ -522,9 +571,8 @@ export class ClaudeContextSettingTab extends PluginSettingTab { await this.plugin.saveSettings(); })); - new Setting(el) + const maxEntriesSetting = new Setting(el) .setName('Maximum entries') - .setDesc('Oldest entries will be deleted when limit is exceeded') .addText(text => text .setPlaceholder('50') .setValue(String(this.plugin.settings.history.maxEntries)) @@ -533,8 +581,17 @@ export class ClaudeContextSettingTab extends PluginSettingTab { if (!isNaN(num) && num > 0) { this.plugin.settings.history.maxEntries = num; await this.plugin.saveSettings(); + const used = this.countHistoryEntries(); + this.setDynamicDesc(maxEntriesSetting, 'Oldest entries will be deleted when limit is exceeded', + `${used} of ${num} used`); } })); + { + const used = this.countHistoryEntries(); + const max = this.plugin.settings.history.maxEntries; + this.setDynamicDesc(maxEntriesSetting, 'Oldest entries will be deleted when limit is exceeded', + `${used} of ${max} used`); + } new Setting(el) .setName('Auto-cleanup (days)') diff --git a/styles.css b/styles.css index 6bdd10e..b58cde1 100644 --- a/styles.css +++ b/styles.css @@ -41,6 +41,10 @@ padding: 20px 0; } +.cc-dynamic-desc { + color: var(--text-faint); +} + /* Tab navigation for settings */ .cc-settings-tabs { display: flex;