Collapsible headers

This commit is contained in:
Elio Struyf
2021-07-21 14:42:52 +02:00
parent 323807c0e1
commit bea11bf7df
12 changed files with 126 additions and 51 deletions
+15 -15
View File
@@ -1,8 +1,8 @@
import * as React from 'react';
import { PanelSettings } from '../../models/PanelSettings';
import { Collapsible } from './Collapsible';
import { CustomScript } from './CustomScript';
import { DateAction } from './DateAction';
import { Icon } from './Icon';
import { PublishAction } from './PublishAction';
import { SlugAction } from './SlugAction';
@@ -19,22 +19,22 @@ export const Actions: React.FunctionComponent<IActionsProps> = (props: React.Pro
}
return (
<div className={`section article__actions`}>
<h3><Icon name={`rocket`} /> Actions</h3>
<Collapsible title="Actions">
<div className={`article__actions`}>
{ metadata && metadata.title && <SlugAction value={metadata.title} crntValue={metadata.slug} slugOpts={settings.slug} /> }
{ metadata && metadata.title && <SlugAction value={metadata.title} crntValue={metadata.slug} slugOpts={settings.slug} /> }
<DateAction />
<DateAction />
{ metadata && typeof metadata.draft !== undefined && <PublishAction draft={metadata.draft} />}
{ metadata && typeof metadata.draft !== undefined && <PublishAction draft={metadata.draft} />}
{
(settings && settings.scripts && settings.scripts.length > 0) && (
settings.scripts.map((value) => (
<CustomScript key={value.title.replace(/ /g, '')} {...value} />
))
)
}
</div>
{
(settings && settings.scripts && settings.scripts.length > 0) && (
settings.scripts.map((value) => (
<CustomScript key={value.title.replace(/ /g, '')} {...value} />
))
)
}
</div>
</Collapsible>
);
};
+2 -4
View File
@@ -10,9 +10,7 @@ export interface IArticleDetailsProps {
}
export const ArticleDetails: React.FunctionComponent<IArticleDetailsProps> = ({details}: React.PropsWithChildren<IArticleDetailsProps>) => {
console.log(details);
if (!details || (details.headings === undefined && details.paragraphs === undefined)) {
return null;
}
@@ -21,7 +19,7 @@ export const ArticleDetails: React.FunctionComponent<IArticleDetailsProps> = ({d
<div className={`seo__status__details valid`}>
<h4>More details</h4>
<VsTable>
<VsTable bordered>
<VsTableHeader slot="header">
<VsTableHeaderCell>Type</VsTableHeaderCell>
<VsTableHeaderCell>Total</VsTableHeaderCell>
+31
View File
@@ -0,0 +1,31 @@
import * as React from 'react';
import { VsCollapsible } from './VscodeComponents';
export interface ICollapsibleProps {
title: string;
sendUpdate?: (open: boolean) => void;
}
export const Collapsible: React.FunctionComponent<ICollapsibleProps> = ({children, title, sendUpdate}: React.PropsWithChildren<ICollapsibleProps>) => {
const [ isOpen, setIsOpen ] = React.useState(true);
// This is a work around for a lit-element issue of duplicate slot names
const triggerClick = (e: React.MouseEvent<HTMLElement>) => {
if ((e.target as any).tagName === 'VSCODE-COLLAPSIBLE') {
setIsOpen(prev => {
if (sendUpdate) {
sendUpdate(!prev);
}
return !prev;
});
}
}
return (
<VsCollapsible title={title} onClick={triggerClick} open={isOpen}>
<div className={`section collapsible__body`} slot="body">
{children}
</div>
</VsCollapsible>
);
};
+1 -1
View File
@@ -24,7 +24,7 @@ export const SeoDetails: React.FunctionComponent<ISeoDetailsProps> = (props: Rea
<div className={`seo__status__details ${validate()}`}>
<h4>{title}</h4>
<VsTable>
<VsTable {...{bordered:true}}>
<VsTableHeader slot="header">
<VsTableHeaderCell className={validate()}>{valueTitle}</VsTableHeaderCell>
<VsTableHeaderCell>Recommended</VsTableHeaderCell>
+15
View File
@@ -0,0 +1,15 @@
import * as React from 'react';
export interface ISeoKeywordsProps {
keywords: string[] | null;
}
export const SeoKeywords: React.FunctionComponent<ISeoKeywordsProps> = ({keywords}: React.PropsWithChildren<ISeoKeywordsProps>) => {
return (
<div className={`seo__status__keywords`}>
<h4>Keywords</h4>
<p>{keywords?.join(',')}</p>
</div>
);
};
+36 -22
View File
@@ -1,8 +1,9 @@
import * as React from 'react';
import { SEO } from '../../models/PanelSettings';
import { ArticleDetails } from './ArticleDetails';
import { Icon } from './Icon';
import { Collapsible } from './Collapsible';
import { SeoDetails } from './SeoDetails';
import { SeoKeywords } from './SeoKeywords';
export interface ISeoStatusProps {
seo: SEO;
@@ -12,6 +13,7 @@ export interface ISeoStatusProps {
export const SeoStatus: React.FunctionComponent<ISeoStatusProps> = (props: React.PropsWithChildren<ISeoStatusProps>) => {
const { data, seo } = props;
const { title } = data;
const [ isOpen, setIsOpen ] = React.useState(true);
const { descriptionField } = seo;
@@ -19,27 +21,39 @@ export const SeoStatus: React.FunctionComponent<ISeoStatusProps> = (props: React
return null;
}
const renderContent = () => {
console.log(`render`);
if (!isOpen) {
return null;
}
return (
<div>
{ (title && seo.title > 0) && <SeoDetails title="Title" valueTitle="Length" allowedLength={seo.title} value={title.length} /> }
{ (data[descriptionField] && seo.description > 0) && <SeoDetails title="Description" valueTitle="Length" allowedLength={seo.description} value={data[descriptionField].length} /> }
{
seo.content > 0 && data?.articleDetails?.wordCount && (
<SeoDetails title="Article length"
valueTitle="Words"
allowedLength={seo.content}
value={data?.articleDetails?.wordCount}
noValidation />
)
}
<SeoKeywords keywords={data?.keywords} />
<ArticleDetails details={data.articleDetails} />
</div>
);
};
return (
<div className="section seo__status">
<h3>
<Icon name="search" /> SEO Status
</h3>
{ (title && seo.title > 0) && <SeoDetails title="Title" valueTitle="Length" allowedLength={seo.title} value={title.length} /> }
{ (data[descriptionField] && seo.description > 0) && <SeoDetails title="Description" valueTitle="Length" allowedLength={seo.description} value={data[descriptionField].length} /> }
{
seo.content > 0 && data?.articleDetails?.wordCount && (
<SeoDetails title="Article length"
valueTitle="Words"
allowedLength={seo.content}
value={data?.articleDetails?.wordCount}
noValidation />
)
}
<ArticleDetails details={data.articleDetails} />
</div>
<Collapsible title="SEO Status" sendUpdate={(value) => setIsOpen(value)}>
{ renderContent() }
</Collapsible>
);
};
+2 -1
View File
@@ -5,4 +5,5 @@ 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 VsTableCell = wrapWc(`vscode-table-cell`);
export const VsCollapsible = wrapWc(`vscode-collapsible`);
+1
View File
@@ -8,6 +8,7 @@ import '@bendera/vscode-webview-elements/dist/vscode-table-header-cell';
import '@bendera/vscode-webview-elements/dist/vscode-table-body';
import '@bendera/vscode-webview-elements/dist/vscode-table-row';
import '@bendera/vscode-webview-elements/dist/vscode-table-cell';
import '@bendera/vscode-webview-elements/dist/vscode-collapsible';
declare const acquireVsCodeApi: <T = unknown>() => {
getState: () => T;