From 624afe9029a428a4a5eeb87ae691782ea87eab30 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Mon, 15 Jan 2024 14:41:10 +0100 Subject: [PATCH] Content tagging --- .../components/Modals/InfoDialog.tsx | 25 +---- .../TaxonomyView/TaxonomyActions.tsx | 104 ++++++++++-------- .../TaxonomyView/TaxonomyManager.tsx | 8 +- .../TaxonomyView/TaxonomyTagging.tsx | 88 +++++++++++++++ .../components/TaxonomyView/TaxonomyView.tsx | 36 ++++-- 5 files changed, 183 insertions(+), 78 deletions(-) create mode 100644 src/dashboardWebView/components/TaxonomyView/TaxonomyTagging.tsx diff --git a/src/dashboardWebView/components/Modals/InfoDialog.tsx b/src/dashboardWebView/components/Modals/InfoDialog.tsx index 33bd7561..0fba9d9b 100644 --- a/src/dashboardWebView/components/Modals/InfoDialog.tsx +++ b/src/dashboardWebView/components/Modals/InfoDialog.tsx @@ -1,7 +1,6 @@ import { Dialog, Transition } from '@headlessui/react'; import * as React from 'react'; import { Fragment } from 'react'; -import useThemeColors from '../../hooks/useThemeColors'; export interface IInfoDialogProps { icon?: JSX.Element; @@ -17,7 +16,6 @@ export const InfoDialog: React.FunctionComponent = ({ description, children }: React.PropsWithChildren) => { - const { getColors } = useThemeColors(); return ( @@ -32,11 +30,7 @@ export const InfoDialog: React.FunctionComponent = ({ leaveFrom="opacity-100" leaveTo="opacity-0" > - + {/* This element is to trick the browser into centering the modal contents. */} @@ -53,31 +47,22 @@ export const InfoDialog: React.FunctionComponent = ({ leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > -
+
{icon && ( -
+
{icon}
)}
{title}
-

{description}

+

{description}

diff --git a/src/dashboardWebView/components/TaxonomyView/TaxonomyActions.tsx b/src/dashboardWebView/components/TaxonomyView/TaxonomyActions.tsx index 1a261b00..261c05f5 100644 --- a/src/dashboardWebView/components/TaxonomyView/TaxonomyActions.tsx +++ b/src/dashboardWebView/components/TaxonomyView/TaxonomyActions.tsx @@ -18,12 +18,14 @@ export interface ITaxonomyActionsProps { field: string | null; value: string; unmapped?: boolean; + onContentTagging: (value: string) => void; } export const TaxonomyActions: React.FunctionComponent = ({ field, value, - unmapped + unmapped, + onContentTagging }: React.PropsWithChildren) => { const onEdit = useCallback(() => { Messenger.send(DashboardMessage.editTaxonomy, { @@ -60,59 +62,65 @@ export const TaxonomyActions: React.FunctionComponent = ( }); }, [field, value]); + const onTagging = useCallback(() => { + onContentTagging(value); + }, [value]); + return ( -
- {unmapped && ( + <> +
+ {unmapped && ( + + + + {l10n.t(LocalizationKey.dashboardTaxonomyViewButtonAddTitle, value)} + + + )} + - + title={`Tag content`} + onClick={onTagging}> + + {l10n.t(LocalizationKey.commonEdit)} + + + + + {l10n.t(LocalizationKey.commonEdit)} + + + + - {l10n.t(LocalizationKey.dashboardTaxonomyViewButtonAddTitle, value)} + {l10n.t(LocalizationKey.dashboardTaxonomyViewButtonMergeTitle, value)} - )} - - - {l10n.t(LocalizationKey.commonEdit)} - + + + + {l10n.t(LocalizationKey.dashboardTaxonomyViewButtonMoveTitle)} + + - - - {l10n.t(LocalizationKey.commonEdit)} - - - - - - {l10n.t(LocalizationKey.dashboardTaxonomyViewButtonMergeTitle, value)} - - - - - - - {l10n.t(LocalizationKey.dashboardTaxonomyViewButtonMoveTitle)} - - - - - - - {l10n.t(LocalizationKey.dashboardTaxonomyViewButtonDeleteTitle, value)} - - -
+ + + + {l10n.t(LocalizationKey.dashboardTaxonomyViewButtonDeleteTitle, value)} + + +
+ ); }; diff --git a/src/dashboardWebView/components/TaxonomyView/TaxonomyManager.tsx b/src/dashboardWebView/components/TaxonomyView/TaxonomyManager.tsx index 705af711..704be138 100644 --- a/src/dashboardWebView/components/TaxonomyView/TaxonomyManager.tsx +++ b/src/dashboardWebView/components/TaxonomyView/TaxonomyManager.tsx @@ -21,12 +21,14 @@ export interface ITaxonomyManagerProps { data: TaxonomyData | undefined; taxonomy: string | null; pages: Page[]; + onContentTagging: (value: string) => void; } export const TaxonomyManager: React.FunctionComponent = ({ data, taxonomy, - pages + pages, + onContentTagging }: React.PropsWithChildren) => { const settings = useRecoilValue(SettingsSelector); const { getColors } = useThemeColors(); @@ -216,7 +218,7 @@ export const TaxonomyManager: React.FunctionComponent = ( - + )) @@ -247,7 +249,7 @@ export const TaxonomyManager: React.FunctionComponent = ( - + ))} diff --git a/src/dashboardWebView/components/TaxonomyView/TaxonomyTagging.tsx b/src/dashboardWebView/components/TaxonomyView/TaxonomyTagging.tsx new file mode 100644 index 00000000..eb48ccdc --- /dev/null +++ b/src/dashboardWebView/components/TaxonomyView/TaxonomyTagging.tsx @@ -0,0 +1,88 @@ +import * as React from 'react'; +import { Page } from '../../models'; +import { useRecoilValue } from 'recoil'; +import { SettingsSelector } from '../../state'; +import { getTaxonomyField } from '../../../helpers/getTaxonomyField'; +import { Sorting } from '../../../helpers/Sorting'; +import { ArrowLeftIcon } from '@heroicons/react/24/outline'; + +export interface ITaxonomyTaggingProps { + taxonomy: string | null; + value: string; + pages: Page[]; + onDismiss: () => void; +} + +export const TaxonomyTagging: React.FunctionComponent = ({ + taxonomy, + value, + pages, + onDismiss +}: React.PropsWithChildren) => { + const settings = useRecoilValue(SettingsSelector); + + const untaggedPages = React.useMemo(() => { + let untagged: Page[] = []; + + if (!pages || !settings?.contentTypes || !taxonomy) { + return untagged; + } + + for (const page of pages) { + if (taxonomy === 'tags') { + if (!page.fmTags || page.fmTags.indexOf(value) === -1) { + untagged.push(page); + } + continue; + } else if (taxonomy === 'categories') { + if (!page.fmCategories || page.fmCategories.indexOf(value) === -1) { + untagged.push(page); + } + continue; + } else { + const contentType = settings.contentTypes.find((ct) => ct.name === page.fmContentType); + + if (!contentType) { + continue; + } + + let fieldName = getTaxonomyField(taxonomy, contentType); + + if (fieldName && (!page[fieldName] || page[fieldName].indexOf(value) === -1)) { + untagged.push(page); + } + } + } + + untagged = untagged.sort(Sorting.number('fmPublished')).reverse(); + + return untagged; + }, [pages, taxonomy, value]); + + return ( +
+
+

+ + + + {taxonomy}: {value} +

+
+ +
+
    + {untaggedPages.map((page) => ( +
  • + + {page.title} +
  • + ))} +
+
+
+ ); +}; \ No newline at end of file diff --git a/src/dashboardWebView/components/TaxonomyView/TaxonomyView.tsx b/src/dashboardWebView/components/TaxonomyView/TaxonomyView.tsx index 5e64f7bf..28d56245 100644 --- a/src/dashboardWebView/components/TaxonomyView/TaxonomyView.tsx +++ b/src/dashboardWebView/components/TaxonomyView/TaxonomyView.tsx @@ -14,6 +14,7 @@ import { SponsorMsg } from '../Layout/SponsorMsg'; import { TaxonomyManager } from './TaxonomyManager'; import * as l10n from '@vscode/l10n'; import { LocalizationKey } from '../../../localization'; +import { TaxonomyTagging } from './TaxonomyTagging'; export interface ITaxonomyViewProps { pages: Page[]; @@ -25,6 +26,7 @@ export const TaxonomyView: React.FunctionComponent = ({ const settings = useRecoilValue(SettingsSelector); const [taxonomySettings, setTaxonomySettings] = useState(); const [selectedTaxonomy, setSelectedTaxonomy] = useState(`tags`); + const [contentTagging, setContentTagging] = useState(null); const onImport = () => { Messenger.send(DashboardMessage.importTaxonomy); @@ -62,7 +64,10 @@ export const TaxonomyView: React.FunctionComponent = ({ > setSelectedTaxonomy(`tags`)} + onClick={() => { + setSelectedTaxonomy(`tags`); + setContentTagging(null); + }} > {l10n.t(LocalizationKey.dashboardTaxonomyViewTaxonomyViewNavigationItemTags)} @@ -70,7 +75,10 @@ export const TaxonomyView: React.FunctionComponent = ({ setSelectedTaxonomy(`categories`)} + onClick={() => { + setSelectedTaxonomy(`categories`); + setContentTagging(null); + }} > {l10n.t(LocalizationKey.dashboardTaxonomyViewTaxonomyViewNavigationItemCategories)} @@ -81,7 +89,10 @@ export const TaxonomyView: React.FunctionComponent = ({ setSelectedTaxonomy(taxonomy.id)} + onClick={() => { + setSelectedTaxonomy(taxonomy.id); + setContentTagging(null); + }} > {taxonomy.id} @@ -90,10 +101,21 @@ export const TaxonomyView: React.FunctionComponent = ({
- + { + contentTagging ? ( + setContentTagging(null)} /> + ) : ( + setContentTagging(value)} /> + ) + }