Skip to content

Commit

Permalink
Adding sorting to results view
Browse files Browse the repository at this point in the history
  • Loading branch information
TfTHacker committed Apr 20, 2024
1 parent 1dc57dd commit a5e4705
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 18 deletions.
86 changes: 86 additions & 0 deletions src/ui/SortOrderDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import type { FunctionComponent } from 'preact';
import { useEffect, useRef, useState } from 'preact/hooks';
import SNWPlugin from 'src/main';
import { SortOption } from './settings';

interface SortOptionUI {
label: string;
icon: string;
}

const sortOptions: Record<string, SortOptionUI> = {
'name-asc': {
label: 'Name',
icon: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-arrow-down-a-z"><path d="m3 16 4 4 4-4"/><path d="M7 20V4"/><path d="M20 8h-5"/><path d="M15 10V6.5a2.5 2.5 0 0 1 5 0V10"/><path d="M15 14h5l-5 6h5"/></svg>'
},
'name-desc': {
label: 'Name',
icon: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-arrow-up-z-a"><path d="m3 8 4-4 4 4"/><path d="M7 4v16"/><path d="M15 4h5l-5 6h5"/><path d="M15 20v-3.5a2.5 2.5 0 0 1 5 0V20"/><path d="M20 18h-5"/></svg>'
},
'mtime-asc': {
label: 'Date',
icon: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-arrow-down-0-1"><path d="m3 16 4 4 4-4"/><path d="M7 20V4"/><rect x="15" y="4" width="4" height="6" ry="2"/><path d="M17 20v-6h-2"/><path d="M15 20h4"/></svg>'
},
'mtime-desc': {
label: 'Date',
icon: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-arrow-up-1-0"><path d="m3 8 4-4 4 4"/><path d="M7 4v16"/><path d="M17 10V4h-2"/><path d="M15 10h4"/><rect x="15" y="14" width="4" height="6" ry="2"/></svg>'
}
};

interface HelpSourceButtonProps {
plugin: SNWPlugin;
onChange: () => void;
}

export const SortOrderDropdown: FunctionComponent<HelpSourceButtonProps> = ({ plugin, onChange }) => {
const [isOpen, setIsOpen] = useState(false);
const menuRef = useRef<HTMLDivElement>(null);

const handleButtonClick = () => {
setIsOpen(!isOpen);
};

const handleOptionClick = async (value: SortOption) => {
setIsOpen(false);
plugin.settings.sortOptionDefault = value;
await plugin.saveSettings();
onChange();
};

useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
setIsOpen(false);
}
};

document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, []);

return (
<div className="snw-sort-dropdown-wrapper" ref={menuRef}>
<button onClick={handleButtonClick} class="snw-sort-dropdown-button">
<div dangerouslySetInnerHTML={{ __html: sortOptions[plugin.settings.sortOptionDefault].icon }} />
</button>
{isOpen && (
<ul className="snw-sort-dropdown-list">
{Object.entries(sortOptions).map(([value, { label, icon }]) => (
<li
id={value}
onClick={async (e: Event) => {
e.stopPropagation();
await handleOptionClick(value as SortOption);
}}
class="snw-sort-dropdown-list-item">
<span dangerouslySetInnerHTML={{ __html: icon }} />
<span className="snw-sort-dropdown-list-item-label">{label}</span>
</li>
))}
</ul>
)}
</div>
);
};
48 changes: 42 additions & 6 deletions src/ui/components/uic-ref-area.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { setIcon } from 'obsidian';
import { getIndexedReferences } from 'src/indexer';
import SNWPlugin from 'src/main';
import { Link } from 'src/types';
import { SortOption } from '../settings';
import { getUIC_Ref_Item } from './uic-ref-item';
import { getUIC_Ref_Title_Div } from './uic-ref-title';

Expand All @@ -13,7 +14,7 @@ export function setPluginVariableUIC_RefArea(snwPlugin: SNWPlugin) {
plugin = snwPlugin;
}

