Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DOP-4916: Implement SoftwareSourceCode structured data #1258

Merged
merged 16 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/components/Breadcrumbs/BreadcrumbContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ const crumbObjectShape = {
};

BreadcrumbContainer.propTypes = {
breadcrumbs: PropTypes.shape(crumbObjectShape).isRequired,
breadcrumbs: PropTypes.arrayOf(PropTypes.shape(crumbObjectShape)).isRequired,
};

export default BreadcrumbContainer;
142 changes: 79 additions & 63 deletions src/components/Code/Code.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { css } from '@emotion/react';
import React, { useCallback, useContext } from 'react';
import React, { useCallback, useContext, useMemo } from 'react';
import PropTypes from 'prop-types';
import styled from '@emotion/styled';
import { default as CodeBlock } from '@leafygreen-ui/code';
Expand All @@ -12,6 +12,7 @@ import { TabContext } from '../Tabs/tab-context';
import { reportAnalytics } from '../../utils/report-analytics';
import { getLanguage } from '../../utils/get-language';
import { DRIVER_ICON_MAP } from '../icons/DriverIconMap';
import { SoftwareSourceCodeSd } from '../../utils/structured-data';
import { baseCodeStyle, borderCodeStyle, lgStyles } from './styles/codeStyle';
import { CodeContext } from './code-context';

Expand Down Expand Up @@ -85,77 +86,92 @@ const Code = ({
reportAnalytics('CodeblockCopied', { code });
}, [code]);

const softwareSourceCodeSd = useMemo(() => {
const sd = new SoftwareSourceCodeSd({ code, lang });
return sd.isValid() ? sd.toString() : undefined;
}, [code, lang]);

return (
<div
css={css`
${baseCodeStyle}

// Remove whitespace when copyable false
> div > div {
display: grid;
grid-template-columns: ${!copyable && (languageOptions?.length === 0 || language === 'none')
? 'auto 0px !important'
: 'code panel'};
}

> div {
border-top-left-radius: ${captionBorderRadius};
border-top-right-radius: ${captionBorderRadius};
display: grid;
border-color: ${palette.gray.light2};

.dark-theme & {
border-color: ${palette.gray.dark2};
<>
{softwareSourceCodeSd && (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: softwareSourceCodeSd,
}}
/>
)}
<div
css={css`
${baseCodeStyle}

// Remove whitespace when copyable false
> div > div {
display: grid;
grid-template-columns: ${!copyable && (languageOptions?.length === 0 || language === 'none')
? 'auto 0px !important'
: 'code panel'};
}
}

pre {
background-color: ${palette.gray.light3};
color: ${palette.black};
> div {
border-top-left-radius: ${captionBorderRadius};
border-top-right-radius: ${captionBorderRadius};
display: grid;
border-color: ${palette.gray.light2};

.dark-theme & {
background-color: ${palette.black};
color: ${palette.gray.light3};
.dark-theme & {
border-color: ${palette.gray.dark2};
Copy link
Collaborator Author

@rayangler rayangler Sep 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No CSS changes actually applied here

}
}
}

[data-testid='leafygreen-code-panel'] {
background-color: ${palette.white};
border-color: ${palette.gray.light2};
pre {
background-color: ${palette.gray.light3};
color: ${palette.black};

.dark-theme & {
background-color: ${palette.gray.dark2};
border-color: ${palette.gray.dark2};
.dark-theme & {
background-color: ${palette.black};
color: ${palette.gray.light3};
}
}
}

${lgStyles}
`}
>
{captionSpecified && (
<div>
<CaptionContainer style={{ '--border-color': darkMode ? palette.gray.dark2 : palette.gray.light2 }}>
<Caption style={{ '--color': darkMode ? palette.gray.light2 : palette.gray.dark1 }}>{caption}</Caption>
</CaptionContainer>
</div>
)}
<CodeBlock
copyable={copyable}
highlightLines={emphasizeLines}
language={language}
languageOptions={languageOptions}
onChange={(selectedOption) => {
setActiveTab({ drivers: selectedOption.id });
}}
onCopy={reportCodeCopied}
showLineNumbers={linenos}
showCustomActionButtons={sourceSpecified}
customActionButtons={customActionButtonList}
lineNumberStart={lineno_start}

[data-testid='leafygreen-code-panel'] {
background-color: ${palette.white};
border-color: ${palette.gray.light2};

.dark-theme & {
background-color: ${palette.gray.dark2};
border-color: ${palette.gray.dark2};
}
}

${lgStyles}
`}
>
{code}
</CodeBlock>
</div>
{captionSpecified && (
<div>
<CaptionContainer style={{ '--border-color': darkMode ? palette.gray.dark2 : palette.gray.light2 }}>
<Caption style={{ '--color': darkMode ? palette.gray.light2 : palette.gray.dark1 }}>{caption}</Caption>
</CaptionContainer>
</div>
)}
<CodeBlock
copyable={copyable}
highlightLines={emphasizeLines}
language={language}
languageOptions={languageOptions}
onChange={(selectedOption) => {
setActiveTab({ drivers: selectedOption.id });
}}
onCopy={reportCodeCopied}
showLineNumbers={linenos}
showCustomActionButtons={sourceSpecified}
customActionButtons={customActionButtonList}
lineNumberStart={lineno_start}
>
{code}
</CodeBlock>
</div>
</>
);
};

