mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-07-05 09:21:39 +02:00
Changes to the taxonomy dashboard
This commit is contained in:
@@ -30,7 +30,13 @@ export const Item: React.FunctionComponent<IItemProps> = ({ fmFilePath, date, ti
|
||||
}
|
||||
|
||||
const tagField = settings.dashboardState.contents.tags;
|
||||
return pageData[tagField] || [];
|
||||
const tagsValue = pageData[tagField] || [];
|
||||
|
||||
if (Array.isArray(tagsValue)) {
|
||||
return tagsValue;
|
||||
}
|
||||
|
||||
return [tagsValue];
|
||||
}, [settings, pageData]);
|
||||
|
||||
if (view === DashboardViewType.Grid) {
|
||||
|
||||
@@ -20,6 +20,7 @@ import { ToastContainer, toast, Slide } from 'react-toastify';
|
||||
import 'react-toastify/dist/ReactToastify.css';
|
||||
import { DataType } from '../../../models/DataType';
|
||||
import { TelemetryEvent } from '../../../constants';
|
||||
import { NavigationItem } from '../Layout';
|
||||
|
||||
export interface IDataViewProps {}
|
||||
|
||||
@@ -150,14 +151,13 @@ export const DataView: React.FunctionComponent<IDataViewProps> = (props: React.P
|
||||
{
|
||||
(dataFiles && dataFiles.length > 0) && (
|
||||
dataFiles.map((dataFile, idx) => (
|
||||
<button
|
||||
<NavigationItem
|
||||
key={`${dataFile.id}-${idx}`}
|
||||
type='button'
|
||||
className={`px-4 py-2 flex items-center text-sm font-medium w-full text-left hover:bg-gray-200 dark:hover:bg-vulcan-400 hover:text-vulcan-500 dark:hover:text-whisper-500 ${selectedData?.id === dataFile.id ? 'bg-gray-300 dark:bg-vulcan-300 text-vulcan-500 dark:text-whisper-500' : 'text-gray-500 dark:text-whisper-900'}`}
|
||||
isSelected={selectedData?.id === dataFile.id}
|
||||
onClick={() => setSchema(dataFile)}>
|
||||
<ChevronRightIcon className='-ml-1 w-5 mr-2' />
|
||||
<span>{dataFile.title}</span>
|
||||
</button>
|
||||
</NavigationItem>
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface INavigationBarProps {
|
||||
title?: string;
|
||||
bottom?: JSX.Element;
|
||||
}
|
||||
|
||||
export const NavigationBar: React.FunctionComponent<INavigationBarProps> = ({title, bottom, children}: React.PropsWithChildren<INavigationBarProps>) => {
|
||||
return (
|
||||
<aside className={`w-2/12 px-4 py-6 h-full flex flex-col flex-grow border-r border-gray-200 dark:border-vulcan-300`}>
|
||||
{
|
||||
title && <h2 className={`text-lg text-gray-500 dark:text-whisper-900`}>{title}</h2>
|
||||
}
|
||||
|
||||
<nav className={`flex-1 py-4 -mx-4 h-full`}>
|
||||
<div className={`divide-y divide-gray-200 dark:divide-vulcan-300 border-t border-b border-gray-200 dark:border-vulcan-300`}>
|
||||
<div>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{
|
||||
bottom && bottom
|
||||
}
|
||||
</aside>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface INavigationItemProps {
|
||||
isSelected?: boolean;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
export const NavigationItem: React.FunctionComponent<INavigationItemProps> = ({isSelected, onClick, children}: React.PropsWithChildren<INavigationItemProps>) => {
|
||||
return (
|
||||
<button
|
||||
type='button'
|
||||
className={`px-4 py-2 flex items-center text-sm font-medium w-full text-left hover:bg-gray-200 dark:hover:bg-vulcan-400 hover:text-vulcan-500 dark:hover:text-whisper-500 cursor-pointer ${isSelected ? 'bg-gray-300 dark:bg-vulcan-300 text-vulcan-500 dark:text-whisper-500' : 'text-gray-500 dark:text-whisper-900'}`}
|
||||
onClick={onClick}>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
@@ -5,11 +5,12 @@ import { Header } from '../Header';
|
||||
|
||||
export interface IPageLayoutProps {
|
||||
header?: React.ReactNode;
|
||||
folders?: string[] | undefined
|
||||
totalPages?: number | undefined
|
||||
folders?: string[] | undefined;
|
||||
totalPages?: number | undefined;
|
||||
contentClass?: string;
|
||||
}
|
||||
|
||||
export const PageLayout: React.FunctionComponent<IPageLayoutProps> = ({ header, folders, totalPages, children }: React.PropsWithChildren<IPageLayoutProps>) => {
|
||||
export const PageLayout: React.FunctionComponent<IPageLayoutProps> = ({ header, folders, totalPages, contentClass, children }: React.PropsWithChildren<IPageLayoutProps>) => {
|
||||
const settings = useRecoilValue(SettingsSelector);
|
||||
|
||||
return (
|
||||
@@ -20,7 +21,7 @@ export const PageLayout: React.FunctionComponent<IPageLayoutProps> = ({ header,
|
||||
totalPages={totalPages}
|
||||
settings={settings} />
|
||||
|
||||
<div className="w-full flex justify-between flex-col flex-grow max-w-7xl mx-auto pt-6 px-4">
|
||||
<div className={contentClass || "w-full flex justify-between flex-col flex-grow max-w-7xl mx-auto pt-6 px-4"}>
|
||||
{ children }
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './NavigationBar';
|
||||
export * from './NavigationItem';
|
||||
export * from './PageLayout';
|
||||
@@ -83,7 +83,7 @@ export const Snippets: React.FunctionComponent<ISnippetsProps> = (props: React.P
|
||||
</FeatureFlag>
|
||||
)}>
|
||||
|
||||
<div className="flex flex-col">
|
||||
<div className="flex flex-col h-full">
|
||||
{
|
||||
viewData?.data?.filePath && (
|
||||
<div className={`text-xl text-center mb-6`}>
|
||||
|
||||
@@ -12,7 +12,7 @@ export interface ISponsorMsgProps {
|
||||
export const SponsorMsg: React.FunctionComponent<ISponsorMsgProps> = ({beta, isBacker, version}: React.PropsWithChildren<ISponsorMsgProps>) => {
|
||||
|
||||
return (
|
||||
<p className={`bg-gray-100 dark:bg-vulcan-500 w-full px-4 text-vulcan-50 dark:text-whisper-900 py-2 text-center space-x-8 flex items-center border-t border-gray-200 dark:border-vulcan-300 ${isBacker ? 'justify-center' : 'justify-between'}`}>
|
||||
<footer className={`bg-gray-100 dark:bg-vulcan-500 w-full px-4 text-vulcan-50 dark:text-whisper-900 py-2 text-center space-x-8 flex items-center border-t border-gray-200 dark:border-vulcan-300 ${isBacker ? 'justify-center' : 'justify-between'}`}>
|
||||
{
|
||||
isBacker ? (
|
||||
<span>Front Matter{version ? ` (v${version.installedVersion}${!!beta ? ` BETA` : ''})` : ''}</span>
|
||||
@@ -28,6 +28,6 @@ export const SponsorMsg: React.FunctionComponent<ISponsorMsgProps> = ({beta, isB
|
||||
</>
|
||||
)
|
||||
}
|
||||
</p>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
@@ -33,6 +33,7 @@ const Folder = ({ wsFolder, folder, folders, addFolder }: { wsFolder: string, fo
|
||||
|
||||
export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps> = ({settings}: React.PropsWithChildren<IStepsToGetStartedProps>) => {
|
||||
const [framework, setFramework] = useState<string | null>(null);
|
||||
const [taxImported, setTaxImported] = useState<boolean>(false);
|
||||
|
||||
const frameworks: Framework[] = FrameworkDetectors.map((detector: any) => detector.framework);
|
||||
|
||||
@@ -55,6 +56,11 @@ export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps>
|
||||
Messenger.send(DashboardMessage.reload);
|
||||
};
|
||||
|
||||
const importTaxonomy = () => {
|
||||
Messenger.send(DashboardMessage.importTaxonomy);
|
||||
setTaxImported(true);
|
||||
}
|
||||
|
||||
const steps = [
|
||||
{
|
||||
name: 'Initialize project',
|
||||
@@ -136,6 +142,12 @@ export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps>
|
||||
),
|
||||
status: settings.contentFolders && settings.contentFolders.length > 0 ? Status.Completed : Status.NotStarted
|
||||
},
|
||||
{
|
||||
name: 'Import all tags and categories (optional)',
|
||||
description: <>Now that Front Matter knows all the content folders. Would you like to import all tags and categories from the available content?</>,
|
||||
status: taxImported ? Status.Completed : Status.NotStarted,
|
||||
onClick: settings.contentFolders && settings.contentFolders.length > 0 ? importTaxonomy : undefined
|
||||
},
|
||||
{
|
||||
name: 'Show the dashboard',
|
||||
description: <>Once all actions are completed, the dashboard can be loaded.</>,
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
import { Messenger } from '@estruyf/vscode/dist/client';
|
||||
import { PencilIcon, PlusIcon, TrashIcon } from '@heroicons/react/outline';
|
||||
import * as React from 'react';
|
||||
import { useCallback } from 'react';
|
||||
import { MergeIcon } from '../../../components/icons/MergeIcon';
|
||||
import { DashboardMessage } from '../../DashboardMessage';
|
||||
|
||||
export interface ITaxonomyActionsProps {
|
||||
field: string | null;
|
||||
value: string;
|
||||
unmapped?: boolean;
|
||||
}
|
||||
|
||||
export const TaxonomyActions: React.FunctionComponent<ITaxonomyActionsProps> = ({field, value, unmapped}: React.PropsWithChildren<ITaxonomyActionsProps>) => {
|
||||
|
||||
const onEdit = useCallback(() => {
|
||||
Messenger.send(DashboardMessage.editTaxonomy, {
|
||||
type: field,
|
||||
value
|
||||
});
|
||||
}, [field, value]);
|
||||
|
||||
const onAdd = useCallback(() => {
|
||||
Messenger.send(DashboardMessage.addToTaxonomy, {
|
||||
type: field,
|
||||
value
|
||||
});
|
||||
}, [field, value]);
|
||||
|
||||
const onMerge = useCallback(() => {
|
||||
Messenger.send(DashboardMessage.mergeTaxonomy, {
|
||||
type: field,
|
||||
value
|
||||
});
|
||||
}, [field, value]);
|
||||
|
||||
const onDelete = useCallback(() => {
|
||||
Messenger.send(DashboardMessage.deleteTaxonomy, {
|
||||
type: field,
|
||||
value
|
||||
});
|
||||
}, [field, value]);
|
||||
|
||||
return (
|
||||
<div className={`space-x-2`}>
|
||||
{
|
||||
unmapped && (
|
||||
<button
|
||||
className='text-gray-500 hover:text-vulcan-600 dark:text-gray-800 dark:hover:text-whisper-600'
|
||||
type={`button`}
|
||||
title={`Add ${value} to taxonomy settings`}
|
||||
onClick={onAdd}>
|
||||
<PlusIcon className={`w-4 h-4`} aria-hidden={true} />
|
||||
<span className='sr-only'>Add to settings</span>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
<button
|
||||
className='text-gray-500 hover:text-vulcan-600 dark:text-gray-800 dark:hover:text-whisper-600'
|
||||
type={`button`}
|
||||
title={`Edit ${value}`}
|
||||
onClick={onEdit}>
|
||||
<PencilIcon className={`w-4 h-4`} aria-hidden={true} />
|
||||
<span className='sr-only'>Edit</span>
|
||||
</button>
|
||||
<button
|
||||
className='text-gray-500 hover:text-vulcan-600 dark:text-gray-800 dark:hover:text-whisper-600'
|
||||
type={`button`}
|
||||
title={`Merge ${value}`}
|
||||
onClick={onMerge}>
|
||||
<MergeIcon className={`w-4 h-4`} aria-hidden={true} />
|
||||
<span className='sr-only'>Merge</span>
|
||||
</button>
|
||||
<button
|
||||
className='text-gray-500 hover:text-vulcan-600 dark:text-gray-800 dark:hover:text-whisper-600'
|
||||
type={`button`}
|
||||
title={`Delete ${value}`}
|
||||
onClick={onDelete}>
|
||||
<TrashIcon className={`w-4 h-4`} aria-hidden={true} />
|
||||
<span className='sr-only'>Delete</span>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
import * as React from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { Page } from '../../models';
|
||||
import { SettingsSelector } from '../../state';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { getTaxonomyField } from '../../utils';
|
||||
|
||||
export interface ITaxonomyLookupProps {
|
||||
taxonomy: string | null;
|
||||
value: string;
|
||||
pages: Page[];
|
||||
}
|
||||
|
||||
export const TaxonomyLookup: React.FunctionComponent<ITaxonomyLookupProps> = ({ taxonomy, value, pages }: React.PropsWithChildren<ITaxonomyLookupProps>) => {
|
||||
const settings = useRecoilValue(SettingsSelector);
|
||||
|
||||
const total = useMemo(() => {
|
||||
if (!taxonomy || !value || !pages || !settings?.contentTypes) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pages.filter(page => {
|
||||
const contentType = settings.contentTypes.find(ct => ct.name === page.fmContentType);
|
||||
|
||||
if (!contentType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let fieldName = getTaxonomyField(taxonomy, contentType);
|
||||
|
||||
return fieldName && page[fieldName] ? page[fieldName].includes(value) : false;
|
||||
}).length;
|
||||
}, [taxonomy, value, pages, settings?.contentTypes]);
|
||||
|
||||
return (
|
||||
<span className={``}>
|
||||
{total}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,179 @@
|
||||
import { Messenger } from '@estruyf/vscode/dist/client';
|
||||
import { ExclamationIcon, PlusSmIcon, TagIcon } from '@heroicons/react/outline';
|
||||
import * as React from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { TaxonomyData } from '../../../models';
|
||||
import { DashboardMessage } from '../../DashboardMessage';
|
||||
import { Page } from '../../models';
|
||||
import { SettingsSelector } from '../../state';
|
||||
import { getTaxonomyField } from '../../utils';
|
||||
import { TaxonomyActions } from './TaxonomyActions';
|
||||
import { TaxonomyLookup } from './TaxonomyLookup';
|
||||
|
||||
export interface ITaxonomyManagerProps {
|
||||
data: TaxonomyData | undefined;
|
||||
taxonomy: string | null;
|
||||
pages: Page[];
|
||||
}
|
||||
|
||||
export const TaxonomyManager: React.FunctionComponent<ITaxonomyManagerProps> = ({ data, taxonomy, pages }: React.PropsWithChildren<ITaxonomyManagerProps>) => {
|
||||
const settings = useRecoilValue(SettingsSelector);
|
||||
|
||||
const onCreate = () => {
|
||||
Messenger.send(DashboardMessage.createTaxonomy, {
|
||||
type: taxonomy
|
||||
});
|
||||
};
|
||||
|
||||
const items = useMemo(() => {
|
||||
if (data && taxonomy) {
|
||||
let crntItems: string[] = [];
|
||||
|
||||
if (taxonomy === "tags" || taxonomy === "categories") {
|
||||
crntItems = data[taxonomy];
|
||||
} else {
|
||||
crntItems = data.customTaxonomy.find(c => c.id === taxonomy)?.options || [];
|
||||
}
|
||||
|
||||
// Alphabetically sort the items
|
||||
crntItems = Object.assign([], crntItems).sort((a: string, b: string) => {
|
||||
if (a.toLowerCase() < b.toLowerCase()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (a.toLowerCase() > b.toLowerCase()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
return crntItems;
|
||||
}
|
||||
|
||||
return [];
|
||||
}, [data, taxonomy]);
|
||||
|
||||
const unmappedItems = useMemo(() => {
|
||||
let unmapped: string[] = [];
|
||||
|
||||
if (!pages || !settings?.contentTypes || !taxonomy) {
|
||||
return unmapped;
|
||||
}
|
||||
|
||||
for (const page of pages) {
|
||||
const contentType = settings.contentTypes.find(ct => ct.name === page.fmContentType);
|
||||
|
||||
if (!contentType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let fieldName = getTaxonomyField(taxonomy, contentType);
|
||||
|
||||
if (fieldName && page[fieldName]) {
|
||||
const values = page[fieldName];
|
||||
|
||||
for (const value of values) {
|
||||
if (!items.includes(value)) {
|
||||
unmapped.push(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [...new Set(unmapped)];
|
||||
}, [items, taxonomy, pages, settings?.contentTypes]);
|
||||
|
||||
return (
|
||||
<div className={`py-6 px-4`}>
|
||||
<div className={`flex w-full justify-between`}>
|
||||
<div>
|
||||
<h2 className={`text-lg text-gray-500 dark:text-whisper-900 first-letter:uppercase`}>{taxonomy}</h2>
|
||||
<p className={`mt-2 text-sm text-gray-500 dark:text-whisper-900 first-letter:uppercase`}>Create, edit, and manage the {taxonomy} of your site</p>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
className={`inline-flex items-center px-3 py-1 border border-transparent text-xs leading-4 font-medium text-white dark:text-vulcan-500 bg-teal-600 hover:bg-teal-700 focus:outline-none disabled:bg-gray-500`}
|
||||
title={`Create a new ${taxonomy} value`}
|
||||
onClick={onCreate}>
|
||||
<PlusSmIcon className={`mr-2 h-6 w-6`} />
|
||||
<span className={`text-sm`}>Create a new {taxonomy} value</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 flex flex-col">
|
||||
<div className="-m-1.5 overflow-x-auto">
|
||||
<div className="p-1.5 min-w-full inline-block align-middle">
|
||||
<div className="overflow-hidden">
|
||||
<table className="min-w-full divide-y divide-gray-200 dark:divide-vulcan-300">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-whisper-900 uppercase">Name</th>
|
||||
<th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-whisper-900 uppercase">Times used</th>
|
||||
<th scope="col" className="px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-whisper-900 uppercase">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-gray-200 dark:divide-vulcan-300">
|
||||
{
|
||||
items && items.length > 0 ?
|
||||
items.map((item, index) => (
|
||||
<tr key={index}>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-200">
|
||||
<TagIcon className="inline-block h-4 w-4 mr-2" />
|
||||
<span>{item}</span>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-200">
|
||||
<TaxonomyLookup
|
||||
taxonomy={taxonomy}
|
||||
value={item}
|
||||
pages={pages} />
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
||||
<TaxonomyActions
|
||||
field={taxonomy}
|
||||
value={item} />
|
||||
</td>
|
||||
</tr>
|
||||
)) : (
|
||||
!unmappedItems || unmappedItems.length === 0 && (
|
||||
<tr>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-200" colSpan={4}>No {taxonomy} found</td>
|
||||
</tr>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
{
|
||||
unmappedItems && unmappedItems.length > 0 &&
|
||||
unmappedItems.map((item, index) => (
|
||||
<tr key={index}>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-200" title='Missing in your settings'>
|
||||
<ExclamationIcon className="inline-block h-4 w-4 mr-2" />
|
||||
<span>{item}</span>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-200">
|
||||
<TaxonomyLookup
|
||||
taxonomy={taxonomy}
|
||||
value={item}
|
||||
pages={pages} />
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
||||
<TaxonomyActions
|
||||
field={taxonomy}
|
||||
value={item}
|
||||
unmapped />
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,44 +1,97 @@
|
||||
import { EventData } from '@estruyf/vscode';
|
||||
import { Messenger } from '@estruyf/vscode/dist/client';
|
||||
import { ChevronRightIcon, DownloadIcon } from '@heroicons/react/outline';
|
||||
import * as React from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { TelemetryEvent } from '../../../constants';
|
||||
import { DashboardCommand } from '../../DashboardCommand';
|
||||
import { TaxonomyData } from '../../../models';
|
||||
import { DashboardMessage } from '../../DashboardMessage';
|
||||
import { Page } from '../../models';
|
||||
import { SettingsSelector } from '../../state';
|
||||
import { NavigationBar, NavigationItem } from '../Layout';
|
||||
import { PageLayout } from '../Layout/PageLayout';
|
||||
import { SponsorMsg } from '../SponsorMsg';
|
||||
import { TaxonomyManager } from './TaxonomyManager';
|
||||
|
||||
export interface ITaxonomyViewProps {
|
||||
pages: Page[];
|
||||
}
|
||||
|
||||
export const TaxonomyView: React.FunctionComponent<ITaxonomyViewProps> = ({ pages }: React.PropsWithChildren<ITaxonomyViewProps>) => {
|
||||
|
||||
const messageListener = (message: MessageEvent<EventData<any>>) => {
|
||||
const { command, data } = message.data;
|
||||
const settings = useRecoilValue(SettingsSelector);
|
||||
const [ taxonomySettings, setTaxonomySettings ] = useState<TaxonomyData>();
|
||||
const [ selectedTaxonomy, setSelectedTaxonomy ] = useState<string | null>(`tags`);
|
||||
|
||||
if (command === DashboardCommand.setTaxonomyData) {
|
||||
console.log('TaxonomyView: setTaxonomyData', data);
|
||||
}
|
||||
const onImport = () => {
|
||||
Messenger.send(DashboardMessage.importTaxonomy);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setTaxonomySettings({
|
||||
tags: settings?.tags || [],
|
||||
categories: settings?.categories || [],
|
||||
customTaxonomy: settings?.customTaxonomy || [],
|
||||
});
|
||||
}, [settings?.tags, settings?.categories, settings?.customTaxonomy]);
|
||||
|
||||
useEffect(() => {
|
||||
Messenger.send(DashboardMessage.sendTelemetry, {
|
||||
event: TelemetryEvent.webviewTaxonomyDashboard
|
||||
});
|
||||
|
||||
Messenger.send(DashboardMessage.getTaxonomyData);
|
||||
|
||||
Messenger.listen(messageListener);
|
||||
|
||||
return () => {
|
||||
Messenger.unlisten(messageListener);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<PageLayout>
|
||||
{pages.length}
|
||||
<PageLayout
|
||||
contentClass={`relative w-full flex-grow flex flex-col mx-auto overflow-hidden`}>
|
||||
|
||||
<div className={`h-full w-full flex`}>
|
||||
<NavigationBar
|
||||
title='Select the taxonomy'
|
||||
bottom={(
|
||||
<button
|
||||
className={`-mb-4 text-xs opacity-80 flex items-center text-gray-500 dark:text-whisper-900 hover:text-gray-700 dark:hover:text-whisper-500`}
|
||||
title="Import taxonomy"
|
||||
onClick={onImport}>
|
||||
<DownloadIcon className={`w-5 mr-2`} />
|
||||
<span>Import taxonomy</span>
|
||||
</button>
|
||||
)}>
|
||||
<NavigationItem
|
||||
isSelected={selectedTaxonomy === "tags"}
|
||||
onClick={() => setSelectedTaxonomy(`tags`)}>
|
||||
<ChevronRightIcon className='-ml-1 w-5 mr-2' />
|
||||
<span>Tags</span>
|
||||
</NavigationItem>
|
||||
|
||||
<NavigationItem
|
||||
isSelected={selectedTaxonomy === "categories"}
|
||||
onClick={() => setSelectedTaxonomy(`categories`)}>
|
||||
<ChevronRightIcon className='-ml-1 w-5 mr-2' />
|
||||
<span>Categories</span>
|
||||
</NavigationItem>
|
||||
|
||||
{
|
||||
taxonomySettings?.customTaxonomy && taxonomySettings.customTaxonomy.map((taxonomy, index) => (
|
||||
<NavigationItem
|
||||
key={`${taxonomy.id}-${index}`}
|
||||
isSelected={selectedTaxonomy === taxonomy.id}
|
||||
onClick={() => setSelectedTaxonomy(taxonomy.id)}>
|
||||
<ChevronRightIcon className='-ml-1 w-5 mr-2' />
|
||||
<span className={`first-letter:uppercase`}>{taxonomy.id}</span>
|
||||
</NavigationItem>
|
||||
))
|
||||
}
|
||||
</NavigationBar>
|
||||
|
||||
<div className={`w-10/12`}>
|
||||
<TaxonomyManager
|
||||
data={taxonomySettings}
|
||||
taxonomy={selectedTaxonomy}
|
||||
pages={pages} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SponsorMsg beta={settings?.beta} version={settings?.versionInfo} isBacker={settings?.isBacker} />
|
||||
</PageLayout>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user