Merge branch 'dev' of github.com:estruyf/vscode-front-matter into dev

This commit is contained in:
Elio Struyf
2024-04-01 15:11:17 +02:00
15 changed files with 113 additions and 50 deletions

View File

@@ -22,6 +22,7 @@
- [#768](https://github.com/estruyf/vscode-front-matter/issues/768): Update broken link to the documentation
- [#771](https://github.com/estruyf/vscode-front-matter/issues/771): Fix lowercase `data` tab label
- [#782](https://github.com/estruyf/vscode-front-matter/issues/782): Fix for setting the correct view when inserting media or snippets
- [#786](https://github.com/estruyf/vscode-front-matter/issues/786): Remove on startup as VSCode now triggers on known commands
## [10.0.2] - 2024-03-01

View File

@@ -50,8 +50,7 @@
},
"activationEvents": [
"workspaceContains:**/.frontmatter",
"workspaceContains:**/frontmatter.json",
"onStartupFinished"
"workspaceContains:**/frontmatter.json"
],
"main": "./dist/extension.js",
"contributes": {

View File

@@ -36,7 +36,7 @@ export const DateField: React.FunctionComponent<IDateFieldProps> = ({
}
return (
<span className={`date__field ${className || ''} text-xs text-[var(--frontmatter-text)]`}>
<span className={`date__field ${className || ''} text-xs text-[var(--frontmatter-secondary-text)]`}>
{dateValue}
</span>
);

View File

@@ -5,27 +5,27 @@ import { useMemo } from 'react';
export interface IItemSelectionProps {
filePath: string;
isRowItem?: boolean;
show?: boolean;
}
export const ItemSelection: React.FunctionComponent<IItemSelectionProps> = ({
filePath,
isRowItem
show
}: React.PropsWithChildren<IItemSelectionProps>) => {
const { onMultiSelect, selectedFiles } = useSelectedItems();
const cssNames = useMemo(() => {
if (isRowItem) {
if (show) {
return 'block';
}
return `${selectedFiles.includes(filePath) ? 'block' : 'hidden'} absolute top-2 left-2`;
}, [isRowItem, selectedFiles]);
}, [show, selectedFiles]);
return (
<div className={`${cssNames} group-hover:block`}>
<VSCodeCheckbox
style={{
boxShadow: isRowItem ? "" : "0 0 3px var(--frontmatter-border-preserve)"
boxShadow: show ? "" : "0 0 3px var(--frontmatter-border-preserve)"
}}
onClick={(e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
e.stopPropagation();

View File

@@ -1,11 +1,12 @@
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 { EyeIcon, GlobeEuropeAfricaIcon, TrashIcon } from '@heroicons/react/24/solid';
import { LocalizationKey } from '../../../localization';
import { openFile, openOnWebsite } from '../../utils';
import { useRecoilState } from 'recoil';
import { SelectedItemActionAtom } from '../../state';
// import { ItemSelection } from '../Common/ItemSelection';
export interface IFooterActionsProps {
filePath: string;
@@ -19,7 +20,9 @@ export const FooterActions: React.FunctionComponent<IFooterActionsProps> = ({
const [, setSelectedItemAction] = useRecoilState(SelectedItemActionAtom);
return (
<div className={`py-2 w-full flex items-center justify-evenly border-t border-t-[var(--frontmatter-border)] bg-[var(--frontmatter-sideBar-background)] group-hover:bg-[var(--vscode-list-hoverBackground)]`}>
<div className={`py-2 w-full flex items-center justify-evenly border-t border-t-[var(--frontmatter-border)] bg-[var(--frontmatter-sideBar-background)] group-hover:bg-[var(--vscode-list-hoverBackground)] rounded`}>
{/* <ItemSelection filePath={filePath} show /> */}
<QuickAction
title={l10n.t(LocalizationKey.dashboardContentsContentActionsMenuItemView)}
className={`text-[var(--frontmatter-secondary-text)]`}

View File

@@ -11,13 +11,14 @@ import * as React from 'react';
import useExtensibility from '../../hooks/useExtensibility';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
import { useNavigate } from 'react-router-dom';
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';
import useSelectedItems from '../../hooks/useSelectedItems';
import { cn } from '../../../utils/cn';
import { Tags } from './Tags';
export interface IItemProps extends Page { }
@@ -26,12 +27,12 @@ const PREVIEW_IMAGE_FIELD = 'fmPreviewImage';
export const Item: React.FunctionComponent<IItemProps> = ({
...pageData
}: React.PropsWithChildren<IItemProps>) => {
const { selectedFiles } = useSelectedItems();
const view = useRecoilValue(ViewSelector);
const settings = useRecoilValue(SettingsSelector);
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);
const navigate = useNavigate();
const { titleHtml, descriptionHtml, dateHtml, statusHtml, tagsHtml, imageHtml, footerHtml } = useExtensibility({
fmFilePath: pageData.fmFilePath,
date: pageData.date,
@@ -41,6 +42,8 @@ export const Item: React.FunctionComponent<IItemProps> = ({
pageData
});
const isSelected = useMemo(() => selectedFiles.includes(pageData.fmFilePath), [selectedFiles, pageData.fmFilePath]);
const onOpenFile = React.useCallback(() => {
openFile(pageData.fmFilePath);
}, [pageData.fmFilePath]);
@@ -107,12 +110,12 @@ export const Item: React.FunctionComponent<IItemProps> = ({
return (
<li className="relative">
<div
className={`group flex flex-col items-start content-start h-full w-full text-left shadow-md dark:shadow-none hover:shadow-xl border rounded bg-[var(--vscode-sideBar-background)] hover:bg-[var(--vscode-list-hoverBackground)] text-[var(--vscode-sideBarTitle-foreground)] border-[var(--frontmatter-border)]`}
className={cn(`group flex flex-col items-start content-start h-full w-full text-left shadow-md dark:shadow-none hover:shadow-xl border rounded bg-[var(--vscode-sideBar-background)] hover:bg-[var(--vscode-list-hoverBackground)] text-[var(--vscode-sideBarTitle-foreground)] border-[var(--frontmatter-border)]`, isSelected && `border-[var(--frontmatter-border-active)]`)}
>
<button
title={escapedTitle ? l10n.t(LocalizationKey.commonOpenWithValue, escapedTitle) : l10n.t(LocalizationKey.commonOpen)}
onClick={onOpenFile}
className={`relative h-36 w-full overflow-hidden border-b cursor-pointer border-[var(--frontmatter-border)]`}
className={`relative rounded h-36 w-full overflow-hidden border-b cursor-pointer border-[var(--frontmatter-border)]`}
>
{
imageHtml ?
@@ -139,9 +142,9 @@ export const Item: React.FunctionComponent<IItemProps> = ({
<div className="relative p-4 w-full grow">
{
(statusPlaceholder || datePlaceholder) && (
<div className={`flex justify-between items-center ${hasDraftOrDate ? `mb-2` : ``}`}>
{statusPlaceholder}
{datePlaceholder}
<div className={`space-y-2 ${hasDraftOrDate ? `mb-2` : ``}`}>
<div>{statusPlaceholder}</div>
<div>{datePlaceholder}</div>
</div>
)
}
@@ -183,7 +186,7 @@ export const Item: React.FunctionComponent<IItemProps> = ({
descriptionHtml ? (
<div dangerouslySetInnerHTML={{ __html: descriptionHtml }} />
) : (
<p className={`text-xs text-[vara(--vscode-titleBar-activeForeground)]`}>{escapedDescription}</p>
<p className={`text-xs text-[var(--frontmatter-secondary-text)]`}>{escapedDescription}</p>
)
}
</button>
@@ -194,27 +197,7 @@ export const Item: React.FunctionComponent<IItemProps> = ({
tagsHtml ? (
<div className="mt-2" dangerouslySetInnerHTML={{ __html: tagsHtml }} />
) : (
tags && tags.length > 0 && (
<div className="mt-2">
{tags.map(
(tag, index) => tag && (
<button
key={index}
className={`inline-block mr-1 mt-1 text-xs text-[var(--vscode-textPreformat-foreground)] hover:brightness-75 hover:underline hover:underline-offset-1`}
title={l10n.t(LocalizationKey.commonFilterValue, tag)}
onClick={() => {
const tagField = settings?.dashboardState.contents.tags;
if (tagField) {
navigate(`${routePaths.contents}?taxonomy=${tagField}&value=${tag}`);
}
}}
>
#{tag}
</button>
)
)}
</div>
)
<Tags values={tags} tagField={settings?.dashboardState?.contents?.tags} />
)
}
</div>
@@ -238,7 +221,7 @@ export const Item: React.FunctionComponent<IItemProps> = ({
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)]`}
>
<div className="col-span-8 font-bold truncate flex items-center space-x-4">
<ItemSelection filePath={pageData.fmFilePath} isRowItem />
<ItemSelection filePath={pageData.fmFilePath} show />
<button
title={escapedTitle ? l10n.t(LocalizationKey.commonOpenWithValue, escapedTitle) : l10n.t(LocalizationKey.commonOpen)}

View File

@@ -7,21 +7,26 @@ import { SettingsSelector } from '../../state';
import { useRecoilValue } from 'recoil';
import { ItemSelection } from '../Common/ItemSelection';
import { openFile } from '../../utils';
import useSelectedItems from '../../hooks/useSelectedItems';
import { cn } from '../../../utils/cn';
export interface IPinnedItemProps extends Page { }
export const PinnedItem: React.FunctionComponent<IPinnedItemProps> = ({
...pageData
}: React.PropsWithChildren<IPinnedItemProps>) => {
const { selectedFiles } = useSelectedItems();
const settings = useRecoilValue(SettingsSelector);
const { escapedTitle } = useCard(pageData, settings?.dashboardState?.contents?.cardFields);
const isSelected = React.useMemo(() => selectedFiles.includes(pageData.fmFilePath), [selectedFiles, 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'>
<li className={cn(`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`, isSelected && `border-[var(--frontmatter-border-active)]`)}>
<button onClick={onOpenFile} className='relative h-full w-1/3'>
{
pageData["fmPreviewImage"] ? (

View File

@@ -34,7 +34,7 @@ export const Status: React.FunctionComponent<IStatusProps> = ({
if (draftValue) {
return (
<span
className={`inline-block px-1 py-1 leading-none rounded-sm font-semibold uppercase tracking-wide text-[0.7rem] text-[var(--vscode-badge-foreground)] bg-[var(--vscode-badge-background)]`}
className={`inline-block px-[3px] py-[2px] rounded font-semibold uppercase tracking-wide text-[0.7rem] text-[var(--vscode-badge-foreground)] bg-[var(--vscode-badge-background)]`}
>
{draftValue}
</span>
@@ -51,7 +51,7 @@ export const Status: React.FunctionComponent<IStatusProps> = ({
return (
<span
className={`draft__status
inline-block px-1 py-1 leading-none rounded-sm font-semibold uppercase tracking-wide text-[0.7rem]
inline-block px-[3px] py-[2px] rounded font-semibold uppercase tracking-wide text-[0.7rem]
${draftValue ?
'bg-[var(--vscode-statusBarItem-errorBackground)] text-[var(--vscode-statusBarItem-errorForeground)]' :
isFuture ?

View File

@@ -0,0 +1,35 @@
import * as React from 'react';
import * as l10n from '@vscode/l10n';
import { routePaths } from '../..';
import { LocalizationKey } from '../../../localization';
import { useNavigate } from 'react-router-dom';
export interface ITagProps {
value?: string;
tagField?: string | null | undefined;
}
export const Tag: React.FunctionComponent<ITagProps> = ({
value,
tagField
}: React.PropsWithChildren<ITagProps>) => {
const navigate = useNavigate();
if (!value) {
return null;
}
return (
<button
className={`inline-block mr-1 mt-1 text-xs text-[var(--vscode-button-secondaryForeground)] bg-[var(--vscode-button-secondaryBackground)] hover:bg-[var(--vscode-button-secondaryHoverBackground)] border border-[var(--frontmatter-border)] rounded px-1 py-0.5`}
title={l10n.t(LocalizationKey.commonFilterValue, value)}
onClick={() => {
if (tagField) {
navigate(`${routePaths.contents}?taxonomy=${tagField}&value=${value}`);
}
}}
>
#{value}
</button>
);
};

View File

@@ -0,0 +1,29 @@
import * as React from 'react';
import { Tag } from './Tag';
export interface ITagsProps {
values?: string[];
tagField?: string | null | undefined;
}
export const Tags: React.FunctionComponent<ITagsProps> = ({
values,
tagField
}: React.PropsWithChildren<ITagsProps>) => {
if (!values || values.length === 0) {
return null;
}
return (
<div className="mt-2">
{values.map(
(tag, index) => tag && (
<Tag
key={index}
value={tag}
tagField={tagField} />
)
)}
</div>
);
};

View File

@@ -2,7 +2,7 @@ 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 { ClipboardIcon, CodeBracketIcon, EyeIcon, PencilIcon, PlusIcon, TrashIcon } from '@heroicons/react/24/solid';
import { useRecoilState } from 'recoil';
import { SelectedItemActionAtom } from '../../state';
import { MediaInfo, Snippet, ViewData } from '../../../models';

View File

@@ -52,7 +52,8 @@ export const routePaths: { [name: string]: string } = {
};
const mutationObserver = new MutationObserver((_, __) => {
updateCssVariables();
const darkMode = document.body.classList.contains('vscode-dark');
updateCssVariables(darkMode);
});
const elm = document.querySelector('#app');
@@ -67,7 +68,7 @@ if (elm) {
const webviewUrl = elm?.getAttribute('data-webview-url');
const isCrashDisabled = elm?.getAttribute('data-is-crash-disabled');
updateCssVariables();
updateCssVariables(document.body.classList.contains('vscode-dark'));
mutationObserver.observe(document.body, { childList: false, attributes: true });
if (isProd === 'true' && isCrashDisabled === 'false') {

View File

@@ -57,7 +57,9 @@ export const darkenColor = (color: string | undefined, percentage: number) => {
// Check if the color is in rgba format
if (color.startsWith('rgba')) {
// Extract the alpha value
const alpha = Number(color.match(/[\d\.]+$/));
const alphaMatch = color.match(/[\d\.]+(?=\))/);
const alpha = alphaMatch ? Number(alphaMatch[0]) : 1;
console.log('alpha:', alpha);
return `rgba(${darkenedR}, ${darkenedG}, ${darkenedB}, ${alpha})`;
}

View File

@@ -1,7 +1,7 @@
import { darkenColor } from './darkenColor';
import { preserveColor } from './preserveColor';
export const updateCssVariables = () => {
export const updateCssVariables = (isDarkTheme: boolean = true) => {
const styles = getComputedStyle(document.documentElement);
// Lightbox
@@ -83,4 +83,9 @@ export const updateCssVariables = () => {
'--frontmatter-sideBar-background',
darkenColor(sideBarBg, 2) || 'var(--vscode-sideBar-background)'
);
document.documentElement.style.setProperty(
'--frontmatter-border-active',
darkenColor(borderColor, isDarkTheme ? -30 : 30) || 'var(--vscode-activityBar-activeBorder)'
);
};

View File

@@ -1,4 +1,4 @@
import { useState, useEffect } from 'react';
import { useEffect } from 'react';
export default function useDarkMode() {
const setTheme = (elm: HTMLElement) => {