From b8dee7a5c99b5e4b15b9d2c19c5d25369e10a3a5 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Fri, 3 Sep 2021 16:45:22 +0200 Subject: [PATCH] #73 - List view --- .vscode/recoil.code-snippets | 66 +++++++++++++++ package-lock.json | 15 ++++ package.json | 9 +- src/pagesView/components/Header/Header.tsx | 7 +- .../components/Header/ViewSwitch.tsx | 30 +++++++ src/pagesView/components/Item.tsx | 84 +++++++++++++------ src/pagesView/components/List.tsx | 28 ++++++- src/pagesView/constants/Storage.ts | 1 + src/pagesView/index.tsx | 3 +- src/pagesView/state/atom/ViewAtom.ts | 14 ++++ src/pagesView/state/atom/index.ts | 1 + src/pagesView/state/index.ts | 2 + src/pagesView/state/selectors/ViewSelector.ts | 9 ++ src/pagesView/state/selectors/index.ts | 1 + 14 files changed, 235 insertions(+), 35 deletions(-) create mode 100644 .vscode/recoil.code-snippets create mode 100644 src/pagesView/components/Header/ViewSwitch.tsx create mode 100644 src/pagesView/constants/Storage.ts create mode 100644 src/pagesView/state/atom/ViewAtom.ts create mode 100644 src/pagesView/state/atom/index.ts create mode 100644 src/pagesView/state/index.ts create mode 100644 src/pagesView/state/selectors/ViewSelector.ts create mode 100644 src/pagesView/state/selectors/index.ts diff --git a/.vscode/recoil.code-snippets b/.vscode/recoil.code-snippets new file mode 100644 index 00000000..e041ee3e --- /dev/null +++ b/.vscode/recoil.code-snippets @@ -0,0 +1,66 @@ +{ + "Recoil Atom": { + "prefix": "sq-atom", + "body": [ + "import { atom } from 'recoil';", + "", + "export const ${1:CollectionId}Atom = atom({", + " key: '${1:CollectionId}Atom',", + " default: 1", + "});" + ], + "description": "Creates a new atom", + "scope": "typescript" + }, + "Recoil Selector (sync)": { + "prefix": "sq-selector-sync", + "body": [ + "import { selector } from 'recoil';", + "", + "export const ${1:CollectionData}Selector = selector({", + " key: '${1:CollectionData}Selector',", + " get: ({get}) => {", + " return get(${2:CollectionIdState});", + " }", + "});" + ], + "description": "Creates a new synchronous selector", + "scope": "typescript" + }, + "Recoil Selector (async)": { + "prefix": "sq-selector-async", + "body": [ + "import { selector } from 'recoil';", + "", + "export const ${1:CollectionData}Selector = selector({", + " key: '${1:CollectionData}Selector',", + " get: async ({get}) => {", + " return await dataFetch(get(${2:CollectionIdState}));", + " }", + "});" + ], + "description": "Creates a new asynchronous selector", + "scope": "typescript" + }, + "Recoil selectorFamily": { + "prefix": "sq-selector-fam", + "body": [ + "import { selectorFamily } from 'recoil';", + "", + "export const ${1:CollectionData}Selector = selectorFamily({", + " key: '${1:CollectionData}Selector',", + " get: id => async () => {", + " return await dataFetch({id});", + " }", + "});" + ], + "description": "Creates a selectorFamily (same as selector, but used to provide parameters)", + "scope": "typescript" + }, + "useTranslation": { + "prefix": ["sq-translation", "useTranslation"], + "body": "const { t: strings } = useTranslation();", + "description": "Include the translations", + "scope": "typescriptreact" + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index d646aea0..b46b0fb3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2638,6 +2638,12 @@ "strip-bom-string": "^1.0.0" } }, + "hamt_plus": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hamt_plus/-/hamt_plus-1.0.2.tgz", + "integrity": "sha1-4hwlKWjH4zsg9qGwlM2FeHomVgE=", + "dev": true + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -4758,6 +4764,15 @@ "picomatch": "^2.2.1" } }, + "recoil": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/recoil/-/recoil-0.4.1.tgz", + "integrity": "sha512-vp6KPwlHOjJ4bJofmdDchmgI9ilMTCoUisK8/WYLl8dThH7e7KmtZttiLgvDb2Em99dUfTEsk8vT8L1nUMgqXQ==", + "dev": true, + "requires": { + "hamt_plus": "1.0.2" + } + }, "reduce-css-calc": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz", diff --git a/package.json b/package.json index d3a22608..5b62eeeb 100644 --- a/package.json +++ b/package.json @@ -391,6 +391,8 @@ }, "devDependencies": { "@bendera/vscode-webview-elements": "0.6.2", + "@headlessui/react": "1.4.0", + "@heroicons/react": "1.0.4", "@iarna/toml": "2.2.3", "@types/glob": "7.1.3", "@types/js-yaml": "3.12.1", @@ -410,11 +412,13 @@ "gray-matter": "4.0.2", "html-loader": "1.3.2", "html-webpack-plugin": "4.5.0", + "lodash.uniqby": "4.7.0", "mdast-util-from-markdown": "1.0.0", "postcss": "^8.3.6", "postcss-loader": "4.3.0", "react": "17.0.1", "react-dom": "17.0.1", + "recoil": "^0.4.1", "style-loader": "2.0.0", "tailwindcss": "^2.2.7", "ts-loader": "8.0.3", @@ -422,10 +426,7 @@ "typescript": "4.0.2", "wc-react": "github:estruyf/wc-react", "webpack": "4.44.2", - "webpack-cli": "3.3.12", - "@headlessui/react": "1.4.0", - "@heroicons/react": "1.0.4", - "lodash.uniqby": "4.7.0" + "webpack-cli": "3.3.12" }, "dependencies": { "@docsearch/js": "^3.0.0-alpha.40" diff --git a/src/pagesView/components/Header/Header.tsx b/src/pagesView/components/Header/Header.tsx index f9e4abdb..ec0f7290 100644 --- a/src/pagesView/components/Header/Header.tsx +++ b/src/pagesView/components/Header/Header.tsx @@ -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 = ({currentTab, curre
-
+
-
+
@@ -80,6 +81,8 @@ export const Header: React.FunctionComponent = ({currentTab, curre + +
diff --git a/src/pagesView/components/Header/ViewSwitch.tsx b/src/pagesView/components/Header/ViewSwitch.tsx new file mode 100644 index 00000000..be79633f --- /dev/null +++ b/src/pagesView/components/Header/ViewSwitch.tsx @@ -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 = (props: React.PropsWithChildren) => { + 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 ( +
+ + +
+ ); +}; \ No newline at end of file diff --git a/src/pagesView/components/Item.tsx b/src/pagesView/components/Item.tsx index 3aa2cd7c..b01d5b43 100644 --- a/src/pagesView/components/Item.tsx +++ b/src/pagesView/components/Item.tsx @@ -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 = ({ fmFilePath, date, title, draft, description, preview }: React.PropsWithChildren) => { + 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 ( -
  • - -
  • - ); + +
    + +

    {title}

    + +

    {description}

    + + + + ); + } else if (view === ViewType.List) { + return ( +
  • + +
  • + ); + } + + return null; }; diff --git a/src/pagesView/components/List.tsx b/src/pagesView/components/List.tsx index abf0746b..89c6f8c4 100644 --- a/src/pagesView/components/List.tsx +++ b/src/pagesView/components/List.tsx @@ -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 = ({children}: React.PropsWithChildren) => { + 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 ( -
      +
        + {view === ViewType.List && ( +
      • +
        +
        + Title +
        +
        + Date +
        +
        + Status +
        +
        +
      • + )} {children}
      ); diff --git a/src/pagesView/constants/Storage.ts b/src/pagesView/constants/Storage.ts new file mode 100644 index 00000000..8a9dba9a --- /dev/null +++ b/src/pagesView/constants/Storage.ts @@ -0,0 +1 @@ +export const STORAGE_VIEW_TYPE = 'FrontMatter:ListViewType'; \ No newline at end of file diff --git a/src/pagesView/index.tsx b/src/pagesView/index.tsx index 7b0a6720..d76aba26 100644 --- a/src/pagesView/index.tsx +++ b/src/pagesView/index.tsx @@ -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: () => { const elm = document.querySelector("#app"); const welcome = elm?.getAttribute("data-showWelcome"); -render(, elm); \ No newline at end of file +render(, elm); \ No newline at end of file diff --git a/src/pagesView/state/atom/ViewAtom.ts b/src/pagesView/state/atom/ViewAtom.ts new file mode 100644 index 00000000..085bba1c --- /dev/null +++ b/src/pagesView/state/atom/ViewAtom.ts @@ -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({ + key: 'ViewAtom', + default: isNaN(defaultView) ? ViewType.Grid : defaultView +}); \ No newline at end of file diff --git a/src/pagesView/state/atom/index.ts b/src/pagesView/state/atom/index.ts new file mode 100644 index 00000000..d9c475b7 --- /dev/null +++ b/src/pagesView/state/atom/index.ts @@ -0,0 +1 @@ +export * from './ViewAtom'; diff --git a/src/pagesView/state/index.ts b/src/pagesView/state/index.ts new file mode 100644 index 00000000..29f3d16e --- /dev/null +++ b/src/pagesView/state/index.ts @@ -0,0 +1,2 @@ +export * from './atom'; +export * from './selectors'; diff --git a/src/pagesView/state/selectors/ViewSelector.ts b/src/pagesView/state/selectors/ViewSelector.ts new file mode 100644 index 00000000..1d1d7f82 --- /dev/null +++ b/src/pagesView/state/selectors/ViewSelector.ts @@ -0,0 +1,9 @@ +import { selector } from 'recoil'; +import { ViewAtom } from '..'; + +export const ViewSelector = selector({ + key: 'ViewSelector', + get: ({get}) => { + return get(ViewAtom); + } +}); \ No newline at end of file diff --git a/src/pagesView/state/selectors/index.ts b/src/pagesView/state/selectors/index.ts new file mode 100644 index 00000000..d68a7566 --- /dev/null +++ b/src/pagesView/state/selectors/index.ts @@ -0,0 +1 @@ +export * from './ViewSelector';