Expand Down
16 changes: 9 additions & 7 deletions src/components/Code/CodeIO.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ const outputButtonStyling = LeafyCss`
margin: 8px;
`;

const outputContainerStyle = (showOutput) => LeafyCss`
${!showOutput && 'display: none;'}
`;

const CodeIO = ({ nodeData: { children }, ...rest }) => {
const { darkMode } = useDarkMode();
const needsIOToggle = children.length === 2;
Expand All @@ -32,12 +36,8 @@ const CodeIO = ({ nodeData: { children }, ...rest }) => {
const outputBorderRadius = !showOutput ? '12px' : '0px';
const singleInputBorderRadius = onlyInputSpecified ? '12px' : '0px';

const handleClick = (e) => {
if (showOutput) {
setShowOutput(false);
} else {
setShowOutput(true);
}
const handleClick = () => {
setShowOutput((val) => !val);
};

if (children.length === 0) {
Expand Down Expand Up @@ -77,7 +77,9 @@ const CodeIO = ({ nodeData: { children }, ...rest }) => {
{buttonText}
</Button>
</IOToggle>
{showOutput && <Output nodeData={children[1]} />}
<div className={outputContainerStyle(showOutput)}>
<Output nodeData={children[1]} />
</div>
</>
)}
{onlyInputSpecified && <Input nodeData={children[0]} />}
Expand Down
65 changes: 40 additions & 25 deletions src/components/Code/Output.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React from 'react';
import React, { useMemo } from 'react';
import styled from '@emotion/styled';
import PropTypes from 'prop-types';
import { default as CodeBlock } from '@leafygreen-ui/code';
import { useDarkMode } from '@leafygreen-ui/leafygreen-provider';
import { palette } from '@leafygreen-ui/palette';
import { getLanguage } from '../../utils/get-language';
import { SoftwareSourceCodeSd } from '../../utils/structured-data';

const OutputContainer = styled.div`
> div > * {
Expand All @@ -27,36 +28,50 @@ const OutputContainer = styled.div`
}
`;

const Output = ({ nodeData: { children }, ...rest }) => {
const Output = ({ nodeData: { children } }) => {
const { darkMode } = useDarkMode();
const { emphasize_lines, value, linenos, lang, lineno_start } = children[0];
const language = getLanguage(lang);
const softwareSourceCodeSd = useMemo(() => {
const sd = new SoftwareSourceCodeSd({ code: value, lang });
return sd.isValid() ? sd.toString() : undefined;
}, [value, lang]);

return (
<OutputContainer
style={
darkMode
? {
'--code-container-border': 'none',
'--code-pre-border': `1px solid ${palette.gray.dark2}`,
}
: {
'--code-container-border': 'initial',
'--code-pre-border': `none`,
}
}
>
<CodeBlock
highlightLines={emphasize_lines}
language={language}
showLineNumbers={linenos}
darkMode={true}
copyable={false}
lineNumberStart={lineno_start}
<>
{softwareSourceCodeSd && (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: softwareSourceCodeSd,
}}
/>
)}
<OutputContainer
style={
darkMode
? {
'--code-container-border': 'none',
'--code-pre-border': `1px solid ${palette.gray.dark2}`,
}
: {
'--code-container-border': 'initial',
'--code-pre-border': `none`,
}
}
>
{value}
</CodeBlock>
</OutputContainer>
<CodeBlock
highlightLines={emphasize_lines}
language={language}
showLineNumbers={linenos}
darkMode={true}
copyable={false}
lineNumberStart={lineno_start}
>
{value}
</CodeBlock>
</OutputContainer>
</>
);
};

Expand Down
2 changes: 1 addition & 1 deletion src/components/StructuredData/DocsLandingSD.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import { baseUrl } from '../../utils/base-url';

const DocsLandingSD = () => (
<script id="structured data" type="application/ld+json">
<script type="application/ld+json">
{JSON.stringify({
'@context': 'http://schema.org',
'@type': 'WebSite',
Expand Down
33 changes: 13 additions & 20 deletions src/components/Video/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useMemo } from 'react';
import ReactPlayerYT from 'react-player/youtube';
import ReactPlayerWistia from 'react-player/wistia';
import PropTypes from 'prop-types';
Expand All @@ -7,6 +7,7 @@ import { css } from '@emotion/react';
import { palette } from '@leafygreen-ui/palette';
import { withPrefix } from 'gatsby';
import { theme } from '../../theme/docsTheme';
import { VideoObjectSd } from '../../utils/structured-data';
import VideoPlayButton from './VideoPlayButton';

// Imported both players to keep bundle size low and rendering the one associated to the URL being passed in
Expand Down Expand Up @@ -73,21 +74,10 @@ const Video = ({ nodeData: { argument, options = {} } }) => {
// use placeholder image for video thumbnail if invalid URL provided
const [previewImage, setPreviewImage] = useState(withPrefix('assets/meta_generic.png'));
const { title, description, 'upload-date': uploadDate, 'thumbnail-url': thumbnailUrl } = options;
// Required fields based on https://developers.google.com/search/docs/appearance/structured-data/video#video-object
const hasAllReqFields = [url, title, uploadDate, thumbnailUrl].every((val) => !!val);

const structuredData = {
'@context': 'https://schema.org',
'@type': 'VideoObject',
embedUrl: url,
name: title,
uploadDate,
thumbnailUrl,
};

if (description) {
structuredData['description'] = description;
}
const videoObjectSd = useMemo(() => {
const sd = new VideoObjectSd({ embedUrl: url, name: title, uploadDate, thumbnailUrl, description });
return sd.isValid() ? sd.toString() : undefined;
}, [url, title, uploadDate, thumbnailUrl, description]);

useEffect(() => {
// handles URL validity checking for well-formed YT links
Expand Down Expand Up @@ -121,10 +111,13 @@ const Video = ({ nodeData: { argument, options = {} } }) => {

return (
<>
{hasAllReqFields && (
<script id={`video-object-sd-${url}`} type="application/ld+json">
{JSON.stringify(structuredData)}
</script>
{videoObjectSd && (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: videoObjectSd,
}}
/>
)}
<ReactPlayerWrapper>
<ReactPlayer
Expand Down
Loading
Loading