diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index e9623e9..5ab1665 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install modules run: npm i diff --git a/.gitignore b/.gitignore index e09a007..9e42502 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ data.json # Exclude macOS Finder (System Explorer) View States .DS_Store +yarn.lock diff --git a/src/main.ts b/src/main.ts index aefd95e..b728beb 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,6 +4,8 @@ import {GraphManipulatorModule} from "./modules/GraphManipulatorModule"; import {EventEmitter} from "events"; import {DEFAULT_SETTINGS, PluginSetting, PluginSettingsTab} from "./models/PluginSettingsTab"; import {FolderNoteModule} from "./modules/FolderNoteModule"; +import {ContextMenuModule} from "./modules/ContextMenuModule"; + // Remember to rename these classes and interfaces! export default class FolderIndexPlugin extends Plugin { @@ -17,7 +19,8 @@ export default class FolderIndexPlugin extends Plugin { eventManager: EventEmitter oldGraphSetting = false static PLUGIN: FolderIndexPlugin; - + // @ts-ignore + private contextMenuModule: ContextMenuModule; constructor(app: App, manifest: PluginManifest) { super(app, manifest); @@ -50,6 +53,9 @@ export default class FolderIndexPlugin extends Plugin { if (this.settings.graphOverwrite) { this.graphManipulator = new GraphManipulatorModule(this.app, this) } + + this.contextMenuModule = new ContextMenuModule(this.app, this); + this.contextMenuModule.addFolderContextMenu(); } onSettingsUpdate() { diff --git a/src/models/PluginSettingsTab.ts b/src/models/PluginSettingsTab.ts index 5cfe426..26528bc 100644 --- a/src/models/PluginSettingsTab.ts +++ b/src/models/PluginSettingsTab.ts @@ -2,8 +2,11 @@ import {App, PluginSettingTab, Setting, TextAreaComponent} from "obsidian"; import FolderIndexPlugin from "../main"; export enum SortBy { + // eslint-disable-next-line no-unused-vars None = "Disabled", + // eslint-disable-next-line no-unused-vars Alphabetically = "Alphabetically", + // eslint-disable-next-line no-unused-vars ReverseAlphabetically = "Reverse Alphabetically" } @@ -27,6 +30,8 @@ export interface PluginSetting { excludeFolders: string[]; recursionLimit: number; headlineLimit: number; + indexFileUserSpecified: boolean; + indexFilename: string; } export const DEFAULT_SETTINGS: PluginSetting = { @@ -49,6 +54,8 @@ export const DEFAULT_SETTINGS: PluginSetting = { excludeFolders: [], recursionLimit: -1, headlineLimit: 6, + indexFileUserSpecified: false, + indexFilename: "!" } export class PluginSettingsTab extends PluginSettingTab { @@ -144,6 +151,25 @@ export class PluginSettingsTab extends PluginSettingTab { await this.plugin.saveSettings() })) + new Setting(containerEl) + .setName("User defined index filename") + .setDesc("This will automatically create an IndexFile with the user defined name") + .addToggle(component => component.setValue(this.plugin.settings.indexFileUserSpecified) + .onChange(async (value) => { + this.plugin.settings.indexFileUserSpecified = value + await this.plugin.saveSettings() + })) + + new Setting(containerEl) + .setName("Index filename") + .setDesc("the filename that is used as the folder index") + .addText(component => component.setValue(this.plugin.settings.indexFilename) + .setPlaceholder("!.md") + .onChange(async (value) => { + this.plugin.settings.indexFilename = value + await this.plugin.saveSettings() + })) + new Setting(containerEl) .setName("Hide IndexFile") .setDesc("This will hide IndexFiles from the file explorer (Disabled as it causes bugs right now)") diff --git a/src/modules/ContextMenuModule.ts b/src/modules/ContextMenuModule.ts new file mode 100644 index 0000000..7ffb0b1 --- /dev/null +++ b/src/modules/ContextMenuModule.ts @@ -0,0 +1,55 @@ +import { TFolder, Notice, App } from 'obsidian'; +import FolderIndexPlugin from "../main"; + +export class ContextMenuModule { + // eslint-disable-next-line no-unused-vars + constructor(private app: App, private plugin: FolderIndexPlugin) { + } + + addFolderContextMenu() { + this.app.workspace.on("file-menu", (menu, folder) => { + if (folder instanceof TFolder) { + const indexFileForFolder = this.getIndexFileForFolder(folder.path) + + if (!this.doesIndexFileExistForFolder(indexFileForFolder)) { + menu.addItem((item) => { + item.setTitle("Create Index File") + .setIcon("any-icon") + .onClick(() => this.createIndexFileForFolder(indexFileForFolder)); + }); + } + } + }); + } + + private doesIndexFileExistForFolder(fullPath:string): boolean { + return this.app.vault.getAbstractFileByPath(fullPath) != null + } + + private getIndexFileForFolder(path:string): string { + return path + "/" + this.getIndexFileName(path) + ".md"; + } + + private getIndexFileName(path: string) { + return (this.plugin.settings.indexFileUserSpecified) + ? this.plugin.settings.indexFilename + : path.split("/").pop() || ""; + } + + private async createIndexFileForFolder(indexFileForFolder: string) { + const filePath = indexFileForFolder.substring(0, indexFileForFolder.lastIndexOf("/")) + try { + // Create a new markdown file + const newFile = await this.app.vault.create(indexFileForFolder, this.plugin.settings.indexFileInitText.replace("{{folder}}", this.getIndexFileForFolder(indexFileForFolder))) + + // Notify the user + new Notice(`File "${newFile.name}" created successfully in folder "${newFile.path}".`); + // eslint-disable-next-line no-console + console.log(`File created at path: ${newFile.path}`); + } catch (error) { + // eslint-disable-next-line no-console + console.error(`Failed to create file at path: ${filePath}`, error); + new Notice("Failed to create file. See console for details."); + } + } +} diff --git a/src/modules/FolderNoteModule.ts b/src/modules/FolderNoteModule.ts index d961ce2..5af07d4 100644 --- a/src/modules/FolderNoteModule.ts +++ b/src/modules/FolderNoteModule.ts @@ -59,6 +59,15 @@ export class FolderNoteModule { return null } + private indexFilePathOnClick(dataPath: string) { + if (this.plugin.settings.indexFileUserSpecified) { + return dataPath + "/" + this.plugin.settings.indexFilename + ".md" + } else { + const folderName = dataPath.split("/").pop() + return dataPath + "/" + folderName + ".md" + } + } + private async onClick(event: MouseEvent) { const target = this.getTargetFromEvent(event) if (target == null) @@ -73,8 +82,7 @@ export class FolderNoteModule { dataPath = dataPathAttribute.value } - const folderName = dataPath.split("/").pop() - let indexFilePath = dataPath + "/" + folderName + ".md" + let indexFilePath = this.indexFilePathOnClick(dataPath) // This is the root folder, so we open the root index file if (indexFilePath == "//.md") { diff --git a/src/types/Utilities.ts b/src/types/Utilities.ts index f52ed90..05ebc70 100644 --- a/src/types/Utilities.ts +++ b/src/types/Utilities.ts @@ -14,6 +14,9 @@ export function isIndexFile(path: string) { if (pathParts.length < 2) return false const fileName = pathParts[pathParts.length - 1] + if (FolderIndexPlugin.PLUGIN.settings.indexFileUserSpecified) { + return fileName == FolderIndexPlugin.PLUGIN.settings.indexFilename + ".md"; + } const folderName = pathParts[pathParts.length - 2] + ".md" return fileName == folderName || fileName == FolderIndexPlugin.PLUGIN.settings.rootIndexFile; }