New table implementation

This commit is contained in:
Elio Struyf
2024-03-13 14:52:06 +01:00
parent ec9f55b982
commit 5e77419f5a
27 changed files with 347 additions and 292 deletions
+1 -14
View File
@@ -247,14 +247,6 @@
background-color: var(--vscode-button-secondaryHoverBackground);
}
.table__cell {
overflow: hidden;
}
.table__title {
text-transform: capitalize;
}
.table__cell__seo_details {
padding: 10px;
}
@@ -281,11 +273,6 @@
margin-left: 0.5rem;
}
.seo__status__note {
font-size: 10px;
padding: 3px 0;
}
/* Fields */
.field__toggle {
position: relative;
@@ -364,7 +351,7 @@ input:checked + .field__toggle__slider:before {
}
/* File list */
.file_list vscode-label {
.file_list label {
border-bottom: 1px solid var(--vscode-foreground);
}
+56 -19
View File
@@ -13,7 +13,6 @@
},
"devDependencies": {
"@actions/core": "^1.10.0",
"@bendera/vscode-webview-elements": "0.6.2",
"@estruyf/vscode": "^1.1.0",
"@headlessui/react": "^1.7.18",
"@heroicons/react": "^2.1.1",
@@ -38,6 +37,7 @@
"@types/vscode": "^1.73.0",
"@typescript-eslint/eslint-plugin": "^5.50.0",
"@typescript-eslint/parser": "^5.50.0",
"@vscode-elements/elements": "^1.2.0",
"@vscode/l10n": "^0.0.14",
"@vscode/webview-ui-toolkit": "^1.2.2",
"@webpack-cli/serve": "^1.7.0",
@@ -400,15 +400,6 @@
"node": ">=6.9.0"
}
},
"node_modules/@bendera/vscode-webview-elements": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/@bendera/vscode-webview-elements/-/vscode-webview-elements-0.6.2.tgz",
"integrity": "sha512-smtr+KvCKV2MwjVrmyvrhonpaXVpxCjTMXUQOwDwWSAQ42x5pnlpjCGElz2dljc5VHS1Mh1ovPSQ/P3jAm7vMQ==",
"dev": true,
"dependencies": {
"lit-element": "^2.5.1"
}
},
"node_modules/@ctrl/tinycolor": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
@@ -764,6 +755,21 @@
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==",
"dev": true
},
"node_modules/@lit-labs/ssr-dom-shim": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.0.tgz",
"integrity": "sha512-yWJKmpGE6lUURKAaIltoPIE/wrbY3TEkqQt+X0m+7fQNnAv0keydnYvbiJFP1PnMhizmIWRWOG5KLhYyc/xl+g==",
"dev": true
},
"node_modules/@lit/reactive-element": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.0.4.tgz",
"integrity": "sha512-GFn91inaUa2oHLak8awSIigYz0cU0Payr1rcFsrkf5OJ5eSPxElyZfKh0f2p9FsTiZWXQdWGJeXZICEfXXYSXQ==",
"dev": true,
"dependencies": {
"@lit-labs/ssr-dom-shim": "^1.2.0"
}
},
"node_modules/@microsoft/fast-element": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/@microsoft/fast-element/-/fast-element-1.12.0.tgz",
@@ -2073,6 +2079,12 @@
"integrity": "sha512-bTHG8fcxEqv1M9+TD14P8ok8hjxoOCkfKc8XXLaaD05kI7ohpeI956jtDOD3XHKBQrlyPughUtzm1jtVhHpA5Q==",
"dev": true
},
"node_modules/@types/trusted-types": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
"dev": true
},
"node_modules/@types/uglify-js": {
"version": "3.17.4",
"resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.17.4.tgz",
@@ -2337,6 +2349,15 @@
"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
"dev": true
},
"node_modules/@vscode-elements/elements": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@vscode-elements/elements/-/elements-1.2.0.tgz",
"integrity": "sha512-aCsf9iEnx+PE2rRfAySjvFTSgqP4NUvHG0nOc5AxFB1FXHyG/ayYA2TN9XpT7zuO024tRAu+XoKREbRC7uAmLA==",
"dev": true,
"dependencies": {
"lit": "^3.1.2"
}
},
"node_modules/@vscode/l10n": {
"version": "0.0.14",
"resolved": "https://registry.npmjs.org/@vscode/l10n/-/l10n-0.0.14.tgz",
@@ -6574,20 +6595,36 @@
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
"dev": true
},
"node_modules/lit-element": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/lit-element/-/lit-element-2.5.1.tgz",
"integrity": "sha512-ogu7PiJTA33bEK0xGu1dmaX5vhcRjBXCFexPja0e7P7jqLhTpNKYRPmE+GmiCaRVAbiQKGkUgkh/i6+bh++dPQ==",
"node_modules/lit": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/lit/-/lit-3.1.2.tgz",
"integrity": "sha512-VZx5iAyMtX7CV4K8iTLdCkMaYZ7ipjJZ0JcSdJ0zIdGxxyurjIn7yuuSxNBD7QmjvcNJwr0JS4cAdAtsy7gZ6w==",
"dev": true,
"dependencies": {
"lit-html": "^1.1.1"
"@lit/reactive-element": "^2.0.4",
"lit-element": "^4.0.4",
"lit-html": "^3.1.2"
}
},
"node_modules/lit-element": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.0.4.tgz",
"integrity": "sha512-98CvgulX6eCPs6TyAIQoJZBCQPo80rgXR+dVBs61cstJXqtI+USQZAbA4gFHh6L/mxBx9MrgPLHLsUgDUHAcCQ==",
"dev": true,
"dependencies": {
"@lit-labs/ssr-dom-shim": "^1.2.0",
"@lit/reactive-element": "^2.0.4",
"lit-html": "^3.1.2"
}
},
"node_modules/lit-html": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/lit-html/-/lit-html-1.4.1.tgz",
"integrity": "sha512-B9btcSgPYb1q4oSOb/PrOT6Z/H+r6xuNzfH4lFli/AWhYwdtrgQkQWBbIc6mdnf6E2IL3gDXdkkqNktpU0OZQA==",
"dev": true
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.1.2.tgz",
"integrity": "sha512-3OBZSUrPnAHoKJ9AMjRL/m01YJxQMf+TMHanNtTHG68ubjnZxK0RFl102DPzsw4mWnHibfZIBJm3LWCZ/LmMvg==",
"dev": true,
"dependencies": {
"@types/trusted-types": "^2.0.2"
}
},
"node_modules/load-json-file": {
"version": "4.0.0",
+1 -1
View File
@@ -2744,7 +2744,6 @@
},
"devDependencies": {
"@actions/core": "^1.10.0",
"@bendera/vscode-webview-elements": "0.6.2",
"@estruyf/vscode": "^1.1.0",
"@headlessui/react": "^1.7.18",
"@heroicons/react": "^2.1.1",
@@ -2769,6 +2768,7 @@
"@types/vscode": "^1.73.0",
"@typescript-eslint/eslint-plugin": "^5.50.0",
"@typescript-eslint/parser": "^5.50.0",
"@vscode-elements/elements": "^1.2.0",
"@vscode/l10n": "^0.0.14",
"@vscode/webview-ui-toolkit": "^1.2.2",
"@webpack-cli/serve": "^1.7.0",
+36 -40
View File
@@ -1,14 +1,7 @@
import * as React from 'react';
import {
VsTable,
VsTableBody,
VsTableHeader,
VsTableHeaderCell,
VsTableRow,
VsTableCell
} from './VscodeComponents';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../localization';
import { VSCodeTable, VSCodeTableBody, VSCodeTableCell, VSCodeTableHead, VSCodeTableHeader, VSCodeTableRow } from './VSCode/VSCodeTable';
export interface IArticleDetailsProps {
details: {
@@ -32,52 +25,55 @@ const ArticleDetails: React.FunctionComponent<IArticleDetailsProps> = ({
<div className={`seo__status__details valid`}>
<h4>{l10n.t(LocalizationKey.panelArticleDetailsTitle)}</h4>
<VsTable bordered>
<VsTableHeader slot="header">
<VsTableHeaderCell>
{l10n.t(LocalizationKey.panelArticleDetailsType)}
</VsTableHeaderCell>
<VsTableHeaderCell>
{l10n.t(LocalizationKey.panelArticleDetailsTotal)}
</VsTableHeaderCell>
</VsTableHeader>
<VsTableBody slot="body">
<VSCodeTable>
<VSCodeTableHeader>
<VSCodeTableRow>
<VSCodeTableHead>
{l10n.t(LocalizationKey.panelArticleDetailsType)}
</VSCodeTableHead>
<VSCodeTableHead>
{l10n.t(LocalizationKey.panelArticleDetailsTotal)}
</VSCodeTableHead>
</VSCodeTableRow>
</VSCodeTableHeader>
<VSCodeTableBody>
{details?.headings !== undefined && (
<VsTableRow>
<VsTableCell>{l10n.t(LocalizationKey.panelArticleDetailsHeadings)}</VsTableCell>
<VsTableCell>{details.headings}</VsTableCell>
</VsTableRow>
<VSCodeTableRow>
<VSCodeTableCell>{l10n.t(LocalizationKey.panelArticleDetailsHeadings)}</VSCodeTableCell>
<VSCodeTableCell>{details.headings}</VSCodeTableCell>
</VSCodeTableRow>
)}
{details?.paragraphs !== undefined && (
<VsTableRow>
<VsTableCell>{l10n.t(LocalizationKey.panelArticleDetailsParagraphs)}</VsTableCell>
<VsTableCell>{details.paragraphs}</VsTableCell>
</VsTableRow>
<VSCodeTableRow>
<VSCodeTableCell>{l10n.t(LocalizationKey.panelArticleDetailsParagraphs)}</VSCodeTableCell>
<VSCodeTableCell>{details.paragraphs}</VSCodeTableCell>
</VSCodeTableRow>
)}
{details?.internalLinks !== undefined && (
<VsTableRow>
<VsTableCell>{l10n.t(LocalizationKey.panelArticleDetailsInternalLinks)}</VsTableCell>
<VsTableCell>{details.internalLinks}</VsTableCell>
</VsTableRow>
<VSCodeTableRow>
<VSCodeTableCell>{l10n.t(LocalizationKey.panelArticleDetailsInternalLinks)}</VSCodeTableCell>
<VSCodeTableCell>{details.internalLinks}</VSCodeTableCell>
</VSCodeTableRow>
)}
{details?.externalLinks !== undefined && (
<VsTableRow>
<VsTableCell>{l10n.t(LocalizationKey.panelArticleDetailsExternalLinks)}</VsTableCell>
<VsTableCell>{details.externalLinks}</VsTableCell>
</VsTableRow>
<VSCodeTableRow>
<VSCodeTableCell>{l10n.t(LocalizationKey.panelArticleDetailsExternalLinks)}</VSCodeTableCell>
<VSCodeTableCell>{details.externalLinks}</VSCodeTableCell>
</VSCodeTableRow>
)}
{details?.images !== undefined && (
<VsTableRow>
<VsTableCell>{l10n.t(LocalizationKey.panelArticleDetailsImages)}</VsTableCell>
<VsTableCell>{details.images}</VsTableCell>
</VsTableRow>
<VSCodeTableRow>
<VSCodeTableCell>{l10n.t(LocalizationKey.panelArticleDetailsImages)}</VSCodeTableCell>
<VSCodeTableCell>{details.images}</VSCodeTableCell>
</VSCodeTableRow>
)}
</VsTableBody>
</VsTable>
</VSCodeTableBody>
</VSCodeTable>
</div>
);
};
+1 -1
View File
@@ -66,7 +66,7 @@ const Collapsible: React.FunctionComponent<ICollapsibleProps> = ({
return (
<VsCollapsible title={title} onClick={triggerClick} open={isOpen}>
<div className={`section collapsible__body ${className || ''}`} slot="body">
<div className={`section collapsible__body ${className || ''}`}>
{children}
</div>
</VsCollapsible>
@@ -5,9 +5,9 @@ import { useMemo } from 'react';
import { Field } from '../../../models';
import { CommandToCode } from '../../CommandToCode';
import { IMetadata } from '../Metadata';
import { VsLabel } from '../VscodeComponents';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
import { VSCodeLabel } from '../VSCode';
export interface IContentTypeValidatorProps {
fields: Field[];
@@ -50,7 +50,7 @@ export const ContentTypeValidator: React.FunctionComponent<IContentTypeValidator
return (
<div className="hint">
<VsLabel>
<VSCodeLabel>
<div className={`metadata_field__label metadata_field__alert`}>
<svg
width="16"
@@ -70,7 +70,7 @@ export const ContentTypeValidator: React.FunctionComponent<IContentTypeValidator
{l10n.t(LocalizationKey.panelContentTypeContentTypeValidatorTitle)}
</span>
</div>
</VsLabel>
</VSCodeLabel>
{l10n.t(LocalizationKey.panelContentTypeContentTypeValidatorHint).split(`\n`).map(s => (<p className="inline_hint" key={s}>{s}</p>))}
@@ -1,12 +1,12 @@
import { RectangleStackIcon, PlusIcon } from '@heroicons/react/24/outline';
import { RectangleStackIcon } from '@heroicons/react/24/outline';
import * as React from 'react';
import { VsLabel } from '../VscodeComponents';
import { DataBlockRecord } from '.';
import { SortableContainer, SortEnd } from 'react-sortable-hoc';
import { useCallback } from 'react';
import { FieldGroup } from '../../../models';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
import { VSCodeLabel } from '../VSCode';
export interface IDataBlockRecordsProps {
fieldGroups?: FieldGroup[];
@@ -52,7 +52,7 @@ export const DataBlockRecords = ({
return (
<div className="json_data__list">
<VsLabel>
<VSCodeLabel>
<div className={`metadata_field__label`}>
<div>
<RectangleStackIcon style={{ width: '16px', height: '16px' }} />
@@ -61,7 +61,7 @@ export const DataBlockRecords = ({
</span>
</div>
</div>
</VsLabel>
</VSCodeLabel>
<Container onSortEnd={onSort} useDragHandle>
{records.map((v: any, idx: number) => (
@@ -1,8 +1,8 @@
import * as React from 'react';
import * as Sentry from '@sentry/react';
import { VsLabel } from '../VscodeComponents';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
import { VSCodeLabel } from '../VSCode';
export interface IFieldBoundaryProps {
fieldName: string;
@@ -34,11 +34,11 @@ export default class FieldBoundary extends React.Component<
if (this.state.hasError) {
return (
<div className={`metadata_field`}>
<VsLabel>
<VSCodeLabel>
<div className={`metadata_field__label`}>
<span style={{ lineHeight: '16px' }}>{this.props.fieldName}</span>
</div>
</VsLabel>
</VSCodeLabel>
<div className={`metadata_field__error`}>
<span>
{l10n.t(LocalizationKey.panelErrorBoundaryFieldBoundaryLabel)}
@@ -1,7 +1,7 @@
import * as React from 'react';
import { useMemo } from 'react';
import { VsLabel } from '../VscodeComponents';
import { RequiredAsterix } from './RequiredAsterix';
import { VSCodeLabel } from '../VSCode';
export interface IFieldTitleProps {
label: string | JSX.Element;
@@ -23,7 +23,7 @@ export const FieldTitle: React.FunctionComponent<IFieldTitleProps> = ({
}, [icon]);
return (
<VsLabel>
<VSCodeLabel>
<div className={`metadata_field__label ${className || ''}`}>
<div>
{Icon}
@@ -33,6 +33,6 @@ export const FieldTitle: React.FunctionComponent<IFieldTitleProps> = ({
{actionElement}
</div>
</VsLabel>
</VSCodeLabel>
);
};
+3 -3
View File
@@ -1,9 +1,9 @@
import * as React from 'react';
import { FileInfo } from '../../models';
import { FileItem } from './FileItem';
import { VsLabel } from './VscodeComponents';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../localization';
import { VSCodeLabel } from './VSCode';
export interface IFileListProps {
folderName: string;
@@ -22,9 +22,9 @@ const FileList: React.FunctionComponent<IFileListProps> = ({
return (
<div className={`file_list`}>
<VsLabel>
<VSCodeLabel>
{folderName} - {files.length === 1 ? l10n.t(LocalizationKey.panelFileListLabelSingular) : l10n.t(LocalizationKey.panelFileListLabelPlural)}: {totalFiles}
</VsLabel>
</VSCodeLabel>
<ul className="file_list__items">
{files &&
@@ -2,9 +2,9 @@ import * as React from 'react';
import { FolderInfo } from '../../models';
import { Collapsible } from './Collapsible';
import { FileList } from './FileList';
import { VsLabel } from './VscodeComponents';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../localization';
import { VSCodeLabel } from './VSCode';
export interface IFolderAndFilesProps {
data: FolderInfo[] | undefined;
@@ -35,9 +35,9 @@ const FolderAndFiles: React.FunctionComponent<IFolderAndFilesProps> = ({
/>
</div>
) : isBase ? (
<VsLabel key={`${folder.title}-${idx}`}>
<VSCodeLabel key={`${folder.title}-${idx}`}>
{folder.title}: {folder.files} {folder.files > 1 ? l10n.t(LocalizationKey.panelFileListLabelPlural) : l10n.t(LocalizationKey.panelFileListLabelSingular)}
</VsLabel>
</VSCodeLabel>
) : null}
</div>
))}
@@ -3,12 +3,12 @@ import { PanelSettings } from '../../models';
import { CommandToCode } from '../CommandToCode';
import { useDebounce } from '../../hooks/useDebounce';
import { Collapsible } from './Collapsible';
import { VsLabel } from './VscodeComponents';
import useStartCommand from '../hooks/useStartCommand';
import { VSCodeCheckbox } from '@vscode/webview-ui-toolkit/react';
import { Messenger } from '@estruyf/vscode/dist/client';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../localization';
import { VSCodeLabel } from './VSCode';
export interface IGlobalSettingsProps {
settings: PanelSettings | undefined;
@@ -78,25 +78,25 @@ const GlobalSettings: React.FunctionComponent<IGlobalSettingsProps> = ({
title={l10n.t(LocalizationKey.panelGlobalSettingsTitle)}
>
<div className={`base__action`}>
<VsLabel>
<VSCodeLabel>
{l10n.t(LocalizationKey.panelGlobalSettingsActionModifiedDateLabel)}
</VsLabel>
</VSCodeLabel>
<VSCodeCheckbox checked={modifiedDateUpdate} onClick={onDateCheck}>
{l10n.t(LocalizationKey.panelGlobalSettingsActionModifiedDateDescription)}
</VSCodeCheckbox>
</div>
<div className={`base__action`}>
<VsLabel>
<VSCodeLabel>
{l10n.t(LocalizationKey.panelGlobalSettingsActionFrontMatterLabel)}
</VsLabel>
</VSCodeLabel>
<VSCodeCheckbox checked={fmHighlighting} onClick={onHighlightCheck}>
{l10n.t(LocalizationKey.panelGlobalSettingsActionFrontMatterDescription)}
</VSCodeCheckbox>
</div>
<div className={`base__action`}>
<VsLabel>
<VSCodeLabel>
{l10n.t(LocalizationKey.panelGlobalSettingsActionPreviewLabel)}
</VsLabel>
</VSCodeLabel>
<input
type={`text`}
placeholder={l10n.t(LocalizationKey.dashboardPreviewInputPlaceholder, `http://localhost:1313`)}
@@ -105,9 +105,9 @@ const GlobalSettings: React.FunctionComponent<IGlobalSettingsProps> = ({
/>
</div>
<div className={`base__action`}>
<VsLabel>
<VSCodeLabel>
{l10n.t(LocalizationKey.panelGlobalSettingsActionServerLabel)}
</VsLabel>
</VSCodeLabel>
<input
type={`text`}
placeholder={l10n.t(LocalizationKey.panelGlobalSettingsActionServerPlaceholder, `hugo server -D`)}
@@ -1,23 +0,0 @@
import * as React from 'react';
export interface ICheckIconProps {}
export const CheckIcon: React.FunctionComponent<ICheckIconProps> = (
props: React.PropsWithChildren<ICheckIconProps>
) => {
return (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M14.431 3.323l-8.47 10-.79-.036-3.35-4.77.818-.574 2.978 4.24 8.051-9.506.764.646z"
/>
</svg>
);
};
@@ -1,23 +0,0 @@
import * as React from 'react';
export interface IWarningIconProps {}
export const WarningIcon: React.FunctionComponent<IWarningIconProps> = (
props: React.PropsWithChildren<IWarningIconProps>
) => {
return (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M7.56 1h.88l6.54 12.26-.44.74H1.44L1 13.26 7.56 1zM8 2.28L2.28 13H13.7L8 2.28zM8.625 12v-1h-1.25v1h1.25zm-1.25-2V6h1.25v4h-1.25z"
/>
</svg>
);
};
@@ -2,10 +2,10 @@ import * as React from 'react';
import { useState, useMemo, useCallback, useEffect } from 'react';
import { Field, PanelSettings } from '../../../models';
import { PencilIcon } from '@heroicons/react/24/outline';
import { VsLabel } from '../VscodeComponents';
import { JsonFieldRecords, JsonFieldForm, JsonFieldSelector } from '.';
import { SortEnd } from 'react-sortable-hoc';
import { arrayMoveImmutable } from 'array-move';
import { VSCodeLabel } from '../VSCode';
export interface IJsonFieldProps {
label: string;
@@ -101,12 +101,12 @@ export const JsonField: React.FunctionComponent<IJsonFieldProps> = ({
return (
<div className="json_data__field">
<VsLabel>
<VSCodeLabel>
<div className={`metadata_field__label`}>
<PencilIcon style={{ width: '16px', height: '16px' }} />{' '}
<span style={{ lineHeight: '16px' }}>{label}</span>
</div>
</VsLabel>
</VSCodeLabel>
<JsonFieldSelector
field={field}
@@ -1,10 +1,10 @@
import { CircleStackIcon, PlusIcon } from '@heroicons/react/24/outline';
import * as React from 'react';
import { VsLabel } from '../VscodeComponents';
import { JsonFieldRecord } from '.';
import { SortableContainer, SortEnd } from 'react-sortable-hoc';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
import { VSCodeLabel } from '../VSCode';
export interface IJsonFieldRecordsProps {
records: any[];
@@ -33,7 +33,7 @@ export const JsonFieldRecords = ({
return (
<div className="json_data__list">
<VsLabel>
<VSCodeLabel>
<div className={`metadata_field__label`}>
<div>
<CircleStackIcon style={{ width: '16px', height: '16px' }} />
@@ -44,7 +44,7 @@ export const JsonFieldRecords = ({
<PlusIcon style={{ width: '16px', height: '16px' }} />
</button>
</div>
</VsLabel>
</VSCodeLabel>
<Container onSortEnd={onSort} useDragHandle>
{records.map((v: any, idx: number) => (
+19 -23
View File
@@ -1,14 +1,7 @@
import * as React from 'react';
import {
VsTable,
VsTableBody,
VsTableHeader,
VsTableHeaderCell,
VsTableRow,
VsTableCell
} from './VscodeComponents';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../localization';
import { VSCodeTable, VSCodeTableBody, VSCodeTableCell, VSCodeTableHead, VSCodeTableHeader, VSCodeTableRow } from './VSCode/VSCodeTable';
export interface ISeoDetailsProps {
allowedLength: number;
@@ -23,30 +16,33 @@ const SeoDetails: React.FunctionComponent<ISeoDetailsProps> = (
) => {
const { allowedLength, title, value, valueTitle, noValidation } = props;
const validate = () => {
const validate = React.useMemo(() => {
if (noValidation) {
return '';
}
return value <= allowedLength ? 'valid' : 'not-valid';
};
}, [value, allowedLength, noValidation]);
return (
<div className={`seo__status__details ${validate()}`}>
<div className={`seo__status__details ${validate}`}>
<h4>{title}</h4>
<VsTable bordered>
<VsTableHeader slot="header">
<VsTableHeaderCell className={validate()}>{valueTitle}</VsTableHeaderCell>
<VsTableHeaderCell>{l10n.t(LocalizationKey.panelSeoDetailsRecommended)}</VsTableHeaderCell>
</VsTableHeader>
<VsTableBody slot="body">
<VsTableRow>
<VsTableCell className={validate()}>{value}</VsTableCell>
<VsTableCell>{allowedLength}</VsTableCell>
</VsTableRow>
</VsTableBody>
</VsTable>
<VSCodeTable>
<VSCodeTableHeader>
<VSCodeTableRow>
<VSCodeTableHead className={validate}>{valueTitle}</VSCodeTableHead>
<VSCodeTableHead>{l10n.t(LocalizationKey.panelSeoDetailsRecommended)}</VSCodeTableHead>
</VSCodeTableRow>
</VSCodeTableHeader>
<VSCodeTableBody>
<VSCodeTableRow>
<VSCodeTableCell className={validate}>{value}</VSCodeTableCell>
<VSCodeTableCell>{allowedLength}</VSCodeTableCell>
</VSCodeTableRow>
</VSCodeTableBody>
</VSCodeTable>
</div>
);
};
+6 -10
View File
@@ -1,6 +1,6 @@
import * as React from 'react';
import { ValidInfo } from './ValidInfo';
import { VsTableCell, VsTableRow } from './VscodeComponents';
import { VSCodeTableCell, VSCodeTableRow } from './VSCode/VSCodeTable';
export interface ISeoFieldInfoProps {
title: string;
@@ -16,15 +16,11 @@ const SeoFieldInfo: React.FunctionComponent<ISeoFieldInfoProps> = ({
isValid
}: React.PropsWithChildren<ISeoFieldInfoProps>) => {
return (
<VsTableRow>
<VsTableCell className={`table__cell table__title`}>{title}</VsTableCell>
<VsTableCell className={`table__cell`}>
{value}/{recommendation}
</VsTableCell>
<VsTableCell className={`table__cell table__cell__validation`}>
{isValid !== undefined ? <ValidInfo label={undefined} isValid={isValid} /> : <span>-</span>}
</VsTableCell>
</VsTableRow>
<VSCodeTableRow>
<VSCodeTableCell className={`capitalize`}>{title}</VSCodeTableCell>
<VSCodeTableCell>{value}/{recommendation}</VSCodeTableCell>
<VSCodeTableCell>{isValid !== undefined ? <ValidInfo label={undefined} isValid={isValid} /> : <span>-</span>}</VSCodeTableCell>
</VSCodeTableRow>
);
};
+14 -12
View File
@@ -1,8 +1,8 @@
import * as React from 'react';
import { ValidInfo } from './ValidInfo';
import { VsTableCell, VsTableRow } from './VscodeComponents';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../localization';
import { VSCodeTableCell, VSCodeTableRow } from './VSCode/VSCodeTable';
export interface ISeoKeywordInfoProps {
keyword: string;
@@ -71,22 +71,22 @@ const SeoKeywordInfo: React.FunctionComponent<ISeoKeywordInfoProps> = ({
}
return (
<VsTableRow>
<VsTableCell className={`table__cell`}>{keyword}</VsTableCell>
<VsTableCell className={`table__cell table__cell__validation table__cell__seo_details`}>
<div>
<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>
<div className='flex items-center'>
<ValidInfo
label={l10n.t(LocalizationKey.commonDescription)}
isValid={!!description && description.toLowerCase().includes(keyword.toLowerCase())}
/>
</div>
<div>
<div className='flex items-center'>
<ValidInfo
label={l10n.t(LocalizationKey.commonSlug)}
isValid={
@@ -96,16 +96,18 @@ const SeoKeywordInfo: React.FunctionComponent<ISeoKeywordInfoProps> = ({
}
/>
</div>
<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>{checkHeadings()}</div>}
{wordCount && <div>{density()}</div>}
</VsTableCell>
</VsTableRow>
{headings && headings.length > 0 &&
<div className='flex items-center'>{checkHeadings()}</div>}
{wordCount &&
<div className='flex items-center'>{density()}</div>}
</VSCodeTableCell>
</VSCodeTableRow>
);
};
+17 -14
View File
@@ -1,9 +1,9 @@
import * as React from 'react';
import { SeoKeywordInfo } from './SeoKeywordInfo';
import { VsTable, VsTableBody, VsTableHeader, VsTableHeaderCell } from './VscodeComponents';
import { ErrorBoundary } from '@sentry/react';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../localization';
import { VSCodeTable, VSCodeTableBody, VSCodeTableHead, VSCodeTableHeader, VSCodeTableRow } from './VSCode/VSCodeTable';
export interface ISeoKeywordsProps {
keywords: string[] | null;
@@ -54,16 +54,19 @@ const SeoKeywords: React.FunctionComponent<ISeoKeywordsProps> = ({
<div className={`seo__status__keywords`}>
<h4>{l10n.t(LocalizationKey.panelSeoKeywordsTitle)}</h4>
<VsTable bordered columns={['30%', 'auto']}>
<VsTableHeader slot="header">
<VsTableHeaderCell className={`table__cell`}>
{l10n.t(LocalizationKey.panelSeoKeywordsHeaderKeyword)}
</VsTableHeaderCell>
<VsTableHeaderCell className={`table__cell`}>
{l10n.t(LocalizationKey.panelSeoKeywordsHeaderDetails)}
</VsTableHeaderCell>
</VsTableHeader>
<VsTableBody slot="body">
<VSCodeTable>
<VSCodeTableHeader>
<VSCodeTableRow>
<VSCodeTableHead>
{l10n.t(LocalizationKey.panelSeoKeywordsHeaderKeyword)}
</VSCodeTableHead>
<VSCodeTableHead>
{l10n.t(LocalizationKey.panelSeoKeywordsHeaderDetails)}
</VSCodeTableHead>
</VSCodeTableRow>
</VSCodeTableHeader>
<VSCodeTableBody>
{validateKeywords().map((keyword, index) => {
return (
<ErrorBoundary key={keyword} fallback={<div />}>
@@ -71,11 +74,11 @@ const SeoKeywords: React.FunctionComponent<ISeoKeywordsProps> = ({
</ErrorBoundary>
);
})}
</VsTableBody>
</VsTable>
</VSCodeTableBody>
</VSCodeTable>
{data.wordCount && (
<div className={`seo__status__note`}>
<div className={`text-xs mt-2`}>
{l10n.t(LocalizationKey.panelSeoKeywordsDensity)}
</div>
)}
+25 -55
View File
@@ -1,5 +1,4 @@
import * as React from 'react';
import { useEffect } from 'react';
import { SEO } from '../../models/PanelSettings';
import { TagType } from '../TagType';
import { ArticleDetails } from './ArticleDetails';
@@ -9,9 +8,9 @@ import { SymbolKeywordIcon } from './Icons/SymbolKeywordIcon';
import { SeoFieldInfo } from './SeoFieldInfo';
import { SeoKeywords } from './SeoKeywords';
import { TagPicker } from './TagPicker';
import { VsTable, VsTableBody, VsTableHeader, VsTableHeaderCell } from './VscodeComponents';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../localization';
import { VSCodeTable, VSCodeTableBody, VSCodeTableHead, VSCodeTableHeader, VSCodeTableRow } from './VSCode/VSCodeTable';
export interface ISeoStatusProps {
seo: SEO;
@@ -27,90 +26,61 @@ const SeoStatus: React.FunctionComponent<ISeoStatusProps> = ({
unsetFocus
}: React.PropsWithChildren<ISeoStatusProps>) => {
const { title, slug } = data;
const [isOpen, setIsOpen] = React.useState(true);
const tableRef = React.useRef<HTMLElement>();
const pushUpdate = React.useRef((value: boolean) => {
setTimeout(() => {
setIsOpen(value);
}, 10);
}).current;
const { descriptionField, titleField } = seo;
// Workaround for lit components not updating render
useEffect(() => {
setTimeout(() => {
let height = 0;
tableRef.current?.childNodes.forEach((elm: any) => {
height += elm.clientHeight;
});
if (height > 0 && tableRef.current) {
tableRef.current.style.height = `${height}px`;
}
}, 10);
}, [title, data[titleField], data[descriptionField], data?.articleDetails?.wordCount]);
const renderContent = () => {
if (!isOpen) {
return null;
}
const tableContent = React.useMemo(() => {
return (
<div>
<div className={`seo__status__details`}>
<h4>{l10n.t(LocalizationKey.panelSeoStatusTitle)}</h4>
<VsTable ref={tableRef} bordered zebra>
<VsTableHeader slot="header">
<VsTableHeaderCell className={`table__cell`}>
{l10n.t(LocalizationKey.panelSeoStatusHeaderProperty)}
</VsTableHeaderCell>
<VsTableHeaderCell className={`table__cell`}>
{l10n.t(LocalizationKey.panelSeoStatusHeaderLength)}
</VsTableHeaderCell>
<VsTableHeaderCell className={`table__cell`}>
{l10n.t(LocalizationKey.panelSeoStatusHeaderValid)}
</VsTableHeaderCell>
</VsTableHeader>
<VsTableBody slot="body">
{data[titleField] && seo.title > 0 && (
<VSCodeTable>
<VSCodeTableHeader>
<VSCodeTableRow>
<VSCodeTableHead>{l10n.t(LocalizationKey.panelSeoStatusHeaderProperty)}</VSCodeTableHead>
<VSCodeTableHead>{l10n.t(LocalizationKey.panelSeoStatusHeaderLength)}</VSCodeTableHead>
<VSCodeTableHead>{l10n.t(LocalizationKey.panelSeoStatusHeaderValid)}</VSCodeTableHead>
</VSCodeTableRow>
</VSCodeTableHeader>
<VSCodeTableBody>
{data[titleField] && seo.title > 0 ? (
<SeoFieldInfo
title={titleField}
value={data[titleField].length}
recommendation={l10n.t(LocalizationKey.panelSeoStatusSeoFieldInfoCharacters, seo.title)}
isValid={data[titleField].length <= seo.title}
/>
)}
) : null}
{slug && seo.slug > 0 && (
{slug && seo.slug > 0 ? (
<SeoFieldInfo
title={`slug`}
value={slug.length}
recommendation={l10n.t(LocalizationKey.panelSeoStatusSeoFieldInfoCharacters, seo.slug)}
isValid={slug.length <= seo.slug}
/>
)}
) : null}
{data[descriptionField] && seo.description > 0 && (
{data[descriptionField] && seo.description > 0 ? (
<SeoFieldInfo
title={descriptionField}
value={data[descriptionField].length}
recommendation={l10n.t(LocalizationKey.panelSeoStatusSeoFieldInfoCharacters, seo.description)}
isValid={data[descriptionField].length <= seo.description}
/>
)}
) : null}
{seo.content > 0 && data?.articleDetails?.wordCount > 0 && (
{seo.content > 0 && data?.articleDetails?.wordCount > 0 ? (
<SeoFieldInfo
title={l10n.t(LocalizationKey.panelSeoStatusSeoFieldInfoArticle)}
value={data?.articleDetails?.wordCount}
recommendation={l10n.t(LocalizationKey.panelSeoStatusSeoFieldInfoWords, seo.content)}
/>
)}
</VsTableBody>
</VsTable>
) : null}
</VSCodeTableBody>
</VSCodeTable>
</div>
<SeoKeywords
@@ -139,10 +109,10 @@ const SeoStatus: React.FunctionComponent<ISeoStatusProps> = ({
<ArticleDetails details={data.articleDetails} />
</div>
);
};
}, [data, seo, focusElm, unsetFocus]);
return (
<Collapsible id={`seo`} title={l10n.t(LocalizationKey.panelSeoStatusCollapsibleTitle)} sendUpdate={pushUpdate}>
<Collapsible id={`seo`} title={l10n.t(LocalizationKey.panelSeoStatusCollapsibleTitle)}>
{!title && !data[descriptionField] ? (
<div className={`seo__status__empty`}>
<p>
@@ -150,7 +120,7 @@ const SeoStatus: React.FunctionComponent<ISeoStatusProps> = ({
</p>
</div>
) : (
renderContent()
tableContent
)}
</Collapsible>
);
@@ -0,0 +1,27 @@
import * as React from 'react';
export interface IVSCodeLabelProps { }
export const VSCodeLabel: React.FunctionComponent<IVSCodeLabelProps> = ({
children
}: React.PropsWithChildren<IVSCodeLabelProps>) => {
const DEFAULT_LINE_HEIGHT = 16;
const DEFAULT_FONT_SIZE = 13;
const INPUT_LINE_HEIGHT_RATIO = DEFAULT_LINE_HEIGHT / DEFAULT_FONT_SIZE;
return (
<label style={{
color: "var(--vscode-foreground)",
fontFamily: "var(--vscode-font-family)",
fontSize: "var(--vscode-font-size)",
fontWeight: "600",
lineHeight: INPUT_LINE_HEIGHT_RATIO,
cursor: "default",
display: "block",
padding: "5px 0"
}}>
{children}
</label >
);
};
@@ -0,0 +1,103 @@
import * as React from "react"
import { cn } from "../../../utils/cn"
const VSCodeTable = React.forwardRef<
HTMLTableElement,
React.HTMLAttributes<HTMLTableElement>
>(({ className, ...props }, ref) => (
<div className="relative w-full overflow-auto">
<table
ref={ref}
className={cn("w-full text-base border-collapse indent-0 [&_tr:nth-child(2n)]:bg-[var(--vscode-keybindingTable-rowsBackground)]", className)}
{...props}
/>
</div>
))
VSCodeTable.displayName = "VSCodeTable"
const VSCodeTableHeader = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<thead ref={ref} className={cn("[&_tr]:border-b bg-[var(--vscode-keybindingTable-headerBackground)]", className)} {...props} />
))
VSCodeTableHeader.displayName = "VSCodeTableHeader"
const VSCodeTableBody = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<tbody
ref={ref}
className={cn("[&_tr:last-child]:border-0", className)}
{...props}
/>
))
VSCodeTableBody.displayName = "VSCodeTableBody"
const VSCodeTableFooter = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<tfoot
ref={ref}
className={cn(
"border-t font-medium [&>tr]:last:border-b-0",
className
)}
{...props}
/>
))
VSCodeTableFooter.displayName = "VSCodeTableFooter"
const VSCodeTableRow = React.forwardRef<
HTMLTableRowElement,
React.HTMLAttributes<HTMLTableRowElement>
>(({ className, ...props }, ref) => (
<tr
ref={ref}
className={cn(
"border-solid border-0 border-b border-b-[var(--vscode-editorGroup-border)] transition-colors [&_td]:border-r [&_td]:border-r-[var(--vscode-editorGroup-border)] [&_td:last-child]:border-r-0",
className
)}
{...props}
/>
))
VSCodeTableRow.displayName = "VSCodeTableRow"
const VSCodeTableHead = React.forwardRef<
HTMLTableCellElement,
React.ThHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
<th
ref={ref}
className={cn(
"h-6 px-2 py-2 text-left align-middle font-bold",
className
)}
{...props}
/>
))
VSCodeTableHead.displayName = "VSCodeTableHead"
const VSCodeTableCell = React.forwardRef<
HTMLTableCellElement,
React.TdHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
<td
ref={ref}
className={cn("border-solid border-0 h-6 px-2 overflow-hidden align-middle", className)}
{...props}
/>
))
VSCodeTableCell.displayName = "VSCodeTableCell"
export {
VSCodeTable,
VSCodeTableHeader,
VSCodeTableBody,
VSCodeTableFooter,
VSCodeTableHead,
VSCodeTableRow,
VSCodeTableCell,
}
@@ -0,0 +1 @@
export * from './VSCodeLabel';
+3 -8
View File
@@ -1,6 +1,5 @@
import * as React from 'react';
import { CheckIcon } from './Icons/CheckIcon';
import { WarningIcon } from './Icons/WarningIcon';
import { CheckIcon, ExclamationTriangleIcon } from '@heroicons/react/24/outline';
export interface IValidInfoProps {
label?: string;
@@ -14,13 +13,9 @@ const ValidInfo: React.FunctionComponent<IValidInfoProps> = ({
return (
<>
{isValid ? (
<span className="valid">
<CheckIcon />
</span>
<CheckIcon className={`h-4 w-4 text-[#46ec86] mr-2`} />
) : (
<span className="warning">
<WarningIcon />
</span>
<ExclamationTriangleIcon className={`h-4 w-4 text-[var(--vscode-statusBarItem-warningBackground)] mr-2`} />
)}
{label && <span>{label}</span>}
</>
@@ -1,11 +1,5 @@
import { wrapWc } from 'wc-react';
// @bendera/vscode-webview-elements
export const VsTable = wrapWc(`vscode-table`);
export const VsTableHeader = wrapWc(`vscode-table-header`);
export const VsTableHeaderCell = wrapWc(`vscode-table-header-cell`);
export const VsTableBody = wrapWc(`vscode-table-body`);
export const VsTableRow = wrapWc(`vscode-table-row`);
export const VsTableCell = wrapWc(`vscode-table-cell`);
export const VsCollapsible = wrapWc(`vscode-collapsible`);
export const VsLabel = wrapWc(`vscode-label`);
// export const VsLabel = wrapWc(`vscode-label`);
+2 -8
View File
@@ -9,14 +9,8 @@ import { SentryInit } from '../utils/sentryInit';
import './styles.css';
// require('@vscode/codicons/dist/codicon.css');
import '@bendera/vscode-webview-elements/dist/vscode-table.js';
import '@bendera/vscode-webview-elements/dist/vscode-table-header.js';
import '@bendera/vscode-webview-elements/dist/vscode-table-header-cell.js';
import '@bendera/vscode-webview-elements/dist/vscode-table-body.js';
import '@bendera/vscode-webview-elements/dist/vscode-table-row.js';
import '@bendera/vscode-webview-elements/dist/vscode-table-cell.js';
import '@bendera/vscode-webview-elements/dist/vscode-collapsible.js';
import '@bendera/vscode-webview-elements/dist/vscode-label.js';
import '@vscode-elements/elements/dist/vscode-collapsible/index.js';
// import '@bendera/vscode-webview-elements/dist/vscode-label/index.js';
// import '@bendera/vscode-webview-elements/dist/vscode-checkbox.js';
// import '@vscode/webview-ui-toolkit/dist/esm/checkbox';