SebastianMC / obsidian-custom-sort

Take full control over the order and sorting of folders and notes in File Explorer in Obsidian
GNU General Public License v3.0
255 stars 19 forks source link

[Feature Request] Separators #55

Closed replete closed 1 year ago

replete commented 1 year ago

This plugin works great, especially having a single sortspec to deal with manual sorting of the main navigation and pinning important notes to the top of lists.

I would love to be able to add in a UI separator to the file explorer view in my sortspec, something like this, using a simple --- delimiter:

---
sorting-spec: |
    target-folder: Daily
    Tracker
    > a-z
    target-folder: /
    Home
    ---
    Daily
    Weekly
    Projects
    Notes
    ---
    Journal
    Dreams
    Thoughts
    Writing
    ---
    Assets
    Temporary
    ...
    z-a
---

This would create a separator in the workspace which would have markup like:

<div class="nav-folder is-collapsed"/>
<div class="nav-separator">
    <div class="nav-separator-inner"></div>
 </div>

And CSS like:

.nav-folder-separator {
display:block;
width:100%:
padding: var(--some-var) var(--some-var)
}
.nav-folder-separator-inner {
/* you get the idea*/
}

I could help with the markup/CSS part if this sounds like a good idea.

SebastianMC commented 1 year ago

Hi @replete

thanks for your feedback and input!

I also needed separators so I investigated the available options to generate them on-the-fly by the plugin. It turned out that technically it is not feasible or far too complicated to be worth it.

For example, following the idea which you described is not feasible because the custom-sort plugin, same as the Obsidian File Explorer, operates at the level of logical folders-files tree. The logical tree is a reflection of the underneath filesystem and the plugin only changes the order of items in the logical tree, on-the-fly. The rendering phase (generation of HTML DOM) for the File Explorer view is done later on by Obsidian, off the logical tree. It involves the idea of a virtual view, which displays only part of the logical tree, and as user scrolls the tree up and down, expands and collapses the folders, the relevant HTML elements are created and discarded as needed, based on the logical folders-files tree. The plugin is not connected to this HTML/DOM creation phase, it operates on an earlier stage on the logical files-folders tree. And keeping this single-point-of-integration of the plugin and Obsidian is essential to make it long-term compatible with future Obsidian releases.

I also exercised another option which was to inject in the folders-files tree some artificial notes with tile like '---' (or similar approach). I didn't work either because the File Explorer HTML/DOM rendering logic got fooled for some reason. Trying to render items non existing in the filesystem caused the view refresh problems and observable slowness. Strange, I didn't investigate it further.

Eventually I ended up with a simple approach to explicitly create notes acting as separators. There is a nice unicode character U+23AF Horizontal Line Extension: which can be used as note name, repeated as many times as wanted

Taking your example as an input, you could create three notes:

Then, in the sorting specification include the names explicitly. The result could look like:

issue-55-separators

obviously for the titles you can use simple dashes, or the unicode line repeated more times, according to visual preferences

Not being ideal (the artificial notes need to exist in the vault), the approach works for me

At the same time, I'm keeping in mind the automatic generation of the separators. Maybe some new idea crosses my mind, if so I will give it a try.

replete commented 1 year ago

@SebastianMC Thank you for such a comprehensive answer.

I woke up and had an idea, and just made a very quick proof of concept:

Screenshot 2023-02-14 at 11 20 00

.nav-folder:nth-of-type(4) {
    margin-bottom:15px;
}

.nav-folder:nth-of-type(4)::after {
    content:'';
    display:block;
    height:1px;
    width:100%;
    background:var(--tx3);
    bottom:-9px;
    position:absolute;
}

If the plugin can apply a style hook (data-attribute or css class) for items that should have a separator underneath them, then through use of the seemingly reliable css variables for metrics, I could write CSS that should work for most themes without adjustments. From a quick test, it works as expected, the CSS generated content (::after) requires no new markup and because it is absolutely positioned it is not included in box model of the item it is attached to.

If the plugin could figure out what element is above the separator and add a CSS class, then the problem is only styling.

As an aside, I've spent a week hacking CSS snippets to make all the plugins I want to use look better, so my first thought was 'Can I do this in just CSS?'

