Skip to content
82 changes: 44 additions & 38 deletions apps/website/screens/theme-generator/ThemeGeneratorConfigPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ import { DxcContainer, DxcFlex, DxcWizard } from "@dxc-technology/halstack-react
import StepHeading from "./components/StepHeading";
import BottomButtons from "./components/BottomButtons";
import ThemeGeneratorPreviewPage from "./ThemeGeneratorPreviewPage";
// import { FileData } from "../../../../packages/lib/src/file-input/types";

import { BrandingDetails } from "./steps/BrandingDetails";
import { generateTokens, handleExport } from "./utils";
import { Colors, FileData, Step } from "./types";
import ReviewDetails from "./steps/ReviewDetails";
import Tour from "./components/Tour/Tour";

const steps = [
{
Expand Down Expand Up @@ -38,6 +37,7 @@ const wizardSteps = steps.map(({ label, description }) => ({

const ThemeGeneratorConfigPage = () => {
const [currentStep, setCurrentStep] = useState<Step>(0);
const [tourStepIndex, setTourStepIndex] = useState(0);
const [colors, setColors] = useState<Colors>({
primary: "#5F249F",
secondary: "#0067B3",
Expand Down Expand Up @@ -104,50 +104,56 @@ const ThemeGeneratorConfigPage = () => {
case 0:
return <BrandingDetails colors={colors} onColorsChange={setColors} logos={logos} onLogosChange={setLogos} />;
case 1:
return <ThemeGeneratorPreviewPage tokens={tokens} logos={logos} />;
return <ThemeGeneratorPreviewPage tokens={tokens} logos={logos} showDefaultComponents={tourStepIndex === 2} />;
case 2:
return <ReviewDetails tokens={tokens} logos={logos} themeJson={themeJson} />;
}
};

return (
<DxcContainer
height="100%"
boxSizing="border-box"
padding={{ top: "var(--spacing-padding-xl)" }}
background={{ color: "var(--color-bg-neutral-lighter)" }}
>
<DxcFlex direction="column" gap="var(--spacing-gap-xl)" fullHeight>
<DxcContainer width="80%" maxWidth="1112px" margin={{ left: "auto", right: "auto" }}>
<DxcWizard
steps={wizardSteps}
currentStep={currentStep}
onStepClick={(i) => {
handleChangeStep(i as Step);
}}
/>
</DxcContainer>
<>
<DxcContainer
height="100%"
boxSizing="border-box"
padding={{ top: "var(--spacing-padding-xl)" }}
background={{ color: "var(--color-bg-neutral-lighter)" }}
>
<Tour currentStep={currentStep} onTourStepIndexChange={setTourStepIndex} />

<DxcContainer
maxWidth="1332px"
width="90%"
height="100%"
boxSizing="border-box"
margin={{ left: "auto", right: "auto" }}
>
<DxcFlex direction="column" alignItems="center" gap="var(--spacing-gap-xl)" fullHeight>
<StepHeading title={steps[currentStep].title} subtitle={steps[currentStep].subtitle} />
{renderStepContent()}
</DxcFlex>
</DxcContainer>
<DxcFlex direction="column" gap="var(--spacing-gap-xl)" fullHeight>
<DxcContainer width="80%" maxWidth="1112px" margin={{ left: "auto", right: "auto" }}>
<div id="wizard-tour">
<DxcWizard
steps={wizardSteps}
currentStep={currentStep}
onStepClick={(i) => {
handleChangeStep(i as Step);
}}
/>
</div>
</DxcContainer>

<BottomButtons
currentStep={currentStep}
onChangeStep={handleChangeStep}
onExport={() => handleExport(themeJson)}
/>
</DxcFlex>
</DxcContainer>
<DxcContainer
maxWidth="1332px"
width="90%"
height="100%"
boxSizing="border-box"
margin={{ left: "auto", right: "auto" }}
>
<DxcFlex direction="column" alignItems="center" gap="var(--spacing-gap-xl)" fullHeight>
<StepHeading title={steps[currentStep].title} subtitle={steps[currentStep].subtitle} />
{renderStepContent()}
</DxcFlex>
</DxcContainer>

<BottomButtons
currentStep={currentStep}
onChangeStep={handleChangeStep}
onExport={() => handleExport(themeJson)}
/>
</DxcFlex>
</DxcContainer>
</>
);
};

Expand Down
31 changes: 20 additions & 11 deletions apps/website/screens/theme-generator/ThemeGeneratorPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,22 +69,31 @@ const ThemeGeneratorPage = () => {
>
<DxcFlex direction="column" fullHeight alignItems="center" justifyContent="center">
<DxcContainer width="80%">
<DxcFlex direction="column" fullHeight justifyContent="center" gap="var(--spacing-gap-ml)">
<DxcFlex direction="column" justifyContent="center" gap="var(--spacing-gap-m)">
<DxcHeading text="Welcome to Halstack Theme Generator" />
<DxcContainer maxWidth="60%">
<DxcTypography fontSize="var(--typography-body-xl)">
<DxcFlex direction="column" gap="var(--spacing-gap-ml)" alignItems="center">
<DxcContainer maxWidth="70%">
<DxcFlex direction="column" justifyContent="center" alignItems="center" gap="var(--spacing-gap-m)">
Comment thread
Jialecl marked this conversation as resolved.
<DxcHeading text="Build your theme with Halstack Theme Generator" />
<DxcTypography fontSize="var(--typography-body-xl)" textAlign="center">
Create and explore your brand within Halstack. Configure your core colors, upload your logo
variants, and see in real time how your theme works across components, layouts, and real product
scenarios.
<br />
Learn how your theme is built step by step.
</DxcTypography>
</DxcContainer>
</DxcFlex>
</DxcContainer>
<DxcFlex alignItems="center" gap="var(--spacing-gap-xl)">
<Link href="/theme-generator/configuration?tour=true" passHref legacyBehavior>
<DxcLink icon="explore" iconPosition="after">
Take a tour
</DxcLink>
</Link>
<Link href="/theme-generator/configuration" passHref legacyBehavior>
<DxcLink icon="arrow_forward" iconPosition="after">
Start building
</DxcLink>
</Link>
</DxcFlex>
<Link href="/theme-generator/configuration" passHref legacyBehavior>
<DxcLink icon="arrow_forward" iconPosition="after">
Start your theme
</DxcLink>
</Link>
</DxcFlex>
</DxcContainer>
</DxcFlex>
Expand Down
192 changes: 108 additions & 84 deletions apps/website/screens/theme-generator/ThemeGeneratorPreviewPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
DxcTypography,
HalstackProvider,
} from "@dxc-technology/halstack-react";
import { ReactNode, SVGProps, useMemo, useState } from "react";
import { ReactNode, SVGProps, useMemo, useState, useEffect } from "react";
import componentsList from "../common/componentsList.json";
import { componentsRegistry, examplesRegistry } from "screens/theme-generator/componentsRegistry";
import styled from "@emotion/styled";
Expand Down Expand Up @@ -109,7 +109,15 @@ const mapToSelectGroups = (data: ComponentItem[]) => {
}));
};

const ThemeGeneratorPreviewPage = ({ tokens, logos }: { tokens: Record<string, string>; logos: Logos }) => {
const ThemeGeneratorPreviewPage = ({
tokens,
logos,
showDefaultComponents,
}: {
tokens: Record<string, string>;
logos: Logos;
showDefaultComponents?: boolean;
}) => {
const [mode, setMode] = useState<"components" | "examples">("components");

const [selectedComponents, setSelectedComponents] = useState<string[]>([]);
Expand All @@ -119,6 +127,15 @@ const ThemeGeneratorPreviewPage = ({ tokens, logos }: { tokens: Record<string, s
return mapToSelectGroups(componentsList as ComponentItem[]);
}, []);

// Set default components when requested and clear on cleanup
useEffect(() => {
if (showDefaultComponents) {
setSelectedComponents(["/components/button", "/components/alert", "/components/switch"]);
} else {
setSelectedComponents([]);
}
}, [showDefaultComponents]);

const getLabelFromValue = (value: string) =>
componentOptions.flatMap((group) => group.options).find((opt) => opt.value === value)?.label;

Expand Down Expand Up @@ -163,40 +180,44 @@ const ThemeGeneratorPreviewPage = ({ tokens, logos }: { tokens: Record<string, s
<DxcContainer width="100%" height="100%">
<DxcFlex direction="column" gap="var(--spacing-gap-s)" fullHeight>
<DxcFlex direction="row" justifyContent="space-between" alignItems="center">
<DxcToggleGroup
options={[
{ label: "Components", icon: "category", value: 1 },
{ label: "Layout examples", icon: "dashboard", value: 2 },
]}
value={mode === "components" ? 1 : 2}
onChange={(value: number) => setMode(value === 1 ? "components" : "examples")}
/>
{mode === "components" && (
<DxcSelect
placeholder="Select components"
options={componentOptions}
multiple
value={selectedComponents}
onChange={({ value }) => {
setSelectedComponents(value);
}}
enableSelectAll
searchable
size="small"
<div id="toggle-tour">
<DxcToggleGroup
options={[
{ label: "Components", icon: "category", value: 1 },
{ label: "Layout examples", icon: "dashboard", value: 2 },
]}
value={mode === "components" ? 1 : 2}
onChange={(value: number) => setMode(value === 1 ? "components" : "examples")}
/>
)}
</div>
<div id="select-preview-tour">
{mode === "components" && (
<DxcSelect
placeholder="Select components"
options={componentOptions}
multiple
value={selectedComponents}
onChange={({ value }) => {
setSelectedComponents(value);
}}
enableSelectAll
searchable
size="small"
/>
)}

{mode === "examples" && (
<DxcSelect
placeholder="Select examples"
options={exampleOptions}
value={selectedExample}
onChange={({ value }) => {
setSelectedExample(value);
}}
searchable
/>
)}
{mode === "examples" && (
<DxcSelect
placeholder="Select examples"
options={exampleOptions}
value={selectedExample}
onChange={({ value }) => {
setSelectedExample(value);
}}
searchable
/>
)}
</div>
</DxcFlex>
{mode === "examples" && (
<DxcFlex gap="var(--spacing-gap-xs)">
Expand All @@ -212,57 +233,60 @@ const ThemeGeneratorPreviewPage = ({ tokens, logos }: { tokens: Record<string, s
</DxcFlex>
)}
{/* TODO: Turn this into a separate componente called PreviewArea or similar? */}
<DxcContainer
borderRadius="var(--border-radius-l)"
border={{
width: "var(--border-width-s)",
color: "var(--border-color-neutral-medium)",
style: "var(--border-style-default)",
}}
background={{ color: "var(--color-bg-neutral-lightest)" }}
padding="var(--spacing-padding-s)"
height="100%"
>
{(mode === "components" && selectedComponents.length > 0) || (mode === "examples" && !!selectedExample) ? (
<DxcFlex direction="column" gap="var(--spacing-gap-ml)" fullHeight>
<DxcFlex justifyContent="flex-end">
<DxcButton
icon="filled_delete"
size={{ height: "medium" }}
title="Delete selection"
onClick={() => {
if (mode === "components") {
setSelectedComponents([]);
} else {
setSelectedExample("");
}
}}
mode="secondary"
semantic="error"
disabled={mode === "components" ? selectedComponents.length === 0 : !selectedExample}
/>
<div id="preview-area-tour" style={{ height: "100%" }}>
<DxcContainer
borderRadius="var(--border-radius-l)"
border={{
width: "var(--border-width-s)",
color: "var(--border-color-neutral-medium)",
style: "var(--border-style-default)",
}}
background={{ color: "var(--color-bg-neutral-lightest)" }}
padding="var(--spacing-padding-s)"
height="100%"
boxSizing="border-box"
>
{(mode === "components" && selectedComponents.length > 0) || (mode === "examples" && !!selectedExample) ? (
<DxcFlex direction="column" gap="var(--spacing-gap-ml)" fullHeight>
<DxcFlex justifyContent="flex-end">
<DxcButton
icon="filled_delete"
size={{ height: "medium" }}
title="Delete selection"
onClick={() => {
if (mode === "components") {
setSelectedComponents([]);
} else {
setSelectedExample("");
}
}}
mode="secondary"
semantic="error"
disabled={mode === "components" ? selectedComponents.length === 0 : !selectedExample}
/>
</DxcFlex>
<PreviewAreaContainer>
<HalstackProvider opinionatedTheme={{ tokens, logos: processedLogos }}>
<DxcFlex direction="column" gap="var(--spacing-gap-l)">
{displayedPreview}
</DxcFlex>
</HalstackProvider>
</PreviewAreaContainer>
</DxcFlex>
) : (
<DxcFlex alignItems="center" justifyContent="center" fullHeight>
<DxcTypography
color="var(--color-fg-neutral-dark)"
fontFamily="var(--typography-font-family)"
fontSize="var(--typography-body-s)"
fontWeight="var(--typography-body-regular)"
>
Select {mode === "components" ? "a component" : "an example"} to preview
</DxcTypography>
</DxcFlex>
<PreviewAreaContainer>
<HalstackProvider opinionatedTheme={{ tokens, logos: processedLogos }}>
<DxcFlex direction="column" gap="var(--spacing-gap-l)">
{displayedPreview}
</DxcFlex>
</HalstackProvider>
</PreviewAreaContainer>
</DxcFlex>
) : (
<DxcFlex alignItems="center" justifyContent="center" fullHeight>
<DxcTypography
color="var(--color-fg-neutral-dark)"
fontFamily="var(--typography-font-family)"
fontSize="var(--typography-body-s)"
fontWeight="var(--typography-body-regular)"
>
Select {mode === "components" ? "a component" : "an example"} to preview
</DxcTypography>
</DxcFlex>
)}
</DxcContainer>
)}
</DxcContainer>
</div>
</DxcFlex>
</DxcContainer>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ const BottomButtons = ({
size={{ height: "medium" }}
/>
{currentStep === MAX_STEP ? (
<DxcButton label="Export theme" onClick={onExport} size={{ height: "medium" }} />
<div id="export-tour">
<DxcButton label="Export theme" onClick={onExport} size={{ height: "medium" }} />
</div>
) : (
<DxcButton label="Next" onClick={() => onChangeStep((currentStep + 1) as Step)} size={{ height: "medium" }} />
)}
Expand Down
Loading
Loading