#73 - List view

This commit is contained in:
Elio Struyf
2021-09-03 16:45:22 +02:00
parent 3b6a7e9b71
commit b8dee7a5c9
14 changed files with 235 additions and 35 deletions
+5 -2
View File
@@ -13,6 +13,7 @@ import { Button } from '../Button';
import { Navigation } from '../Navigation';
import { Grouping } from '.';
import { GroupOption } from '../../constants/GroupOption';
import { ViewSwitch } from './ViewSwitch';
export interface IHeaderProps {
settings: Settings;
@@ -66,11 +67,11 @@ export const Header: React.FunctionComponent<IHeaderProps> = ({currentTab, curre
</div>
<div className="px-4 flex flex-col lg:flex-row items-center border-b border-gray-200 dark:border-whisper-600">
<div className={`w-full`}>
<div className={`w-full lg:w-auto`}>
<Navigation currentTab={currentTab} totalPages={totalPages} switchTab={switchTab} />
</div>
<div className={`my-4 lg:my-0 w-full flex items-center justify-between order-first lg:order-last `}>
<div className={`my-4 lg:my-0 w-full flex items-center justify-end space-x-4 lg:space-x-6 xl:space-x-8 order-first lg:order-last`}>
<Folders crntFolder={crntFolder} folders={folders} switchFolder={switchFolder} />
<Filter label={`Tag filter`} activeItem={crntTag} items={settings.tags} onClick={switchTag} />
@@ -80,6 +81,8 @@ export const Header: React.FunctionComponent<IHeaderProps> = ({currentTab, curre
<Grouping group={crntGroup} switchGroup={switchGroup} />
<Sorting currentSorting={currentSorting} switchSorting={switchSorting} />
<ViewSwitch />
</div>
</div>
</div>
@@ -0,0 +1,30 @@
import * as React from 'react';
import { useRecoilState } from 'recoil';
import { ViewAtom, ViewType } from '../../state';
import { ViewGridIcon, ViewListIcon } from '@heroicons/react/solid';
import { STORAGE_VIEW_TYPE } from '../../constants/Storage';
export interface IViewSwitchProps {}
export const ViewSwitch: React.FunctionComponent<IViewSwitchProps> = (props: React.PropsWithChildren<IViewSwitchProps>) => {
const [ view, setView ] = useRecoilState(ViewAtom);
const toggleView = () => {
const newView = view === ViewType.Grid ? ViewType.List : ViewType.Grid;
window.localStorage.setItem(STORAGE_VIEW_TYPE, newView.toString());
setView(newView);
};
return (
<div className={`flex rounded-sm bg-vulcan-50 lg:mb-1`}>
<button className={`flex items-center p-2 rounded-l-sm ${view === ViewType.Grid ? 'bg-teal-500 text-vulcan-500' : 'text-whisper-500'}`} onClick={toggleView}>
<ViewGridIcon className={`w-4 h-4`} />
<span className={`sr-only`}>Change to grid</span>
</button>
<button className={`flex items-center p-2 rounded-r-sm ${view === ViewType.List ? 'bg-teal-500 text-vulcan-500' : 'text-whisper-500'}`} onClick={toggleView}>
<ViewListIcon className={`w-4 h-4`} />
<span className={`sr-only`}>Change to list</span>
</button>
</div>
);
};
+57 -27
View File
@@ -1,47 +1,77 @@
import * as React from 'react';
import { useRecoilValue } from 'recoil';
import { MessageHelper } from '../../helpers/MessageHelper';
import { MarkdownIcon } from '../../viewpanel/components/Icons/MarkdownIcon';
import { DashboardMessage } from '../DashboardMessage';
import { Page } from '../models/Page';
import { ViewSelector, ViewType } from '../state';
import { DateField } from './DateField';
import { Status } from './Status';
export interface IItemProps extends Page {}
export const Item: React.FunctionComponent<IItemProps> = ({ fmFilePath, date, title, draft, description, preview }: React.PropsWithChildren<IItemProps>) => {
const view = useRecoilValue(ViewSelector);
let className = '';
if (view === ViewType.Grid) {
className = `grid grid-cols-2 gap-x-4 gap-y-8 sm:grid-cols-3 sm:gap-x-6 lg:grid-cols-4 xl:gap-x-8`;
} else if (view === ViewType.List) {
className = `divide-y divide-vulcan-200`;
}
const openFile = () => {
MessageHelper.sendMessage(DashboardMessage.openFile, fmFilePath);
};
return (
<li className="relative">
<button className={`group cursor-pointer flex flex-wrap items-start content-start h-full w-full bg-gray-50 dark:bg-vulcan-200 text-vulcan-500 dark:text-whisper-500 text-left overflow-hidden shadow-md hover:shadow-xl dark:hover:bg-vulcan-100`}
onClick={openFile}>
<div className="relative h-36 w-full overflow-hidden border-b border-gray-100 dark:border-vulcan-100 dark:group-hover:border-vulcan-200">
{
preview ? (
<img src={`${preview}`} alt={title} className="absolute inset-0 h-full w-full object-cover" loading="lazy" />
) : (
<div className={`flex items-center justify-center bg-whisper-500 dark:bg-vulcan-200 dark:group-hover:bg-vulcan-100`}>
<MarkdownIcon className={`h-32 text-vulcan-100 dark:text-whisper-100`} />
</div>
)
}
</div>
<div className="p-4 w-full">
<div className={`flex justify-between items-center`}>
<Status draft={!!draft} />
<DateField value={date} />
if (view === ViewType.Grid) {
return (
<li className="relative">
<button className={`group cursor-pointer flex flex-wrap items-start content-start h-full w-full bg-gray-50 dark:bg-vulcan-200 text-vulcan-500 dark:text-whisper-500 text-left overflow-hidden shadow-md hover:shadow-xl dark:hover:bg-vulcan-100`}
onClick={openFile}>
<div className="relative h-36 w-full overflow-hidden border-b border-gray-100 dark:border-vulcan-100 dark:group-hover:border-vulcan-200">
{
preview ? (
<img src={`${preview}`} alt={title} className="absolute inset-0 h-full w-full object-cover" loading="lazy" />
) : (
<div className={`flex items-center justify-center bg-whisper-500 dark:bg-vulcan-200 dark:group-hover:bg-vulcan-100`}>
<MarkdownIcon className={`h-32 text-vulcan-100 dark:text-whisper-100`} />
</div>
)
}
</div>
<h2 className="mt-2 mb-2 font-bold">{title}</h2>
<div className="p-4 w-full">
<div className={`flex justify-between items-center`}>
<Status draft={!!draft} />
<p className="text-xs text-vulcan-200 dark:text-whisper-800">{description}</p>
</div>
</button>
</li>
);
<DateField value={date} />
</div>
<h2 className="mt-2 mb-2 font-bold">{title}</h2>
<p className="text-xs text-vulcan-200 dark:text-whisper-800">{description}</p>
</div>
</button>
</li>
);
} else if (view === ViewType.List) {
return (
<li className="relative">
<button className={`px-5 cursor-pointer w-full text-left grid grid-cols-12 gap-x-4 sm:gap-x-6 xl:gap-x-8 py-2 border-b border-vulcan-50 hover:bg-vulcan-50 hover:bg-opacity-70`} onClick={openFile}>
<div className="col-span-8 font-bold truncate">
{title}
</div>
<div className="col-span-2">
<DateField value={date} />
</div>
<div className="col-span-2">
<Status draft={!!draft} />
</div>
</button>
</li>
);
}
return null;
};
+27 -1
View File
@@ -1,10 +1,36 @@
import * as React from 'react';
import { useRecoilValue } from 'recoil';
import { ViewSelector, ViewType } from '../state';
export interface IListProps {}
export const List: React.FunctionComponent<IListProps> = ({children}: React.PropsWithChildren<IListProps>) => {
const view = useRecoilValue(ViewSelector);
let className = '';
if (view === ViewType.Grid) {
className = `grid grid-cols-2 gap-x-4 gap-y-8 sm:grid-cols-3 sm:gap-x-6 lg:grid-cols-4 xl:gap-x-8`;
} else if (view === ViewType.List) {
className = `-mx-5`;
}
return (
<ul role="list" className="grid grid-cols-2 gap-x-4 gap-y-8 sm:grid-cols-3 sm:gap-x-6 lg:grid-cols-4 xl:gap-x-8">
<ul role="list" className={className}>
{view === ViewType.List && (
<li className="px-5 relative uppercase text-vulcan-100 dark:text-whisper-900 py-2 border-b border-vulcan-50">
<div className={`grid grid-cols-12 gap-x-4 sm:gap-x-6 xl:gap-x-8`}>
<div className="col-span-8">
Title
</div>
<div className="col-span-2">
Date
</div>
<div className="col-span-2">
Status
</div>
</div>
</li>
)}
{children}
</ul>
);
+1
View File
@@ -0,0 +1 @@
export const STORAGE_VIEW_TYPE = 'FrontMatter:ListViewType';
+2 -1
View File
@@ -1,5 +1,6 @@
import * as React from "react";
import { render } from "react-dom";
import { RecoilRoot } from "recoil";
import { Dashboard } from "./components/Dashboard";
import './styles.css';
@@ -12,4 +13,4 @@ declare const acquireVsCodeApi: <T = unknown>() => {
const elm = document.querySelector("#app");
const welcome = elm?.getAttribute("data-showWelcome");
render(<Dashboard showWelcome={!!welcome} />, elm);
render(<RecoilRoot><Dashboard showWelcome={!!welcome} /></RecoilRoot>, elm);
+14
View File
@@ -0,0 +1,14 @@
import { atom } from 'recoil';
import { STORAGE_VIEW_TYPE } from '../../constants/Storage';
export enum ViewType {
Grid = 1,
List
}
const defaultView: number = parseInt(window.localStorage.getItem(STORAGE_VIEW_TYPE) as string);
export const ViewAtom = atom<ViewType>({
key: 'ViewAtom',
default: isNaN(defaultView) ? ViewType.Grid : defaultView
});
+1
View File
@@ -0,0 +1 @@
export * from './ViewAtom';
+2
View File
@@ -0,0 +1,2 @@
export * from './atom';
export * from './selectors';
@@ -0,0 +1,9 @@
import { selector } from 'recoil';
import { ViewAtom } from '..';
export const ViewSelector = selector({
key: 'ViewSelector',
get: ({get}) => {
return get(ViewAtom);
}
});
+1
View File
@@ -0,0 +1 @@
export * from './ViewSelector';