diff --git a/apps/website/screens/theme-generator/ThemeGeneratorConfigPage.tsx b/apps/website/screens/theme-generator/ThemeGeneratorConfigPage.tsx
index 599561a72..9f810c991 100644
--- a/apps/website/screens/theme-generator/ThemeGeneratorConfigPage.tsx
+++ b/apps/website/screens/theme-generator/ThemeGeneratorConfigPage.tsx
@@ -5,6 +5,7 @@ import BottomButtons from "./components/BottomButtons";
import { BrandingDetails } from "./steps/BrandingDetails";
import { generateTokens, handleExport } from "./utils";
import { Colors, FileData, Step } from "./types";
+import ReviewDetails from "./steps/ReviewDetails";
const steps = [
{
@@ -89,7 +90,7 @@ const ThemeGeneratorConfigPage = () => {
case 1:
return <>>;
case 2:
- return <>>;
+ return ;
}
};
diff --git a/apps/website/screens/theme-generator/components/review/ReviewBrandingAssets.tsx b/apps/website/screens/theme-generator/components/review/ReviewBrandingAssets.tsx
new file mode 100644
index 000000000..1c1a32e5e
--- /dev/null
+++ b/apps/website/screens/theme-generator/components/review/ReviewBrandingAssets.tsx
@@ -0,0 +1,45 @@
+import { DxcContainer, DxcFlex, DxcGrid, DxcImage, DxcTypography } from "@dxc-technology/halstack-react";
+import { useMemo } from "react";
+import { Logos } from "../../types";
+
+const BrandingAsset = ({ label, logo }: { label: string; logo?: string }) => {
+ if (!logo) return null;
+ return (
+
+
+ {label}
+
+
+
+
+
+
+
+ );
+};
+
+const ReviewBrandingAssets = ({ logos }: { logos: Logos }) => {
+ const brandingAssets = useMemo(() => {
+ return [
+ { label: "Main logo", logo: logos.mainLogo?.[0]?.preview },
+ { label: "Footer logo", logo: logos.footerLogo?.[0]?.preview },
+ { label: "Reduced footer logo", logo: logos.footerReducedLogo?.[0]?.preview },
+ { label: "Favicon", logo: logos.favicon?.[0]?.preview },
+ ];
+ }, [logos]);
+
+ return (
+
+ {brandingAssets.length &&
+ brandingAssets.map(({ label, logo }) => )}
+
+ );
+};
+
+export default ReviewBrandingAssets;
diff --git a/apps/website/screens/theme-generator/components/review/ReviewSectionContainer.tsx b/apps/website/screens/theme-generator/components/review/ReviewSectionContainer.tsx
new file mode 100644
index 000000000..a15502c24
--- /dev/null
+++ b/apps/website/screens/theme-generator/components/review/ReviewSectionContainer.tsx
@@ -0,0 +1,22 @@
+import { DxcContainer, DxcFlex } from "@dxc-technology/halstack-react";
+
+const ReviewSectionContainer = ({ title, children }: { title: React.ReactNode; children: React.ReactNode }) => {
+ return (
+
+
+ {title}
+ {children}
+
+
+ );
+};
+
+export default ReviewSectionContainer;
diff --git a/apps/website/screens/theme-generator/components/review/ReviewTokensGrid.tsx b/apps/website/screens/theme-generator/components/review/ReviewTokensGrid.tsx
new file mode 100644
index 000000000..639f62244
--- /dev/null
+++ b/apps/website/screens/theme-generator/components/review/ReviewTokensGrid.tsx
@@ -0,0 +1,60 @@
+import { DxcFlex, DxcGrid, DxcTypography } from "@dxc-technology/halstack-react";
+import { Tokens } from "../../types";
+import React, { useMemo } from "react";
+import { divideColorTokens, SHADE_VALUES } from "../../utils";
+
+const ReviewTokensGrid = ({ generatedTokens }: { generatedTokens: Tokens }) => {
+ const tokenGroups = useMemo(() => divideColorTokens(generatedTokens), [generatedTokens]);
+ return (
+
+ {SHADE_VALUES.map((value, index) =>
+ index === 0 ? (
+
+
+ {value}
+
+
+ ) : (
+
+ {value}
+
+ )
+ )}
+ {Object.entries(tokenGroups).map(([group, colors]) => (
+
+
+
+ {group.charAt(0).toUpperCase() + group.slice(1)}
+
+
+ {colors.map((color: string, index: number) => (
+
+ ))}
+
+ ))}
+
+ );
+};
+
+export default ReviewTokensGrid;
diff --git a/apps/website/screens/theme-generator/components/review/ReviewTokensList.tsx b/apps/website/screens/theme-generator/components/review/ReviewTokensList.tsx
new file mode 100644
index 000000000..59a414aea
--- /dev/null
+++ b/apps/website/screens/theme-generator/components/review/ReviewTokensList.tsx
@@ -0,0 +1,13 @@
+import { DxcContainer, DxcTypography } from "@dxc-technology/halstack-react";
+
+const ReviewTokensList = ({ themeJson }: { themeJson: string }) => {
+ return (
+
+
+ {themeJson}
+
+
+ );
+};
+
+export default ReviewTokensList;
diff --git a/apps/website/screens/theme-generator/steps/ReviewDetails.tsx b/apps/website/screens/theme-generator/steps/ReviewDetails.tsx
new file mode 100644
index 000000000..904ad6455
--- /dev/null
+++ b/apps/website/screens/theme-generator/steps/ReviewDetails.tsx
@@ -0,0 +1,68 @@
+import { DxcButton, DxcFlex, DxcGrid, DxcTypography, useToast } from "@dxc-technology/halstack-react";
+import { Logos, Tokens } from "../types";
+import ReviewTokensGrid from "../components/review/ReviewTokensGrid";
+import ReviewTokensList from "../components/review/ReviewTokensList";
+import ReviewBrandingAssets from "../components/review/ReviewBrandingAssets";
+import { copyToClipboard } from "../utils";
+import { useMemo } from "react";
+import ReviewSectionContainer from "../components/review/ReviewSectionContainer";
+
+const ReviewDetails = ({ generatedTokens, logos }: { generatedTokens: Tokens; logos: Logos }) => {
+ const toast = useToast();
+
+ const themeJson = useMemo(() => {
+ const themeObject = {
+ tokens: generatedTokens,
+ logos: {
+ mainLogo: "",
+ footerLogo: "",
+ footerReducedLogo: "",
+ favicon: "",
+ },
+ };
+ return JSON.stringify(themeObject, null, 2);
+ }, [generatedTokens]);
+
+ const handleCopy = () => {
+ copyToClipboard(themeJson)
+ .then(() => {
+ toast.success({ message: "Copied to clipboard" });
+ })
+ .catch(() => {
+ toast.warning({ message: "Failed to copy to clipboard" });
+ });
+ };
+
+ return (
+ <>
+
+
+ Color palette & theme
+
+
+
+ }
+ >
+
+
+
+
+
+
+
+
+ Branding assets
+
+ }
+ >
+
+
+ >
+ );
+};
+
+export default ReviewDetails;
diff --git a/apps/website/screens/theme-generator/types.ts b/apps/website/screens/theme-generator/types.ts
index 0a444a9f1..0b82e2375 100644
--- a/apps/website/screens/theme-generator/types.ts
+++ b/apps/website/screens/theme-generator/types.ts
@@ -5,6 +5,7 @@ export type Tokens = Record;
export type BaseColors = Record;
export type Step = 0 | 1 | 2;
+
export type Colors = {
primary: CssColor;
secondary: CssColor;
@@ -15,22 +16,38 @@ export type Colors = {
error: CssColor;
warning: CssColor;
};
+
+export type TokenGroups = {
+ primary: string[];
+ secondary: string[];
+ tertiary: string[];
+ semantic01: string[];
+ semantic02: string[];
+ semantic03: string[];
+ semantic04: string[];
+ neutral: string[];
+ alpha: string[];
+};
+
export type FileData = {
error?: string;
file: File;
preview?: string;
};
+
export type Logos = {
mainLogo: FileData[];
footerLogo: FileData[];
footerReducedLogo: FileData[];
favicon: FileData[];
};
+
export type Field = {
id: string;
label: string;
helperText: string;
};
+
export type BrandingDetailsSection = {
id: string;
title: string;
diff --git a/apps/website/screens/theme-generator/utils.ts b/apps/website/screens/theme-generator/utils.ts
index 25cf9062a..2f08c97df 100644
--- a/apps/website/screens/theme-generator/utils.ts
+++ b/apps/website/screens/theme-generator/utils.ts
@@ -1,5 +1,5 @@
import { Color, BackgroundColor, Theme, type CssColor } from "@adobe/leonardo-contrast-colors";
-import { BaseColors, Tokens } from "./types";
+import { BaseColors, TokenGroups, Tokens } from "./types";
/**
* Contrast ratios for generating color shades
@@ -106,3 +106,30 @@ export const handleExport = (tokens: Tokens) => {
export const copyToClipboard = (value: string) => {
return navigator.clipboard.writeText(value);
};
+
+export const divideColorTokens = (tokens: Tokens) => {
+ const groups: TokenGroups = {
+ primary: [],
+ secondary: [],
+ tertiary: [],
+ semantic01: [],
+ semantic02: [],
+ semantic03: [],
+ semantic04: [],
+ neutral: [],
+ alpha: [],
+ };
+
+ for (const [key, value] of Object.entries(tokens)) {
+ // divides tokens names into 3 sections
+ const sections = key.match(/^--color-([a-z0-9]+)-(.+)$/);
+ if (sections) {
+ // the second section indicates the group (primary, secondary, etc.)
+ const group = sections[1];
+ if (group && group in groups) {
+ groups[group as keyof TokenGroups].push(value);
+ }
+ }
+ }
+ return groups;
+};