Skip to content

Commit

Permalink
feat(root): add stackblitz button and add new variant of "copy code" …
Browse files Browse the repository at this point in the history
…button for small screen sizes

Add new optional Stackblitz button to ComponentPreview & CodePreview components, connect Stackblitz
SDK to onClick of StackblitzButton component, add cleanup function to useEffect in CookieData
component

. #751
  • Loading branch information
GCHQ-Developer-112 committed Feb 8, 2024
1 parent 713c535 commit 64607cd
Show file tree
Hide file tree
Showing 9 changed files with 467 additions and 44 deletions.
55 changes: 55 additions & 0 deletions gatsby-node.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const path = require(`path`);
const fs = require("fs");
// eslint-disable-next-line import/no-extraneous-dependencies
const webpack = require("webpack");
const pagesConfig = require("./src/config");
Expand Down Expand Up @@ -236,6 +237,11 @@ exports.createResolvers = ({ createResolvers }) => {

exports.onCreateWebpackConfig = ({ actions }) => {
actions.setWebpackConfig({
resolve: {
fallback: {
fs: false,
},
},
plugins: [
/**
* See line 203 of:
Expand Down Expand Up @@ -277,3 +283,52 @@ exports.onCreateWebpackConfig = ({ actions }) => {
],
});
};

exports.sourceNodes = ({ actions, createNodeId, createContentDigest }) => {
const { createNode } = actions;

// Read all files in the sub-directories of the patterns folder
function getFilePaths(dirPath) {
let filePaths = [];
const files = fs.readdirSync(dirPath);

files.forEach((file) => {
const absolutePath = path.join(dirPath, file);
if (fs.statSync(absolutePath).isDirectory()) {
filePaths = filePaths.concat(getFilePaths(absolutePath));
} else {
filePaths.push(absolutePath);
}
});

return filePaths;
}

// Read all files in the patterns folder
const patternsDir = path.resolve(
__dirname,
"src/content/structured/patterns/templates"
);
const filePaths = getFilePaths(patternsDir);

// For each file in the patterns folder, read the contents of the file and create a data node
filePaths.forEach((filePath) => {
const content = fs.readFileSync(filePath, "utf8");
const regex = /(\/patterns\/templates\/.*)$/;
const regexMatchedFilePath = filePath.match(regex)[0];

const nodeMeta = {
id: createNodeId(`${regexMatchedFilePath}`),
parent: null,
children: [],
internal: {
type: `PatternsTemplates`,
contentFilePath: regexMatchedFilePath,
content,
contentDigest: createContentDigest(content),
},
};

createNode(nodeMeta);
});
};
18 changes: 18 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"@mdi/react": "^1.5.0",
"@mdx-js/mdx": "^1.6.22",
"@mdx-js/react": "^1.6.22",
"@stackblitz/sdk": "^1.9.0",
"@ukic/docs": "^2.9.2",
"@ukic/fonts": "^2.6.0",
"@ukic/react": "^2.11.0",
Expand Down Expand Up @@ -42,6 +43,8 @@
"gatsby-transformer-remark": "^6.12.0",
"gatsby-transformer-sharp": "^4.2.0",
"github-slugger": "^1.4.0",
"lodash.kebabcase": "^4.1.1",
"lodash.startcase": "^4.4.0",
"performant-array-to-tree": "^1.9.1",
"prism-react-renderer": "^1.3.1",
"prismjs": "^1.25.0",
Expand Down
1 change: 1 addition & 0 deletions src/assets/svg/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export { default as GCHQLogo } from "./gchq-logo.svg";
export { default as MI5Logo } from "./mi5-logo.svg";
export { default as SISLogo } from "./sis-logo.svg";
export { default as ICDSLogo } from "./icds-logo.svg";
export { default as StackblitzLogo } from "./stackblitz-logo.svg";
1 change: 1 addition & 0 deletions src/assets/svg/stackblitz-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
134 changes: 97 additions & 37 deletions src/components/CodePreview/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Highlight, { defaultProps } from "prism-react-renderer";
import React, { CSSProperties, ReactNode } from "react";
import React, { CSSProperties, ReactNode, useState, useEffect } from "react";

import {
mdiCheckboxMarkedCircle,
Expand All @@ -11,56 +11,109 @@ import clsx from "clsx";
import { SlottedSVG } from "@ukic/react";

import "./index.css";
import StackblitzButton, {
StackblitzProps,
} from "../../content/structured/patterns/components/StackblitzButton";
import { debounce } from "../../utils/helpers";

interface Snippet {
language: string;
snippet: string;
}

interface ComponentPreviewProps {
interface ComponentPreviewProps extends Partial<StackblitzProps> {
snippets?: Snippet[];
left?: boolean;
noPadding?: boolean;
centered?: boolean;
children: ReactNode;
style: CSSProperties;
state: "none" | "good" | "bad";
showStackblitzBtn?: boolean;
}

const CodeSnippet: React.FC<{ code: string }> = ({ code }) => (
<>
<Highlight {...defaultProps} code={code} language="jsx" theme={undefined}>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<pre className={clsx(className, "snippet")} style={style}>
<code>
{tokens.map((line, i) => (
<div {...getLineProps({ line, key: i })}>
{line.map((token, key) => (
<span {...getTokenProps({ token, key })} />
))}
</div>
))}
</code>
</pre>
)}
</Highlight>
<div className="snippet-container">
<ic-button
variant="tertiary"
appearance="dark"
onClick={() => {
navigator.clipboard.writeText(code);
document
.querySelector<HTMLIcToastElement>("#copy-to-clipboard-toast")
?.setVisible();
}}
>
Copy code
<SlottedSVG path={mdiContentCopy} slot="left-icon" />
</ic-button>
</div>
</>
);
interface CodeSnippetProps extends Partial<StackblitzProps> {
code: string;
showStackblitzBtn?: boolean;
}

const CodeSnippet: React.FC<CodeSnippetProps> = ({
code,
isWebComponents,
showStackblitzBtn,
projectTitle,
projectDescription,
}) => {
let defaultViewportWidth = 0;

if (typeof window !== "undefined") {
defaultViewportWidth = window.innerWidth;
}

const [viewportWidth, setViewportWidth] =
useState<number>(defaultViewportWidth);

const isLargeViewport: boolean = viewportWidth > 992;

useEffect(() => {
const handleResize = debounce(() => setViewportWidth(window.innerWidth));

window.addEventListener("resize", handleResize);

// Cleanup function
return () => {
window.removeEventListener("resize", handleResize);
};
}, []);

return (
<>
<Highlight {...defaultProps} code={code} language="jsx" theme={undefined}>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<pre className={clsx(className, "snippet")} style={style}>
<code>
{tokens.map((line, i) => (
<div {...getLineProps({ line, key: i })}>
{line.map((token, key) => (
<span {...getTokenProps({ token, key })} />
))}
</div>
))}
</code>
</pre>
)}
</Highlight>
<div className="snippet-container">
{showStackblitzBtn && projectTitle !== undefined && (
<StackblitzButton
codeSnippet={code}
isWebComponents={isWebComponents}
projectTitle={projectTitle}
projectDescription={projectDescription}
/>
)}
<ic-button
aria-label={isLargeViewport ? "" : "Copy code"}
variant={isLargeViewport ? "tertiary" : "icon"}
appearance="dark"
onClick={() => {
navigator.clipboard.writeText(code);
document
.querySelector<HTMLIcToastElement>("#copy-to-clipboard-toast")
?.setVisible();
}}
>
<SlottedSVG
path={mdiContentCopy}
slot={isLargeViewport ? "left-icon" : undefined}
viewBow="0 0 24 24"
/>
{isLargeViewport && "Copy code"}
</ic-button>
</div>
</>
);
};

const ComponentPreview: React.FC<ComponentPreviewProps> = ({
snippets,
Expand All @@ -70,6 +123,7 @@ const ComponentPreview: React.FC<ComponentPreviewProps> = ({
centered = true,
style,
state = "none",
showStackblitzBtn,
}) => (
<div className="comp-preview">
<h4 className="offscreen">Interactive example</h4>
Expand Down Expand Up @@ -111,7 +165,13 @@ const ComponentPreview: React.FC<ComponentPreviewProps> = ({
</div>
{snippets.map((snippet, index) => (
<ic-tab-panel tab-position={index}>
<CodeSnippet code={snippet.snippet} />
<CodeSnippet
code={snippet.snippet}
showStackblitzBtn={showStackblitzBtn}
isWebComponents={snippet.language === "Web component"}
projectTitle="Top Navigation Pattern"
projectDescription="this is a top nav"
/>
</ic-tab-panel>
))}
</ic-tab-context>
Expand Down
18 changes: 11 additions & 7 deletions src/content/static/components/CookiesData/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import { debounce } from "../../../../utils/helpers";

import CookiesCards from "./CookiesCards";
Expand Down Expand Up @@ -31,14 +31,18 @@ const CookiesData = ({ headers, data, caption }: CookiesDataProps) => {

const [viewportWidth, setViewportWidth] = useState(defaultViewportWidth);

React.useEffect(() => {
window.addEventListener(
"resize",
debounce(() => setViewportWidth(window.innerWidth))
);
useEffect(() => {
const handleResize = debounce(() => setViewportWidth(window.innerWidth));

window.addEventListener("resize", handleResize);

// Cleanup function
return () => {
window.removeEventListener("resize", handleResize);
};
}, []);

if (viewportWidth > 991) {
if (viewportWidth > 992) {
return <CookiesTable {...props} />;
}

Expand Down
Loading

0 comments on commit 64607cd

Please sign in to comment.