#173 - Allow to specify your own sorting

This commit is contained in:
Elio Struyf
2021-11-10 15:18:35 +01:00
parent 5b38e6fa56
commit 8261f1de1b
13 changed files with 148 additions and 26 deletions
+43 -1
View File
@@ -175,6 +175,48 @@
"markdownDescription": "Specify the folder name where all your assets are located. For instance in Hugo this is the `static` folder. [Check in the docs](https://frontmatter.codes/docs/settings#frontmatter.content.publicfolder)",
"scope": "Content"
},
"frontMatter.content.sorting": {
"type": "object",
"default": [],
"markdownDescription": "Define the sorting options for your dashboard content. [Check in the docs](https://frontmatter.codes/docs/settings#frontMatter.content.sorting)",
"items": {
"type": "object",
"properties": {
"title": {
"type": "string",
"description": "Name of the sorting label"
},
"name": {
"type": "string",
"description": "Name of the metadata field to sort by"
},
"order": {
"type": "string",
"enum": [
"asc",
"desc"
],
"description": "Order of the sorting"
},
"type": {
"type": "string",
"default": "string",
"enum": [
"string",
"date"
],
"description": "Type of the field value"
}
},
"additionalProperties": false,
"required": [
"title",
"name",
"order"
]
},
"scope": "Content"
},
"frontMatter.custom.scripts": {
"type": "array",
"default": [],
@@ -797,4 +839,4 @@
"dependencies": {
"@docsearch/js": "^3.0.0-alpha.40"
}
}
}
+3 -2
View File
@@ -1,10 +1,10 @@
import { SETTINGS_CONTENT_STATIC_FOLDER, SETTING_DATE_FIELD, SETTING_SEO_DESCRIPTION_FIELD, SETTINGS_DASHBOARD_OPENONSTART, SETTINGS_DASHBOARD_MEDIA_SNIPPET, SETTING_TAXONOMY_CONTENT_TYPES, DefaultFields, HOME_PAGE_NAVIGATION_ID, ExtensionState, COMMAND_NAME, SETTINGS_FRAMEWORK_ID, SETTINGS_CONTENT_DRAFT_FIELD } from '../constants';
import { SETTINGS_CONTENT_STATIC_FOLDER, SETTING_DATE_FIELD, SETTING_SEO_DESCRIPTION_FIELD, SETTINGS_DASHBOARD_OPENONSTART, SETTINGS_DASHBOARD_MEDIA_SNIPPET, SETTING_TAXONOMY_CONTENT_TYPES, DefaultFields, HOME_PAGE_NAVIGATION_ID, ExtensionState, COMMAND_NAME, SETTINGS_FRAMEWORK_ID, SETTINGS_CONTENT_DRAFT_FIELD, SETTINGS_CONTENT_SORTING } from '../constants';
import { ArticleHelper } from './../helpers/ArticleHelper';
import { basename, dirname, extname, join, parse } from "path";
import { existsSync, readdirSync, statSync, unlinkSync, writeFileSync } from "fs";
import { commands, Uri, ViewColumn, Webview, WebviewPanel, window, workspace, env, Position } from "vscode";
import { Settings as SettingsHelper } from '../helpers';
import { DraftField, Framework, TaxonomyType } from '../models';
import { DraftField, Framework, SortingSetting, TaxonomyType } from '../models';
import { Folders } from './Folders';
import { DashboardCommand } from '../dashboardWebView/DashboardCommand';
import { DashboardMessage } from '../dashboardWebView/DashboardMessage';
@@ -280,6 +280,7 @@ export class Dashboard {
mediaSnippet: SettingsHelper.get<string[]>(SETTINGS_DASHBOARD_MEDIA_SNIPPET) || [],
contentTypes: SettingsHelper.get(SETTING_TAXONOMY_CONTENT_TYPES) || [],
draftField: SettingsHelper.get<DraftField>(SETTINGS_CONTENT_DRAFT_FIELD),
customSorting: SettingsHelper.get<SortingSetting[]>(SETTINGS_CONTENT_SORTING),
contentFolders: Folders.get(),
crntFramework: SettingsHelper.get<string>(SETTINGS_FRAMEWORK_ID),
framework: (!isInitialized && wsFolder) ? FrameworkDetector.get(wsFolder.fsPath) : null,
+1
View File
@@ -40,6 +40,7 @@ export const SETTINGS_CONTENT_PAGE_FOLDERS = "content.pageFolders";
export const SETTINGS_CONTENT_STATIC_FOLDER = "content.publicFolder";
export const SETTINGS_CONTENT_FRONTMATTER_HIGHLIGHT = "content.fmHighlight";
export const SETTINGS_CONTENT_DRAFT_FIELD = "content.draftField";
export const SETTINGS_CONTENT_SORTING = "content.sorting";
export const SETTINGS_DASHBOARD_OPENONSTART = "dashboard.openOnStart";
export const SETTINGS_DASHBOARD_MEDIA_SNIPPET = "dashboard.mediaSnippet";
@@ -36,7 +36,7 @@ export const ClearFilters: React.FunctionComponent<IClearFiltersProps> = (props:
};
React.useEffect(() => {
if (sorting !== DEFAULT_SORTING_OPTION || folder !== DEFAULT_FOLDER_STATE || tag !== DEFAULT_TAG_STATE || category !== DEFAULT_CATEGORY_STATE) {
if (sorting.id !== DEFAULT_SORTING_OPTION || folder !== DEFAULT_FOLDER_STATE || tag !== DEFAULT_TAG_STATE || category !== DEFAULT_CATEGORY_STATE) {
setShow(true);
} else {
setShow(false);
@@ -1,36 +1,49 @@
import { Menu } from '@headlessui/react';
import * as React from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { SortOrder, SortType } from '../../../models';
import { SortOption } from '../../constants/SortOption';
import { SearchSelector, SortingAtom } from '../../state';
import { SearchSelector, SettingsSelector, SortingAtom } from '../../state';
import { MenuButton, MenuItem, MenuItems } from '../Menu';
export interface ISortingProps {}
export const sortOptions = [
{ name: "Last modified", id: SortOption.LastModified },
{ name: "By filename (asc)", id: SortOption.FileNameAsc },
{ name: "By filename (desc)", id: SortOption.FileNameDesc },
export const sortOptions: { title?: string; name: string; id: SortOption | string; order: SortOrder, type: SortType; }[] = [
{ name: "Last modified", id: SortOption.LastModified, order: SortOrder.desc, type: SortType.string },
{ name: "By filename (asc)", id: SortOption.FileNameAsc, order: SortOrder.asc, type: SortType.string },
{ name: "By filename (desc)", id: SortOption.FileNameDesc, order: SortOrder.desc, type: SortType.string },
];
export const Sorting: React.FunctionComponent<ISortingProps> = ({}: React.PropsWithChildren<ISortingProps>) => {
const [ crntSorting, setCrntSorting ] = useRecoilState(SortingAtom);
const searchValue = useRecoilValue(SearchSelector);
const settings = useRecoilValue(SettingsSelector);
const crntSort = sortOptions.find(x => x.id === crntSorting);
let allOptions = [...sortOptions];
if (settings?.customSorting) {
allOptions = [...allOptions, ...settings.customSorting.map((s) => ({
title: s.title || s.name,
name: s.name,
id: `${s.name}-${s.order}`,
order: s.order,
type: s.type
}))];
}
let crntSort = allOptions.find(x => x.id === crntSorting.id);
return (
<div className="flex items-center">
<Menu as="div" className="relative z-10 inline-block text-left">
<MenuButton label={`Sort by`} title={crntSort?.name || ""} disabled={!!searchValue} />
<MenuButton label={`Sort by`} title={crntSort?.title || crntSort?.name || ""} disabled={!!searchValue} />
<MenuItems>
{sortOptions.map((option) => (
{allOptions.map((option) => (
<MenuItem
key={option.id}
title={option.name}
value={option.id}
isCurrent={option.id === crntSorting}
title={option.title || option.name}
value={option}
isCurrent={option.id === crntSorting.id}
onClick={(value) => setCrntSorting(value)} />
))}
</MenuItems>
+3 -3
View File
@@ -1,5 +1,5 @@
export enum SortOption {
LastModified = 1,
FileNameAsc,
FileNameDesc
LastModified = "LastModified",
FileNameAsc = "FileNameAsc",
FileNameDesc = "FileNameDesc"
}
+44 -5
View File
@@ -5,6 +5,8 @@ import { Page } from '../models/Page';
import Fuse from 'fuse.js';
import { useRecoilValue } from 'recoil';
import { CategorySelector, FolderSelector, SearchSelector, SettingsSelector, SortingSelector, TabSelector, TagSelector } from '../state';
import { SortOrder, SortType } from '../../models';
import { DateHelper } from '../../helpers/DateHelper';
const fuseOptions: Fuse.IFuseOptions<Page> = {
keys: [
@@ -24,6 +26,29 @@ export default function usePages(pages: Page[]) {
const tag = useRecoilValue(TagSelector);
const category = useRecoilValue(CategorySelector);
// Sort field value alphabetically
const sortAlphabetically = (property: string) => {
return (a: Page, b: Page) => {
if (a[property] < b[property]) {
return -1;
}
if (a[property] > b[property]) {
return 1;
}
return 0;
};
};
// Sort by date
const sortByDate = (property: string) => {
return (a: Page, b: Page) => {
const dateA = DateHelper.tryParse(a[property]);
const dateB = DateHelper.tryParse(b[property]);
return (dateA || new Date(0)).getTime() - (dateB || new Date(0)).getTime();
};
};
useEffect(() => {
const draftField = settings?.draftField;
@@ -58,12 +83,26 @@ export default function usePages(pages: Page[]) {
// Sort the pages
let pagesSorted: Page[] = Object.assign([], pagesToShow);
if (!search) {
if (sorting === SortOption.FileNameAsc) {
pagesSorted = pagesToShow.sort((a, b) => a.fmFileName.toLowerCase().localeCompare(b.fmFileName.toLowerCase()));
} else if (sorting === SortOption.FileNameDesc) {
pagesSorted = pagesToShow.sort((a, b) => b.fmFileName.toLowerCase().localeCompare(a.fmFileName.toLowerCase()));
if (sorting.id === SortOption.FileNameAsc) {
pagesSorted = pagesSorted.sort(sortAlphabetically("fmFileName"));
} else if (sorting.id === SortOption.FileNameDesc) {
pagesSorted = pagesSorted.sort(sortAlphabetically("fmFileName")).reverse();
} else if (sorting.id === SortOption.LastModified) {
pagesSorted = pagesSorted.sort((a, b) => b.fmModified - a.fmModified);
} else if (sorting.id && sorting.name) {
const { order, name, type } = sorting;
if (type === SortType.string) {
pagesSorted = pagesSorted.sort(sortAlphabetically(name));
} else if (type === SortType.date) {
pagesSorted = pagesSorted.sort(sortByDate(name));
}
if (order === SortOrder.desc) {
pagesSorted = pagesSorted.reverse();
}
} else {
pagesSorted = pagesToShow.sort((a, b) => b.fmModified - a.fmModified);
pagesSorted = pagesSorted.sort((a, b) => b.fmModified - a.fmModified);
}
}
+2 -1
View File
@@ -1,7 +1,7 @@
import { VersionInfo } from '../../models/VersionInfo';
import { ViewType } from '../state';
import { ContentFolder } from '../../models/ContentFolder';
import { ContentType, DraftField, Framework } from '../../models';
import { ContentType, DraftField, Framework, SortingSetting } from '../../models';
export interface Settings {
beta: boolean;
@@ -20,4 +20,5 @@ export interface Settings {
crntFramework: string;
framework: Framework | null | undefined;
draftField: DraftField | null | undefined;
customSorting: SortingSetting[] | undefined;
}
@@ -1,9 +1,15 @@
import { atom } from 'recoil';
import { SortOrder, SortType } from '../../../models';
import { SortOption } from '../../constants/SortOption';
export const DEFAULT_SORTING_OPTION = SortOption.LastModified;
export const SortingAtom = atom<SortOption>({
export const SortingAtom = atom<{ id: SortOption, name: string, order: SortOrder, type: SortType }>({
key: 'SortingAtom',
default: DEFAULT_SORTING_OPTION
default: {
id: DEFAULT_SORTING_OPTION,
name: "",
type: SortType.string,
order: SortOrder.desc
}
});
+4
View File
@@ -0,0 +1,4 @@
export enum SortOrder {
asc = 'asc',
desc = 'desc'
}
+4
View File
@@ -0,0 +1,4 @@
export enum SortType {
string = 'string',
date = 'date'
}
+8
View File
@@ -0,0 +1,8 @@
import { SortOrder, SortType } from ".";
export interface SortingSetting {
title: string;
name: string;
order: SortOrder;
type: SortType;
}
+3
View File
@@ -5,5 +5,8 @@ export * from './DraftField';
export * from './Framework';
export * from './MediaPaths';
export * from './PanelSettings';
export * from './SortOrder';
export * from './SortType';
export * from './SortingSetting';
export * from './TaxonomyType';
export * from './VersionInfo';