//Crates the primarhy "AREA" body for displaying refrences. This is the overall wrapper for the title and individaul references
//Creates the primarhy "AREA" body for displaying refrences. This is the overall wrapper for the title and individaul references
export const getUIC_Ref_Area = async (
refType: string,
realLink: string,
Expand All @@ -26,7 +27,21 @@ export const getUIC_Ref_Area = async (
const refAreaContainerEl = createDiv();

//get title header for this reference area
refAreaContainerEl.append(getUIC_Ref_Title_Div(refType, realLink, key, filePath, refAreaItems.refCount, lineNu, isHoverView, plugin));
refAreaContainerEl.append(
getUIC_Ref_Title_Div(refType, realLink, key, filePath, refAreaItems.refCount, lineNu, isHoverView, plugin, async () => {
// Callback to re-render the references area when the sort option is changed
const refAreaEl: HTMLElement | null = refAreaContainerEl.querySelector('.snw-ref-area');
if (refAreaEl) {
refAreaEl.style.visibility = 'hidden';
while (refAreaEl.firstChild) {
refAreaEl.removeChild(refAreaEl.firstChild);
}
refAreaEl.style.visibility = 'visible';
const refAreaItems = await getRefAreaItems(refType, key, filePath);
refAreaEl.prepend(refAreaItems.response);
}
})
);

const refAreaEl = createDiv({ cls: 'snw-ref-area' });
refAreaEl.append(refAreaItems.response);
Expand All @@ -35,6 +50,25 @@ export const getUIC_Ref_Area = async (
return refAreaContainerEl;
};

const sortLinks = (links: Link[], option: SortOption): Link[] => {
return links.sort((a, b) => {
const fileA = a.sourceFile;
const fileB = b.sourceFile;
switch (option) {
case 'name-asc':
return fileA!.basename.localeCompare(fileB!.basename);
case 'name-desc':
return fileB!.basename.localeCompare(fileA!.basename);
case 'mtime-asc':
return fileA!.stat.mtime - fileB!.stat.mtime;
case 'mtime-desc':
return fileB!.stat.mtime - fileA!.stat.mtime;
default:
return 0;
}
});
};

// Creates a DIV for a colection of reference blocks to be displayed
const getRefAreaItems = async (refType: string, key: string, filePath: string): Promise<{ response: HTMLElement; refCount: number }> => {
let countOfRefs = 0;
Expand All @@ -60,10 +94,12 @@ const getRefAreaItems = async (refType: string, key: string, filePath: string):
}

// get the unique file names for files in thie refeernces
const uniqueFileKeys: Link[] = Array.from(new Set(linksToLoop.map((a) => a.sourceFile.path))).map((file_path) => {
return linksToLoop.find((a) => a.sourceFile.path === file_path);
const uniqueFileKeys: Link[] = Array.from(new Set(linksToLoop.map((a: Link) => a.sourceFile?.path))).map((file_path) => {
return linksToLoop.find((a) => a.sourceFile?.path === file_path);
});

const sortedFileKeys = sortLinks(uniqueFileKeys, plugin.settings.sortOptionDefault);

const wrapperEl = createDiv();

let maxItemsToShow = plugin.settings.maxFileCountToDisplay;
Expand All @@ -74,9 +110,9 @@ const getRefAreaItems = async (refType: string, key: string, filePath: string):

let itemsDisplayedCounter = 0;

for (let index = 0; index < uniqueFileKeys.length; index++) {
for (let index = 0; index < sortedFileKeys.length; index++) {
if (itemsDisplayedCounter > maxItemsToShow) continue;
const file_path = uniqueFileKeys[index];
const file_path = sortedFileKeys[index];
const responseItemContainerEl = createDiv();
responseItemContainerEl.addClass('snw-ref-item-container');
responseItemContainerEl.addClass('tree-item');
Expand Down
26 changes: 15 additions & 11 deletions src/ui/components/uic-ref-title.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import SNWPlugin from 'src/main';
import { hideAll } from 'tippy.js';
import { IconMoreDetails } from '../icons';
import { render } from 'preact';
import { SortOption } from '../settings';
import { SortOrderDropdown } from '../SortOrderDropdown';

export const getUIC_Ref_Title_Div = (
refType: string,
Expand All @@ -13,7 +15,8 @@ export const getUIC_Ref_Title_Div = (
refCount: number,
lineNu: number,
isPopover: boolean,
plugin: SNWPlugin
plugin: SNWPlugin,
handleSortOptionChangeCallback: () => void
): HTMLElement => {
const titleElJsx = (
<div
Expand All @@ -24,14 +27,15 @@ export const getUIC_Ref_Title_Div = (
snw-data-file-name={filePath}
snw-data-line-number={lineNu.toString()}>
<div className="snw-ref-title-popover-label">{realLink}</div>
<span
className="snw-ref-title-popover-open-sidepane-icon"
snw-ref-title-type={refType}
snw-ref-title-reallink={realLink}
snw-ref-title-key={key}
snw-data-file-name={filePath}
snw-data-line-number={lineNu.toString()}>
{isPopover && (
<SortOrderDropdown plugin={plugin} onChange={handleSortOptionChangeCallback} />
{isPopover && (
<span
className="snw-ref-title-popover-open-sidepane-icon"
snw-ref-title-type={refType}
snw-ref-title-reallink={realLink}
snw-ref-title-key={key}
snw-data-file-name={filePath}
snw-data-line-number={lineNu.toString()}>
<span
className="snw-ref-title-popover-icon"
onClick={(e: MouseEvent) => {
Expand All @@ -41,8 +45,8 @@ export const getUIC_Ref_Title_Div = (
}}>
<IconMoreDetails />
</span>
)}
</span>
</span>
)}
</div>
);

Expand Down
6 changes: 5 additions & 1 deletion src/ui/settings.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export type SortOption = 'name-asc' | 'name-desc' | 'mtime-asc' | 'mtime-desc';

export interface Settings {
enableOnStartupDesktop: boolean;
enableOnStartupMobile: boolean;
Expand All @@ -21,6 +23,7 @@ export interface Settings {
enableIgnoreObsExcludeFoldersLinksFrom: boolean; //Use Obsidians Exclude Files from folder - links from those files outgoing to other files
enableIgnoreObsExcludeFoldersLinksTo: boolean; //Use Obsidians Exclude Files from folder - links to those "excluded" files
requireModifierKeyToActivateSNWView: boolean; //require CTRL hover to activate SNW view
sortOptionDefault: SortOption;
}

export const DEFAULT_SETTINGS: Settings = {
Expand All @@ -45,5 +48,6 @@ export const DEFAULT_SETTINGS: Settings = {
enableRenderingEmbedsInLivePreview: true,
enableIgnoreObsExcludeFoldersLinksFrom: false,
enableIgnoreObsExcludeFoldersLinksTo: false,
requireModifierKeyToActivateSNWView: false
requireModifierKeyToActivateSNWView: false,
sortOptionDefault: 'name-asc'
};
52 changes: 52 additions & 0 deletions styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,58 @@ div:has(> .snw-reference),
color: transparent;
}

/* Dropdown options */
.snw-sort-dropdown-wrapper {
position: relative;
}

.snw-sort-dropdown-button {
border: none !important;
box-shadow: none !important;
width: 35px;
background-color: unset !important;
opacity: var(--snw-icon-opacity);

>svg {
width: 25px;
color: var(--tab-text-color-focused) !important;
}
}

.snw-sort-dropdown-list {
position: absolute;
right: 0;
top: 15px;
width: 90px;
padding: 5px;
z-index: 1;
border: 3px solid var(--divider-color);
border-radius: 2px;
background-color: var(--background-primary);
overflow-y: auto;
list-style: none;
color: var(--nav-item-color);
font-size: var(--nav-item-size);
font-weight: var(--nav-item-weight);
}



.snw-sort-dropdown-list-item {
padding-left: 5px;
}

.snw-sort-dropdown-list-item:hover {
background-color: var(--background-modifier-hover);
}

.snw-sort-dropdown-list-item-label {
padding-left: 5px;
position: relative;
bottom: 5px;
}



/* prevent printing of reference numbers */
@media print {
Expand Down

0 comments on commit a5e4705

Please sign in to comment.