(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 (
+ <>
+
+ {({ className, style, tokens, getLineProps, getTokenProps }) => (
+
+
+ {tokens.map((line, i) => (
+
+ {line.map((token, key) => (
+
+ ))}
+
+ ))}
+
+
+ )}
+
+
+ {showStackblitzBtn && projectTitle !== undefined && (
+
+ )}
+ {
+ navigator.clipboard.writeText(code);
+ document
+ .querySelector("#copy-to-clipboard-toast")
+ ?.setVisible();
+ }}
+ >
+
+ {isLargeViewport && "Copy code"}
+
+
+ >
+ );
+};
const ComponentPreview: React.FC = ({
snippets,
@@ -70,6 +123,9 @@ const ComponentPreview: React.FC = ({
centered = true,
style,
state = "none",
+ showStackblitzBtn,
+ projectTitle,
+ projectDescription,
}) => (
Interactive example
@@ -111,7 +167,17 @@ const ComponentPreview: React.FC = ({
{snippets.map((snippet, index) => (
-
+
))}
diff --git a/src/content/static/components/CookiesData/index.tsx b/src/content/static/components/CookiesData/index.tsx
index e0bc43306..345597f28 100644
--- a/src/content/static/components/CookiesData/index.tsx
+++ b/src/content/static/components/CookiesData/index.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from "react";
+import React, { useState, useEffect } from "react";
import { debounce } from "../../../../utils/helpers";
import CookiesCards from "./CookiesCards";
@@ -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 ;
}
diff --git a/src/content/structured/patterns/components/StackblitzButton/configFiles.ts b/src/content/structured/patterns/components/StackblitzButton/configFiles.ts
new file mode 100644
index 000000000..1361f8e97
--- /dev/null
+++ b/src/content/structured/patterns/components/StackblitzButton/configFiles.ts
@@ -0,0 +1,113 @@
+// eslint-disable-next-line import/no-extraneous-dependencies
+import kebabCase from "lodash/kebabCase";
+const designSystemPackageJson = require("../../../../../../package.json");
+
+export const createIndexTsx = (
+ componentName: string
+) => `import { StrictMode } from 'react';
+ import { createRoot } from 'react-dom/client';
+ import { BrowserRouter } from 'react-router-dom';
+
+ import ${componentName} from './app';
+
+ const root = createRoot(document.getElementById('root'));
+
+ root.render(
+
+
+ <${componentName} />
+
+
+ );`;
+
+export const createReactHTML = (ext: string) => `
+
+
+
+
+ Vite + React + TS
+
+
+
+
+
+ `;
+
+export const packageJson = (projectTitle: string, isWebComponents: boolean) => {
+ const dependencies = isWebComponents
+ ? {}
+ : {
+ "@mdi/js": "^7.4.47",
+ "@ukic/fonts": `${designSystemPackageJson.dependencies["@ukic/fonts"]}`,
+ "@ukic/react": `${designSystemPackageJson.dependencies["@ukic/react"]}`,
+ react: "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-router-dom": "^6.22.0",
+ };
+
+ const reactDevDependencies = {
+ "@types/react": "^18.2.48",
+ "@types/react-dom": "^18.2.18",
+ "@vitejs/plugin-react": "^4.2.1",
+ };
+ const devDependencies = { vite: "^5.0.12" };
+
+ return {
+ name: `icds-${kebabCase(projectTitle)}`,
+ version: "0.0.0",
+ private: true,
+ scripts: {
+ dev: "vite",
+ build: "vite build",
+ preview: "vite preview",
+ },
+ dependencies,
+ devDependencies: isWebComponents
+ ? { ...devDependencies }
+ : { ...devDependencies, ...reactDevDependencies },
+ };
+};
+
+export const tsConfig = `{
+ "compilerOptions": {
+ "jsx": "react-jsx",
+ "lib": ["DOM", "ES2022"],
+ "moduleResolution": "node",
+ "target": "ES2022"
+ }
+ }`;
+
+export const viteConfig = `import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [react()],
+})
+`;
+
+export const createWebComponentsIndexHTML = (
+ codeSnippet: string
+) => `
+
+
+ Home
+
+
+
+
+
+
+
+ ${codeSnippet}
+
+
+
+ `;
diff --git a/src/content/structured/patterns/components/StackblitzButton/index.tsx b/src/content/structured/patterns/components/StackblitzButton/index.tsx
new file mode 100644
index 000000000..174494d21
--- /dev/null
+++ b/src/content/structured/patterns/components/StackblitzButton/index.tsx
@@ -0,0 +1,174 @@
+import React, { useEffect, useState } from "react";
+import sdk from "@stackblitz/sdk";
+// eslint-disable-next-line import/no-extraneous-dependencies
+import startCase from "lodash/startCase";
+import { graphql, useStaticQuery } from "gatsby";
+import {
+ createIndexTsx,
+ createReactHTML,
+ createWebComponentsIndexHTML,
+ packageJson,
+ tsConfig,
+ viteConfig,
+} from "./configFiles";
+import { StackblitzLogo } from "../../../../../assets/svg";
+import { debounce } from "../../../../../utils/helpers";
+
+export type StackblitzProps = {
+ codeSnippet?: string;
+ filePaths?: string[];
+ isWebComponents?: boolean;
+ projectTitle: string;
+ projectDescription?: string;
+};
+
+const StackblitzButton: React.FC = ({
+ codeSnippet,
+ filePaths,
+ isWebComponents,
+ projectTitle,
+ projectDescription,
+}) => {
+ let defaultViewportWidth = 0;
+
+ if (typeof window !== "undefined") {
+ defaultViewportWidth = window.innerWidth;
+ }
+
+ const [viewportWidth, setViewportWidth] =
+ useState(defaultViewportWidth);
+
+ const isLargeViewport: boolean = viewportWidth > 992;
+
+ useEffect(() => {
+ const handleResize = debounce(() => setViewportWidth(window.innerWidth));
+
+ window.addEventListener("resize", handleResize);
+
+ // Cleanup function
+ return () => {
+ window.removeEventListener("resize", handleResize);
+ };
+ }, []);
+
+ const data = useStaticQuery(graphql`
+ query {
+ allPatternsTemplates {
+ nodes {
+ internal {
+ content
+ contentFilePath
+ }
+ }
+ }
+ }
+ `);
+
+ const createStackblitzProject = (paths?: string[]) => {
+ const files: { [key: string]: string } = {};
+ let isWebComponentsInternal: boolean =
+ isWebComponents !== undefined ? isWebComponents : true;
+ let isJSX: boolean = true;
+ let fileName: string | undefined;
+
+ if (paths && paths.length > 0) {
+ paths.forEach((path) => {
+ data.allPatternsTemplates.nodes
+ .filter((node: { internal: { contentFilePath: string } }) =>
+ node.internal.contentFilePath.includes(path)
+ )
+ .forEach(
+ (node: {
+ internal: { contentFilePath: string; content: string };
+ }) => {
+ // Check if path ends in HTML, CSS, TSX or JSX
+ const extension = path.match(/\.([a-z]+)$/i);
+ if (
+ extension &&
+ ["html", "css", "tsx", "jsx"].includes(extension[1])
+ ) {
+ if (extension[1] !== "css") {
+ if (extension[1] !== "html") {
+ isWebComponentsInternal = false;
+ }
+ if (extension[1] !== "jsx") {
+ isJSX = false;
+ }
+ fileName = node.internal.contentFilePath.split("/").pop();
+ }
+ files[
+ `${
+ isWebComponentsInternal
+ ? `index.${extension[1]}`
+ : `src/index.${extension[1]}`
+ }`
+ ] = node.internal.content;
+ }
+ }
+ );
+ });
+ } else if (codeSnippet !== undefined && codeSnippet !== "") {
+ if (isWebComponents) {
+ files[`index.html`] = createWebComponentsIndexHTML(codeSnippet);
+ }
+ }
+
+ const ext = isJSX ? "jsx" : "tsx";
+ const componentName = startCase(fileName?.split(".")[0]).replace(/ /g, "");
+
+ // Define the index.tsx content for a React app
+ const indexTsx = createIndexTsx(componentName);
+
+ // Change file structure for React code examples
+ if (
+ (isWebComponents !== undefined && !isWebComponents) ||
+ !isWebComponentsInternal
+ ) {
+ files[`src/app.${ext}`] = files[`src/index.${ext}`];
+ files[`src/index.${ext}`] = indexTsx;
+ files[`index.html`] = createReactHTML(ext);
+ files["vite.config.js"] = viteConfig;
+ if (ext === "tsx") {
+ files["tsconfig.json"] = tsConfig;
+ }
+ }
+
+ files["package.json"] = JSON.stringify(
+ packageJson(projectTitle, isWebComponentsInternal),
+ null,
+ 2
+ );
+
+ const description =
+ projectDescription === undefined || projectDescription === ""
+ ? ""
+ : projectDescription;
+
+ sdk.openProject({
+ title: `ICDS ${projectTitle}`,
+ description,
+ files,
+ template: "node",
+ });
+ };
+
+ return (
+ createStackblitzProject(filePaths)}
+ >
+ {isLargeViewport ? (
+
+
+
+ ) : (
+
+ )}
+ {isLargeViewport && "Stackblitz"}
+
+ );
+};
+
+export default StackblitzButton;