diff --git a/package.json b/package.json index f98849a..371c634 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,9 @@ "scripts": { "dev": "node esbuild.config.mjs", "build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production", - "version": "node version-bump.mjs && git add manifest.json versions.json" + "version": "node version-bump.mjs && git add manifest.json versions.json", + "folder-overview": "node ./src/folderOverview/esbuild.config.mjs", + "fv": "npm run folder-overview" }, "keywords": [], "author": "Alan Grainger", diff --git a/src/folderOverview/FolderOverview.ts b/src/folderOverview/FolderOverview.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/folderOverview/esbuild.config.mjs b/src/folderOverview/esbuild.config.mjs index 6aafc7f..ad24ca1 100644 --- a/src/folderOverview/esbuild.config.mjs +++ b/src/folderOverview/esbuild.config.mjs @@ -15,7 +15,7 @@ esbuild.build({ banner: { js: banner, }, - entryPoints: ['./src/main.ts'], + entryPoints: ['./src/folderOverview/src/main.ts'], bundle: true, external: [ 'obsidian', @@ -38,6 +38,6 @@ esbuild.build({ logLevel: 'info', sourcemap: prod ? false : 'inline', treeShaking: true, - outfile: 'main.js', + outfile: './src/folderOverview/main.js', conditions: ['types'], }).catch(() => process.exit(1)); diff --git a/src/folderOverview/src/FileExplorer.ts b/src/folderOverview/src/FileExplorer.ts index 6bfc4e7..cf466cd 100644 --- a/src/folderOverview/src/FileExplorer.ts +++ b/src/folderOverview/src/FileExplorer.ts @@ -198,7 +198,7 @@ export class FileExplorerOverview { } if (excludedFolder?.excludeFromFolderOverview) { return; } - const svg = ''; + const svg = ''; if (yaml.includeTypes.includes('folder')) { folderElement = childrenElement.createDiv({ cls: 'tree-item nav-folder', diff --git a/src/folderOverview/src/FolderOverview.ts b/src/folderOverview/src/FolderOverview.ts index baa4d63..30b26c7 100644 --- a/src/folderOverview/src/FolderOverview.ts +++ b/src/folderOverview/src/FolderOverview.ts @@ -50,13 +50,10 @@ export class FolderOverview { eventListeners: (() => void)[] = []; constructor(plugin: FolderNotesPlugin | FolderOverviewPlugin, ctx: MarkdownPostProcessorContext, source: string, el: HTMLElement, defaultSettings: overviewSettings) { - console.log('creating folder overview'); - console.log('defaultSettings', defaultSettings); this.plugin = plugin; this.emitter = new CustomEventEmitter(); let yaml: overviewSettings = parseYaml(source); if (!yaml) { yaml = {} as overviewSettings; } - console.log('yaml', yaml); const includeTypes = yaml?.includeTypes || defaultSettings.includeTypes || ['folder', 'markdown']; this.ctx = ctx; this.source = source; @@ -82,7 +79,6 @@ export class FolderOverview { disableCollapseIcon: yaml?.disableCollapseIcon ?? defaultSettings.disableCollapseIcon, alwaysCollapse: yaml?.alwaysCollapse ?? defaultSettings.alwaysCollapse, }; - console.log('this.yaml', this.yaml); const customChild = new CustomMarkdownRenderChild(el, this); @@ -174,7 +170,7 @@ export class FolderOverview { if (!sourceFolder && sourceFolderPath == '') { sourceFolderPath = '/'; } - if (!(sourceFolder instanceof TFolder)) { return; } + if (!(sourceFolder instanceof TFolder) && sourceFolderPath !== '/') { return; } if (sourceFolderPath == '/') { const rootFiles: TAbstractFile[] = []; @@ -184,11 +180,10 @@ export class FolderOverview { } }); files = rootFiles; - } else if (sourceFolder) { + } else if (sourceFolder instanceof TFolder) { files = sourceFolder.children; } - files = await this.filterFiles(files, plugin, sourceFolderPath, this.yaml.depth, this.pathBlacklist); if (!this.yaml.includeTypes.includes('folder')) { @@ -252,20 +247,19 @@ export class FolderOverview { } } } - if (this.yaml.includeTypes.length > 1 && (!this.yaml.showEmptyFolders || this.yaml.onlyIncludeSubfolders) && this.yaml.style === 'list') { - this.removeEmptyFolders(ul, 1, this.yaml); - } + + // if (this.yaml.includeTypes.length > 1 && (!this.yaml.showEmptyFolders || this.yaml.onlyIncludeSubfolders) && this.yaml.style === 'list') { + // this.removeEmptyFolders(ul, 1, this.yaml); + // } } addEditButton(root: HTMLElement) { - console.log('adding edit button'); const editButton = root.createEl('button', { cls: 'folder-overview-edit-button' }); editButton.innerText = 'Edit overview'; editButton.addEventListener('click', (e) => { e.stopImmediatePropagation(); e.preventDefault(); e.stopPropagation(); - console.log({ 'this.plugin': this.plugin, 'this.yaml': this.yaml, 'this.ctx': this.ctx, 'this.el': this.el }); new FolderOverviewSettings(this.plugin.app as App, this.plugin, this.yaml, this.ctx, this.el, this.plugin.settings as overviewSettings).open(); }, { capture: true }); } @@ -274,9 +268,10 @@ export class FolderOverview { const filteredFiles = await Promise.all(files.map(async (file) => { const folderPath = getFolderPathFromString(file.path); const isBlacklisted = pathBlacklist.includes(file.path); - const isSubfolder = folderPath.startsWith(sourceFolderPath) && sourceFolderPath !== '/'; + const isSubfolder = sourceFolderPath === '/' || folderPath.startsWith(sourceFolderPath); const isSourceFile = file.path === this.sourceFilePath; let isExcludedFromOverview = false; + if (plugin instanceof FolderNotesPlugin) { isExcludedFromOverview = (await getExcludedFolder(plugin, file.path, true))?.excludeFromFolderOverview ?? false; } @@ -285,7 +280,7 @@ export class FolderOverview { return null; } - const fileDepth = file.path.split('/').length - sourceFolderPath.split('/').length; + const fileDepth = file.path.split('/').length - (sourceFolderPath === '/' ? 0 : sourceFolderPath.split('/').length); return fileDepth <= depth ? file : null; })); @@ -293,6 +288,7 @@ export class FolderOverview { } + sortFiles(files: TAbstractFile[]): TAbstractFile[] { const yaml = this.yaml; @@ -333,24 +329,6 @@ export class FolderOverview { return files; } - removeEmptyFolders(ul: HTMLUListElement | HTMLLIElement, depth: number, yaml: overviewSettings) { - const childrensToRemove: ChildNode[] = []; - ul.childNodes.forEach((el) => { - if ((el.childNodes[0] as HTMLElement)?.classList && (el.childNodes[0] as HTMLElement)?.classList.contains('internal-link')) { return; } - const childrens = (el as Element).querySelector('ul'); - if (!childrens || childrens === null) { return; } - if (childrens && !childrens?.hasChildNodes() && !(el instanceof HTMLUListElement)) { - childrensToRemove.push(el); - } else if (el instanceof HTMLUListElement || el instanceof HTMLLIElement) { - this.removeEmptyFolders(el, depth + 1, yaml); - } - }); - childrensToRemove.forEach((el) => { - if (yaml.onlyIncludeSubfolders && depth === 1) { return; } - el.remove(); - }); - } - getAllFiles(files: TAbstractFile[], sourceFolderPath: string, depth: number) { const allFiles: TAbstractFile[] = []; diff --git a/src/folderOverview/src/ListStyle.ts b/src/folderOverview/src/ListStyle.ts index e414b6d..eb5fa14 100644 --- a/src/folderOverview/src/ListStyle.ts +++ b/src/folderOverview/src/ListStyle.ts @@ -1,5 +1,5 @@ import { MarkdownPostProcessorContext, TFolder, TFile, Plugin } from 'obsidian'; -import { getFolderNote } from '../../functions/folderNoteFunctions'; +import { extractFolderName, getFolderNote } from '../../functions/folderNoteFunctions'; import { FolderOverview, overviewSettings } from './FolderOverview'; import { getFolderPathFromString } from '../../functions/utils'; import FolderOverviewPlugin from 'src/main'; @@ -41,6 +41,14 @@ export function renderListOverview(plugin: FolderOverviewPlugin | FolderNotesPlu } export function addFolderList(plugin: FolderOverviewPlugin | FolderNotesPlugin | FolderNotesPlugin, list: HTMLUListElement | HTMLLIElement, pathBlacklist: string[], folder: TFolder, folderOverview: FolderOverview) { + const isFirstLevelSub = folder.path.split('/').length === folderOverview.yaml.folderPath.split('/').length + 1; + if (!folderOverview.yaml.showEmptyFolders && folder.children.length === 0 && !folderOverview.yaml.onlyIncludeSubfolders) { + return; + } else if (folderOverview.yaml.onlyIncludeSubfolders && !isFirstLevelSub && folder.children.length === 0) { + return; + } + + const folderItem = list.createEl('li', { cls: 'folder-overview-list folder-list' }); if (plugin instanceof FolderNotesPlugin) { const folderNote = getFolderNote(plugin, folder.path); @@ -115,6 +123,9 @@ function addFileList(plugin: FolderOverviewPlugin | FolderNotesPlugin, list: HTM if (!folderOverview.yaml.showFolderNotes) { if (pathBlacklist.includes(file.path)) return; + if (plugin instanceof FolderNotesPlugin && extractFolderName(plugin.settings.folderNoteName, file.basename) === file.parent?.name) { + return; + } } const listItem = list.createEl('li', { cls: 'folder-overview-list file-link' }); diff --git a/src/folderOverview/src/modals/Settings.ts b/src/folderOverview/src/modals/Settings.ts index c459a5c..cf61807 100644 --- a/src/folderOverview/src/modals/Settings.ts +++ b/src/folderOverview/src/modals/Settings.ts @@ -21,8 +21,6 @@ export class FolderOverviewSettings extends Modal { if (!yaml) { this.yaml = this.defaultSettings; } else if (ctx) { - console.log('yaml 3: ', yaml); - console.log('settings: ', defaultSettings); const includeTypes = yaml?.includeTypes || defaultSettings.includeTypes || ['folder', 'markdown']; this.yaml = { id: yaml?.id ?? crypto.randomUUID(), @@ -55,8 +53,6 @@ export class FolderOverviewSettings extends Modal { onOpen() { const { contentEl } = this; - console.log('yaml 6: ', this.yaml); - console.log('settings: ', this.defaultSettings); this.display(contentEl, this.yaml, this.plugin, this.defaultSettings, this.display, this.el, this.ctx); } @@ -75,8 +71,6 @@ export class FolderOverviewSettings extends Modal { contentEl.createEl('h2', { text: 'Default folder overview settings' }); } - console.log('yaml 4: ', yaml); - console.log('settings: ', defaultSettings); createOverviewSettings(contentEl, yaml, plugin, defaultSettings, display, el, ctx, undefined, undefined, modal); } diff --git a/src/folderOverview/src/settings.ts b/src/folderOverview/src/settings.ts index f6c6187..a116508 100644 --- a/src/folderOverview/src/settings.ts +++ b/src/folderOverview/src/settings.ts @@ -1,4 +1,4 @@ -import { MarkdownPostProcessorContext, Plugin, PluginSettingTab, Setting, TFile, TFolder } from 'obsidian'; +import { MarkdownPostProcessorContext, Plugin, Plugin$1, PluginSettingTab, Setting, TFile, TFolder } from 'obsidian'; import { updateYaml, updateYamlById, overviewSettings, includeTypes } from './FolderOverview'; import { FolderSuggest } from './suggesters/FolderSuggester'; import { ListComponent } from './utils/ListComponent'; @@ -29,8 +29,25 @@ export const DEFAULT_SETTINGS: overviewSettings = { alwaysCollapse: false, } +export class SettingsTab extends PluginSettingTab { + plugin: FolderOverviewPlugin; + + constructor(plugin: FolderOverviewPlugin) { + super(plugin.app, plugin); + } + + display() { + const { containerEl } = this; + + this.display = this.display.bind(this); + + containerEl.empty(); + createOverviewSettings(containerEl, this.plugin.settings, this.plugin, this.plugin.settings, this.display, undefined, undefined, undefined, this); + + } +} + export async function createOverviewSettings(contentEl: HTMLElement, yaml: overviewSettings, plugin: FolderOverviewPlugin | FolderNotesPlugin, defaultSettings: overviewSettings, display: CallableFunction, el?: HTMLElement, ctx?: MarkdownPostProcessorContext, file?: TFile | null, settingsTab?: PluginSettingTab, modal?: FolderOverviewSettings) { - console.log('yaml 5: ', yaml); new Setting(contentEl) .setName('Show the title') .setDesc('Choose if the title should be shown') @@ -242,7 +259,7 @@ export async function createOverviewSettings(contentEl: HTMLElement, yaml: overv if (yaml.showEmptyFolders) { new Setting(contentEl) - .setName('Only show first empty subfolders of current folder') + .setName('Only show empty folders which are on the first level of the folder overview') .addToggle((toggle) => { toggle .setValue(yaml.onlyIncludeSubfolders) @@ -282,7 +299,7 @@ export async function createOverviewSettings(contentEl: HTMLElement, yaml: overv } async function updateSettings(contentEl: HTMLElement, yaml: overviewSettings, plugin: FolderOverviewPlugin | FolderNotesPlugin, defaultSettings: overviewSettings, el?: HTMLElement, ctx?: MarkdownPostProcessorContext, file?: TFile | null) { - if (defaultSettings) { + if (!yaml.id) { return plugin.saveSettings(); } diff --git a/src/folderOverview/src/utils/ListComponent.ts b/src/folderOverview/src/utils/ListComponent.ts index 946a770..a7d224b 100644 --- a/src/folderOverview/src/utils/ListComponent.ts +++ b/src/folderOverview/src/utils/ListComponent.ts @@ -54,7 +54,7 @@ export class ListComponent { } span.setAttribute('extension', value); const removeSpan = span.createEl('span', { cls: 'ofn-list-item-remove setting-hotkey-icon' }); - const svg = ''; + const svg = ''; const svgElement = removeSpan.createEl('span', { cls: 'ofn-list-item-remove-icon' }); svgElement.innerHTML = svg; removeSpan.onClickEvent((e) => { @@ -73,7 +73,7 @@ export class ListComponent { addResetButton() { const resetButton = this.controlEl.createEl('span', { cls: 'clickable-icon setting-restore-hotkey-button' }); - const svg = ''; + const svg = ''; resetButton.innerHTML = svg; resetButton.onClickEvent((e) => { this.setValues(this.defaultValues); diff --git a/src/folderOverview/src/view.ts b/src/folderOverview/src/view.ts index 580a11a..78b8b18 100644 --- a/src/folderOverview/src/view.ts +++ b/src/folderOverview/src/view.ts @@ -18,6 +18,11 @@ export class FolderOverviewView extends ItemView { this.plugin = plugin; this.display = this.display.bind(this); + if (plugin instanceof FolderOverviewPlugin) { + this.defaultSettings = this.plugin.settings as overviewSettings; + } else { + this.defaultSettings = plugin.settings.defaultOverview; + } this.registerEvent( this.plugin.app.workspace.on('file-open', (file) => { @@ -95,9 +100,8 @@ export class FolderOverviewView extends ItemView { cb.addOption('default', 'Default'); cb.setValue(yaml?.id ?? 'default'); - console.log(yaml); - if (cb.getValue() === 'default' || defaultSettings) { + if (cb.getValue() === 'default' || !yaml?.id.trim()) { yaml = defaultSettings; cb.setValue('default'); } else { diff --git a/src/functions/ListComponent.ts b/src/functions/ListComponent.ts index 8354c85..8a2d112 100644 --- a/src/functions/ListComponent.ts +++ b/src/functions/ListComponent.ts @@ -54,7 +54,7 @@ export class ListComponent { } span.setAttribute('extension', value); const removeSpan = span.createEl('span', { cls: 'ofn-list-item-remove setting-hotkey-icon' }); - const svg = ''; + const svg = ''; const svgElement = removeSpan.createEl('span', { cls: 'ofn-list-item-remove-icon' }); svgElement.innerHTML = svg; removeSpan.onClickEvent((e) => { @@ -73,7 +73,7 @@ export class ListComponent { addResetButton() { const resetButton = this.controlEl.createEl('span', { cls: 'clickable-icon setting-restore-hotkey-button' }); - const svg = ''; + const svg = ''; resetButton.innerHTML = svg; resetButton.onClickEvent((e) => { this.setValues(this.defaultValues); diff --git a/src/modals/AddSupportedFileType.ts b/src/modals/AddSupportedFileType.ts index 590a6a8..990b451 100644 --- a/src/modals/AddSupportedFileType.ts +++ b/src/modals/AddSupportedFileType.ts @@ -27,7 +27,7 @@ export default class AddSupportedFileModal extends Modal { }); contentEl.createEl('h2', { text: 'Extension name' }); new Setting(contentEl) - .setName('Enter the name of the extension (only the short form, e.g. 'md')') + .setName('Enter the name of the extension (only the short form, e.g. "md")') .addText((text) => text .setValue('') diff --git a/src/modals/DeleteConfirmation.ts b/src/modals/DeleteConfirmation.ts index 54ad929..c460e81 100644 --- a/src/modals/DeleteConfirmation.ts +++ b/src/modals/DeleteConfirmation.ts @@ -23,7 +23,7 @@ export default class DeleteConfirmationModal extends Modal { modalContent.createEl('p', { text: 'It will be moved to your system trash.' }); break; case 'obsidianTrash': - modalContent.createEl('p', { text: 'It will be moved to your Obsidian trash, which is located in the '.trash' hidden folder in your vault.' }); + modalContent.createEl('p', { text: 'It will be moved to your Obsidian trash, which is located in the ".trash" hidden folder in your vault.' }); break; case 'delete': modalContent.createEl('p', { text: 'It will be permanently deleted.' }).setCssStyles({ color: 'red' }); diff --git a/src/settings/GeneralSettings.ts b/src/settings/GeneralSettings.ts index d8848b8..3035979 100644 --- a/src/settings/GeneralSettings.ts +++ b/src/settings/GeneralSettings.ts @@ -36,7 +36,7 @@ export async function renderGeneral(settingsTab: SettingsTab) { if (settingsTab.plugin.settings.newFolderNoteName !== '{{folder_name}}') { new Setting(containerEl) .setName('Use folder name instead of folder note name in the tab title') - .setDesc('When you\'re using a folder note name like 'folder note' and have multiple folder notes open you can\'t separate them anymore by their name. This setting uses the folder name instead and allows you to indentify the different files.') + .setDesc('When you\'re using a folder note name like "folder note" and have multiple folder notes open you can\'t separate them anymore by their name. This setting uses the folder name instead and allows you to indentify the different files.') .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.tabManagerEnabled)