.nav-folder.mod-root > .nav-folder-children > [class*=nav-]:has([data-path=Journal]),
.nav-folder.mod-root > .nav-folder-children > [class*=nav-]:has([data-path="Assets/Templater/Startup/skipFrontmatter.md"){
{
    outline: 2px solid red;
}

Almost - the :has() seems to fail, possibly due to out of spec or outdated rendering engine. Just checked, :has is supported in Chrome 105 and latest version of Obsidian is Chrome 100, so in the future I can make a basic separator hack in a css snippet.

Adding a has-separator CSS class or hook to navigation items through sortspec would be ideal, but I understand why it might feel like a shoehorned solution.

Would be pretty cool to add css class hooks to items through sort-spec though!

Thanks again for looking into this, much appreciated.

Phil

replete commented 1 year ago

For anyone else who stumbles upon this, this is my CSS hack for the time being to add separators to my main vault structure (which doesn't change much):


/* counter */
.nav-folder.mod-root > .nav-folder-children {
    counter-reset: count;
    counter-increment: count;
}
/* comment this out after you've edited the CSS rules */
.nav-folder.mod-root > .nav-folder-children > [class*=nav-]::before {
    counter-increment: count;
    content:'nth-of-type(' counter(count) ")";
    position:absolute;
    font-size:10px;
    right: 0;
    color:red;

}

.nav-folder.mod-root > .nav-folder-children > [class*=nav-]:nth-of-type(2),
.nav-folder.mod-root > .nav-folder-children > [class*=nav-]:nth-of-type(4),
.nav-folder.mod-root > .nav-folder-children > [class*=nav-]:nth-of-type(6),
.nav-folder.mod-root > .nav-folder-children > [class*=nav-]:nth-of-type(10),
.nav-folder.mod-root > .nav-folder-children > [class*=nav-]:nth-of-type(12) {
    margin-bottom: 14px;
}

.nav-folder.mod-root > .nav-folder-children > [class*=nav-]:nth-of-type(2)::after,
.nav-folder.mod-root > .nav-folder-children > [class*=nav-]:nth-of-type(4)::after,
.nav-folder.mod-root > .nav-folder-children > [class*=nav-]:nth-of-type(6)::after,
.nav-folder.mod-root > .nav-folder-children > [class*=nav-]:nth-of-type(10)::after,
.nav-folder.mod-root > .nav-folder-children > [class*=nav-]:nth-of-type(12)::after {
    content:'';
    display:block;
    height:1px;
    width:100%;
    bottom:-7px;
    left:-8px;
    background:linear-gradient(to right, var(--divider-color), transparent);
    position:absolute;
}

Screenshot 2023-02-14 at 12 21 17 Screenshot 2023-02-14 at 12 21 35

There's a css rule above that is just for figuring out the index values for the nth-of-type(x) css rules, it looks like this when its uncommented:

Screenshot 2023-02-14 at 12 28 36

Obviously, this will break when you re-sort your hierarchy, but its the best we can do with the css features available at the moment..

replete commented 1 year ago

Screenshot 2023-02-14 at 14 35 14 Btw kudos for so elegantly solving one of the most widely requested features, might be worth dropping a comment in here if you haven't already https://forum.obsidian.md/t/file-explorer-custom-sort/1602/19

SebastianMC commented 1 year ago

Hi @replete,

thank you for the feedback and all the insightful comments!

Special thanks for presenting the details of CSS-based solution. I learned a lot from it about the CSS-only no-JS visual manipulations and I'm impressed - the flexibility of the CSS-only approach is really stunning!

I have some additional comments, and the first one should make you happy :-)

1. Obsidian 1.1.9 is using Electron v21 and Chrome 106 so the :has() selector is now available!

The trick is that you can have 1.1.9 and still an older version of Chrome, because it is the version of Obsidian Installer which decides, not the version of Obsidian. Tricky and extremely confusing. Reinstalling Obsidian from scratch helps.

See this message on forum: Switching to a new Chrome version -> Obsidian 1.1.9 is using Electron v21 and Chrome 106 so the :has() selector is now available!

2. Copying this thread to Discussions section

Finding our exchange here very valuable and worth sharing, I will copy this issue to git Discussions. Closed issues (like this one) are rarely examined, at the same time Discussions section is intended to be exposed and available by definition, and the Q&A category is probably the best match for these information about introducing and customising separators in File Explorer.

3. Presenting the CSS and has()-based solution for visual separators

Knowing good news from 1. I'd appreciate if you post (in Discussions) a short description of the solution (as a kind of final comment on this thread copied there)

4. Including the hints on Separators in manual of this plugin

Not sure if people read manuals :-) Anyways, I will also copy the CSS and has()-based version description to manual of this plugin, adding references to this git issue and to the relevant section in Discussions

5. (Not) Updating this Custom Sort plugin to allow CSS-manipulations

I examined the technical side of how a plugin can manipulate HTML/CSS of File Explorer views in Obsidian and it seems... complicated. It would deserve a new plugin on its own, because - comparing to the Custom Sorting plugin - the integration points with Obsidian are different, there are more integration points, there is a need to handle a set of events to correctly populate and update the CSS/HTML adjustments, and so on.

BTW I reviewed the code of the excellent Aidenlx' Folder Note plugin to get an insight into that specific area of Obsidian programming

So, I'd rather keep the Custom Sorting plugin in its current shape, that is a lightweight plugin which modifies the logical Obsidian data structures and doesn't deal with HTML/CSS etc.

And especially when I know that the CSS and has()-based version of Separators can be applied quickly and easily, regardless of any other plugins.

6. Announcing the Custom Sorting plugin

Yes, I've spread the news about releasing of this Custom Sorting plugin in many places, including various threads in Obsidian community and Discord channels. The links there are noticed by people and followed by persons who seek this kind of solution. There is also a group of Obsidian users who want the UI-only drag & drop solution for reordering items.

thanks a lot! Seb