Merge pull request #240 from LostPaul/fix-css-style-issues

Fix css style issues
This commit is contained in:
Lost Paul 2025-06-20 17:52:45 +02:00 committed by GitHub
commit c5c001cffc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 426 additions and 394 deletions

View file

@ -1,8 +1,4 @@
# Folder overview
This page will be updated soon and there also will be new features.
This feature/plugin creates a code block
This feature/plugin creates a [code block](https://help.obsidian.md/Editing+and+formatting/Basic+formatting+syntax#Code+blocks) that provides an overview of your entire vault or specific folders. Instructions for creating or editing a folder overview, along with additional guidance, can be found further down the page.
Currently there are two styles available: **file explorer** & **list style**, with more coming soon. The **overview updates** itself **automatically** when you create, delete or modify a file. You can also integrate it into **templates**, as explained further down below this page.
@ -13,11 +9,14 @@ There are two options to create a folder overview in a note
- Use the command "Insert folder overview" from the [command palette](https://help.obsidian.md/Plugins/Command+palette)
- On desktop right click and click on the option "Create folder overview"
## Edit overview
If the overview shows no files or folders yet you can just click on the button that says "Edit overview". But if there are already files/folders it's a bit more complicated than the button and to then edit the overview you have to hover over the overview and click on the "Edit this block" button on the right top corner of the overview with only an icon.
If the overview shows no files or folders yet you can just click on the button that says "Edit overview". But if there are already files/folders you can use the command "Edit folder overview" from the [command palette](https://help.obsidian.md/Plugins/Command+palette) or click on the button as showed in the video below.
The video below shows the steps explained in the text.
![type:video](../assets/n5AGi3VCxF5JcNx2Wm5O.mp4)
## Default settings
To edit the settings for a new folder overview that hasn't been created yet you have to open the plugin settings and go to the folder overview tab and click on the manage button.
![Screenshot](../assets/ngkJjEcxUUTkX6eB4mSs.png)
To edit the default values for new folder overviews you can either use the command "Edit folder overview" or open the plugins settings tab and then the folder overview tab to the edit the default settings.
![Screenshot](../assets/screenshots/b4QOtkzJs0.png)
(On the left is the plugin settings tab and the right the view you see when you use the "Edit folder overview" command)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

View file

@ -3,8 +3,8 @@ import FolderNotesPlugin from './main';
import { getFolderNote, createFolderNote, deleteFolderNote, turnIntoFolderNote, openFolderNote, extractFolderName, detachFolderNote } from './functions/folderNoteFunctions';
import { ExcludedFolder } from './ExcludeFolders/ExcludeFolder';
import { getFolderPathFromString, getFileExplorerActiveFolder } from './functions/utils';
import { addExcludedFolder, deleteExcludedFolder, getDetachedFolder, getExcludedFolder } from './ExcludeFolders/functions/folderFunctions';
import { applyCSSClassesToFolder } from './functions/styleFunctions';
import { deleteExcludedFolder, getDetachedFolder, getExcludedFolder } from './ExcludeFolders/functions/folderFunctions';
import { hideFolderNoteInFileExplorer, showFolderNoteInFileExplorer } from './functions/styleFunctions';
@ -403,10 +403,7 @@ export class Commands {
item.setTitle('Hide folder note in explorer')
.setIcon('eye-off')
.onClick(() => {
this.plugin.settings.excludeFolders = this.plugin.settings.excludeFolders.filter(
(folder) => (folder.path !== file.path) && folder.showFolderNote);
this.plugin.saveSettings(false);
applyCSSClassesToFolder(file.path, this.plugin);
hideFolderNoteInFileExplorer(file.path, this.plugin);
});
});
} else {
@ -414,17 +411,7 @@ export class Commands {
item.setTitle('Show folder note in explorer')
.setIcon('eye')
.onClick(() => {
const excludedFolder = new ExcludedFolder(file.path, this.plugin.settings.excludeFolders.length, undefined, this.plugin);
excludedFolder.subFolders = false;
excludedFolder.disableSync = false;
excludedFolder.disableAutoCreate = false;
excludedFolder.disableFolderNote = false;
excludedFolder.enableCollapsing = false;
excludedFolder.excludeFromFolderOverview = false;
excludedFolder.hideInSettings = true;
excludedFolder.showFolderNote = true;
addExcludedFolder(this.plugin, excludedFolder, false);
applyCSSClassesToFolder(file.path, this.plugin);
showFolderNoteInFileExplorer(file.path, this.plugin);
});
});
}

View file

