diff --git a/src/dashboardWebView/components/Contents/FooterActions.tsx b/src/dashboardWebView/components/Contents/FooterActions.tsx index 26961933..1dcfc991 100644 --- a/src/dashboardWebView/components/Contents/FooterActions.tsx +++ b/src/dashboardWebView/components/Contents/FooterActions.tsx @@ -19,11 +19,12 @@ export const FooterActions: React.FunctionComponent = ({ const [, setSelectedItemAction] = useRecoilState(SelectedItemActionAtom); return ( -
+
openFile(filePath)}> + {l10n.t(LocalizationKey.dashboardContentsContentActionsMenuItemView)} @@ -33,6 +34,7 @@ export const FooterActions: React.FunctionComponent = ({ title={l10n.t(LocalizationKey.commonOpenOnWebsite)} className={`text-[var(--frontmatter-secondary-text)]`} onClick={() => openOnWebsite(websiteUrl, filePath)}> + {l10n.t(LocalizationKey.commonOpenOnWebsite)}
diff --git a/src/dashboardWebView/components/Media/FooterActions.tsx b/src/dashboardWebView/components/Media/FooterActions.tsx new file mode 100644 index 00000000..fab383a4 --- /dev/null +++ b/src/dashboardWebView/components/Media/FooterActions.tsx @@ -0,0 +1,98 @@ +import * as React from 'react'; +import * as l10n from '@vscode/l10n'; +import { QuickAction } from '../Menu'; +import { LocalizationKey } from '../../../localization'; +import { ClipboardIcon, CodeBracketIcon, EyeIcon, PencilIcon, PlusIcon, TrashIcon } from '@heroicons/react/24/outline'; +import { useRecoilState } from 'recoil'; +import { SelectedItemActionAtom } from '../../state'; +import { MediaInfo, Snippet, ViewData } from '../../../models'; +import { copyToClipboard } from '../../utils'; +import { parseWinPath } from '../../../helpers/parseWinPath'; + +export interface IFooterActionsProps { + media: MediaInfo; + snippets: Snippet[]; + relPath?: string; + viewData?: ViewData | undefined + insertIntoArticle: () => void; + insertSnippet: () => void; + onDelete: () => void; +} + +export const FooterActions: React.FunctionComponent = ({ + relPath, + media, + snippets, + viewData, + insertIntoArticle, + insertSnippet, + onDelete, +}: React.PropsWithChildren) => { + const [, setSelectedItemAction] = useRecoilState(SelectedItemActionAtom); + + return ( +
+ setSelectedItemAction({ + path: media.fsPath, + action: 'view' + })}> + + + setSelectedItemAction({ + path: media.fsPath, + action: 'edit' + })}> + + + {viewData?.filePath ? ( + <> + + + + {viewData?.position && snippets.length > 0 && ( + + + )} + + ) : ( + <> + { + relPath && ( + copyToClipboard(parseWinPath(relPath) || '')}> + + ) + } + + )} + + + +
+ ); +}; \ No newline at end of file diff --git a/src/dashboardWebView/components/Media/Item.tsx b/src/dashboardWebView/components/Media/Item.tsx index cc84aae9..b932c436 100644 --- a/src/dashboardWebView/components/Media/Item.tsx +++ b/src/dashboardWebView/components/Media/Item.tsx @@ -32,6 +32,7 @@ import { getRelPath } from '../../utils'; import { Snippet } from '../../../models'; import useMediaInfo from '../../hooks/useMediaInfo'; import { ItemSelection } from '../Common/ItemSelection'; +import { FooterActions } from './FooterActions'; export interface IItemProps { media: MediaInfo; @@ -185,13 +186,6 @@ export const Item: React.FunctionComponent = ({ } }, [media.vsPath]); - const updateMetadata = useCallback(() => { - setSelectedItemAction({ - path: media.fsPath, - action: 'edit' - }); - }, [media]); - const renderMediaIcon = useMemo(() => { const path = media.fsPath; const extension = path.split('.').pop(); @@ -265,7 +259,7 @@ export const Item: React.FunctionComponent = ({ return ( <> -
  • +
  • )} -
    + +
    = ({ snippets={mediaSnippets} scripts={settings?.scripts} insertIntoArticle={insertIntoArticle} - insertSnippet={insertSnippet} - showUpdateMedia={updateMetadata} - showMediaDetails={() => setSelectedItemAction({ path: media.fsPath, action: 'view' })} + showUpdateMedia={() => setSelectedItemAction({ + path: media.fsPath, + action: 'edit' + })} + showMediaDetails={() => setSelectedItemAction({ + path: media.fsPath, + action: 'view' + })} processSnippet={processSnippet} onDelete={() => setShowAlert(true)} /> @@ -371,6 +371,15 @@ export const Item: React.FunctionComponent = ({

    )}
    + + setShowAlert(true)} /> {showSnippetSelection && ( diff --git a/src/dashboardWebView/components/Media/ItemMenu.tsx b/src/dashboardWebView/components/Media/ItemMenu.tsx index 6f55b9b9..37f59008 100644 --- a/src/dashboardWebView/components/Media/ItemMenu.tsx +++ b/src/dashboardWebView/components/Media/ItemMenu.tsx @@ -1,13 +1,13 @@ import * as React from 'react'; import * as l10n from '@vscode/l10n'; import { LocalizationKey } from '../../../localization'; -import { QuickAction } from '../Menu'; -import { ClipboardIcon, CodeBracketIcon, CommandLineIcon, EllipsisVerticalIcon, EyeIcon, PencilIcon, PlusIcon, TrashIcon } from '@heroicons/react/24/outline'; +import { ClipboardIcon, CodeBracketIcon, CommandLineIcon, EllipsisHorizontalIcon, EyeIcon, PencilIcon, PlusIcon, TrashIcon } from '@heroicons/react/24/outline'; import { CustomScript, MediaInfo, ScriptType, Snippet, ViewData } from '../../../models'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '../../../components/shadcn/Dropdown'; import { messageHandler } from '@estruyf/vscode/dist/client'; import { DashboardMessage } from '../../DashboardMessage'; import { parseWinPath } from '../../../helpers/parseWinPath'; +import { copyToClipboard } from '../../utils'; export interface IItemMenuProps { media: MediaInfo; @@ -17,7 +17,6 @@ export interface IItemMenuProps { snippets: Snippet[]; scripts?: CustomScript[]; insertIntoArticle: () => void; - insertSnippet: () => void; showUpdateMedia: () => void; showMediaDetails: () => void; processSnippet: (snippet: Snippet) => void; @@ -32,17 +31,14 @@ export const ItemMenu: React.FunctionComponent = ({ snippets, scripts, insertIntoArticle, - insertSnippet, showUpdateMedia, showMediaDetails, processSnippet, onDelete, }: React.PropsWithChildren) => { - const copyToClipboard = React.useCallback(() => { - if (relPath) { - messageHandler.send(DashboardMessage.copyToClipboard, parseWinPath(relPath) || ''); - } + const onCopyToClipboard = React.useCallback(() => { + copyToClipboard(parseWinPath(relPath) || ''); }, [relPath]); const runCustomScript = React.useCallback((script: CustomScript) => { @@ -75,65 +71,20 @@ export const ItemMenu: React.FunctionComponent = ({ return (
    -
    +
    -
    - - - - - - - {viewData?.filePath ? ( - <> - - - - {viewData?.position && snippets.length > 0 && ( - - - )} - - ) : ( - <> - { - relPath && ( - - - ) - } - - )} - - - -
    - {l10n.t(LocalizationKey.commonMenu)} - + + + {l10n.t(LocalizationKey.commonView)} + + {l10n.t(LocalizationKey.dashboardMediaItemMenuItemEditMetadata)} @@ -165,7 +116,7 @@ export const ItemMenu: React.FunctionComponent = ({ ) : ( <> - + {l10n.t(LocalizationKey.dashboardMediaItemQuickActionCopyPath)} diff --git a/src/dashboardWebView/utils/MessageHandlers.ts b/src/dashboardWebView/utils/MessageHandlers.ts index c4e60aaf..b665cf0f 100644 --- a/src/dashboardWebView/utils/MessageHandlers.ts +++ b/src/dashboardWebView/utils/MessageHandlers.ts @@ -28,3 +28,11 @@ export const openOnWebsite = (websiteUrl?: string, filePath?: string) => { filePath }); }; + +export const copyToClipboard = (value: string) => { + if (!value) { + return; + } + + messageHandler.send(DashboardMessage.copyToClipboard, value); +}; diff --git a/src/dashboardWebView/utils/darkenColor.ts b/src/dashboardWebView/utils/darkenColor.ts new file mode 100644 index 00000000..84fd577c --- /dev/null +++ b/src/dashboardWebView/utils/darkenColor.ts @@ -0,0 +1,70 @@ +export const darkenColor = (color: string | undefined, percentage: number) => { + if (!color) { + return color; + } + + // Remove any whitespace and convert to lowercase + color = color.trim().toLowerCase(); + + // Check if the color is in hex format + if (color.startsWith('#')) { + // Remove the "#" symbol + color = color.slice(1); + + // Convert the color to rgb format + const hexToRgb = (hex: string) => { + const bigint = parseInt(hex, 16); + const r = (bigint >> 16) & 255; + const g = (bigint >> 8) & 255; + const b = bigint & 255; + return [r, g, b]; + }; + + const [r, g, b] = hexToRgb(color); + + // Calculate the darkened color + const darkenValue = Math.round(255 * (percentage / 100)); + const darkenedR = Math.max(r - darkenValue, 0); + const darkenedG = Math.max(g - darkenValue, 0); + const darkenedB = Math.max(b - darkenValue, 0); + + // Convert the darkened color back to hex format + const rgbToHex = (r: number, g: number, b: number) => { + const toHex = (c: number) => { + const hex = c.toString(16); + return hex.length === 1 ? '0' + hex : hex; + }; + return `#${toHex(r)}${toHex(g)}${toHex(b)}`; + }; + + return rgbToHex(darkenedR, darkenedG, darkenedB); + } + + // Check if the color is in rgb or rgba format + if (color.startsWith('rgb')) { + // Extract the RGB values + const rgbValues = color.match(/\d+/g); + + if (rgbValues) { + const [r, g, b] = rgbValues.map(Number); + + // Calculate the darkened color + const darkenValue = Math.round(255 * (percentage / 100)); + const darkenedR = Math.max(r - darkenValue, 0); + const darkenedG = Math.max(g - darkenValue, 0); + const darkenedB = Math.max(b - darkenValue, 0); + + // Check if the color is in rgba format + if (color.startsWith('rgba')) { + // Extract the alpha value + const alpha = Number(color.match(/[\d\.]+$/)); + + return `rgba(${darkenedR}, ${darkenedG}, ${darkenedB}, ${alpha})`; + } + + return `rgb(${darkenedR}, ${darkenedG}, ${darkenedB})`; + } + } + + return color; +}; diff --git a/src/dashboardWebView/utils/index.ts b/src/dashboardWebView/utils/index.ts index f7f33f31..fd12dd78 100644 --- a/src/dashboardWebView/utils/index.ts +++ b/src/dashboardWebView/utils/index.ts @@ -1,4 +1,5 @@ export * from './MessageHandlers'; +export * from './darkenColor'; export * from './getRelPath'; export * from './preserveColor'; export * from './updateCssVariables'; diff --git a/src/dashboardWebView/utils/updateCssVariables.ts b/src/dashboardWebView/utils/updateCssVariables.ts index 1308ac04..3a2ad906 100644 --- a/src/dashboardWebView/utils/updateCssVariables.ts +++ b/src/dashboardWebView/utils/updateCssVariables.ts @@ -1,3 +1,4 @@ +import { darkenColor } from './darkenColor'; import { preserveColor } from './preserveColor'; export const updateCssVariables = () => { @@ -75,4 +76,11 @@ export const updateCssVariables = () => { preserveColor(buttonHoverBackground) || 'var(--vscode-button-hoverBackground)' ); } + + // Darken the background of a color + const sideBarBg = styles.getPropertyValue('--vscode-sideBar-background'); + document.documentElement.style.setProperty( + '--frontmatter-sideBar-background', + darkenColor(sideBarBg, 2) || 'var(--vscode-sideBar-background)' + ); };