#77 - Grouping implementation

This commit is contained in:
Elio Struyf
2021-09-01 09:44:15 +02:00
parent 265f788f98
commit be55a2237d
8 changed files with 104 additions and 14 deletions
+3
View File
@@ -15,6 +15,7 @@ import { Template } from './Template';
import { Notifications } from '../helpers/Notifications';
import { Settings } from '../pagesView/models/Settings';
import { Extension } from '../helpers/Extension';
import { parseJSON } from 'date-fns';
export class Dashboard {
@@ -181,6 +182,8 @@ export class Dashboard {
fmModified: file.mtime,
fmFilePath: file.filePath,
fmFileName: file.fileName,
fmDraft: article?.data.draft ? "Draft" : "Published",
fmYear: article?.data[dateField] ? parseJSON(article?.data[dateField]).getFullYear() : null,
// Make sure these are always set
title: article?.data.title,
slug: article?.data.slug,
+6
View File
@@ -0,0 +1,6 @@
export const groupBy = (array: any[], key: string) => {
return array.reduce((result, currentValue) => {
(result[currentValue[key]] = result[currentValue[key]] || []).push(currentValue);
return result;
}, {});
};
+5 -4
View File
@@ -9,6 +9,7 @@ import useDarkMode from '../../hooks/useDarkMode';
import usePages from '../hooks/usePages';
import { SponsorMsg } from './SponsorMsg';
import { WelcomeScreen } from './WelcomeScreen';
import { GroupOption } from '../constants/GroupOption';
export interface IDashboardProps {
showWelcome: boolean;
@@ -22,7 +23,7 @@ export const Dashboard: React.FunctionComponent<IDashboardProps> = ({showWelcome
const [ search, setSearch ] = React.useState<string | null>(null);
const [ tag, setTag ] = React.useState<string | null>(null);
const [ category, setCategory ] = React.useState<string | null>(null);
const [ group, setGroup ] = React.useState<string | null>(null);
const [ group, setGroup ] = React.useState<GroupOption>(GroupOption.none);
const { pageItems } = usePages(pages, tab, sorting, folder, search, tag, category);
useDarkMode();
@@ -56,13 +57,13 @@ export const Dashboard: React.FunctionComponent<IDashboardProps> = ({showWelcome
switchFolder={(folderName: string | null) => setFolder(folderName)}
switchTag={(tagId: string | null) => setTag(tagId)}
switchCategory={(categoryId: string | null) => setCategory(categoryId)}
switchGroup={(groupName: string | null) => setGroup(groupName)}
switchGroup={(groupId: GroupOption) => setGroup(groupId)}
onSearch={(value: string | null) => setSearch(value)}
settings={settings}
/>
<div className="flex-grow max-w-7xl mx-auto py-6 px-4">
{ loading ? <Spinner /> : <Overview pages={pageItems} settings={settings} /> }
<div className="w-full flex-grow max-w-7xl mx-auto py-6 px-4">
{ loading ? <Spinner /> : <Overview pages={pageItems} settings={settings} grouping={group} /> }
</div>
<SponsorMsg />
+30 -6
View File
@@ -1,14 +1,38 @@
import { Menu } from '@headlessui/react';
import * as React from 'react';
import { GroupOption } from '../../constants/GroupOption';
import { MenuButton, MenuItem, MenuItems } from '../Menu';
export interface IGroupingProps {
crntGroup: string | null;
switchGroup: (group: string | null) => void;
group: GroupOption;
switchGroup: (group: GroupOption) => void;
}
export const Grouping: React.FunctionComponent<IGroupingProps> = (props: React.PropsWithChildren<IGroupingProps>) => {
return (
<>
export const groupOptions = [
{ name: "None", id: GroupOption.none },
{ name: "Year", id: GroupOption.Year },
{ name: "Draft/Published", id: GroupOption.Draft },
];
</>
export const Grouping: React.FunctionComponent<IGroupingProps> = ({group, switchGroup}: React.PropsWithChildren<IGroupingProps>) => {
const crntGroup = groupOptions.find(x => x.id === group);
return (
<div className="flex items-center ml-6">
<Menu as="div" className="relative z-10 inline-block text-left">
<MenuButton label={`Group by`} title={crntGroup?.name || ""} />
<MenuItems>
{groupOptions.map((option) => (
<MenuItem
key={option.id}
title={option.name}
value={option.id}
isCurrent={option.id === crntGroup?.id}
onClick={switchGroup} />
))}
</MenuItems>
</Menu>
</div>
);
};
+4 -3
View File
@@ -12,6 +12,7 @@ import { Startup } from '../Startup';
import { Button } from '../Button';
import { Navigation } from '../Navigation';
import { Grouping } from '.';
import { GroupOption } from '../../constants/GroupOption';
export interface IHeaderProps {
settings: Settings;
@@ -42,8 +43,8 @@ export interface IHeaderProps {
switchCategory: (category: string | null) => void;
// Grouping
crntGroup: string | null;
switchGroup: (groupId: string | null) => void;
crntGroup: GroupOption;
switchGroup: (groupId: GroupOption) => void;
}
export const Header: React.FunctionComponent<IHeaderProps> = ({currentTab, currentSorting, switchSorting, switchTab, totalPages, crntFolder, folders, switchFolder, onSearch, settings, switchTag, crntTag, switchCategory, crntCategory, crntGroup, switchGroup}: React.PropsWithChildren<IHeaderProps>) => {
@@ -73,7 +74,7 @@ export const Header: React.FunctionComponent<IHeaderProps> = ({currentTab, curre
<Filter label={`Category filter`} activeItem={crntCategory} items={settings.categories} onClick={switchCategory} />
<Grouping crntGroup={crntGroup} switchGroup={switchGroup} />
<Grouping group={crntGroup} switchGroup={switchGroup} />
<Sorting currentSorting={currentSorting} switchSorting={switchSorting} />
</div>
+47 -1
View File
@@ -1,5 +1,9 @@
import { Disclosure } from '@headlessui/react';
import { ChevronRightIcon } from '@heroicons/react/solid';
import * as React from 'react';
import { groupBy } from '../../helpers/GroupBy';
import { FrontMatterIcon } from '../../viewpanel/components/Icons/FrontMatterIcon';
import { GroupOption } from '../constants/GroupOption';
import { Page } from '../models/Page';
import { Settings } from '../models/Settings';
import { Item } from './Item';
@@ -7,11 +11,13 @@ import { List } from './List';
export interface IOverviewProps {
pages: Page[];
grouping: GroupOption;
settings: Settings;
}
export const Overview: React.FunctionComponent<IOverviewProps> = ({pages, settings}: React.PropsWithChildren<IOverviewProps>) => {
export const Overview: React.FunctionComponent<IOverviewProps> = ({pages, settings, grouping}: React.PropsWithChildren<IOverviewProps>) => {
const [ open, setOpen ] = React.useState(true);
if (!pages || !pages.length) {
return (
@@ -32,6 +38,46 @@ export const Overview: React.FunctionComponent<IOverviewProps> = ({pages, settin
);
}
if (grouping !== GroupOption.none) {
const groupedPages = groupBy(pages, grouping === GroupOption.Year ? 'fmYear' : 'fmDraft');
let groupKeys = Object.keys(groupedPages);
if (grouping === GroupOption.Year) {
groupKeys = groupKeys.sort((a, b) => { return parseInt(b) - parseInt(a) });
}
return (
<>
{
groupKeys.map((groupId, idx) => (
<Disclosure key={groupId} as={`div`} className={`w-full`} defaultOpen>
{({ open }) => (
<>
<Disclosure.Button className={`mb-4 ${idx !== 0 ? "mt-8" : ""}`}>
<h2 className={`text-2xl font-bold flex items-center`}>
<ChevronRightIcon
className={`w-8 h-8 mr-1 ${open ? "transform rotate-90" : ""}`}
/>
{GroupOption[grouping]}: {groupId} ({groupedPages[groupId].length})
</h2>
</Disclosure.Button>
<Disclosure.Panel>
<List>
{groupedPages[groupId].map((page: Page) => (
<Item key={page.slug} {...page} />
))}
</List>
</Disclosure.Panel>
</>
)}
</Disclosure>
))
}
</>
);
}
return (
<List>
{pages.map(page => (
+7
View File
@@ -0,0 +1,7 @@
export enum GroupOption {
none = 1,
Year,
Draft
}
+2
View File
@@ -5,6 +5,8 @@ export interface Page {
fmFilePath: string;
fmFileName: string;
fmModified: number;
fmDraft: "Draft" | "Published",
fmYear: number | null;
title: string;
slug: string;