mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-08-07 09:23:00 +02:00
#73 - List view
This commit is contained in:
@@ -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>
|
||||
);
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export const STORAGE_VIEW_TYPE = 'FrontMatter:ListViewType';
|
||||
@@ -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);
|
||||
@@ -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
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
export * from './ViewAtom';
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
export * from './ViewSelector';
|
||||
Reference in New Issue
Block a user