@ -1,9 +1,9 @@
import { Keymap, Platform } from 'obsidian';
import FolderNotesPlugin from 'src/main';
import { getFolderNote } from 'src/functions/folderNoteFunctions';
import { handleFolderClick, handleViewHeaderClick } from './handleClick';
import { handleViewHeaderClick } from './handleClick';
import { getExcludedFolder } from 'src/ExcludeFolders/functions/folderFunctions';
import { applyCSSClassesToFolder } from 'src/functions/styleFunctions';
import { updateCSSClassesForFolder } from 'src/functions/styleFunctions';
let fileExplorerMutationObserver: MutationObserver | null = null;
@ -114,7 +114,7 @@ async function setupFolderTitle(folderTitle: HTMLElement, plugin: FolderNotesPlu
if (!folderPath) return;
folderTitle.dataset.initialized = 'true';
await applyCSSClassesToFolder(folderPath, plugin);
await updateCSSClassesForFolder(folderPath, plugin);
if (plugin.settings.frontMatterTitle.enabled) {
plugin.fmtpHandler?.fmptUpdateFolderName({ id: '', result: false, path: folderPath, pathOnly: false }, false);
@ -122,12 +122,6 @@ async function setupFolderTitle(folderTitle: HTMLElement, plugin: FolderNotesPlu
if (Platform.isMobile && plugin.settings.disableOpenFolderNoteOnClick) return;
folderTitle.addEventListener('auxclick', (event: MouseEvent) => {
if (event.button === 1) handleFolderClick(event, plugin);
}, { capture: true });
folderTitle.onclick = (event: MouseEvent) => handleFolderClick(event, plugin);
plugin.registerDomEvent(folderTitle, 'pointerover', (event: MouseEvent) => {
plugin.hoveredElement = folderTitle;
plugin.mouseEvent = event;

View file

@ -2,7 +2,7 @@ import { Keymap, Platform } from 'obsidian';
import FolderNotesPlugin from 'src/main';
import { openFolderNote, createFolderNote, getFolderNote } from 'src/functions/folderNoteFunctions';
import { getExcludedFolder } from 'src/ExcludeFolders/functions/folderFunctions';
import { addCSSClassToTitleEL, removeCSSClassFromEL } from 'src/functions/styleFunctions';
import { addCSSClassToFileExplorerEl, removeCSSClassFromFileExplorerEL } from 'src/functions/styleFunctions';
export async function handleViewHeaderClick(event: MouseEvent, plugin: FolderNotesPlugin) {
event.stopImmediatePropagation();
@ -38,65 +38,11 @@ export async function handleViewHeaderClick(event: MouseEvent, plugin: FolderNot
} else if (event.altKey || Keymap.isModEvent(event) === 'tab') {
if ((plugin.settings.altKey && event.altKey) || (plugin.settings.ctrlKey && Keymap.isModEvent(event) === 'tab')) {
await createFolderNote(plugin, folderPath, true, undefined, true);
addCSSClassToTitleEL(folderPath, 'has-folder-note', plugin);
removeCSSClassFromEL(folderPath, 'has-not-folder-note', plugin);
addCSSClassToFileExplorerEl(folderPath, 'has-folder-note', false, plugin);
removeCSSClassFromFileExplorerEL(folderPath, 'has-not-folder-note', false, plugin);
return;
}
}
event.target.onclick = null;
event.target.click();
}
export async function handleFolderClick(event: MouseEvent, plugin: FolderNotesPlugin) {
if (!(event.target instanceof HTMLElement)) return;
event.target.setAttribute('data-initialized', 'false');
if (!event || !event.target) return;
if (!event.shiftKey) {
event.stopImmediatePropagation();
} else {
return;
}
const folderPath = event.target.parentElement?.getAttribute('data-path');
if (!folderPath) { return; }
const excludedFolder = getExcludedFolder(plugin, folderPath, true);
if (excludedFolder?.disableFolderNote) {
event.target.onclick = null;
event.target.click();
return;
} else if (excludedFolder?.enableCollapsing || plugin.settings.enableCollapsing) {
event.target.onclick = null;
event.target.click();
}
const folderNote = getFolderNote(plugin, folderPath);
if (folderNote) {
if (plugin.settings.openByClick) {
return openFolderNote(plugin, folderNote, event);
} else if (plugin.settings.openWithCtrl && Keymap.isModEvent(event) === 'tab') {
return openFolderNote(plugin, folderNote, event);
} else if (plugin.settings.openWithAlt && event.altKey) {
return openFolderNote(plugin, folderNote, event);
} else {
if (plugin.settings.enableCollapsing) return;
event.target.parentElement?.click();
return;
}
} else if (event.altKey || Keymap.isModEvent(event) === 'tab') {
if ((plugin.settings.altKey && event.altKey) || (plugin.settings.ctrlKey && Keymap.isModEvent(event) === 'tab')) {
await createFolderNote(plugin, folderPath, true, undefined, true);
addCSSClassToTitleEL(folderPath, 'has-folder-note', plugin);
removeCSSClassFromEL(folderPath, 'has-not-folder-note', plugin);
return;
}
} else if (!folderNote) {
if (plugin.settings.enableCollapsing) return;
return event.target.parentElement?.click();
}
event.target.onclick = null;
event.target.click();
}

View file

@ -2,17 +2,17 @@ import { TAbstractFile, TFolder, TFile } from 'obsidian';
import FolderNotesPlugin from 'src/main';
import { createFolderNote, getFolder, getFolderNote, turnIntoFolderNote } from 'src/functions/folderNoteFunctions';
import { getExcludedFolder } from 'src/ExcludeFolders/functions/folderFunctions';
import { removeCSSClassFromEL, addCSSClassToTitleEL } from 'src/functions/styleFunctions';
import { removeCSSClassFromFileExplorerEL, addCSSClassToFileExplorerEl } from 'src/functions/styleFunctions';
export async function handleCreate(file: TAbstractFile, plugin: FolderNotesPlugin) {
if (!plugin.app.workspace.layoutReady) return;
const folder = file.parent;
if (folder instanceof TFolder) {
if (plugin.isEmptyFolderNoteFolder(folder)) {
addCSSClassToTitleEL(folder.path, 'only-has-folder-note', plugin);
if (plugin.isEmptyFolderNoteFolder(folder) && getFolderNote(plugin, folder.path)) {
addCSSClassToFileExplorerEl(folder.path, 'only-has-folder-note', true, plugin);
} else {
removeCSSClassFromEL(folder.path, 'only-has-folder-note', plugin);
removeCSSClassFromFileExplorerEL(folder.path, 'only-has-folder-note', true, plugin);
}
}
@ -32,7 +32,7 @@ async function handleFileCreation(file: TFile, plugin: FolderNotesPlugin) {
turnIntoFolderNote(plugin, file, newFolder);
} else if (folder instanceof TFolder) {
if (folder.children.length >= 1) {
removeCSSClassFromEL(folder.path, 'fn-empty-folder', plugin);
removeCSSClassFromFileExplorerEL(folder.path, 'fn-empty-folder', false, plugin);
}
const detachedFolder = getExcludedFolder(plugin, folder.path, true);
@ -40,8 +40,8 @@ async function handleFileCreation(file: TFile, plugin: FolderNotesPlugin) {
const folderNote = getFolderNote(plugin, folder.path);
if (folderNote && folderNote.path === file.path) {
addCSSClassToTitleEL(folder.path, 'has-folder-note', plugin);
addCSSClassToTitleEL(file.path, 'is-folder-note', plugin);
addCSSClassToFileExplorerEl(folder.path, 'has-folder-note', false, plugin);
addCSSClassToFileExplorerEl(file.path, 'is-folder-note', false, plugin);
} else if (plugin.settings.autoCreateForFiles) {
if (!file.parent) { return; }
const newFolder = await plugin.app.fileManager.createNewFolder(file.parent);
@ -56,7 +56,7 @@ async function handleFolderCreation(folder: TFolder, plugin: FolderNotesPlugin)
const attachmentFolderPath = plugin.app.vault.getConfig('attachmentFolderPath') as string;
const cleanAttachmentFolderPath = attachmentFolderPath?.replace('./', '') || '';
const attachmentsAreInRootFolder = attachmentFolderPath === './' || attachmentFolderPath === '';
addCSSClassToTitleEL(folder.path, 'fn-empty-folder', plugin);
addCSSClassToFileExplorerEl(folder.path, 'fn-empty-folder', false, plugin);
if (!plugin.settings.autoCreateForAttachmentFolder) {
if (!attachmentsAreInRootFolder && cleanAttachmentFolderPath === folder.name) return;
@ -71,5 +71,5 @@ async function handleFolderCreation(folder: TFolder, plugin: FolderNotesPlugin)
if (folderNote) return;
createFolderNote(plugin, folder.path, openFile, undefined, true);
addCSSClassToTitleEL(folder.path, 'has-folder-note', plugin);
addCSSClassToFileExplorerEl(folder.path, 'has-folder-note', false, plugin);
}

View file

@ -1,16 +1,16 @@
import { TAbstractFile, TFolder, TFile } from 'obsidian';
import FolderNotesPlugin from 'src/main';
import { getFolderNote, getFolder, deleteFolderNote } from 'src/functions/folderNoteFunctions';
import { removeCSSClassFromEL, addCSSClassToTitleEL } from 'src/functions/styleFunctions';
import { removeCSSClassFromFileExplorerEL, addCSSClassToFileExplorerEl, hideFolderNoteInFileExplorer } from 'src/functions/styleFunctions';
import { getFolderPathFromString } from 'src/functions/utils';
export function handleDelete(file: TAbstractFile, plugin: FolderNotesPlugin) {
const folder = plugin.app.vault.getAbstractFileByPath(getFolderPathFromString(file.path));
if (folder instanceof TFolder) {
if (plugin.isEmptyFolderNoteFolder(folder)) {
addCSSClassToTitleEL(folder.path, 'only-has-folder-note', plugin);
if (plugin.isEmptyFolderNoteFolder(folder) && getFolderNote(plugin, folder.path)) {
addCSSClassToFileExplorerEl(folder.path, 'only-has-folder-note', true, plugin);
} else {
removeCSSClassFromEL(folder.path, 'only-has-folder-note', plugin);
removeCSSClassFromFileExplorerEL(folder.path, 'only-has-folder-note', true, plugin);
}
}
@ -19,14 +19,15 @@ export function handleDelete(file: TAbstractFile, plugin: FolderNotesPlugin) {
if (!folder) { return; }
const folderNote = getFolderNote(plugin, folder.path);
if (folderNote) { return; }
removeCSSClassFromEL(folder.path, 'has-folder-note', plugin);
removeCSSClassFromEL(folder.path, 'only-has-folder-note', plugin);
removeCSSClassFromFileExplorerEL(folder.path, 'has-folder-note', false, plugin);
removeCSSClassFromFileExplorerEL(folder.path, 'only-has-folder-note', true, plugin);
hideFolderNoteInFileExplorer(folder.path, plugin);
}
if (!(file instanceof TFolder)) { return; }
const folderNote = getFolderNote(plugin, file.path);
if (!folderNote) { return; }
removeCSSClassFromEL(folderNote.path, 'is-folder-note', plugin);
removeCSSClassFromFileExplorerEL(folderNote.path, 'is-folder-note', false, plugin);
if (!plugin.settings.syncDelete) { return; }
deleteFolderNote(plugin, folderNote, false);
}

View file

@ -3,39 +3,40 @@ import FolderNotesPlugin from 'src/main';
import { extractFolderName, getFolderNote, getFolderNoteFolder } from '../functions/folderNoteFunctions';
import { getExcludedFolder, addExcludedFolder, updateExcludedFolder, deleteExcludedFolder, getDetachedFolder } from '../ExcludeFolders/functions/folderFunctions';
import { ExcludedFolder } from 'src/ExcludeFolders/ExcludeFolder';
import { removeCSSClassFromEL, addCSSClassToTitleEL } from 'src/functions/styleFunctions';
import { removeCSSClassFromFileExplorerEL, addCSSClassToFileExplorerEl, markFileAsFolderNote, unmarkFileAsFolderNote, unmarkFolderAsFolderNote, markFolderWithFolderNoteClasses, hideFolderNoteInFileExplorer, removeActiveFolder, setActiveFolder } from 'src/functions/styleFunctions';
import { getFolderPathFromString, removeExtension, getFileNameFromPathString } from 'src/functions/utils';
export function handleRename(file: TAbstractFile, oldPath: string, plugin: FolderNotesPlugin) {
const folder = file.parent;
const oldFolder = plugin.app.vault.getAbstractFileByPath(getFolderPathFromString(oldPath));
const isRename = (file.parent?.path === getFolderPathFromString(oldPath));
if (folder instanceof TFolder) {
if (plugin.isEmptyFolderNoteFolder(folder)) {
addCSSClassToTitleEL(folder.path, 'only-has-folder-note', plugin);
if (plugin.isEmptyFolderNoteFolder(folder) && getFolderNote(plugin, folder.path)) {
addCSSClassToFileExplorerEl(folder.path, 'only-has-folder-note', true, plugin);
} else {
removeCSSClassFromEL(folder.path, 'only-has-folder-note', plugin);
removeCSSClassFromFileExplorerEL(folder.path, 'only-has-folder-note', true, plugin);
}
}
if (oldFolder instanceof TFolder) {
if (plugin.isEmptyFolderNoteFolder(oldFolder)) {
addCSSClassToTitleEL(oldFolder.path, 'only-has-folder-note', plugin);
if (plugin.isEmptyFolderNoteFolder(oldFolder) && getFolderNote(plugin, oldFolder.path)) {
addCSSClassToFileExplorerEl(oldFolder.path, 'only-has-folder-note', true, plugin);
} else {
removeCSSClassFromEL(oldFolder.path, 'only-has-folder-note', plugin);
removeCSSClassFromFileExplorerEL(oldFolder.path, 'only-has-folder-note', true, plugin);
}
}
if (file instanceof TFolder) {
plugin.tabManager.updateTab(file.path);
updateExcludedFolderPath(file, oldPath, plugin);
if (isRename) {
return handleFolderRename(file, oldPath, plugin);
const folder = file;
plugin.tabManager.updateTab(folder.path);
updateExcludedFolderPath(folder, oldPath, plugin);
if (isFolderRename(folder, oldPath)) {
return handleFolderRename(folder, oldPath, plugin);
} else {
return handleFolderMove(file, oldPath, plugin);
return handleFolderMove(folder, oldPath, plugin);
}
} else if (file instanceof TFile) {
if (isRename) {
if (isFileRename(file, oldPath)) {
return fmptUpdateFileName(file, oldPath, plugin);
} else {
return handleFileMove(file, oldPath, plugin);
@ -43,6 +44,26 @@ export function handleRename(file: TAbstractFile, oldPath: string, plugin: Folde
}
}
function isFileRename(file: TFile, oldPath: string): boolean {
const oldFolderPath = getFolderPathFromString(oldPath);
const newFolderPath = file.parent?.path;
const oldName = getFileNameFromPathString(oldPath);
const newName = file.name;
return oldFolderPath === newFolderPath && oldName !== newName;
}
function isFolderRename(folder: TFolder, oldPath: string): boolean {
const oldName = getFileNameFromPathString(oldPath);
const newName = folder.name;
const oldParent = getFolderPathFromString(oldPath);
const newParent = folder.parent?.path;
return oldParent === newParent && oldName !== newName;
}
export function handleFolderMove(file: TFolder, oldPath: string, plugin: FolderNotesPlugin) {
// Soon
@ -54,12 +75,19 @@ export async function handleFileMove(file: TFile, oldPath: string, plugin: Folde
const folderName = extractFolderName(plugin.settings.folderNoteName, file.basename) || file.basename;
const oldFileName = removeExtension(getFileNameFromPathString(oldPath));
const newFolder = getFolderNoteFolder(plugin, file, file.basename);
const folderNote = getFolderNote(plugin, oldPath, plugin.settings.storageLocation, file);
let excludedFolder = getExcludedFolder(plugin, newFolder?.path || '', true);
const oldFolder = getFolderNoteFolder(plugin, oldPath, oldFileName);
const folderNote = getFolderNote(plugin, oldPath, plugin.settings.storageLocation, file);
// file has been moved into position where it can be a folder note!
if (folderName === newFolder?.name && folderNote) {
const isFileNowFolderNoteInNewFolder = folderName === newFolder?.name;
const isFileMovedFromOldFolderNote = oldFolder && oldFolder.name === oldFileName && newFolder?.path !== oldFolder.path;
// this is for turning files into folder notes for folders that already have a folder note
// e.g. Turn into folder note for "Folder name"
const isFileNowFolderNoteWithExistingNote = folderName === newFolder?.name && folderNote;
if (isFileNowFolderNoteWithExistingNote) {
let excludedFolderExisted = true;
let disabledSync = false;
@ -81,12 +109,28 @@ export async function handleFileMove(file: TFile, oldPath: string, plugin: Folde
updateExcludedFolder(plugin, excludedFolder, excludedFolder);
}
});
} else if (oldFolder && oldFolder.name === oldFileName && newFolder?.path !== oldFolder.path) {
// the note has been moved somewhere and is no longer a folder note
// cleanup css on the folder and note
removeCSSClassFromEL(oldFolder.path, 'has-folder-note', plugin);
removeCSSClassFromEL(file.path, 'is-folder-note', plugin);
removeCSSClassFromEL(oldPath, 'is-folder-note', plugin);
} else if (isFileNowFolderNoteInNewFolder) {
if (!excludedFolder?.disableFolderNote) {
markFileAsFolderNote(file, plugin);
if (newFolder instanceof TFolder) {
markFolderWithFolderNoteClasses(newFolder, plugin);
if (plugin.app.workspace.getActiveFile()?.path === file.path) {
removeActiveFolder(plugin);
setActiveFolder(newFolder.path, plugin);
}
}
if (oldFolder instanceof TFolder) {
hideFolderNoteInFileExplorer(oldFolder.path, plugin);
unmarkFolderAsFolderNote(oldFolder, plugin);
}
}
} else if (isFileMovedFromOldFolderNote) {
unmarkFileAsFolderNote(file, plugin);
if (oldFolder instanceof TFolder) {
removeActiveFolder(plugin);
hideFolderNoteInFileExplorer(oldFolder.path, plugin);
unmarkFolderAsFolderNote(oldFolder, plugin);
}
}
}
@ -96,14 +140,13 @@ export async function handleFolderRename(file: TFolder, oldPath: string, plugin:
if (fileName === oldFileName) { return; }
const folderNote = getFolderNote(plugin, oldPath);
if (!(folderNote instanceof TFile)) return;
const excludedFolder = getExcludedFolder(plugin, file.path, true);
if (excludedFolder?.disableSync && !folderNote) {
return removeCSSClassFromEL(file.path, 'has-folder-note', plugin);
return removeCSSClassFromFileExplorerEL(file.path, 'has-folder-note', false, plugin);
}
if (!plugin.settings.syncFolderName) { return; }
@ -143,21 +186,21 @@ export async function fmptUpdateFileName(file: TFile, oldPath: string, plugin: F
const folderNote = getFolderNote(plugin, oldPath, plugin.settings.storageLocation, file);
if (!excludedFolder?.disableFolderNote && folderName === newFolder?.name && !detachedExcludedFolder) {
addCSSClassToTitleEL(file.path, 'is-folder-note', plugin);
addCSSClassToTitleEL(newFolder.path, 'has-folder-note', plugin);
addCSSClassToFileExplorerEl(file.path, 'is-folder-note', false, plugin);
addCSSClassToFileExplorerEl(newFolder.path, 'has-folder-note', false, plugin);
return;
} else if (excludedFolder?.disableFolderNote || (folderName !== newFolder?.name)) {
removeCSSClassFromEL(file.path, 'is-folder-note', plugin);
removeCSSClassFromEL(newFolder?.path || '', 'has-folder-note', plugin);
removeCSSClassFromFileExplorerEL(file.path, 'is-folder-note', false, plugin);
removeCSSClassFromFileExplorerEL(newFolder?.path || '', 'has-folder-note', false, plugin);
}
if (excludedFolder?.disableSync || !plugin.settings.syncFolderName) { return; }
if (folderName === newFolder?.name) {
addCSSClassToTitleEL(file.path, 'is-folder-note', plugin);
removeCSSClassFromEL(oldFolder?.path, 'has-folder-note', plugin);
addCSSClassToTitleEL(newFolder.path, 'has-folder-note', plugin);
addCSSClassToFileExplorerEl(file.path, 'is-folder-note', false, plugin);
removeCSSClassFromFileExplorerEL(oldFolder?.path, 'has-folder-note', false, plugin);
addCSSClassToFileExplorerEl(newFolder.path, 'has-folder-note', false, plugin);
return;
}
@ -175,12 +218,12 @@ export async function fmptUpdateFileName(file: TFile, oldPath: string, plugin: F
async function renameFolderOnFileRename(file: TFile, oldPath: string, oldFolder: TAbstractFile, plugin: FolderNotesPlugin) {
const newFolderName = extractFolderName(plugin.settings.folderNoteName, file.basename);
if (!newFolderName) {
removeCSSClassFromEL(oldFolder.path, 'has-folder-note', plugin);
removeCSSClassFromEL(file.path, 'is-folder-note', plugin);
removeCSSClassFromFileExplorerEL(oldFolder.path, 'has-folder-note', false, plugin);
removeCSSClassFromFileExplorerEL(file.path, 'is-folder-note', false, plugin);
return;
} else if (newFolderName === oldFolder.name) {
addCSSClassToTitleEL(oldFolder.path, 'has-folder-note', plugin);
addCSSClassToTitleEL(file.path, 'is-folder-note', plugin);
addCSSClassToFileExplorerEl(oldFolder.path, 'has-folder-note', false, plugin);
addCSSClassToFileExplorerEl(file.path, 'is-folder-note', false, plugin);
return;
}

View file

@ -7,7 +7,7 @@ import { addExcludedFolder, deleteExcludedFolder, getDetachedFolder, getExcluded
import { ExcludedFolder } from '../ExcludeFolders/ExcludeFolder';
import { openExcalidrawView } from './excalidraw';
import { AskForExtensionModal } from 'src/modals/AskForExtension';
import { getEl, addCSSClassToTitleEL, removeCSSClassFromEL } from 'src/functions/styleFunctions';
import { addCSSClassToFileExplorerEl, removeCSSClassFromFileExplorerEL, removeActiveFolder, setActiveFolder } from 'src/functions/styleFunctions';
import { getFolderNameFromPathString, getFolderPathFromString, removeExtension } from 'src/functions/utils';
const defaultExcalidrawTemplate = `---
@ -60,7 +60,7 @@ export async function createFolderNote(plugin: FolderNotesPlugin, folderPath: st
if (detachedFolder && folderNote?.extension !== extension && folderNote) {
deleteExcludedFolder(plugin, detachedFolder);
removeCSSClassFromEL(folderNote?.path, 'is-folder-note', plugin);
removeCSSClassFromFileExplorerEL(folderNote?.path, 'is-folder-note', false, plugin);
const folder = plugin.app.vault.getAbstractFileByPath(folderPath) as TFolder;
if (!folderNote || folderNote.basename !== fileName) return;
let count = 1;
@ -120,16 +120,12 @@ export async function createFolderNote(plugin: FolderNotesPlugin, folderPath: st
if (openFile) {
if (plugin.app.workspace.getActiveFile()?.path === path) {
if (plugin.activeFolderDom) {
plugin.activeFolderDom.removeClass('fn-is-active');
plugin.activeFolderDom = null;
}
removeActiveFolder(plugin);
const folder = getFolder(plugin, folderNote);
if (!folder) { return; }
plugin.activeFolderDom = getEl(folder.path, plugin);
if (plugin.activeFolderDom) plugin.activeFolderDom.addClass('fn-is-active');
setActiveFolder(folder.path, plugin);
}
await leaf.openFile(folderNote);
if (plugin.settings.folderNoteType === '.excalidraw' || extension === '.excalidraw') {
@ -144,8 +140,8 @@ export async function createFolderNote(plugin: FolderNotesPlugin, folderPath: st
const folder = plugin.app.vault.getAbstractFileByPath(folderPath);
if (!(folder instanceof TFolder)) return;
addCSSClassToTitleEL(path, 'is-folder-note', plugin, true);
addCSSClassToTitleEL(folder.path, 'has-folder-note', plugin);
addCSSClassToFileExplorerEl(path, 'is-folder-note', false, plugin, true);
addCSSClassToFileExplorerEl(folder.path, 'has-folder-note', false, plugin);
}
export async function turnIntoFolderNote(plugin: FolderNotesPlugin, file: TFile, folder: TFolder, folderNote?: TFile | null | TAbstractFile, skipConfirmation?: boolean) {
@ -156,7 +152,7 @@ export async function turnIntoFolderNote(plugin: FolderNotesPlugin, file: TFile,
if (plugin.settings.showRenameConfirmation && !skipConfirmation && !detachedExcludedFolder) {
return new ExistingFolderNoteModal(plugin.app, plugin, file, folder, folderNote).open();
}
removeCSSClassFromEL(folderNote.path, 'is-folder-note', plugin);
removeCSSClassFromFileExplorerEL(folderNote.path, 'is-folder-note', false, plugin);
const [excludedFolder, excludedFolderExisted, disabledSync] = await tempDisableSync(plugin, folder);
@ -190,16 +186,11 @@ export async function turnIntoFolderNote(plugin: FolderNotesPlugin, file: TFile,
}
await plugin.app.fileManager.renameFile(file, path);
addCSSClassToTitleEL(path, 'is-folder-note', plugin, true);
addCSSClassToTitleEL(folder.path, 'has-folder-note', plugin);
addCSSClassToFileExplorerEl(path, 'is-folder-note', false, plugin, true);
addCSSClassToFileExplorerEl(folder.path, 'has-folder-note', false, plugin);
if (plugin.activeFolderDom) {
plugin.activeFolderDom.removeClass('fn-is-active');
plugin.activeFolderDom = null;
}
plugin.activeFolderDom = getEl(folder.path, plugin);
if (plugin.activeFolderDom) plugin.activeFolderDom.addClass('fn-is-active');
removeActiveFolder(plugin);
setActiveFolder(folder.path, plugin);
}
export async function tempDisableSync(plugin: FolderNotesPlugin, folder: TFolder): Promise<[excludedFolder: ExcludedFolder | undefined, excludedFolderExisted: boolean, disabledSync: boolean]> {
@ -223,7 +214,7 @@ export async function tempDisableSync(plugin: FolderNotesPlugin, folder: TFolder
export async function openFolderNote(plugin: FolderNotesPlugin, file: TAbstractFile, evt?: MouseEvent) {
const path = file.path;
const focusExistingTab = plugin.settings.focusExistingTab;
const focusExistingTab = plugin.settings.focusExistingTab && plugin.settings.openInNewTab;
const activeFilePath = plugin.app.workspace.getActiveFile()?.path;
// If already active and not opening in new tab, do nothing
@ -265,7 +256,7 @@ export async function deleteFolderNote(plugin: FolderNotesPlugin, file: TFile, d
(excludedFolder) => (excludedFolder.path !== folder.path) && excludedFolder.showFolderNote);
plugin.saveSettings(false);
removeCSSClassFromEL(folder.path, 'has-folder-note', plugin);
removeCSSClassFromFileExplorerEL(folder.path, 'has-folder-note', false, plugin);
switch (plugin.settings.deleteFilesAction) {
case 'trash':
await plugin.app.vault.trash(file, true);

View file

@ -6,161 +6,186 @@ import { getFileExplorer } from './utils';
import { ExcludedFolder } from 'src/ExcludeFolders/ExcludeFolder';
import FolderOverviewPlugin from 'src/obsidian-folder-overview/src/main';
export function updateAllFileStyles(forceReload = false, plugin: FolderNotesPlugin) {
/**
* @description Refreshes the CSS classes for all folder notes in the file explorer.
*/
export function refreshAllFolderStyles(forceReload = false, plugin: FolderNotesPlugin) {
if (plugin.activeFileExplorer === getFileExplorer(plugin) && !forceReload) { return; }
plugin.activeFileExplorer = getFileExplorer(plugin);
plugin.app.vault.getAllLoadedFiles().forEach(async (file) => {
if (!(file instanceof TFolder)) { return; }
const folderNote = getFolderNote(plugin, file.path);
if (!folderNote) {
removeCSSClassFromEL(file?.path, 'has-folder-note', plugin);
removeCSSClassFromEL(file?.path, 'only-has-folder-note', plugin);
removeCSSClassFromFileExplorerEL(file?.path, 'has-folder-note', false, plugin);
removeCSSClassFromFileExplorerEL(file?.path, 'only-has-folder-note', true, plugin);
plugin.isEmptyFolderNoteFolder(file);
return;
}
const excludedFolder = getExcludedFolder(plugin, file.path, true);
// cleanup after ourselves
// Incase settings have changed
if (excludedFolder?.disableFolderNote) {
removeCSSClassFromEL(folderNote.path, 'is-folder-note', plugin);
removeCSSClassFromEL(file.path, 'has-folder-note', plugin);
removeCSSClassFromEL(file?.path, 'only-has-folder-note', plugin);
removeCSSClassFromFileExplorerEL(folderNote.path, 'is-folder-note', false, plugin);
removeCSSClassFromFileExplorerEL(file.path, 'has-folder-note', false, plugin);
removeCSSClassFromFileExplorerEL(file?.path, 'only-has-folder-note', true, plugin);
} else {
if (!excludedFolder?.showFolderNote) {
addCSSClassToTitleEL(folderNote.path, 'is-folder-note', plugin);
addCSSClassToFileExplorerEl(folderNote.path, 'is-folder-note', false, plugin);
}
addCSSClassesToFolder(file, plugin);
markFolderWithFolderNoteClasses(file, plugin);
}
});
}
export async function applyCSSClassesToFolder(folderPath: string, plugin: FolderNotesPlugin) {
/**
* @description Updates the CSS classes for a specific folder in the file explorer.
*/
export async function updateCSSClassesForFolder(folderPath: string, plugin: FolderNotesPlugin) {
const folder = plugin.app.vault.getAbstractFileByPath(folderPath);
if (!folder || !(folder instanceof TFolder)) { return; }
const folderNote = getFolderNote(plugin, folder.path);
// console.log('Updating CSS classes for folder:', folder.path, 'Folder Note:', folderNote);
const detachedFolderNote = getDetachedFolder(plugin, folder.path);
if (folder.children.length === 0) {
addCSSClassToTitleEL(folder.path, 'fn-empty-folder', plugin);
addCSSClassToFileExplorerEl(folder.path, 'fn-empty-folder', false, plugin);
}
if (!folderNote || detachedFolderNote) {
removeCSSClassFromEL(folder?.path, 'has-folder-note', plugin);
removeCSSClassFromEL(folder?.path, 'only-has-folder-note', plugin);
removeCSSClassFromFileExplorerEL(folder?.path, 'has-folder-note', false, plugin);
removeCSSClassFromFileExplorerEL(folder?.path, 'only-has-folder-note', true, plugin);
return;
}
const excludedFolder = getExcludedFolder(plugin, folder.path, true);
if (excludedFolder?.disableFolderNote) {
removeCSSClassFromEL(folderNote.path, 'is-folder-note', plugin);
removeCSSClassFromEL(folder.path, 'has-folder-note', plugin);
removeCSSClassFromEL(folder?.path, 'only-has-folder-note', plugin);
removeCSSClassFromFileExplorerEL(folderNote.path, 'is-folder-note', false, plugin);
removeCSSClassFromFileExplorerEL(folder.path, 'has-folder-note', false, plugin);
removeCSSClassFromFileExplorerEL(folder?.path, 'only-has-folder-note', true, plugin);
} else {
addCSSClassesToFolder(folder, plugin);
markFolderWithFolderNoteClasses(folder, plugin);
if (excludedFolder?.showFolderNote) {
removeCSSClassFromFolderNote(folderNote, plugin);
addCSSClassToFileExplorerEl(folder.path, 'show-folder-note-in-explorer', true, plugin);
unmarkFileAsFolderNote(folderNote, plugin);
return;
}
if (plugin.isEmptyFolderNoteFolder(folder)) {
addCSSClassToTitleEL(folder.path, 'only-has-folder-note', plugin);
if (plugin.isEmptyFolderNoteFolder(folder) && getFolderNote(plugin, folder.path)) {
addCSSClassToFileExplorerEl(folder.path, 'only-has-folder-note', true, plugin);
} else {
removeCSSClassFromEL(folder.path, 'only-has-folder-note', plugin);
removeCSSClassFromFileExplorerEL(folder.path, 'only-has-folder-note', true, plugin);
}
}
addCSSClassesToBothFolderAndNote(folderNote, folder, plugin);
markFolderAndNoteWithClasses(folderNote, folder, plugin);
}
export async function applyCSSClassesToFolderNote(filePath: string, plugin: FolderNotesPlugin) {
/**
* @description Updates the CSS classes for a folder note file in the file explorer and then also updates the folder it belongs to.
*/
export async function updateCSSClassesForFolderNote(filePath: string, plugin: FolderNotesPlugin) {
const file = plugin.app.vault.getAbstractFileByPath(filePath);
if (!file || !(file instanceof TFile)) { return; }
const folder = getFolder(plugin, file);
if (!folder || !(folder instanceof TFolder)) { return; }
applyCSSClassesToFolder(folder.path, plugin);
updateCSSClassesForFolder(folder.path, plugin);
}
export function addCSSClassesToBothFolderAndNote(file: TFile, folder: TFolder, plugin: FolderNotesPlugin) {
addCSSClassToFolderNote(file, plugin);
addCSSClassesToFolder(folder, plugin);
export function markFolderAndNoteWithClasses(file: TFile, folder: TFolder, plugin: FolderNotesPlugin) {
markFileAsFolderNote(file, plugin);
markFolderWithFolderNoteClasses(folder, plugin);
}
export function removeCSSClassesFromBothFolderAndNote(folder: TFolder, file: TFile, plugin: FolderNotesPlugin) {
removeCSSClassFromFolderNote(file, plugin);
removeCSSClassesFromFolder(folder, plugin);
export function clearFolderAndNoteClasses(folder: TFolder, file: TFile, plugin: FolderNotesPlugin) {
unmarkFileAsFolderNote(file, plugin);
clearFolderNoteClassesFromFolder(folder, plugin);
}
export function addCSSClassesToFolder(folder: TFolder, plugin: FolderNotesPlugin) {
addCSSClassToTitleEL(folder.path, 'has-folder-note', plugin);
if (plugin.isEmptyFolderNoteFolder(folder)) {
addCSSClassToTitleEL(folder.path, 'only-has-folder-note', plugin);
export function markFolderWithFolderNoteClasses(folder: TFolder, plugin: FolderNotesPlugin) {
addCSSClassToFileExplorerEl(folder.path, 'has-folder-note', false, plugin);
if (plugin.isEmptyFolderNoteFolder(folder) && getFolderNote(plugin, folder.path)) {
addCSSClassToFileExplorerEl(folder.path, 'only-has-folder-note', true, plugin);
} else {
removeCSSClassFromEL(folder.path, 'only-has-folder-note', plugin);
removeCSSClassFromFileExplorerEL(folder.path, 'only-has-folder-note', true, plugin);
}
}
export function addCSSClassToFolderNote(file: TFile, plugin: FolderNotesPlugin) {
addCSSClassToTitleEL(file.path, 'is-folder-note', plugin);
export function markFileAsFolderNote(file: TFile, plugin: FolderNotesPlugin) {
addCSSClassToFileExplorerEl(file.path, 'is-folder-note', false, plugin);
}
export function removeCSSClassFromFolderNote(file: TFile, plugin: FolderNotesPlugin) {
removeCSSClassFromEL(file.path, 'is-folder-note', plugin);
export function unmarkFileAsFolderNote(file: TFile, plugin: FolderNotesPlugin) {
removeCSSClassFromFileExplorerEL(file.path, 'is-folder-note', false, plugin);
}
export function removeCSSClassesFromFolder(folder: TFolder, plugin: FolderNotesPlugin) {
removeCSSClassFromEL(folder.path, 'has-folder-note', plugin);
removeCSSClassFromEL(folder.path, 'only-has-folder-note', plugin);
export function unmarkFolderAsFolderNote(folder: TFolder, plugin: FolderNotesPlugin) {
removeCSSClassFromFileExplorerEL(folder.path, 'has-folder-note', false, plugin);
removeCSSClassFromFileExplorerEL(folder.path, 'only-has-folder-note', true, plugin);
}
export async function addCSSClassToTitleEL(path: string, cssClass: string, plugin: FolderNotesPlugin, waitForCreate = false, count = 0) {
const fileExplorerItem = getEl(path, plugin);
export function clearFolderNoteClassesFromFolder(folder: TFolder, plugin: FolderNotesPlugin) {
removeCSSClassFromFileExplorerEL(folder.path, 'has-folder-note', false, plugin);
removeCSSClassFromFileExplorerEL(folder.path, 'only-has-folder-note', true, plugin);
}
/**
* @param path Can be a folder or file path
* @returns nothing
*/
export async function addCSSClassToFileExplorerEl(path: string, cssClass: string, parent = false, plugin: FolderNotesPlugin, waitForCreate = false, count = 0) {
const fileExplorerItem = getFileExplorerElement(path, plugin);
if (!fileExplorerItem) {
if (waitForCreate && count < 5) {
// sleep for a second for the file-explorer event to catch up
// this is annoying as in most scanarios our plugin recieves the event before file explorer
// If we could guarrantee load order it wouldn't be an issue but we can't
// realise this is racey and needs to be fixed.
await new Promise((r) => setTimeout(r, 500));
addCSSClassToTitleEL(path, cssClass, plugin, waitForCreate, count + 1);
addCSSClassToFileExplorerEl(path, cssClass, parent, plugin, waitForCreate, count + 1);
return;
}
return;
}
fileExplorerItem.addClass(cssClass);
const viewHeaderItems = document.querySelectorAll(`[data-path='${CSS.escape(path)}']`);
viewHeaderItems.forEach((item) => {
item.addClass(cssClass);
});
if (parent) {
const parentElement = fileExplorerItem?.parentElement;
if (parentElement) {
parentElement.addClass(cssClass);
}
} else {
fileExplorerItem.addClass(cssClass);
document.querySelectorAll(`[data-path='${CSS.escape(path)}']`).forEach((item) => {
item.addClass(cssClass);
});
}
}
export function removeCSSClassFromEL(path: string | undefined, cssClass: string, plugin: FolderNotesPlugin) {
/**
* @param path Can be a folder or file path
* @param cssClass The CSS class to remove from the file explorer element
* @returns nothing
*/
export function removeCSSClassFromFileExplorerEL(path: string | undefined, cssClass: string, parent: boolean, plugin: FolderNotesPlugin) {
if (!path) return;
const fileExplorerItem = getEl(path, plugin);
const viewHeaderItems = document.querySelectorAll(`[data-path='${CSS.escape(path)}']`);
viewHeaderItems.forEach((item) => {
const fileExplorerItem = getFileExplorerElement(path, plugin);
document.querySelectorAll(`[data-path='${CSS.escape(path)}']`).forEach((item) => {
item.removeClass(cssClass);
});
if (!fileExplorerItem) { return; }
fileExplorerItem.removeClass(cssClass);
if (parent) {
const parentElement = fileExplorerItem?.parentElement;
if (parentElement) {
parentElement.removeClass(cssClass);
}
return;
} else {
fileExplorerItem.removeClass(cssClass);
}
}
export function getEl(path: string, plugin: FolderNotesPlugin | FolderOverviewPlugin): HTMLElement | null {
export function getFileExplorerElement(path: string, plugin: FolderNotesPlugin | FolderOverviewPlugin): HTMLElement | null {
const fileExplorer = getFileExplorer(plugin);
if (!fileExplorer) { return null; }
if (!fileExplorer.view) { return null; }
if (!fileExplorer.view.fileItems) { return null; }
if (!fileExplorer?.view?.fileItems) { return null; }
const fileExplorerItem = fileExplorer.view.fileItems?.[path];
if (!fileExplorerItem) { return null; }
if (fileExplorerItem.selfEl) return fileExplorerItem.selfEl;
return fileExplorerItem.titleEl;
return fileExplorerItem?.selfEl ?? fileExplorerItem?.titleEl ?? null;
}
export function showFolderNoteInFileExplorer(path: string, plugin: FolderNotesPlugin) {
const excludedFolder = new ExcludedFolder(path, plugin.settings.excludeFolders.length, undefined, plugin);
excludedFolder.subFolders = false;
@ -172,12 +197,30 @@ export function showFolderNoteInFileExplorer(path: string, plugin: FolderNotesPl
excludedFolder.hideInSettings = true;
excludedFolder.showFolderNote = true;
addExcludedFolder(plugin, excludedFolder, false);
applyCSSClassesToFolder(path, plugin);
addCSSClassToFileExplorerEl(path, 'show-folder-note-in-explorer', true, plugin);
updateCSSClassesForFolder(path, plugin);
}
export function hideFolderNoteInFileExplorer(path: string, plugin: FolderNotesPlugin) {
export function hideFolderNoteInFileExplorer(folderPath: string, plugin: FolderNotesPlugin) {
plugin.settings.excludeFolders = plugin.settings.excludeFolders.filter(
(folder) => (folder.path !== path) && folder.showFolderNote);
(folder) => (folder.path !== folderPath) && folder.showFolderNote);
plugin.saveSettings(false);
applyCSSClassesToFolder(path, plugin);
removeCSSClassFromFileExplorerEL(folderPath, 'show-folder-note-in-explorer', true, plugin);
updateCSSClassesForFolder(folderPath, plugin);
}
export function setActiveFolder(folderPath: string, plugin: FolderNotesPlugin) {
const fileExplorerItem = getFileExplorerElement(folderPath, plugin);
if (fileExplorerItem) {
fileExplorerItem.addClass('fn-is-active');
plugin.activeFolderDom = fileExplorerItem;
}
}
export function removeActiveFolder(plugin: FolderNotesPlugin) {
if (plugin.activeFolderDom) {
plugin.activeFolderDom.removeClass('fn-is-active');
plugin.activeFolderDom?.removeClass('has-focus');
plugin.activeFolderDom = null;
}
}

View file

@ -1,12 +1,11 @@
import { Plugin, TFile, TFolder, TAbstractFile, MarkdownPostProcessorContext, parseYaml, Notice, Keymap, WorkspaceLeaf, requireApiVersion } from 'obsidian';
import { Plugin, TFile, TFolder, TAbstractFile, MarkdownPostProcessorContext, parseYaml, Notice, Keymap, WorkspaceLeaf, requireApiVersion, Platform } from 'obsidian';
import { DEFAULT_SETTINGS, FolderNotesSettings, SettingsTab } from './settings/SettingsTab';
import { Commands } from './Commands';
import { FileExplorerWorkspaceLeaf } from './globals';
import { handleFolderClick } from './events/handleClick';
import { registerFileExplorerObserver, unregisterFileExplorerObserver } from './events/MutationObserver';
import { handleRename } from './events/handleRename';
import { getFolderNote, getFolder, openFolderNote } from './functions/folderNoteFunctions';
import { getFolderNote, getFolder, openFolderNote, createFolderNote } from './functions/folderNoteFunctions';
import { handleCreate } from './events/handleCreate';
import { FrontMatterTitlePluginHandler } from './events/FrontMatterTitle';
import { FolderOverviewSettings } from './obsidian-folder-overview/src/modals/Settings';
@ -14,7 +13,7 @@ import { FolderOverview } from './obsidian-folder-overview/src/FolderOverview';
import { TabManager } from './events/TabManager';
import './functions/ListComponent';
import { handleDelete } from './events/handleDelete';
import { addCSSClassToTitleEL, getEl, updateAllFileStyles } from './functions/styleFunctions';
import { addCSSClassToFileExplorerEl, getFileExplorerElement, removeCSSClassFromFileExplorerEL, refreshAllFolderStyles, setActiveFolder, removeActiveFolder } from './functions/styleFunctions';
import { getExcludedFolder } from './ExcludeFolders/functions/folderFunctions';
import { FileExplorerView, InternalPlugin } from 'obsidian-typings';
import { getFocusedItem } from './functions/utils';
@ -110,10 +109,7 @@ export default class FolderNotesPlugin extends Plugin {
}));
this.registerEvent(this.app.workspace.on('file-open', async (openFile: TFile | null) => {
if (this.activeFolderDom) {
this.activeFolderDom.removeClass('fn-is-active');
this.activeFolderDom = null;
}
removeActiveFolder(this);
if (!openFile || !openFile.basename) { return; }
@ -124,8 +120,7 @@ export default class FolderNotesPlugin extends Plugin {
const folderNote = getFolderNote(this, folder.path);
if (!folderNote) { return; }
if (folderNote.path !== openFile.path) { return; }
this.activeFolderDom = getEl(folder.path, this);
if (this.activeFolderDom) this.activeFolderDom.addClass('fn-is-active');
setActiveFolder(folder.path, this);
}));
this.registerEvent(this.app.vault.on('rename', (file: TAbstractFile, oldPath: string) => {
@ -139,6 +134,19 @@ export default class FolderNotesPlugin extends Plugin {
this.registerMarkdownCodeBlockProcessor('folder-overview', (source: string, el: HTMLElement, ctx: MarkdownPostProcessorContext) => {
this.handleOverviewBlock(source, el, ctx);
});
this.registerEvent(
this.app.workspace.on('layout-change', () => {
const fileExplorerLeaf = this.app.workspace.getLeavesOfType('file-explorer')[0];
if (!fileExplorerLeaf) return;
const container = fileExplorerLeaf.view.containerEl;
if (container) {
this.registerDomEvent(container, 'click', (evt: MouseEvent) => {
this.handleFileExplorerClick(evt);
}, true);
}
})
);
}
onLayoutReady() {
@ -152,6 +160,16 @@ export default class FolderNotesPlugin extends Plugin {
this.tabManager = new TabManager(this);
this.tabManager.updateTabs();
const fileExplorerLeaf = this.app.workspace.getLeavesOfType('file-explorer')[0];
if (fileExplorerLeaf) {
const container = fileExplorerLeaf.view.containerEl;
if (container) {
this.registerDomEvent(container, 'click', (evt: MouseEvent) => {
this.handleFileExplorerClick(evt);
}, true);
}
}
const fileExplorerPlugin = this.app.internalPlugins.getEnabledPluginById('file-explorer');
if (fileExplorerPlugin) {
const originalRevealInFolder = fileExplorerPlugin.revealInFolder.bind(fileExplorerPlugin);
@ -219,6 +237,49 @@ export default class FolderNotesPlugin extends Plugin {
};
}
handleFileExplorerClick(evt: MouseEvent) {
const target = evt.target as HTMLElement;
if (evt.shiftKey) return;
if (Platform.isMobile && this.settings.disableOpenFolderNoteOnClick) return;
// Check if the click is on a folder
const folderTitleEl = target.closest('.nav-folder-title') as HTMLElement;
if (!folderTitleEl) return;
const onlyClickedOnFolderTitle = !!target.closest('.nav-folder-title-content');
if (!this.settings.stopWhitespaceCollapsing && !onlyClickedOnFolderTitle) return;
// Ignore clicks on the collapse icon
if (target.closest('.collapse-icon')) return;
const folderPath = folderTitleEl.getAttribute('data-path');
if (!folderPath) return;
const excludedFolder = getExcludedFolder(this, folderPath, true);
if (excludedFolder?.disableFolderNote) return;
const folderNote = getFolderNote(this, folderPath);
if (!folderNote && (evt.altKey || Keymap.isModEvent(evt) === 'tab')) {
if ((this.settings.altKey && evt.altKey) || (this.settings.ctrlKey && Keymap.isModEvent(evt) === 'tab')) {
createFolderNote(this, folderPath, true, undefined, true);
addCSSClassToFileExplorerEl(folderPath, 'has-folder-note', false, this);
removeCSSClassFromFileExplorerEL(folderPath, 'has-not-folder-note', false, this);
return;
}
}
if (!(folderNote instanceof TFile)) return;
if (this.settings.openWithCtrl && !evt.ctrlKey) return;
if (this.settings.openWithAlt && !evt.altKey) return;
if (!this.settings.enableCollapsing) {
evt.preventDefault();
evt.stopImmediatePropagation();
}
openFolderNote(this, folderNote, evt);
}
handleOverviewBlock(source: string, el: HTMLElement, ctx: MarkdownPostProcessorContext) {
const observer = new MutationObserver(() => {
@ -280,7 +341,7 @@ export default class FolderNotesPlugin extends Plugin {
const attachmentsAreInRootFolder = attachmentFolderPath === './' || attachmentFolderPath === '';
const threshold = this.settings.storageLocation === 'insideFolder' ? 1 : 0;
if (folder.children.length === 0) {
addCSSClassToTitleEL(folder.path, 'fn-empty-folder', this);
addCSSClassToFileExplorerEl(folder.path, 'fn-empty-folder', false, this);
}
if (folder.children.length === threshold) {
@ -293,7 +354,7 @@ export default class FolderNotesPlugin extends Plugin {
const attachmentFolder = this.app.vault.getAbstractFileByPath(folderPath);
if (attachmentFolder instanceof TFolder && folder.children.length <= threshold + 1) {
if (!folder.collapsed) {
getEl(folder.path, this)?.click();
getFileExplorerElement(folder.path, this)?.click();
}
}
return folder.children.length <= threshold + 1;
@ -306,7 +367,7 @@ export default class FolderNotesPlugin extends Plugin {
async changeFolderNameInExplorer(folder: TFolder, newName: string | null | undefined, waitForCreate = false, count = 0) {
if (!newName) newName = folder.name;
let fileExplorerItem = getEl(folder.path, this);
let fileExplorerItem = getFileExplorerElement(folder.path, this);
if (!fileExplorerItem) {
if (waitForCreate && count < 5) {
await new Promise((r) => setTimeout(r, 500));
@ -358,21 +419,13 @@ export default class FolderNotesPlugin extends Plugin {
});
}
reloadHandlers() {
document.querySelectorAll('div.nav-folder-title-content')
.forEach((element: HTMLElement) => {
if (element.onclick) return;
element.onclick = (event: MouseEvent) => handleFolderClick(event, this);
});
}
onunload() {
unregisterFileExplorerObserver();
document.body.classList.remove('folder-notes-plugin');
document.body.classList.remove('folder-note-underline');
document.body.classList.remove('hide-folder-note');
document.body.classList.remove('fn-whitespace-stop-collapsing');
if (this.activeFolderDom) { this.activeFolderDom.removeClass('is-active'); }
removeActiveFolder(this);
if (this.fmtpHandler) {
this.fmtpHandler.deleteEvent();
}
@ -405,7 +458,7 @@ export default class FolderNotesPlugin extends Plugin {
await this.saveData(this.settings);
// cleanup any css if we need too
if ((!this.settingsOpened || reloadStyles === true) && reloadStyles !== false) {
updateAllFileStyles(true, this);
refreshAllFolderStyles(true, this);
}
}

@ -1 +1 @@
Subproject commit 331d3aea842fea661f8979a923b466ebed161379
Subproject commit 192ecd3cd7ca983db1a9d4a97ec90333bdbc8fd8

View file

@ -5,7 +5,7 @@ import AddSupportedFileModal from '../modals/AddSupportedFileType';
import { FrontMatterTitlePluginHandler } from '../events/FrontMatterTitle';
import ConfirmationModal from './modals/CreateFnForEveryFolder';
import { TemplateSuggest } from '../suggesters/TemplateSuggester';
import { updateAllFileStyles } from '../functions/styleFunctions';
import { refreshAllFolderStyles } from '../functions/styleFunctions';
import BackupWarningModal from './modals/BackupWarning';
import RenameFolderNotesModal from './modals/RenameFns';
@ -186,7 +186,7 @@ export async function renderGeneral(settingsTab: SettingsTab) {
settingsTab.plugin.settings.storageLocation = value;
await settingsTab.plugin.saveSettings();
settingsTab.display();
updateAllFileStyles(undefined, settingsTab.plugin);
refreshAllFolderStyles(undefined, settingsTab.plugin);
})
)
.addButton((button) =>

View file

@ -1,36 +1,26 @@
/* ==========================================================================
General States & Utilities
========================================================================== */
.fn-whitespace-stop-collapsing .nav-folder-title-content {
flex-grow: 1 !important;
display: flex;
padding-bottom: 4px !important;
padding-top: 4px !important;
.hide,
.hide-folder .folder-name,
.hide-folder-note .is-folder-note {
display: none;
}
.version-1-7-2.fn-whitespace-stop-collapsing .nav-files-container .collapse-icon {
padding-top: 4px !important;
.pointer-cursor,
.has-folder-note .nav-folder-title-content:hover,
.has-folder-note.view-header-breadcrumb:hover,
.nav-folder-collapse-indicator:hover,
.fn-delete-confirmation-modal-buttons span:hover,
.fn-delete-confirmation-modal-buttons input:hover {
cursor: pointer !important;
}
.mod-rtl .fn-whitespace-stop-collapsing .nav-folder-title-content {
padding-left: 8px !important;
}
.fn-whitespace-stop-collapsing .nav-folder-title {
padding-bottom: 0 !important;
padding-top: 0 !important;
}
body:not(.mod-rtl).fn-whitespace-stop-collapsing .nav-folder-title {
padding-right: 0 !important;
}
.mod-rtl.fn-whitespace-stop-collapsing .nav-folder-title {
padding-left: 0 !important;
}
.fn-whitespace-stop-collapsing .nav-folder-collapse-indicator {
margin-top: 4px !important;
}
/* ==========================================================================
Tree Items
========================================================================== */
body:not(.is-grabbing) .tree-item-self.fn-is-active:hover,
body:not(.disable-folder-highlight) .tree-item-self.fn-is-active {
@ -39,36 +29,17 @@ body:not(.disable-folder-highlight) .tree-item-self.fn-is-active {
font-weight: var(--nav-item-weight-active);
}
.has-folder-note .nav-folder-title-content:hover,
.has-folder-note.view-header-breadcrumb:hover {
cursor: pointer;
}
.hide {
display: none;
}
.hide-folder-note .is-folder-note {
display: none;
}
.hide-folder .folder-name {
display: none;
}
.nav-folder-collapse-indicator:hover {
cursor: pointer;
}
/* ==========================================================================
Exclude Folder Settings
========================================================================== */
.fn-excluded-folder-heading {
margin-top: 0 !important;
border-top: 1px solid var(--background-modifier-border);
}
.add-exclude-folder-item {
padding-bottom: 0 !important;
}
.add-exclude-folder-item,
.fn-exclude-folder-list {
padding-bottom: 0 !important;
}
@ -91,7 +62,10 @@ body:not(.disable-folder-highlight) .tree-item-self.fn-is-active {
width: 100%;
}
/* Modal styles */
/* ==========================================================================
Modal Styles
========================================================================== */
.fn-backup-warning-modal .fn-modal-button-container {
display: flex;
@ -103,9 +77,13 @@ body:not(.disable-folder-highlight) .tree-item-self.fn-is-active {
padding-bottom: 0;
}
.fn-confirmation-modal .setting-item {
border-top: 0 !important;
padding-top: 0 !important;
}
:not(.is-phone) .fn-confirmation-modal-button {
margin-right: 0.7rem;
}
:not(.is-phone) .fn-delete-confirmation-modal-buttons {
@ -114,11 +92,6 @@ body:not(.disable-folder-highlight) .tree-item-self.fn-is-active {
margin-top: 10px;
}
.fn-delete-confirmation-modal-buttons span:hover,
.fn-delete-confirmation-modal-buttons input:hover {
cursor: pointer;
}
:not(.is-phone) .fn-delete-confirmation-modal-buttons .fn-confirmation-modal-button {
margin-left: auto;
}
@ -137,22 +110,17 @@ body:not(.disable-folder-highlight) .tree-item-self.fn-is-active {
margin-top: 10px;
}
/* Folder overview */
/* ==========================================================================
Folder Overview
========================================================================== */
.folder-overview-container.fv-remove-edit-button .folder-overview-edit-button {
display: none;
}
.fn-folder-overview-collapse-icon {
display: block !important;
}
.fn-has-no-files .collapse-icon {
display: none !important;
}
.folder-overview-list {
margin-top: 0 !important;
margin-top: 0 !important;
margin-bottom: 0 !important;
padding-bottom: 1.200 !important;
padding-top: 1.200 !important;
@ -162,7 +130,6 @@ body:not(.disable-folder-highlight) .tree-item-self.fn-is-active {
display: flex;
}
.folder-overview-list::marker {
color: var(--text-faint);
}
@ -177,12 +144,17 @@ body:not(.disable-folder-highlight) .tree-item-self.fn-is-active {
grid-template-columns: repeat(3, 1fr);
}
.folder-overview-grid-item {
flex: 1 1 auto;
margin: 0 1.2rem 1.2rem 0;
}
.folder-overview-grid-item-article article {
padding: 15px;
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 15px;
flex: 1;
}
.folder-overview-grid-item-article a {
@ -204,52 +176,9 @@ body:not(.disable-folder-highlight) .tree-item-self.fn-is-active {
}
.folder-overview-grid-item {
flex: 1 1 auto;
margin-right: 1.200rem;
margin-bottom: 1.200rem;
}
.fn-confirmation-modal .setting-item {
border-top: 0 !important;
padding-top: 0 !important;
}
.pointer-cursor {
cursor: pointer !important;
}
/* Setting tab style */
.fn-settings-tab-bar {
display: flex;
flex-direction: row;
padding-bottom: 1rem;
}
.fn-settings-tab {
display: flex;
flex-direction: row;
align-items: center;
gap: var(--size-4-2);
padding: 10px;
border: 1px solid var(--background-modifier-border)
}
.fn-settings-tab-active {
background-color: var(--color-accent);
color: var(--text-on-accent);
}
.fn-settings-tab-name {
font-weight: bold;
}
.fn-settings-tab-icon {
display: flex;
}
/* File explorer & path styles */
/* ==========================================================================
File Explorer & Path Styling
========================================================================== */
.folder-note-underline .has-folder-note .nav-folder-title-content {
text-decoration-line: underline;
@ -275,14 +204,57 @@ body:not(.disable-folder-highlight) .tree-item-self.fn-is-active {
font-style: italic;
}
.fn-hide-collapse-icon .has-folder-note.only-has-folder-note .tree-item-icon {
/* Collapse Icon Handling */
.fn-folder-overview-collapse-icon {
display: block !important;
}
.fn-has-no-files .collapse-icon,
.fn-hide-collapse-icon .has-folder-note.only-has-folder-note .tree-item-icon,
.fn-hide-empty-collapse-icon .fn-empty-folder .tree-item-icon,
.only-has-folder-note:not(.is-collapsed):not(.show-folder-note-in-explorer) > .nav-folder-children {
display: none;
}
.fn-hide-empty-collapse-icon .fn-empty-folder .tree-item-icon {
display: none;
/* ==========================================================================
Settings Tabs
========================================================================== */
.fn-settings-tab-bar {
display: flex;
flex-direction: row;
padding-bottom: 1rem;
}
.fn-settings-tab {
display: flex;
flex-direction: row;
align-items: center;
gap: var(--size-4-2);
padding: 10px;
border: 1px solid var(--background-modifier-border);
}
.fn-settings-tab-active {
background-color: var(--color-accent);
color: var(--text-on-accent);
}
.fn-settings-tab-name {
font-weight: bold;
}
.fn-settings-tab-icon {
display: flex;
}
/* ==========================================================================
Suggestion Container
========================================================================== */
.fn-suggestion-container {
position: absolute;
@ -299,12 +271,11 @@ body:not(.disable-folder-highlight) .tree-item-self.fn-is-active {
}
/* Mobile style overrides */
.is-phone .fn-overview-folder-path .setting-item-control{
display: block;
}
/* ==========================================================================
Whitelist Folder Input (Desktop & Mobile)
========================================================================== */
/* Default desktop layout */
/* Default Desktop Layout */
.fn-whitelist-folder-input-container {
display: flex;
justify-content: space-between;
@ -316,9 +287,9 @@ body:not(.disable-folder-highlight) .tree-item-self.fn-is-active {
.fn-whitelist-folder-input-container input {
flex-grow: 1;
width: auto;
box-sizing: border-box;
margin-right: 8px;
height: 40px; /* Ensure consistent height */
height: 40px;
box-sizing: border-box;
}
.fn-whitelist-folder-buttons {
@ -330,12 +301,12 @@ body:not(.disable-folder-highlight) .tree-item-self.fn-is-active {
flex-shrink: 0;
}
/* Mobile-specific layout */
/* Mobile Overrides */
@media (max-width: 768px) {
.fn-whitelist-folder-input-container {
display: block;
width: 100%;
text-align: center; /* Center elements vertically when stacked */
text-align: center;
}
.fn-whitelist-folder-input-container input {
@ -350,4 +321,8 @@ body:not(.disable-folder-highlight) .tree-item-self.fn-is-active {
align-items: center;
width: 100%;
}
}
.is-phone .fn-overview-folder-path .setting-item-control {
display: block;
}
}