mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-05-17 14:55:42 +02:00
Merge branch 'dev' into issue/666
This commit is contained in:
@@ -54,6 +54,7 @@ export enum DashboardMessage {
|
||||
insertSnippet = 'insertSnippet',
|
||||
addSnippet = 'addSnippet',
|
||||
updateSnippet = 'updateSnippet',
|
||||
updateSnippetPlaceholders = 'updateSnippetPlaceholders',
|
||||
|
||||
// Taxonomy dashboard
|
||||
getTaxonomyData = 'getTaxonomyData',
|
||||
|
||||
@@ -164,7 +164,7 @@ export const Header: React.FunctionComponent<IHeaderProps> = ({
|
||||
<Searchbox />
|
||||
|
||||
<div className={`flex items-center justify-end space-x-4 flex-1`}>
|
||||
<SyncButton />
|
||||
{/* <SyncButton /> */}
|
||||
|
||||
<ChoiceButton
|
||||
title={l10n.t(LocalizationKey.dashboardHeaderHeaderCreateContent)}
|
||||
|
||||
@@ -18,15 +18,15 @@ export const SyncButton: React.FunctionComponent<ISyncButtonProps> = (
|
||||
const [isSyncing, setIsSyncing] = useState(false);
|
||||
|
||||
const pull = () => {
|
||||
Messenger.send(GeneralCommands.toVSCode.gitSync);
|
||||
Messenger.send(GeneralCommands.toVSCode.git.sync);
|
||||
};
|
||||
|
||||
const messageListener = (message: MessageEvent<EventData<any>>) => {
|
||||
const { command } = message.data;
|
||||
|
||||
if (command === GeneralCommands.toWebview.gitSyncingStart) {
|
||||
if (command === GeneralCommands.toWebview.git.syncingStart) {
|
||||
setIsSyncing(true);
|
||||
} else if (command === GeneralCommands.toWebview.gitSyncingEnd) {
|
||||
} else if (command === GeneralCommands.toWebview.git.syncingEnd) {
|
||||
setIsSyncing(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -42,10 +42,12 @@ import { LocalizationKey } from '../../../localization';
|
||||
|
||||
export interface IItemProps {
|
||||
media: MediaInfo;
|
||||
index: number;
|
||||
}
|
||||
|
||||
export const Item: React.FunctionComponent<IItemProps> = ({
|
||||
media
|
||||
media,
|
||||
index
|
||||
}: React.PropsWithChildren<IItemProps>) => {
|
||||
const [, setLightbox] = useRecoilState(LightboxAtom);
|
||||
const [showAlert, setShowAlert] = useState(false);
|
||||
@@ -66,7 +68,7 @@ export const Item: React.FunctionComponent<IItemProps> = ({
|
||||
|
||||
const [referenceElement, setReferenceElement] = useState<any>(null);
|
||||
const [popperElement, setPopperElement] = useState<any>(null);
|
||||
const { styles, attributes } = usePopper(referenceElement, popperElement, {
|
||||
const { styles, attributes, update } = usePopper(referenceElement, popperElement, {
|
||||
placement: 'bottom-end',
|
||||
strategy: 'fixed'
|
||||
});
|
||||
@@ -400,6 +402,12 @@ export const Item: React.FunctionComponent<IItemProps> = ({
|
||||
setMediaData(undefined);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (update) {
|
||||
update();
|
||||
}
|
||||
}, [update, index]);
|
||||
|
||||
useEffect(() => {
|
||||
const name = basename(parseWinPath(media.fsPath) || '');
|
||||
if (name !== filename) {
|
||||
|
||||
@@ -250,8 +250,8 @@ export const Media: React.FunctionComponent<IMediaProps> = (
|
||||
)}
|
||||
|
||||
<List>
|
||||
{allMedia.map((file) => (
|
||||
<Item key={file.fsPath} media={file} />
|
||||
{allMedia.map((file, idx) => (
|
||||
<Item key={file.fsPath} media={file} index={idx} />
|
||||
))}
|
||||
</List>
|
||||
</div>
|
||||
|
||||
@@ -18,8 +18,7 @@ export const ActionMenuButton: React.FunctionComponent<IActionMenuButtonProps> =
|
||||
ref={ref || null}
|
||||
onClick={(e: React.MouseEvent<HTMLButtonElement>) => e.stopPropagation()}
|
||||
disabled={disabled}
|
||||
className={`group inline-flex justify-center text-sm font-medium text-[var(--vscode-tab-inactiveForeground)] hover:text-[var(--vscode-tab-activeForeground)] ${disabled ? 'opacity-50' : ''
|
||||
}`}
|
||||
className={`group inline-flex justify-center text-sm font-medium text-[var(--vscode-tab-inactiveForeground)] hover:text-[var(--vscode-tab-activeForeground)] ${disabled ? 'opacity-50' : ''}`}
|
||||
>
|
||||
<span className="sr-only">{title}</span>
|
||||
<EllipsisVerticalIcon className="w-4 h-4" aria-hidden="true" />
|
||||
|
||||
@@ -6,15 +6,17 @@ import { useRecoilValue } from 'recoil';
|
||||
import { SettingsSelector } from '../../state';
|
||||
import { SettingsInput } from './SettingsInput';
|
||||
import { VSCodeButton } from '@vscode/webview-ui-toolkit/react';
|
||||
import { FrameworkDetectors, SETTING_FRAMEWORK_START, SETTING_PREVIEW_HOST, SETTING_WEBSITE_URL } from '../../../constants';
|
||||
import { DOCS_SUBMODULES, FrameworkDetectors, GIT_CONFIG, SETTING_FRAMEWORK_START, SETTING_GIT_COMMIT_MSG, SETTING_GIT_ENABLED, SETTING_PREVIEW_HOST, SETTING_WEBSITE_URL } from '../../../constants';
|
||||
import { messageHandler } from '@estruyf/vscode/dist/client';
|
||||
import { DashboardMessage } from '../../DashboardMessage';
|
||||
import { SettingsCheckbox } from './SettingsCheckbox';
|
||||
import { ChevronRightIcon } from '@heroicons/react/24/outline';
|
||||
|
||||
export interface ICommonSettingsProps { }
|
||||
|
||||
interface Config {
|
||||
name: string;
|
||||
value: string;
|
||||
value: string | boolean;
|
||||
}
|
||||
|
||||
export const CommonSettings: React.FunctionComponent<ICommonSettingsProps> = (props: React.PropsWithChildren<ICommonSettingsProps>) => {
|
||||
@@ -22,7 +24,7 @@ export const CommonSettings: React.FunctionComponent<ICommonSettingsProps> = (pr
|
||||
const [config, setConfig] = React.useState<Config[]>([]);
|
||||
const [updated, setUpdated] = React.useState<boolean>(false);
|
||||
|
||||
const onSettingChange = React.useCallback((name: string, value: string) => {
|
||||
const onSettingChange = React.useCallback((name: string, value: string | boolean) => {
|
||||
setConfig((prev) => {
|
||||
const setting = prev.find((c) => c.name === name);
|
||||
if (setting) {
|
||||
@@ -39,7 +41,13 @@ export const CommonSettings: React.FunctionComponent<ICommonSettingsProps> = (pr
|
||||
}, [config]);
|
||||
|
||||
const retrieveSettings = () => {
|
||||
messageHandler.request<Config[]>(DashboardMessage.getSettings, [SETTING_PREVIEW_HOST, SETTING_WEBSITE_URL, SETTING_FRAMEWORK_START]).then((config) => {
|
||||
messageHandler.request<Config[]>(DashboardMessage.getSettings, [
|
||||
SETTING_PREVIEW_HOST,
|
||||
SETTING_WEBSITE_URL,
|
||||
SETTING_FRAMEWORK_START,
|
||||
SETTING_GIT_ENABLED,
|
||||
SETTING_GIT_COMMIT_MSG,
|
||||
]).then((config) => {
|
||||
setConfig(config);
|
||||
setUpdated(false);
|
||||
});
|
||||
@@ -65,6 +73,42 @@ export const CommonSettings: React.FunctionComponent<ICommonSettingsProps> = (pr
|
||||
<Startup settings={settings} />
|
||||
</div>
|
||||
|
||||
<div className='py-4'>
|
||||
<h2 className='text-xl mb-2'>{l10n.t(LocalizationKey.settingsGit)}</h2>
|
||||
|
||||
<div className='space-y-2'>
|
||||
<SettingsCheckbox
|
||||
label={l10n.t(LocalizationKey.settingsGitEnabled)}
|
||||
name={SETTING_GIT_ENABLED}
|
||||
value={(config.find((c) => c.name === SETTING_GIT_ENABLED)?.value || false) as boolean}
|
||||
onChange={onSettingChange}
|
||||
/>
|
||||
|
||||
<SettingsInput
|
||||
label={l10n.t(LocalizationKey.settingsGitCommitMessage)}
|
||||
name={SETTING_GIT_COMMIT_MSG}
|
||||
value={(config.find((c) => c.name === SETTING_GIT_COMMIT_MSG)?.value || "") as string}
|
||||
placeholder={GIT_CONFIG.defaultCommitMessage}
|
||||
onChange={onSettingChange}
|
||||
/>
|
||||
|
||||
<p className={`text-[var(--frontmatter-secondary-text)] flex items-center`}>
|
||||
<ChevronRightIcon className='h-4 w-4 inline' />
|
||||
|
||||
<span>
|
||||
{l10n.t(LocalizationKey.settingsGitSubmoduleInfo)}
|
||||
</span>
|
||||
|
||||
<a
|
||||
href={DOCS_SUBMODULES}
|
||||
title={l10n.t(LocalizationKey.settingsGitSubmoduleLink)}
|
||||
className='text-[var(--vscode-textLink-foreground)] hover:text-[var(--vscode-textLink-activeForeground)]'>
|
||||
{l10n.t(LocalizationKey.settingsGitSubmoduleLink)}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='py-4'>
|
||||
<h2 className='text-xl mb-2'>{l10n.t(LocalizationKey.settingsCommonSettingsWebsiteTitle)}</h2>
|
||||
|
||||
@@ -72,21 +116,21 @@ export const CommonSettings: React.FunctionComponent<ICommonSettingsProps> = (pr
|
||||
<SettingsInput
|
||||
label={l10n.t(LocalizationKey.settingsCommonSettingsPreviewUrl)}
|
||||
name={SETTING_PREVIEW_HOST}
|
||||
value={config.find((c) => c.name === SETTING_PREVIEW_HOST)?.value || ""}
|
||||
value={(config.find((c) => c.name === SETTING_PREVIEW_HOST)?.value || "") as string}
|
||||
onChange={onSettingChange}
|
||||
/>
|
||||
|
||||
<SettingsInput
|
||||
label={l10n.t(LocalizationKey.settingsCommonSettingsWebsiteUrl)}
|
||||
name={SETTING_WEBSITE_URL}
|
||||
value={config.find((c) => c.name === SETTING_WEBSITE_URL)?.value || ""}
|
||||
value={(config.find((c) => c.name === SETTING_WEBSITE_URL)?.value || "") as string}
|
||||
onChange={onSettingChange}
|
||||
/>
|
||||
|
||||
<SettingsInput
|
||||
label={l10n.t(LocalizationKey.settingsCommonSettingsStartCommand)}
|
||||
name={SETTING_FRAMEWORK_START}
|
||||
value={config.find((c) => c.name === SETTING_FRAMEWORK_START)?.value || ""}
|
||||
value={(config.find((c) => c.name === SETTING_FRAMEWORK_START)?.value || "") as string}
|
||||
onChange={onSettingChange}
|
||||
fallback={FrameworkDetectors.find((f) => f.framework.name === settings?.crntFramework)?.commands.start || ""}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { VSCodeCheckbox } from '@vscode/webview-ui-toolkit/react';
|
||||
import * as React from 'react';
|
||||
|
||||
export interface ISettingsCheckboxProps {
|
||||
label: string;
|
||||
name: string;
|
||||
value: boolean;
|
||||
onChange: (key: string, value: boolean) => void;
|
||||
}
|
||||
|
||||
export const SettingsCheckbox: React.FunctionComponent<ISettingsCheckboxProps> = ({
|
||||
label,
|
||||
name,
|
||||
value,
|
||||
onChange
|
||||
}: React.PropsWithChildren<ISettingsCheckboxProps>) => {
|
||||
const [isEnabled, setIsEnabled] = React.useState(false);
|
||||
|
||||
const updateValue = (value: boolean) => {
|
||||
setIsEnabled(value);
|
||||
onChange(name, value);
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
setIsEnabled(value);
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<VSCodeCheckbox
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => updateValue(e.target.checked)}
|
||||
checked={isEnabled}>
|
||||
{label}
|
||||
</VSCodeCheckbox>
|
||||
);
|
||||
};
|
||||
@@ -5,6 +5,7 @@ export interface ISettingsInputProps {
|
||||
label: string;
|
||||
name: string;
|
||||
value: string;
|
||||
placeholder?: string;
|
||||
onChange: (key: string, value: string) => void;
|
||||
fallback?: string;
|
||||
}
|
||||
@@ -13,6 +14,7 @@ export const SettingsInput: React.FunctionComponent<ISettingsInputProps> = ({
|
||||
label,
|
||||
name,
|
||||
value,
|
||||
placeholder,
|
||||
onChange,
|
||||
fallback
|
||||
}: React.PropsWithChildren<ISettingsInputProps>) => {
|
||||
@@ -24,6 +26,7 @@ export const SettingsInput: React.FunctionComponent<ISettingsInputProps> = ({
|
||||
boxShadow: 'none'
|
||||
}}
|
||||
value={value || fallback || ""}
|
||||
placeholder={placeholder}
|
||||
onInput={(e: React.ChangeEvent<HTMLInputElement>) => onChange(name, e.target.value)}>
|
||||
{label}
|
||||
</VSCodeTextField>
|
||||
|
||||
@@ -260,6 +260,7 @@ export const Item: React.FunctionComponent<IItemProps> = ({
|
||||
ref={formRef}
|
||||
snippetKey={snippetKey}
|
||||
snippet={snippet}
|
||||
filePath={viewData?.data?.filePath}
|
||||
fieldInfo={viewData?.data?.snippetInfo?.fields}
|
||||
selection={viewData?.data?.selection} />
|
||||
</FormDialog>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { Messenger } from '@estruyf/vscode/dist/client';
|
||||
import { Messenger, messageHandler } from '@estruyf/vscode/dist/client';
|
||||
import * as React from 'react';
|
||||
import { useCallback, useEffect, useImperativeHandle, useMemo, useState } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { processKnownPlaceholders } from '../../../helpers/PlaceholderHelper';
|
||||
import { SnippetParser } from '../../../helpers/SnippetParser';
|
||||
import { Snippet, SnippetField, SnippetInfoField, SnippetSpecialPlaceholders } from '../../../models';
|
||||
import { DashboardMessage } from '../../DashboardMessage';
|
||||
@@ -14,6 +13,7 @@ export interface ISnippetFormProps {
|
||||
snippetKey?: string;
|
||||
snippet: Snippet;
|
||||
selection: string | undefined;
|
||||
filePath?: string;
|
||||
fieldInfo?: SnippetInfoField[];
|
||||
mediaData?: any;
|
||||
onInsert?: (mediaData: any) => void;
|
||||
@@ -24,7 +24,7 @@ export interface SnippetFormHandle {
|
||||
}
|
||||
|
||||
const SnippetForm: React.ForwardRefRenderFunction<SnippetFormHandle, ISnippetFormProps> = (
|
||||
{ snippetKey, snippet, selection, fieldInfo, mediaData, onInsert },
|
||||
{ snippetKey, snippet, selection, filePath, fieldInfo, mediaData, onInsert },
|
||||
ref
|
||||
) => {
|
||||
const viewData = useRecoilValue(ViewDataSelector);
|
||||
@@ -41,20 +41,19 @@ const SnippetForm: React.ForwardRefRenderFunction<SnippetFormHandle, ISnippetFor
|
||||
);
|
||||
|
||||
const insertPlaceholderValues = useCallback(
|
||||
(value: SnippetSpecialPlaceholders) => {
|
||||
async (value: SnippetSpecialPlaceholders) => {
|
||||
if (value === 'FM_SELECTED_TEXT') {
|
||||
return selection || '';
|
||||
}
|
||||
|
||||
value = processKnownPlaceholders(
|
||||
value = await messageHandler.request<string>(DashboardMessage.updateSnippetPlaceholders, {
|
||||
value,
|
||||
viewData?.data?.fileTitle || '',
|
||||
settings?.date.format || ''
|
||||
);
|
||||
filePath
|
||||
});
|
||||
|
||||
return value;
|
||||
},
|
||||
[selection]
|
||||
[selection, filePath]
|
||||
);
|
||||
|
||||
const insertValueFromMedia = useCallback(
|
||||
@@ -128,7 +127,7 @@ ${snippetBody}
|
||||
}
|
||||
}));
|
||||
|
||||
useEffect(() => {
|
||||
const processFields = useCallback(async () => {
|
||||
// Get all placeholder variables from the snippet
|
||||
const body = typeof snippet.body === 'string' ? snippet.body : snippet.body.join(`\n`);
|
||||
|
||||
@@ -147,7 +146,7 @@ ${snippetBody}
|
||||
if (idx > -1) {
|
||||
allFields.push({
|
||||
...field,
|
||||
value: insertPlaceholderValues(field.default || '')
|
||||
value: await insertPlaceholderValues(field.default || '')
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -167,6 +166,10 @@ ${snippetBody}
|
||||
}
|
||||
|
||||
setFields(allFields);
|
||||
}, [snippet, insertPlaceholderValues, insertValueFromMedia]);
|
||||
|
||||
useEffect(() => {
|
||||
processFields();
|
||||
}, [snippet]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -13,11 +13,12 @@ import { FrameworkDetectors } from '../../../constants/FrameworkDetectors';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../../localization';
|
||||
import { SelectItem } from './SelectItem';
|
||||
import { Templates } from '../../../constants';
|
||||
import { GeneralCommands, SETTING_GIT_ENABLED, Templates } from '../../../constants';
|
||||
import { TemplateItem } from './TemplateItem';
|
||||
import { Spinner } from '../Common/Spinner';
|
||||
import { AstroContentTypes } from '../Configuration/Astro/AstroContentTypes';
|
||||
import { ContentFolders } from '../Configuration/Common/ContentFolders';
|
||||
import { VSCodeCheckbox } from '@vscode/webview-ui-toolkit/react';
|
||||
|
||||
export interface IStepsToGetStartedProps {
|
||||
settings: Settings;
|
||||
@@ -29,6 +30,8 @@ export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps>
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [framework, setFramework] = useState<string | null>(null);
|
||||
const [taxImported, setTaxImported] = useState<boolean>(false);
|
||||
const [isGitEnabled, setIsGitEnabled] = useState<boolean>(false);
|
||||
const [isGitRepo, setIsGitRepo] = useState<boolean>(false);
|
||||
const [templates, setTemplates] = useState<Template[]>([]);
|
||||
const [astroCollectionsStatus, setAstroCollectionsStatus] = useState<Status>(Status.Optional);
|
||||
|
||||
@@ -73,6 +76,15 @@ export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps>
|
||||
setTaxImported(true);
|
||||
};
|
||||
|
||||
const updateSetting = (name: string, value: any) => {
|
||||
setIsGitEnabled(value);
|
||||
Messenger.send(DashboardMessage.updateSetting, {
|
||||
name,
|
||||
value,
|
||||
global: true
|
||||
});
|
||||
}
|
||||
|
||||
const crntTemplates = useMemo(() => {
|
||||
if (!templates || templates.length === 0 || !settings.crntFramework) {
|
||||
return [];
|
||||
@@ -230,6 +242,21 @@ export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps>
|
||||
show: settings.crntFramework === 'astro' || framework === 'astro',
|
||||
status: settings.initialized && settings.staticFolder && settings.staticFolder !== "/" ? Status.Completed : Status.NotStarted,
|
||||
},
|
||||
{
|
||||
id: `welcome-git`,
|
||||
name: l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedGitName),
|
||||
description: (
|
||||
<div className='mt-1'>
|
||||
<VSCodeCheckbox
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => updateSetting(SETTING_GIT_ENABLED, e.target.checked)}
|
||||
checked={isGitEnabled}>
|
||||
{l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedGitDescription)}
|
||||
</VSCodeCheckbox>
|
||||
</div>
|
||||
),
|
||||
show: isGitRepo,
|
||||
status: settings.git?.actions ? Status.Completed : Status.NotStarted
|
||||
},
|
||||
{
|
||||
id: `welcome-import`,
|
||||
name: l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedTagsName),
|
||||
@@ -257,7 +284,7 @@ export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps>
|
||||
: undefined
|
||||
}
|
||||
]
|
||||
), [settings, framework, taxImported, templates, astroCollectionsStatus]);
|
||||
), [settings, framework, taxImported, templates, astroCollectionsStatus, isGitRepo]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (settings.crntFramework || settings.framework?.name) {
|
||||
@@ -265,6 +292,14 @@ export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps>
|
||||
}
|
||||
}, [settings.crntFramework, settings.framework]);
|
||||
|
||||
React.useEffect(() => {
|
||||
messageHandler.request<boolean>(GeneralCommands.toVSCode.git.isRepo).then((result) => {
|
||||
setIsGitRepo(result);
|
||||
});
|
||||
|
||||
setIsGitEnabled(settings.git?.actions || false);
|
||||
}, [settings.git?.actions]);
|
||||
|
||||
React.useEffect(() => {
|
||||
const fetchTemplates = async () => {
|
||||
try {
|
||||
|
||||
@@ -20,7 +20,7 @@ import { DataFile } from '../../models/DataFile';
|
||||
export interface Settings {
|
||||
projects: Project[];
|
||||
project: Project;
|
||||
git: GitSettings;
|
||||
git: GitSettings | undefined;
|
||||
beta: boolean;
|
||||
initialized: boolean;
|
||||
wsFolder: string;
|
||||
|
||||
Reference in New Issue
Block a user