From fdcfdc971d9ad7a69725a5239100d15b35648439 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Tue, 12 Mar 2024 20:40:05 +0100 Subject: [PATCH] Multi-select hook --- .../components/Common/ItemSelection.tsx | 37 ++++++++ .../components/Contents/Item.tsx | 28 ++---- .../components/Contents/PinnedItem.tsx | 5 +- .../components/Header/ActionsBar.tsx | 86 ++++++++++--------- .../components/Header/Header.tsx | 4 +- .../components/Layout/PageLayout.tsx | 2 +- .../components/Media/Item.tsx | 21 +---- .../components/Menu/MenuButton.tsx | 2 +- .../hooks/useSelectedItems.tsx | 20 +++++ src/dashboardWebView/styles.css | 2 +- .../utils/updateCssVariables.ts | 5 ++ 11 files changed, 124 insertions(+), 88 deletions(-) create mode 100644 src/dashboardWebView/components/Common/ItemSelection.tsx create mode 100644 src/dashboardWebView/hooks/useSelectedItems.tsx diff --git a/src/dashboardWebView/components/Common/ItemSelection.tsx b/src/dashboardWebView/components/Common/ItemSelection.tsx new file mode 100644 index 00000000..b8de29e1 --- /dev/null +++ b/src/dashboardWebView/components/Common/ItemSelection.tsx @@ -0,0 +1,37 @@ +import * as React from 'react'; +import useSelectedItems from '../../hooks/useSelectedItems'; +import { VSCodeCheckbox } from '@vscode/webview-ui-toolkit/react'; +import { useMemo } from 'react'; + +export interface IItemSelectionProps { + filePath: string; + isRowItem?: boolean; +} + +export const ItemSelection: React.FunctionComponent = ({ + filePath, + isRowItem +}: React.PropsWithChildren) => { + const { onMultiSelect, selectedFiles } = useSelectedItems(); + + const cssNames = useMemo(() => { + if (isRowItem) { + return 'block'; + } + return `${selectedFiles.includes(filePath) ? 'block' : 'hidden'} absolute top-2 left-2`; + }, [isRowItem, selectedFiles]); + + return ( +
+ ) => { + e.stopPropagation(); + onMultiSelect(filePath); + }} + checked={selectedFiles.includes(filePath)} /> +
+ ); +}; \ No newline at end of file diff --git a/src/dashboardWebView/components/Contents/Item.tsx b/src/dashboardWebView/components/Contents/Item.tsx index eab6b677..89fc51d7 100644 --- a/src/dashboardWebView/components/Contents/Item.tsx +++ b/src/dashboardWebView/components/Contents/Item.tsx @@ -1,13 +1,13 @@ -import { useRecoilState, useRecoilValue } from 'recoil'; +import { useRecoilValue } from 'recoil'; import { MarkdownIcon } from '../../../panelWebView/components/Icons/MarkdownIcon'; import { DashboardMessage } from '../../DashboardMessage'; import { Page } from '../../models/Page'; -import { MultiSelectedItemsAtom, SettingsSelector, ViewSelector } from '../../state'; +import { SettingsSelector, ViewSelector } from '../../state'; import { DateField } from '../Common/DateField'; import { Messenger } from '@estruyf/vscode/dist/client'; import { DashboardViewType } from '../../models'; import { ContentActions } from './ContentActions'; -import { useCallback, useMemo } from 'react'; +import { useMemo } from 'react'; import { Status } from './Status'; import * as React from 'react'; import useExtensibility from '../../hooks/useExtensibility'; @@ -17,7 +17,7 @@ import { useNavigate } from 'react-router-dom'; import { routePaths } from '../..'; import useCard from '../../hooks/useCard'; import { I18nLabel } from './I18nLabel'; -import { VSCodeCheckbox } from '@vscode/webview-ui-toolkit/react'; +import { ItemSelection } from '../Common/ItemSelection'; export interface IItemProps extends Page { } @@ -28,7 +28,6 @@ export const Item: React.FunctionComponent = ({ }: React.PropsWithChildren) => { const view = useRecoilValue(ViewSelector); const settings = useRecoilValue(SettingsSelector); - const [selectedFiles, setSelectedFiles] = useRecoilState(MultiSelectedItemsAtom); const draftField = useMemo(() => settings?.draftField, [settings]); const cardFields = useMemo(() => settings?.dashboardState?.contents?.cardFields, [settings?.dashboardState?.contents?.cardFields]); const { escapedTitle, escapedDescription } = useCard(pageData, settings?.dashboardState?.contents?.cardFields); @@ -104,14 +103,6 @@ export const Item: React.FunctionComponent = ({ return cardFields && (cardFields.state || cardFields.date); }, [cardFields]); - const onMultiSelect = useCallback(() => { - if (selectedFiles.includes(pageData.fmFilePath)) { - setSelectedFiles(selectedFiles.filter((file) => file !== pageData.fmFilePath)); - } else { - setSelectedFiles([...selectedFiles, pageData.fmFilePath]); - } - }, [selectedFiles]); - if (view === DashboardViewType.Grid) { return (
  • @@ -143,14 +134,7 @@ export const Item: React.FunctionComponent = ({ } -
    - ) => { - e.stopPropagation(); - onMultiSelect(); - }} - checked={selectedFiles.includes(pageData.fmFilePath)} /> -
    +
    { @@ -251,6 +235,8 @@ export const Item: React.FunctionComponent = ({ 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 hover:bg-opacity-70 border-[var(--frontmatter-border)] hover:bg-[var(--vscode-sideBar-background)]`} >
    + + + +
    { diff --git a/src/dashboardWebView/components/Header/Header.tsx b/src/dashboardWebView/components/Header/Header.tsx index ec2ecdcc..8a2ac464 100644 --- a/src/dashboardWebView/components/Header/Header.tsx +++ b/src/dashboardWebView/components/Header/Header.tsx @@ -124,7 +124,7 @@ export const Header: React.FunctionComponent = ({ return (
    -
    +
    @@ -186,7 +186,7 @@ export const Header: React.FunctionComponent = ({
    diff --git a/src/dashboardWebView/components/Layout/PageLayout.tsx b/src/dashboardWebView/components/Layout/PageLayout.tsx index 93d24a72..661894ff 100644 --- a/src/dashboardWebView/components/Layout/PageLayout.tsx +++ b/src/dashboardWebView/components/Layout/PageLayout.tsx @@ -20,7 +20,7 @@ export const PageLayout: React.FunctionComponent = ({ const settings = useRecoilValue(SettingsSelector); return ( -
    +
    = ({ }: React.PropsWithChildren) => { const [, setLightbox] = useRecoilState(LightboxAtom); const [, setSelectedItemAction] = useRecoilState(SelectedItemActionAtom); - const [selectedFiles, setSelectedFiles] = useRecoilState(MultiSelectedItemsAtom); const [showAlert, setShowAlert] = useState(false); const [showSnippetSelection, setShowSnippetSelection] = useState(false); const [snippet, setSnippet] = useState(undefined); @@ -246,14 +244,6 @@ export const Item: React.FunctionComponent = ({ return null; }, [media]); - const onMultiSelect = useCallback(() => { - if (selectedFiles.includes(media.fsPath)) { - setSelectedFiles(selectedFiles.filter((file) => file !== media.fsPath)); - } else { - setSelectedFiles([...selectedFiles, media.fsPath]); - } - }, [selectedFiles]); - const clearFormData = () => { setShowSnippetFormDialog(false); setSnippet(undefined); @@ -291,14 +281,7 @@ export const Item: React.FunctionComponent = ({ {renderMedia}
    -
    - ) => { - e.stopPropagation(); - onMultiSelect(); - }} - checked={selectedFiles.includes(media.fsPath)} /> -
    + {hasViewData && (
    = ({ disabled }: React.PropsWithChildren) => { return ( -
    +
    {label}:
    diff --git a/src/dashboardWebView/hooks/useSelectedItems.tsx b/src/dashboardWebView/hooks/useSelectedItems.tsx new file mode 100644 index 00000000..9694efa8 --- /dev/null +++ b/src/dashboardWebView/hooks/useSelectedItems.tsx @@ -0,0 +1,20 @@ +import { useCallback } from 'react'; +import { useRecoilState } from 'recoil'; +import { MultiSelectedItemsAtom } from '../state'; + +export default function useSelectedItems() { + const [selectedFiles, setSelectedFiles] = useRecoilState(MultiSelectedItemsAtom); + + const onMultiSelect = useCallback((filePath: string) => { + if (selectedFiles.includes(filePath)) { + setSelectedFiles(selectedFiles.filter((file) => file !== filePath)); + } else { + setSelectedFiles([...selectedFiles, filePath]); + } + }, [selectedFiles]); + + return { + selectedFiles, + onMultiSelect + }; +} \ No newline at end of file diff --git a/src/dashboardWebView/styles.css b/src/dashboardWebView/styles.css index 45f3bde0..0c830d85 100644 --- a/src/dashboardWebView/styles.css +++ b/src/dashboardWebView/styles.css @@ -411,7 +411,7 @@ } .question { - @apply relative ml-auto mr-3 w-5/6 rounded-full rounded-br-none bg-teal-900 py-2 px-4 text-whisper-500; + @apply relative ml-auto mr-3 w-5/6 rounded-full rounded-br-none bg-teal-900 px-4 py-2 text-whisper-500; &:after { --size: 1rem; diff --git a/src/dashboardWebView/utils/updateCssVariables.ts b/src/dashboardWebView/utils/updateCssVariables.ts index 4175fa06..1308ac04 100644 --- a/src/dashboardWebView/utils/updateCssVariables.ts +++ b/src/dashboardWebView/utils/updateCssVariables.ts @@ -52,7 +52,12 @@ export const updateCssVariables = () => { ); // Borders + const borderColor = styles.getPropertyValue('--vscode-panel-border'); document.documentElement.style.setProperty('--frontmatter-border', 'var(--vscode-panel-border)'); + document.documentElement.style.setProperty( + '--frontmatter-border-preserve', + preserveColor(borderColor) || 'var(--vscode-panel-border)' + ); // Other colors which should be preserved (no opacity) const buttonBackground = styles.getPropertyValue('--vscode-button-background');