mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-07-05 17:31:22 +02:00
#705 - UX improvements for SEO panel
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../localization';
|
||||
import { VSCodeTable, VSCodeTableBody, VSCodeTableCell, VSCodeTableHead, VSCodeTableHeader, VSCodeTableRow } from './VSCode/VSCodeTable';
|
||||
import { VSCodeTableCell, VSCodeTableRow } from './VSCode/VSCodeTable';
|
||||
|
||||
export interface IArticleDetailsProps {
|
||||
details: {
|
||||
@@ -22,59 +22,42 @@ const ArticleDetails: React.FunctionComponent<IArticleDetailsProps> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`seo__status__details valid`}>
|
||||
<h4>{l10n.t(LocalizationKey.panelArticleDetailsTitle)}</h4>
|
||||
<>
|
||||
{details?.headings !== undefined && (
|
||||
<VSCodeTableRow>
|
||||
<VSCodeTableCell>{l10n.t(LocalizationKey.panelArticleDetailsHeadings)}</VSCodeTableCell>
|
||||
<VSCodeTableCell>{details.headings}</VSCodeTableCell>
|
||||
</VSCodeTableRow>
|
||||
)}
|
||||
|
||||
<VSCodeTable>
|
||||
<VSCodeTableHeader>
|
||||
<VSCodeTableRow>
|
||||
<VSCodeTableHead>
|
||||
{l10n.t(LocalizationKey.panelArticleDetailsType)}
|
||||
</VSCodeTableHead>
|
||||
<VSCodeTableHead>
|
||||
{l10n.t(LocalizationKey.panelArticleDetailsTotal)}
|
||||
</VSCodeTableHead>
|
||||
</VSCodeTableRow>
|
||||
</VSCodeTableHeader>
|
||||
{details?.paragraphs !== undefined && (
|
||||
<VSCodeTableRow>
|
||||
<VSCodeTableCell>{l10n.t(LocalizationKey.panelArticleDetailsParagraphs)}</VSCodeTableCell>
|
||||
<VSCodeTableCell>{details.paragraphs}</VSCodeTableCell>
|
||||
</VSCodeTableRow>
|
||||
)}
|
||||
|
||||
<VSCodeTableBody>
|
||||
{details?.headings !== undefined && (
|
||||
<VSCodeTableRow>
|
||||
<VSCodeTableCell>{l10n.t(LocalizationKey.panelArticleDetailsHeadings)}</VSCodeTableCell>
|
||||
<VSCodeTableCell>{details.headings}</VSCodeTableCell>
|
||||
</VSCodeTableRow>
|
||||
)}
|
||||
{details?.internalLinks !== undefined && (
|
||||
<VSCodeTableRow>
|
||||
<VSCodeTableCell>{l10n.t(LocalizationKey.panelArticleDetailsInternalLinks)}</VSCodeTableCell>
|
||||
<VSCodeTableCell>{details.internalLinks}</VSCodeTableCell>
|
||||
</VSCodeTableRow>
|
||||
)}
|
||||
|
||||
{details?.paragraphs !== undefined && (
|
||||
<VSCodeTableRow>
|
||||
<VSCodeTableCell>{l10n.t(LocalizationKey.panelArticleDetailsParagraphs)}</VSCodeTableCell>
|
||||
<VSCodeTableCell>{details.paragraphs}</VSCodeTableCell>
|
||||
</VSCodeTableRow>
|
||||
)}
|
||||
{details?.externalLinks !== undefined && (
|
||||
<VSCodeTableRow>
|
||||
<VSCodeTableCell>{l10n.t(LocalizationKey.panelArticleDetailsExternalLinks)}</VSCodeTableCell>
|
||||
<VSCodeTableCell>{details.externalLinks}</VSCodeTableCell>
|
||||
</VSCodeTableRow>
|
||||
)}
|
||||
|
||||
{details?.internalLinks !== undefined && (
|
||||
<VSCodeTableRow>
|
||||
<VSCodeTableCell>{l10n.t(LocalizationKey.panelArticleDetailsInternalLinks)}</VSCodeTableCell>
|
||||
<VSCodeTableCell>{details.internalLinks}</VSCodeTableCell>
|
||||
</VSCodeTableRow>
|
||||
)}
|
||||
|
||||
{details?.externalLinks !== undefined && (
|
||||
<VSCodeTableRow>
|
||||
<VSCodeTableCell>{l10n.t(LocalizationKey.panelArticleDetailsExternalLinks)}</VSCodeTableCell>
|
||||
<VSCodeTableCell>{details.externalLinks}</VSCodeTableCell>
|
||||
</VSCodeTableRow>
|
||||
)}
|
||||
|
||||
{details?.images !== undefined && (
|
||||
<VSCodeTableRow>
|
||||
<VSCodeTableCell>{l10n.t(LocalizationKey.panelArticleDetailsImages)}</VSCodeTableCell>
|
||||
<VSCodeTableCell>{details.images}</VSCodeTableCell>
|
||||
</VSCodeTableRow>
|
||||
)}
|
||||
</VSCodeTableBody>
|
||||
</VSCodeTable>
|
||||
</div>
|
||||
{details?.images !== undefined && (
|
||||
<VSCodeTableRow>
|
||||
<VSCodeTableCell>{l10n.t(LocalizationKey.panelArticleDetailsImages)}</VSCodeTableCell>
|
||||
<VSCodeTableCell>{details.images}</VSCodeTableCell>
|
||||
</VSCodeTableRow>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -7,19 +7,20 @@ export interface ISeoFieldInfoProps {
|
||||
value: string;
|
||||
recommendation: string;
|
||||
isValid?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const SeoFieldInfo: React.FunctionComponent<ISeoFieldInfoProps> = ({
|
||||
title,
|
||||
value,
|
||||
recommendation,
|
||||
isValid
|
||||
isValid,
|
||||
className
|
||||
}: React.PropsWithChildren<ISeoFieldInfoProps>) => {
|
||||
return (
|
||||
<VSCodeTableRow>
|
||||
<VSCodeTableRow className={className || ""}>
|
||||
<VSCodeTableCell className={`capitalize`}>{title}</VSCodeTableCell>
|
||||
<VSCodeTableCell>{value}/{recommendation}</VSCodeTableCell>
|
||||
<VSCodeTableCell>{isValid !== undefined ? <ValidInfo label={undefined} isValid={isValid} /> : <span>-</span>}</VSCodeTableCell>
|
||||
<VSCodeTableCell className='flex items-center text-nowrap'>{isValid !== undefined ? <ValidInfo label={undefined} isValid={isValid} /> : <span className='inline-block w-4 mr-2'>—</span>} {value}/{recommendation}</VSCodeTableCell>
|
||||
</VSCodeTableRow>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { ValidInfo } from './ValidInfo';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../localization';
|
||||
import { VSCodeTableCell, VSCodeTableRow } from './VSCode/VSCodeTable';
|
||||
|
||||
export interface ISeoKeywordInfoProps {
|
||||
@@ -31,14 +29,14 @@ const SeoKeywordInfo: React.FunctionComponent<ISeoKeywordInfoProps> = ({
|
||||
const pattern = new RegExp(`(^${keyword.toLowerCase()}(?=\\s|$))|(\\s${keyword.toLowerCase()}(?=\\s|$))`, 'ig');
|
||||
const count = (content.match(pattern) || []).length;
|
||||
const density = (count / wordCount) * 100;
|
||||
const densityTitle = l10n.t(LocalizationKey.panelSeoKeywordInfoDensity, `${density.toFixed(2)}%`);
|
||||
const densityTitle = `${density.toFixed(2)}% *`;
|
||||
|
||||
if (density < 0.75) {
|
||||
return <ValidInfo label={densityTitle} isValid={false} />;
|
||||
return <ValidInfo label={densityTitle} isValid={false} className='text-xs' />;
|
||||
} else if (density >= 0.75 && density < 1.5) {
|
||||
return <ValidInfo label={densityTitle} isValid={true} />;
|
||||
return <ValidInfo label={densityTitle} isValid={true} className='text-xs' />;
|
||||
} else {
|
||||
return <ValidInfo label={densityTitle} isValid={false} />;
|
||||
return <ValidInfo label={densityTitle} isValid={false} className='text-xs' />;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -63,7 +61,7 @@ const SeoKeywordInfo: React.FunctionComponent<ISeoKeywordInfoProps> = ({
|
||||
}
|
||||
|
||||
const exists = headings.filter((heading) => validateKeywords(heading, keyword));
|
||||
return <ValidInfo label={l10n.t(LocalizationKey.panelSeoKeywordInfoValidInfoLabel)} isValid={exists.length > 0} />;
|
||||
return <ValidInfo isValid={exists.length > 0} />;
|
||||
};
|
||||
|
||||
if (!keyword || typeof keyword !== 'string') {
|
||||
@@ -73,39 +71,35 @@ const SeoKeywordInfo: React.FunctionComponent<ISeoKeywordInfoProps> = ({
|
||||
return (
|
||||
<VSCodeTableRow>
|
||||
<VSCodeTableCell>{keyword}</VSCodeTableCell>
|
||||
<VSCodeTableCell className={` table__cell__validation`}>
|
||||
<div className='flex items-center'>
|
||||
<ValidInfo
|
||||
label={l10n.t(LocalizationKey.commonTitle)}
|
||||
isValid={!!title && title.toLowerCase().includes(keyword.toLowerCase())}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex items-center'>
|
||||
<ValidInfo
|
||||
label={l10n.t(LocalizationKey.commonDescription)}
|
||||
isValid={!!description && description.toLowerCase().includes(keyword.toLowerCase())}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex items-center'>
|
||||
<ValidInfo
|
||||
label={l10n.t(LocalizationKey.commonSlug)}
|
||||
isValid={
|
||||
!!slug &&
|
||||
(slug.toLowerCase().includes(keyword.toLowerCase()) ||
|
||||
slug.toLowerCase().includes(keyword.replace(/ /g, '-').toLowerCase()))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex items-center'>
|
||||
<ValidInfo
|
||||
label={l10n.t(LocalizationKey.panelSeoKeywordInfoValidInfoContent)}
|
||||
isValid={!!content && content.toLowerCase().includes(keyword.toLowerCase())}
|
||||
/>
|
||||
</div>
|
||||
{headings && headings.length > 0 &&
|
||||
<div className='flex items-center'>{checkHeadings()}</div>}
|
||||
{wordCount &&
|
||||
<div className='flex items-center'>{density()}</div>}
|
||||
<VSCodeTableCell className={`text-center`}>
|
||||
<ValidInfo
|
||||
isValid={!!title && title.toLowerCase().includes(keyword.toLowerCase())}
|
||||
/>
|
||||
</VSCodeTableCell>
|
||||
<VSCodeTableCell className={`text-center`}>
|
||||
<ValidInfo
|
||||
isValid={!!description && description.toLowerCase().includes(keyword.toLowerCase())}
|
||||
/>
|
||||
</VSCodeTableCell>
|
||||
<VSCodeTableCell className={`text-center`}>
|
||||
<ValidInfo
|
||||
isValid={
|
||||
!!slug &&
|
||||
(slug.toLowerCase().includes(keyword.toLowerCase()) ||
|
||||
slug.toLowerCase().includes(keyword.replace(/ /g, '-').toLowerCase()))
|
||||
}
|
||||
/>
|
||||
</VSCodeTableCell>
|
||||
<VSCodeTableCell className={`text-center`}>
|
||||
<ValidInfo
|
||||
isValid={!!content && content.toLowerCase().includes(keyword.toLowerCase())}
|
||||
/>
|
||||
</VSCodeTableCell>
|
||||
<VSCodeTableCell className={`text-center`}>
|
||||
{checkHeadings()}
|
||||
</VSCodeTableCell>
|
||||
<VSCodeTableCell className={`text-center`}>
|
||||
{density()}
|
||||
</VSCodeTableCell>
|
||||
</VSCodeTableRow>
|
||||
);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import * as React from 'react';
|
||||
import { SeoKeywordInfo } from './SeoKeywordInfo';
|
||||
import { ErrorBoundary } from '@sentry/react';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../localization';
|
||||
import { Tooltip } from 'react-tooltip'
|
||||
import { LocalizationKey, localize } from '../../localization';
|
||||
import { VSCodeTable, VSCodeTableBody, VSCodeTableHead, VSCodeTableHeader, VSCodeTableRow } from './VSCode/VSCodeTable';
|
||||
import { Icon } from 'vscrui';
|
||||
|
||||
export interface ISeoKeywordsProps {
|
||||
keywords: string[] | null;
|
||||
@@ -22,6 +23,8 @@ const SeoKeywords: React.FunctionComponent<ISeoKeywordsProps> = ({
|
||||
}: React.PropsWithChildren<ISeoKeywordsProps>) => {
|
||||
const [isReady, setIsReady] = React.useState(false);
|
||||
|
||||
const tooltipClasses = `!py-[2px] !px-[8px] !rounded-[3px] !border-[var(--vscode-editorHoverWidget-border)] !border !border-solid !bg-[var(--vscode-editorHoverWidget-background)] !text-[var(--vscode-editorHoverWidget-foreground)] !font-normal !opacity-100`;
|
||||
|
||||
const validateKeywords = () => {
|
||||
if (!keywords) {
|
||||
return [];
|
||||
@@ -51,17 +54,106 @@ const SeoKeywords: React.FunctionComponent<ISeoKeywordsProps> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`seo__status__keywords`}>
|
||||
<h4>{l10n.t(LocalizationKey.panelSeoKeywordsTitle)}</h4>
|
||||
<section className={`seo__keywords mb-8`}>
|
||||
<h4 className='!text-left'>{localize(LocalizationKey.panelSeoKeywordsTitle)}</h4>
|
||||
|
||||
<VSCodeTable>
|
||||
<VSCodeTableHeader>
|
||||
<VSCodeTableRow>
|
||||
<VSCodeTableRow className={`border-t border-t-[var(--vscode-editorGroup-border)]`}>
|
||||
<VSCodeTableHead>
|
||||
{l10n.t(LocalizationKey.panelSeoKeywordsHeaderKeyword)}
|
||||
{localize(LocalizationKey.panelSeoKeywordsHeaderKeyword)}
|
||||
</VSCodeTableHead>
|
||||
<VSCodeTableHead>
|
||||
{l10n.t(LocalizationKey.panelSeoKeywordsHeaderDetails)}
|
||||
<VSCodeTableHead className='text-center'>
|
||||
<div
|
||||
className='flex items-center justify-center h-full'
|
||||
>
|
||||
<Icon
|
||||
className='!text-[var(--vscode-foreground)]'
|
||||
name='quote'
|
||||
data-tooltip-id="tooltip-title"
|
||||
data-tooltip-content={localize(LocalizationKey.commonTitle)} />
|
||||
<Tooltip id="tooltip-title" className={tooltipClasses} style={{
|
||||
fontSize: '12px',
|
||||
lineHeight: '19px'
|
||||
}} />
|
||||
</div>
|
||||
</VSCodeTableHead>
|
||||
<VSCodeTableHead className='text-center'>
|
||||
<div
|
||||
className='flex items-center justify-center h-full'
|
||||
>
|
||||
<Icon
|
||||
className='!text-[var(--vscode-foreground)]'
|
||||
name='note'
|
||||
data-tooltip-id="tooltip-description"
|
||||
data-tooltip-content={localize(LocalizationKey.commonDescription)} />
|
||||
<Tooltip id="tooltip-description" className={tooltipClasses} style={{
|
||||
fontSize: '12px',
|
||||
lineHeight: '19px'
|
||||
}} />
|
||||
</div>
|
||||
</VSCodeTableHead>
|
||||
<VSCodeTableHead className='text-center'>
|
||||
<div
|
||||
className='flex items-center justify-center h-full'
|
||||
>
|
||||
<Icon
|
||||
className='!text-[var(--vscode-foreground)]'
|
||||
name='link'
|
||||
data-tooltip-id="tooltip-slug"
|
||||
data-tooltip-content={localize(LocalizationKey.commonSlug)} />
|
||||
<Tooltip id="tooltip-slug" className={tooltipClasses} style={{
|
||||
fontSize: '12px',
|
||||
lineHeight: '19px'
|
||||
}} />
|
||||
</div>
|
||||
</VSCodeTableHead>
|
||||
<VSCodeTableHead className='text-center'>
|
||||
<div
|
||||
className='flex items-center justify-center h-full'
|
||||
>
|
||||
<Icon
|
||||
className='!text-[var(--vscode-foreground)]'
|
||||
name='book'
|
||||
data-tooltip-id="tooltip-content"
|
||||
data-tooltip-content={localize(LocalizationKey.panelSeoKeywordInfoValidInfoContent)} />
|
||||
<Tooltip id="tooltip-content" className={tooltipClasses} style={{
|
||||
fontSize: '12px',
|
||||
lineHeight: '19px'
|
||||
}} />
|
||||
</div>
|
||||
</VSCodeTableHead>
|
||||
<VSCodeTableHead className='text-center'>
|
||||
<div
|
||||
className='flex items-center justify-center h-full'
|
||||
>
|
||||
<span
|
||||
className='text-[var(--vscode-foreground)] cursor-default select-none'
|
||||
data-tooltip-id="tooltip-heading"
|
||||
data-tooltip-content={localize(LocalizationKey.panelSeoKeywordInfoValidInfoLabel)}
|
||||
>
|
||||
H1
|
||||
</span>
|
||||
<Tooltip id="tooltip-heading" className={tooltipClasses} style={{
|
||||
fontSize: '12px',
|
||||
lineHeight: '19px'
|
||||
}} />
|
||||
</div>
|
||||
</VSCodeTableHead>
|
||||
<VSCodeTableHead className='text-center'>
|
||||
<div
|
||||
className='flex items-center justify-center h-full'
|
||||
>
|
||||
<Icon
|
||||
className='!text-[var(--vscode-foreground)]'
|
||||
name='percentage'
|
||||
data-tooltip-id="tooltip-density"
|
||||
data-tooltip-content={localize(LocalizationKey.panelSeoKeywordsDensity)} />
|
||||
<Tooltip id="tooltip-density" className={tooltipClasses} style={{
|
||||
fontSize: '12px',
|
||||
lineHeight: '19px'
|
||||
}} />
|
||||
</div>
|
||||
</VSCodeTableHead>
|
||||
</VSCodeTableRow>
|
||||
</VSCodeTableHeader>
|
||||
@@ -79,10 +171,10 @@ const SeoKeywords: React.FunctionComponent<ISeoKeywordsProps> = ({
|
||||
|
||||
{data.wordCount && (
|
||||
<div className={`text-xs mt-2`}>
|
||||
{l10n.t(LocalizationKey.panelSeoKeywordsDensity)}
|
||||
{localize(LocalizationKey.panelSeoKeywordsDensityDescription)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@ import { TagType } from '../TagType';
|
||||
import { ArticleDetails } from './ArticleDetails';
|
||||
import { Collapsible } from './Collapsible';
|
||||
import FieldBoundary from './ErrorBoundary/FieldBoundary';
|
||||
import { SymbolKeywordIcon } from './Icons/SymbolKeywordIcon';
|
||||
import { SeoFieldInfo } from './SeoFieldInfo';
|
||||
import { SeoKeywords } from './SeoKeywords';
|
||||
import { TagPicker } from './Fields/TagPicker';
|
||||
import { LocalizationKey, localize } from '../../localization';
|
||||
import { VSCodeTable, VSCodeTableBody, VSCodeTableHead, VSCodeTableHeader, VSCodeTableRow } from './VSCode/VSCodeTable';
|
||||
import { VSCodeTable, VSCodeTableBody } from './VSCode/VSCodeTable';
|
||||
import useContentType from '../../hooks/useContentType';
|
||||
import { Icon } from 'vscrui';
|
||||
|
||||
export interface ISeoStatusProps {
|
||||
seo: SEO;
|
||||
@@ -38,19 +38,11 @@ const SeoStatus: React.FunctionComponent<ISeoStatusProps> = ({
|
||||
const descriptionFieldName = contentType?.fields.find(f => f.name === descriptionField)?.title || descriptionField;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={`seo__status__details`}>
|
||||
<h4>{localize(LocalizationKey.panelSeoStatusTitle)}</h4>
|
||||
<div className='space-y-8'>
|
||||
<section className={`seo__insights`}>
|
||||
<h4 className='!text-left'>{localize(LocalizationKey.panelSeoStatusTitle)}</h4>
|
||||
|
||||
<VSCodeTable>
|
||||
<VSCodeTableHeader>
|
||||
<VSCodeTableRow>
|
||||
<VSCodeTableHead>{localize(LocalizationKey.panelSeoStatusHeaderProperty)}</VSCodeTableHead>
|
||||
<VSCodeTableHead>{localize(LocalizationKey.panelSeoStatusHeaderLength)}</VSCodeTableHead>
|
||||
<VSCodeTableHead>{localize(LocalizationKey.panelSeoStatusHeaderValid)}</VSCodeTableHead>
|
||||
</VSCodeTableRow>
|
||||
</VSCodeTableHeader>
|
||||
|
||||
<VSCodeTableBody>
|
||||
{metadata[titleField] && seo.title > 0 ? (
|
||||
<SeoFieldInfo
|
||||
@@ -58,6 +50,7 @@ const SeoStatus: React.FunctionComponent<ISeoStatusProps> = ({
|
||||
value={metadata[titleField].length}
|
||||
recommendation={localize(LocalizationKey.panelSeoStatusSeoFieldInfoCharacters, seo.title)}
|
||||
isValid={metadata[titleField].length <= seo.title}
|
||||
className={`border-t border-t-[var(--vscode-editorGroup-border)]`}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
@@ -86,9 +79,11 @@ const SeoStatus: React.FunctionComponent<ISeoStatusProps> = ({
|
||||
recommendation={localize(LocalizationKey.panelSeoStatusSeoFieldInfoWords, seo.content)}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<ArticleDetails details={metadata.articleDetails} />
|
||||
</VSCodeTableBody>
|
||||
</VSCodeTable>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<SeoKeywords
|
||||
keywords={metadata?.keywords}
|
||||
@@ -103,7 +98,7 @@ const SeoStatus: React.FunctionComponent<ISeoStatusProps> = ({
|
||||
<FieldBoundary fieldName={`Keywords`}>
|
||||
<TagPicker
|
||||
type={TagType.keywords}
|
||||
icon={<SymbolKeywordIcon />}
|
||||
icon={<Icon name="symbol-keyword" className='mr-2' />}
|
||||
crntSelected={(metadata.keywords as string[]) || []}
|
||||
options={[]}
|
||||
freeform={true}
|
||||
@@ -112,8 +107,6 @@ const SeoStatus: React.FunctionComponent<ISeoStatusProps> = ({
|
||||
disableConfigurable
|
||||
/>
|
||||
</FieldBoundary>
|
||||
|
||||
<ArticleDetails details={metadata.articleDetails} />
|
||||
</div>
|
||||
);
|
||||
}, [contentType, metadata, seo, focusElm, unsetFocus]);
|
||||
|
||||
@@ -4,21 +4,23 @@ import { CheckIcon, ExclamationTriangleIcon } from '@heroicons/react/24/outline'
|
||||
export interface IValidInfoProps {
|
||||
label?: string;
|
||||
isValid: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const ValidInfo: React.FunctionComponent<IValidInfoProps> = ({
|
||||
label,
|
||||
isValid
|
||||
isValid,
|
||||
className,
|
||||
}: React.PropsWithChildren<IValidInfoProps>) => {
|
||||
return (
|
||||
<>
|
||||
<div className='inline-flex items-center h-full'>
|
||||
{isValid ? (
|
||||
<CheckIcon className={`h-4 w-4 text-[#46ec86] mr-2`} />
|
||||
) : (
|
||||
<ExclamationTriangleIcon className={`h-4 w-4 text-[var(--vscode-statusBarItem-warningBackground)] mr-2`} />
|
||||
)}
|
||||
{label && <span>{label}</span>}
|
||||
</>
|
||||
{label && <span className={className || ""}>{label}</span>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user