mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-03-28 17:42:40 +01:00
#785 - Added content actions at the bottom of the card
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
- [#777](https://github.com/estruyf/vscode-front-matter/issues/777): Show an error in the metadata panel if something went wrong while parsing the front matter
|
||||
- [#778](https://github.com/estruyf/vscode-front-matter/issues/778): Added the ability to open a file or webpage when custom scripts is completed
|
||||
- [#783](https://github.com/estruyf/vscode-front-matter/issues/783): Always show the custom panel view
|
||||
- [#785](https://github.com/estruyf/vscode-front-matter/issues/785): Adding common actions at the bottom of the content and media cards
|
||||
|
||||
### ⚡️ Optimizations
|
||||
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
import { Messenger, messageHandler } from '@estruyf/vscode/dist/client';
|
||||
import { EyeIcon, GlobeEuropeAfricaIcon, CommandLineIcon, TrashIcon, EllipsisVerticalIcon, LanguageIcon } from '@heroicons/react/24/outline';
|
||||
import { EyeIcon, GlobeEuropeAfricaIcon, CommandLineIcon, TrashIcon, LanguageIcon, EllipsisHorizontalIcon } from '@heroicons/react/24/outline';
|
||||
import * as React from 'react';
|
||||
import { CustomScript, I18nConfig, ScriptType } from '../../../models';
|
||||
import { DashboardMessage } from '../../DashboardMessage';
|
||||
import { QuickAction } from '../Menu';
|
||||
import { Alert } from '../Modals/Alert';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../../localization';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { SettingsSelector } from '../../state';
|
||||
import { SelectedItemActionAtom, SettingsSelector } from '../../state';
|
||||
import { COMMAND_NAME, GeneralCommands } from '../../../constants';
|
||||
import { PinIcon } from '../Icons/PinIcon';
|
||||
import { PinnedItemsAtom } from '../../state/atom/PinnedItems';
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuPortal, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from '../../../components/shadcn/Dropdown';
|
||||
import { RenameIcon } from '../../../components/icons/RenameIcon';
|
||||
import { openFile, openOnWebsite } from '../../utils';
|
||||
|
||||
export interface IContentActionsProps {
|
||||
title: string;
|
||||
path: string;
|
||||
relPath: string;
|
||||
scripts: CustomScript[] | undefined;
|
||||
@@ -33,7 +31,6 @@ export interface IContentActionsProps {
|
||||
}
|
||||
|
||||
export const ContentActions: React.FunctionComponent<IContentActionsProps> = ({
|
||||
title,
|
||||
path,
|
||||
relPath,
|
||||
scripts,
|
||||
@@ -43,8 +40,8 @@ export const ContentActions: React.FunctionComponent<IContentActionsProps> = ({
|
||||
translations,
|
||||
locale
|
||||
}: React.PropsWithChildren<IContentActionsProps>) => {
|
||||
const [, setSelectedItemAction] = useRecoilState(SelectedItemActionAtom);
|
||||
const [pinnedItems, setPinnedItems] = useRecoilState(PinnedItemsAtom);
|
||||
const [showDeletionAlert, setShowDeletionAlert] = React.useState(false);
|
||||
const settings = useRecoilValue(SettingsSelector);
|
||||
|
||||
const onView = (e: React.MouseEvent<HTMLButtonElement | HTMLDivElement, MouseEvent>) => {
|
||||
@@ -52,35 +49,19 @@ export const ContentActions: React.FunctionComponent<IContentActionsProps> = ({
|
||||
onOpen();
|
||||
};
|
||||
|
||||
const onDelete = (e: React.MouseEvent<HTMLButtonElement | HTMLDivElement, MouseEvent>) => {
|
||||
const onDelete = React.useCallback((e: React.MouseEvent<HTMLButtonElement | HTMLDivElement, MouseEvent>) => {
|
||||
e.stopPropagation();
|
||||
setShowDeletionAlert(true);
|
||||
};
|
||||
setSelectedItemAction({ path, action: 'delete' });
|
||||
}, [path]);
|
||||
|
||||
const onRename = React.useCallback((e: React.MouseEvent<HTMLButtonElement | HTMLDivElement, MouseEvent>) => {
|
||||
e.stopPropagation();
|
||||
messageHandler.send(DashboardMessage.rename, path);
|
||||
}, [path])
|
||||
|
||||
const onDeleteConfirm = () => {
|
||||
if (path) {
|
||||
Messenger.send(DashboardMessage.deleteFile, path);
|
||||
}
|
||||
setShowDeletionAlert(false);
|
||||
};
|
||||
|
||||
const onOpenFile = (filePath: string) => {
|
||||
messageHandler.send(DashboardMessage.openFile, filePath);
|
||||
}
|
||||
|
||||
const openOnWebsite = React.useCallback((e: React.MouseEvent<HTMLButtonElement | HTMLDivElement, MouseEvent>) => {
|
||||
const onOpenWebsite = React.useCallback((e: React.MouseEvent<HTMLButtonElement | HTMLDivElement, MouseEvent>) => {
|
||||
e.stopPropagation();
|
||||
if (settings?.websiteUrl && path) {
|
||||
Messenger.send(GeneralCommands.toVSCode.openOnWebsite, {
|
||||
websiteUrl: settings.websiteUrl,
|
||||
filePath: path
|
||||
});
|
||||
}
|
||||
openOnWebsite(settings?.websiteUrl, path);
|
||||
}, [settings?.websiteUrl, path]);
|
||||
|
||||
const pinItem = React.useCallback((e: React.MouseEvent<HTMLButtonElement | HTMLDivElement, MouseEvent>) => {
|
||||
@@ -153,7 +134,7 @@ export const ContentActions: React.FunctionComponent<IContentActionsProps> = ({
|
||||
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuItem onClick={() => onOpenFile(crntLocale.path)}>
|
||||
<DropdownMenuItem onClick={() => openFile(crntLocale.path)}>
|
||||
<span>{crntLocale.locale.title || crntLocale.locale.locale}</span>
|
||||
</DropdownMenuItem>
|
||||
|
||||
@@ -163,7 +144,7 @@ export const ContentActions: React.FunctionComponent<IContentActionsProps> = ({
|
||||
otherLocales.map(([key, value]) => (
|
||||
<DropdownMenuItem
|
||||
key={key}
|
||||
onClick={() => onOpenFile(value.path)}
|
||||
onClick={() => openFile(value.path)}
|
||||
>
|
||||
<span>{value.locale.title || value.locale.locale}</span>
|
||||
</DropdownMenuItem>
|
||||
@@ -178,41 +159,19 @@ export const ContentActions: React.FunctionComponent<IContentActionsProps> = ({
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={`${listView ? '' : 'group/card absolute top-6 right-0'
|
||||
className={`${listView ? '' : 'group/card absolute top-6 right-2'
|
||||
} flex flex-col space-y-4`}
|
||||
>
|
||||
<div
|
||||
className={`flex items-center border border-transparent rounded-full ${listView ? '' : 'p-2 -mt-4'
|
||||
className={`flex items-center border border-transparent rounded-full ${listView ? '' : 'p-1 -mt-3'
|
||||
} group-hover/card:bg-[var(--vscode-sideBar-background)] group-hover/card:border-[var(--frontmatter-border)]`}
|
||||
>
|
||||
<div className={`relative flex text-left`}>
|
||||
{!listView && (
|
||||
<div className="hidden group-hover/card:flex">
|
||||
<QuickAction title={l10n.t(LocalizationKey.dashboardContentsContentActionsMenuItemView)} onClick={onView}>
|
||||
<EyeIcon className={`w-4 h-4`} aria-hidden="true" />
|
||||
</QuickAction>
|
||||
|
||||
{
|
||||
settings?.websiteUrl && (
|
||||
<QuickAction title={l10n.t(LocalizationKey.commonOpenOnWebsite)} onClick={openOnWebsite}>
|
||||
<GlobeEuropeAfricaIcon className={`w-4 h-4`} aria-hidden="true" />
|
||||
</QuickAction>
|
||||
)
|
||||
}
|
||||
|
||||
<QuickAction
|
||||
title={l10n.t(LocalizationKey.commonDelete)}
|
||||
className={`hover:text-[var(--vscode-statusBarItem-errorBackground)]`}
|
||||
onClick={onDelete}>
|
||||
<TrashIcon className={`w-4 h-4`} aria-hidden="true" />
|
||||
</QuickAction>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger className='text-[var(--vscode-tab-inactiveForeground)] hover:text-[var(--vscode-tab-activeForeground)] data-[state=open]:text-[var(--vscode-tab-activeForeground)] focus:outline-none'>
|
||||
<DropdownMenuTrigger
|
||||
className='text-[var(--vscode-tab-inactiveForeground)] hover:text-[var(--vscode-tab-activeForeground)] data-[state=open]:text-[var(--vscode-tab-activeForeground)] focus:outline-none'>
|
||||
<span className="sr-only">{l10n.t(LocalizationKey.dashboardContentsContentActionsActionMenuButtonTitle)}</span>
|
||||
<EllipsisVerticalIcon className="w-4 h-4" aria-hidden="true" />
|
||||
<EllipsisHorizontalIcon className="w-4 h-4" aria-hidden="true" />
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
<DropdownMenuContent align="end">
|
||||
@@ -233,7 +192,7 @@ export const ContentActions: React.FunctionComponent<IContentActionsProps> = ({
|
||||
|
||||
{
|
||||
settings?.websiteUrl && (
|
||||
<DropdownMenuItem onClick={openOnWebsite}>
|
||||
<DropdownMenuItem onClick={onOpenWebsite}>
|
||||
<GlobeEuropeAfricaIcon className={`mr-2 h-4 w-4`} aria-hidden={true} />
|
||||
<span>{l10n.t(LocalizationKey.commonOpenOnWebsite)}</span>
|
||||
</DropdownMenuItem>
|
||||
@@ -263,17 +222,6 @@ export const ContentActions: React.FunctionComponent<IContentActionsProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{showDeletionAlert && (
|
||||
<Alert
|
||||
title={l10n.t(LocalizationKey.dashboardContentsContentActionsAlertTitle, title)}
|
||||
description={l10n.t(LocalizationKey.dashboardContentsContentActionsAlertDescription, title)}
|
||||
okBtnText={l10n.t(LocalizationKey.commonDelete)}
|
||||
cancelBtnText={l10n.t(LocalizationKey.commonCancel)}
|
||||
dismiss={() => setShowDeletionAlert(false)}
|
||||
trigger={onDeleteConfirm}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
import * as React from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { Page } from '../../models';
|
||||
import { LoadingAtom, SettingsSelector } from '../../state';
|
||||
import { LoadingAtom, SelectedItemActionAtom, SettingsSelector } from '../../state';
|
||||
import { Overview } from './Overview';
|
||||
import { Spinner } from '../Common/Spinner';
|
||||
import { SponsorMsg } from '../Layout/SponsorMsg';
|
||||
import usePages from '../../hooks/usePages';
|
||||
import { useEffect } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { Messenger } from '@estruyf/vscode/dist/client';
|
||||
import { DashboardMessage } from '../../DashboardMessage';
|
||||
import { TelemetryEvent } from '../../../constants';
|
||||
import { PageLayout } from '../Layout/PageLayout';
|
||||
import { FilesProvider } from '../../providers/FilesProvider';
|
||||
import { Alert } from '../Modals/Alert';
|
||||
import { LocalizationKey } from '../../../localization';
|
||||
import { deletePage } from '../../utils';
|
||||
|
||||
export interface IContentsProps {
|
||||
pages: Page[];
|
||||
@@ -23,9 +27,38 @@ export const Contents: React.FunctionComponent<IContentsProps> = ({
|
||||
const loading = useRecoilValue(LoadingAtom);
|
||||
const settings = useRecoilValue(SettingsSelector);
|
||||
const { pageItems } = usePages(pages);
|
||||
const [showDeletionAlert, setShowDeletionAlert] = React.useState(false);
|
||||
const [page, setPage] = useState<Page | undefined>(undefined);
|
||||
const [selectedItemAction, setSelectedItemAction] = useRecoilState(SelectedItemActionAtom);
|
||||
|
||||
const pageFolders = [...new Set(pageItems.map((page) => page.fmFolder))];
|
||||
|
||||
const onDismiss = useCallback(() => {
|
||||
setShowDeletionAlert(false);
|
||||
setSelectedItemAction(undefined);
|
||||
}, []);
|
||||
|
||||
const onDeleteConfirm = useCallback(() => {
|
||||
if (page) {
|
||||
deletePage(page.fmFilePath);
|
||||
}
|
||||
setShowDeletionAlert(false);
|
||||
setSelectedItemAction(undefined);
|
||||
}, [page]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedItemAction && selectedItemAction.path && selectedItemAction.action === 'delete') {
|
||||
const page = pageItems.find((p) => p.fmFilePath === selectedItemAction.path);
|
||||
|
||||
if (page) {
|
||||
setPage(page);
|
||||
setShowDeletionAlert(true);
|
||||
}
|
||||
|
||||
setSelectedItemAction(undefined);
|
||||
}
|
||||
}, [pageItems, selectedItemAction]);
|
||||
|
||||
useEffect(() => {
|
||||
Messenger.send(DashboardMessage.sendTelemetry, {
|
||||
event: TelemetryEvent.webviewContentsView
|
||||
@@ -46,6 +79,17 @@ export const Contents: React.FunctionComponent<IContentsProps> = ({
|
||||
/>
|
||||
|
||||
<img className='hidden' src="https://api.visitorbadge.io/api/visitors?path=https%3A%2F%2Ffrontmatter.codes%2Fmetrics%2Fdashboards&slug=content" alt="Content metrics" />
|
||||
|
||||
{showDeletionAlert && page && (
|
||||
<Alert
|
||||
title={l10n.t(LocalizationKey.dashboardContentsContentActionsAlertTitle, page.title)}
|
||||
description={l10n.t(LocalizationKey.dashboardContentsContentActionsAlertDescription, page.title)}
|
||||
okBtnText={l10n.t(LocalizationKey.commonDelete)}
|
||||
cancelBtnText={l10n.t(LocalizationKey.commonCancel)}
|
||||
dismiss={onDismiss}
|
||||
trigger={onDeleteConfirm}
|
||||
/>
|
||||
)}
|
||||
</PageLayout>
|
||||
</FilesProvider>
|
||||
);
|
||||
|
||||
49
src/dashboardWebView/components/Contents/FooterActions.tsx
Normal file
49
src/dashboardWebView/components/Contents/FooterActions.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import * as React from 'react';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { QuickAction } from '../Menu';
|
||||
import { EyeIcon, GlobeEuropeAfricaIcon, TrashIcon } from '@heroicons/react/24/outline';
|
||||
import { LocalizationKey } from '../../../localization';
|
||||
import { openFile, openOnWebsite } from '../../utils';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { SelectedItemActionAtom } from '../../state';
|
||||
|
||||
export interface IFooterActionsProps {
|
||||
filePath: string;
|
||||
websiteUrl?: string;
|
||||
}
|
||||
|
||||
export const FooterActions: React.FunctionComponent<IFooterActionsProps> = ({
|
||||
filePath,
|
||||
websiteUrl
|
||||
}: React.PropsWithChildren<IFooterActionsProps>) => {
|
||||
const [, setSelectedItemAction] = useRecoilState(SelectedItemActionAtom);
|
||||
|
||||
return (
|
||||
<div className={`py-2 w-full flex items-center justify-evenly border-t border-t-[var(--frontmatter-border)]`}>
|
||||
<QuickAction
|
||||
title={l10n.t(LocalizationKey.dashboardContentsContentActionsMenuItemView)}
|
||||
className={`text-[var(--frontmatter-secondary-text)]`}
|
||||
onClick={() => openFile(filePath)}>
|
||||
<EyeIcon className={`w-4 h-4`} aria-hidden="true" />
|
||||
</QuickAction>
|
||||
|
||||
{
|
||||
websiteUrl && (
|
||||
<QuickAction
|
||||
title={l10n.t(LocalizationKey.commonOpenOnWebsite)}
|
||||
className={`text-[var(--frontmatter-secondary-text)]`}
|
||||
onClick={() => openOnWebsite(websiteUrl, filePath)}>
|
||||
<GlobeEuropeAfricaIcon className={`w-4 h-4`} aria-hidden="true" />
|
||||
</QuickAction>
|
||||
)
|
||||
}
|
||||
|
||||
<QuickAction
|
||||
title={l10n.t(LocalizationKey.commonDelete)}
|
||||
className={`text-[var(--frontmatter-secondary-text)] hover:text-[var(--vscode-statusBarItem-errorBackground)]`}
|
||||
onClick={() => setSelectedItemAction({ path: filePath, action: 'delete' })}>
|
||||
<TrashIcon className={`w-4 h-4`} aria-hidden="true" />
|
||||
</QuickAction>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,10 +1,8 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { MarkdownIcon } from '../../../panelWebView/components/Icons/MarkdownIcon';
|
||||
import { DashboardMessage } from '../../DashboardMessage';
|
||||
import { Page } from '../../models/Page';
|
||||
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 { useMemo } from 'react';
|
||||
@@ -18,6 +16,8 @@ import { routePaths } from '../..';
|
||||
import useCard from '../../hooks/useCard';
|
||||
import { I18nLabel } from './I18nLabel';
|
||||
import { ItemSelection } from '../Common/ItemSelection';
|
||||
import { openFile } from '../../utils';
|
||||
import { FooterActions } from './FooterActions';
|
||||
|
||||
export interface IItemProps extends Page { }
|
||||
|
||||
@@ -41,9 +41,9 @@ export const Item: React.FunctionComponent<IItemProps> = ({
|
||||
pageData
|
||||
});
|
||||
|
||||
const openFile = () => {
|
||||
Messenger.send(DashboardMessage.openFile, pageData.fmFilePath);
|
||||
};
|
||||
const onOpenFile = React.useCallback(() => {
|
||||
openFile(pageData.fmFilePath);
|
||||
}, [pageData.fmFilePath]);
|
||||
|
||||
const tags: string[] | undefined = useMemo(() => {
|
||||
if (!settings?.dashboardState?.contents?.tags) {
|
||||
@@ -92,9 +92,9 @@ export const Item: React.FunctionComponent<IItemProps> = ({
|
||||
|
||||
return (
|
||||
dateHtml ? (
|
||||
<div className='mr-4' dangerouslySetInnerHTML={{ __html: dateHtml }} />
|
||||
<div className='mr-6' dangerouslySetInnerHTML={{ __html: dateHtml }} />
|
||||
) : (
|
||||
cardFields?.date && pageData.date ? <DateField className={`mr-4`} value={pageData.date} format={pageData.fmDateFormat} /> : null
|
||||
cardFields?.date && pageData.date ? <DateField className={`mr-6`} value={pageData.date} format={pageData.fmDateFormat} /> : null
|
||||
)
|
||||
)
|
||||
}, [dateHtml, cardFields?.date, pageData]);
|
||||
@@ -111,7 +111,7 @@ export const Item: React.FunctionComponent<IItemProps> = ({
|
||||
>
|
||||
<button
|
||||
title={escapedTitle ? l10n.t(LocalizationKey.commonOpenWithValue, escapedTitle) : l10n.t(LocalizationKey.commonOpen)}
|
||||
onClick={openFile}
|
||||
onClick={onOpenFile}
|
||||
className={`relative h-36 w-full overflow-hidden border-b cursor-pointer border-[var(--frontmatter-border)]`}
|
||||
>
|
||||
{
|
||||
@@ -147,21 +147,20 @@ export const Item: React.FunctionComponent<IItemProps> = ({
|
||||
}
|
||||
|
||||
<ContentActions
|
||||
title={pageData.title}
|
||||
path={pageData.fmFilePath}
|
||||
relPath={pageData.fmRelFileWsPath}
|
||||
locale={pageData.fmLocale}
|
||||
isDefaultLocale={pageData.fmDefaultLocale}
|
||||
translations={pageData.fmTranslations}
|
||||
scripts={settings?.scripts}
|
||||
onOpen={openFile}
|
||||
onOpen={onOpenFile}
|
||||
/>
|
||||
|
||||
<I18nLabel page={pageData} />
|
||||
|
||||
<button
|
||||
title={escapedTitle ? l10n.t(LocalizationKey.commonOpenWithValue, escapedTitle) : l10n.t(LocalizationKey.commonOpen)}
|
||||
onClick={openFile}
|
||||
onClick={onOpenFile}
|
||||
className={`text-left block`}>
|
||||
{
|
||||
titleHtml ? (
|
||||
@@ -178,7 +177,7 @@ export const Item: React.FunctionComponent<IItemProps> = ({
|
||||
(escapedDescription || descriptionHtml) && (
|
||||
<button
|
||||
title={escapedTitle ? l10n.t(LocalizationKey.commonOpenWithValue, escapedTitle) : l10n.t(LocalizationKey.commonOpen)}
|
||||
onClick={openFile}
|
||||
onClick={onOpenFile}
|
||||
className={`mt-2 text-left block`}>
|
||||
{
|
||||
descriptionHtml ? (
|
||||
@@ -225,6 +224,10 @@ export const Item: React.FunctionComponent<IItemProps> = ({
|
||||
<div className="placeholder__card__footer p-4 w-full" dangerouslySetInnerHTML={{ __html: footerHtml }} />
|
||||
)
|
||||
}
|
||||
|
||||
<FooterActions
|
||||
filePath={pageData.fmFilePath}
|
||||
websiteUrl={settings?.websiteUrl} />
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
@@ -239,16 +242,15 @@ export const Item: React.FunctionComponent<IItemProps> = ({
|
||||
|
||||
<button
|
||||
title={escapedTitle ? l10n.t(LocalizationKey.commonOpenWithValue, escapedTitle) : l10n.t(LocalizationKey.commonOpen)}
|
||||
onClick={openFile}>
|
||||
onClick={onOpenFile}>
|
||||
{escapedTitle}
|
||||
</button>
|
||||
|
||||
<ContentActions
|
||||
title={escapedTitle || ""}
|
||||
path={pageData.fmFilePath}
|
||||
relPath={pageData.fmRelFileWsPath}
|
||||
scripts={settings?.scripts}
|
||||
onOpen={openFile}
|
||||
onOpen={onOpenFile}
|
||||
listView
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -2,12 +2,11 @@ import * as React from 'react';
|
||||
import { Page } from '../../models';
|
||||
import { MarkdownIcon } from '../../../panelWebView/components/Icons/MarkdownIcon';
|
||||
import { ContentActions } from './ContentActions';
|
||||
import { DashboardMessage } from '../../DashboardMessage';
|
||||
import { messageHandler } from '@estruyf/vscode/dist/client';
|
||||
import useCard from '../../hooks/useCard';
|
||||
import { SettingsSelector } from '../../state';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { ItemSelection } from '../Common/ItemSelection';
|
||||
import { openFile } from '../../utils';
|
||||
|
||||
export interface IPinnedItemProps extends Page { }
|
||||
|
||||
@@ -17,13 +16,13 @@ export const PinnedItem: React.FunctionComponent<IPinnedItemProps> = ({
|
||||
const settings = useRecoilValue(SettingsSelector);
|
||||
const { escapedTitle } = useCard(pageData, settings?.dashboardState?.contents?.cardFields);
|
||||
|
||||
const openFile = React.useCallback(() => {
|
||||
messageHandler.send(DashboardMessage.openFile, pageData.fmFilePath);
|
||||
const onOpenFile = React.useCallback(() => {
|
||||
openFile(pageData.fmFilePath);
|
||||
}, [pageData.fmFilePath]);
|
||||
|
||||
return (
|
||||
<li className='group flex w-full border border-[var(--frontmatter-border)] rounded bg-[var(--vscode-sideBar-background)] hover:bg-[var(--vscode-list-hoverBackground)] text-[var(--vscode-sideBarTitle-foreground)] relative'>
|
||||
<button onClick={openFile} className='relative h-full w-1/3'>
|
||||
<button onClick={onOpenFile} className='relative h-full w-1/3'>
|
||||
{
|
||||
pageData["fmPreviewImage"] ? (
|
||||
<img
|
||||
@@ -44,11 +43,10 @@ export const PinnedItem: React.FunctionComponent<IPinnedItemProps> = ({
|
||||
|
||||
<ItemSelection filePath={pageData.fmFilePath} />
|
||||
|
||||
<button onClick={openFile} className='relative w-2/3 p-4 pr-6 text-left flex items-start'>
|
||||
<button onClick={onOpenFile} className='relative w-2/3 p-4 pr-6 text-left flex items-start'>
|
||||
<p className='font-bold'>{escapedTitle}</p>
|
||||
|
||||
<ContentActions
|
||||
title={pageData.title}
|
||||
path={pageData.fmFilePath}
|
||||
relPath={pageData.fmRelFileWsPath}
|
||||
scripts={settings?.scripts}
|
||||
|
||||
@@ -14,6 +14,7 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSepara
|
||||
import { useFilesContext } from '../../providers/FilesProvider';
|
||||
import { COMMAND_NAME, GeneralCommands } from '../../../constants';
|
||||
import { RenameIcon } from '../../../components/icons/RenameIcon';
|
||||
import { openFile } from '../../utils';
|
||||
|
||||
export interface IActionsBarProps {
|
||||
view: NavigationType;
|
||||
@@ -32,7 +33,7 @@ export const ActionsBar: React.FunctionComponent<IActionsBarProps> = ({
|
||||
const viewFile = React.useCallback(() => {
|
||||
if (selectedFiles.length === 1) {
|
||||
if (view === NavigationType.Contents) {
|
||||
messageHandler.send(DashboardMessage.openFile, selectedFiles[0]);
|
||||
openFile(selectedFiles[0]);
|
||||
} else if (view === NavigationType.Media) {
|
||||
setSelectedItemAction({ path: selectedFiles[0], action: 'view' })
|
||||
}
|
||||
@@ -107,7 +108,7 @@ export const ActionsBar: React.FunctionComponent<IActionsBarProps> = ({
|
||||
|
||||
<DropdownMenuContent align='start'>
|
||||
|
||||
<DropdownMenuItem onClick={() => messageHandler.send(DashboardMessage.openFile, crntLocale.path)}>
|
||||
<DropdownMenuItem onClick={() => openFile(crntLocale.path)}>
|
||||
<span>{crntLocale.locale.title || crntLocale.locale.locale}</span>
|
||||
</DropdownMenuItem>
|
||||
|
||||
@@ -117,7 +118,7 @@ export const ActionsBar: React.FunctionComponent<IActionsBarProps> = ({
|
||||
otherLocales.map(([key, value]) => (
|
||||
<DropdownMenuItem
|
||||
key={key}
|
||||
onClick={() => messageHandler.send(DashboardMessage.openFile, value.path)}
|
||||
onClick={() => openFile(value.path)}
|
||||
>
|
||||
<span>{value.locale.title || value.locale.locale}</span>
|
||||
</DropdownMenuItem>
|
||||
|
||||
@@ -32,7 +32,7 @@ export const MediaItemPanel: React.FunctionComponent<IMediaItemPanelProps> = ({
|
||||
|
||||
setSelectedItemAction(undefined);
|
||||
}
|
||||
}, [allMedia, selectedItemAction])
|
||||
}, [allMedia, selectedItemAction]);
|
||||
|
||||
if (showDetails && media) {
|
||||
return (
|
||||
|
||||
@@ -25,6 +25,7 @@ import { NewForm } from './NewForm';
|
||||
import SnippetForm, { SnippetFormHandle } from './SnippetForm';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../../localization';
|
||||
import { openFile } from '../../utils';
|
||||
|
||||
export interface IItemProps {
|
||||
snippetKey: string;
|
||||
@@ -65,7 +66,7 @@ export const Item: React.FunctionComponent<IItemProps> = ({
|
||||
};
|
||||
|
||||
const showFile = useCallback(() => {
|
||||
Messenger.send(DashboardMessage.openFile, snippet.sourcePath);
|
||||
openFile(snippet.sourcePath);
|
||||
}, [snippet]);
|
||||
|
||||
const onOpenEdit = useCallback(() => {
|
||||
|
||||
@@ -16,6 +16,7 @@ import { Messenger, messageHandler } from '@estruyf/vscode/dist/client';
|
||||
import { DashboardMessage } from '../../DashboardMessage';
|
||||
import { ExtensionState } from '../../../constants';
|
||||
import { LinkButton } from '../Common/LinkButton';
|
||||
import { openFile } from '../../utils';
|
||||
|
||||
export interface ITaxonomyTaggingProps {
|
||||
taxonomy: string | null;
|
||||
@@ -125,7 +126,7 @@ export const TaxonomyTagging: React.FunctionComponent<ITaxonomyTaggingProps> = (
|
||||
}, [untaggedPages, pageMappings.tagged]);
|
||||
|
||||
const onFileView = (filePath: string) => {
|
||||
Messenger.send(DashboardMessage.openFile, filePath);
|
||||
openFile(filePath);
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { atom } from 'recoil';
|
||||
export const SelectedItemActionAtom = atom<
|
||||
| {
|
||||
path: string;
|
||||
action: 'view' | 'edit';
|
||||
action: 'view' | 'edit' | 'delete';
|
||||
}
|
||||
| undefined
|
||||
>({
|
||||
|
||||
30
src/dashboardWebView/utils/MessageHandlers.ts
Normal file
30
src/dashboardWebView/utils/MessageHandlers.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { messageHandler } from '@estruyf/vscode/dist/client';
|
||||
import { DashboardMessage } from '../DashboardMessage';
|
||||
import { GeneralCommands } from '../../constants';
|
||||
|
||||
export const openFile = (filePath?: string) => {
|
||||
if (!filePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
messageHandler.send(DashboardMessage.openFile, filePath);
|
||||
};
|
||||
|
||||
export const deletePage = (filePath?: string) => {
|
||||
if (!filePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
messageHandler.send(DashboardMessage.deleteFile, filePath);
|
||||
};
|
||||
|
||||
export const openOnWebsite = (websiteUrl?: string, filePath?: string) => {
|
||||
if (!websiteUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
messageHandler.send(GeneralCommands.toVSCode.openOnWebsite, {
|
||||
websiteUrl,
|
||||
filePath
|
||||
});
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './MessageHandlers';
|
||||
export * from './getRelPath';
|
||||
export * from './preserveColor';
|
||||
export * from './updateCssVariables';
|
||||
|
||||
Reference in New Issue
Block a user