From 9c8f02576f98b59be48a2de2abcb7933375628dd Mon Sep 17 00:00:00 2001 From: Pelayo Felgueroso Date: Thu, 12 Feb 2026 10:04:08 +0100 Subject: [PATCH 1/4] Firts approach to Theme Generators Structure, mainly top wizard component --- apps/website/pages/_app.tsx | 48 ++++-- .../pages/utilities/theme-generator.tsx | 89 +++++++++++ apps/website/screens/common/pagesList.tsx | 5 + .../theme-generator/ThemeGeneratorPage.tsx | 5 + .../theme-generator/components/ColorCard.tsx | 117 ++++++++++++++ .../components/ThemeSettings.tsx | 144 ++++++++++++++++++ 6 files changed, 392 insertions(+), 16 deletions(-) create mode 100644 apps/website/pages/utilities/theme-generator.tsx create mode 100644 apps/website/screens/utilities/theme-generator/ThemeGeneratorPage.tsx create mode 100644 apps/website/screens/utilities/theme-generator/components/ColorCard.tsx create mode 100644 apps/website/screens/utilities/theme-generator/components/ThemeSettings.tsx diff --git a/apps/website/pages/_app.tsx b/apps/website/pages/_app.tsx index fdffe9c9a5..1bc7f0c8e3 100644 --- a/apps/website/pages/_app.tsx +++ b/apps/website/pages/_app.tsx @@ -23,9 +23,18 @@ type AppPropsWithLayout = AppProps & { Component: NextPageWithLayout; emotionCache?: EmotionCache; }; +type ApplicationLayoutWrapperProps = { + condition: boolean; + wrapper: (_children: ReactNode) => JSX.Element; + children: ReactNode; +}; const clientSideEmotionCache = createCache({ key: "css", prepend: true }); +const ApplicationLayoutWrapper = ({ condition, wrapper, children }: ApplicationLayoutWrapperProps): JSX.Element => ( + <>{condition ? wrapper(children) : children} +); + export default function App({ Component, pageProps, emotionCache = clientSideEmotionCache }: AppPropsWithLayout) { const getLayout = Component.getLayout || ((page) => page); const componentWithLayout = getLayout(); @@ -107,23 +116,30 @@ export default function App({ Component, pageProps, emotionCache = clientSideEmo - } - sidenav={ - } - searchBar={{ placeholder: "Search docs", onChange: (value) => setFilter(value) }} - /> - } + ( + } + sidenav={ + } + searchBar={{ placeholder: "Search docs", onChange: (value) => setFilter(value) }} + /> + } + > + + + {children} + + + + )} > - - - {componentWithLayout} - - - + {componentWithLayout} + ); } diff --git a/apps/website/pages/utilities/theme-generator.tsx b/apps/website/pages/utilities/theme-generator.tsx new file mode 100644 index 0000000000..707aaf2330 --- /dev/null +++ b/apps/website/pages/utilities/theme-generator.tsx @@ -0,0 +1,89 @@ +import Head from "next/head"; +import { useState } from "react"; +import styled from "@emotion/styled"; +import { DxcApplicationLayout, DxcButton, DxcContainer, DxcToastsQueue } from "@dxc-technology/halstack-react"; +import { dxcLogo } from "@/common/images/dxc_logo"; +import { ThemeSettings } from "screens/utilities/theme-generator/components/ThemeSettings"; +import ThemeGeneratorPage from "screens/utilities/theme-generator/ThemeGeneratorPage"; + +export type Color = { + name: string; + value: string; +}; + +export type Colors = Color[]; + +const MainContent = styled.div` + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: var(--spacing-gap-xs); + padding: var(--spacing-padding-none) var(--spacing-padding-ml); + box-sizing: border-box; + padding-top: var(--spacing-padding-s); +`; + +const PageWrapper = styled.div` + width: 100%; + height: 100%; + display: flex; + align-items: flex-start; + gap: var(--spacing-gap-ml); +`; + +const PreviewWrapper = styled.div` + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: var(--spacing-gap-ml); + padding: var(--spacing-padding-l); +`; + +const Index = () => { + const [currentStep, setCurrentStep] = useState<0 | 1 | 2>(0); + const [colors, setColors] = useState([ + { name: "primary", value: "#5f249f" }, + { name: "secondary", value: "#0067b3" }, + { name: "tertiary", value: "#c2c2c2" }, + { name: "info", value: "#0067b3" }, + { name: "success", value: "#24a148" }, + { name: "error", value: "#d0011b" }, + { name: "neutral", value: "#000000" }, + ]); + + return ( + <> + + Theme generator — Halstack Design System + + }> + + + + + + Sidenav + + + + + + + + + + + + ); +}; + +export default Index; diff --git a/apps/website/screens/common/pagesList.tsx b/apps/website/screens/common/pagesList.tsx index 32f1f9f99d..4988317c38 100644 --- a/apps/website/screens/common/pagesList.tsx +++ b/apps/website/screens/common/pagesList.tsx @@ -34,6 +34,11 @@ const utilitiesLinks: LinkDetails[] = [ path: "/utilities/halstack-provider", icon: "integration_instructions", }, + { + label: "Theme generator", + path: "/utilities/theme-generator", + icon: "colorize", + }, ]; const principlesLinks: LinkDetails[] = [ diff --git a/apps/website/screens/utilities/theme-generator/ThemeGeneratorPage.tsx b/apps/website/screens/utilities/theme-generator/ThemeGeneratorPage.tsx new file mode 100644 index 0000000000..be288298a9 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/ThemeGeneratorPage.tsx @@ -0,0 +1,5 @@ +import { Colors } from "pages/utilities/theme-generator"; + +const ThemeGeneratorPage = ({ colors }: { colors: Colors }) => <>Theme generator page; + +export default ThemeGeneratorPage; diff --git a/apps/website/screens/utilities/theme-generator/components/ColorCard.tsx b/apps/website/screens/utilities/theme-generator/components/ColorCard.tsx new file mode 100644 index 0000000000..f69e32b9e7 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/components/ColorCard.tsx @@ -0,0 +1,117 @@ +import { useCallback, useState } from "react"; +import { DxcHeading, DxcPopover, DxcTextInput } from "@dxc-technology/halstack-react"; +import styled from "@emotion/styled"; +import { SketchPicker } from "react-color"; + +const CardWrapper = styled.div` + display: flex; + justify-content: center; + align-items: center; + gap: var(--spacing-gap-s); + padding: var(--spacing-padding-xs); + border-radius: var(--border-radius-m); + background-color: var(--color-bg-neutral-lightest); + box-shadow: var(--shadow-100); +`; + +const ContentWrapper = styled.div` + display: flex; + flex-direction: column; + align-items: flex-start; + gap: var(--spacing-gap-xs); +`; + +const ColorBox = styled.div<{ color: string }>` + width: 124px; + height: 32px; + border-radius: var(--border-radius-s); + background-color: ${(props) => props.color}; + cursor: pointer; +`; + +const ColorText = styled.div` + width: 124px; + display: flex; + justify-content: center; + align-items: center; +`; + +export const ColorCard = ({ + label, + color, + onChange, +}: { + label: string; + color: string; + onChange: (color: string) => void; +}) => { + const [isOpen, setIsOpen] = useState(false); + const [inputValue, setInputValue] = useState(color); + const [error, setError] = useState(""); + + const handleChange = useCallback( + (newColor: { hex: string }) => { + setInputValue(newColor.hex); + onChange(newColor.hex); + }, + [onChange] + ); + + const handleInputChange = useCallback( + ({ value }: { value: string }) => { + setInputValue(value); + // Solo propagar si es un hexadecimal válido (el patrón lo valida el DxcTextInput) + const hexPattern = /^#[0-9A-Fa-f]{3}$|^#[0-9A-Fa-f]{6}$/; + if (hexPattern.test(value)) { + onChange(value); + setError(""); + } + }, + [onChange] + ); + + const onBlur = useCallback( + ({ value, error }: { value: string; error?: string }) => { + let normalizedValue = value; + if (value && !value.startsWith("#")) { + normalizedValue = "#" + value; + setInputValue(normalizedValue); + + const hexPattern = /^#[0-9A-Fa-f]{3}$|^#[0-9A-Fa-f]{6}$/; + if (hexPattern.test(normalizedValue)) { + onChange(normalizedValue); + setError(""); + return; + } + } + setError(error || ""); + }, + [onChange] + ); + + return ( + + + + setIsOpen(true)} + onClose={() => setIsOpen(false)} + popoverContent={} + > + + + + + + + + ); +}; diff --git a/apps/website/screens/utilities/theme-generator/components/ThemeSettings.tsx b/apps/website/screens/utilities/theme-generator/components/ThemeSettings.tsx new file mode 100644 index 0000000000..3675498adc --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/components/ThemeSettings.tsx @@ -0,0 +1,144 @@ +import { useState } from "react"; +import { DxcBadge, DxcButton, DxcContainer, DxcFileInput, DxcFlex, DxcWizard } from "@dxc-technology/halstack-react"; +import styled from "@emotion/styled"; +import { FileData } from "../../../../../../packages/lib/src/file-input/types"; +import { Color, Colors } from "pages/utilities/theme-generator"; +import { ColorCard } from "./ColorCard"; + +const ThemeSettingsWrapper = styled.div` + width: 100%; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: var(--spacing-gap-ml); +`; + +const ColorWrapper = styled.div` + display: flex; + justify-content: center; + align-items: flex-start; + gap: var(--spacing-gap-xs); + align-self: stretch; +`; + +const BrandingWrapper = styled.div` + display: flex; + justify-content: center; + align-items: flex-start; + gap: var(--spacing-gap-l); + align-self: stretch; +`; + +const ButtonsWrapper = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + align-self: stretch; +`; + +const RightButtonsWrapper = styled.div` + display: flex; + align-items: center; + gap: var(--spacing-gap-s); +`; + +const steps = [{ label: "Core colors" }, { label: "Branding" }, { label: "Export" }]; + +export const ThemeSettings = ({ + currentStep, + setCurrentStep, + colors, + setColors, +}: { + currentStep: 0 | 1 | 2; + setCurrentStep: React.Dispatch>; + colors: Colors; + setColors: React.Dispatch>; +}) => { + const [mainLogo, setMainLogo] = useState([]); + const [footerLogo, setFooterLogo] = useState([]); + const [favicon, setFavicon] = useState([]); + + return ( + + + setCurrentStep(i as 0 | 1 | 2)} /> + + + <> + {currentStep === 0 ? ( + + {colors.map((color: Color) => ( + { + const updatedColors = colors.map((c) => (c.name === color.name ? { ...c, value: newColor } : c)); + setColors(updatedColors); + }} + /> + ))} + + ) : currentStep === 1 ? ( + + + + + + + + + + + + + + + + + ) : ( + <> + )} + + + + + + + + + + + ); +}; From eb248061f5fa140da26b3fd161bd826cc3d6a146 Mon Sep 17 00:00:00 2001 From: PelayoFelgueroso Date: Thu, 12 Feb 2026 16:10:13 +0100 Subject: [PATCH 2/4] Start preview area and preview components --- .../pages/utilities/theme-generator.tsx | 61 +++---------------- .../theme-generator/ThemeGeneratorPage.tsx | 58 +++++++++++++++++- .../components/BottomButtons.tsx | 37 +++++++++++ .../theme-generator/components/ColorCard.tsx | 28 +++++++-- .../components/ComponentPreview.tsx | 27 ++++++++ .../components/PreviewArea.tsx | 59 ++++++++++++++++++ .../theme-generator/components/SidePanel.tsx | 16 +++++ .../components/ThemeSettings.tsx | 4 +- .../previews/AccordionPreview.tsx | 21 +++++++ .../theme-generator/previews/AlertPreview.tsx | 38 ++++++++++++ .../previews/AvatarPreview.tsx | 15 +++++ .../theme-generator/previews/BadgePreview.tsx | 30 +++++++++ .../previews/BreadcrumbsPreview.tsx | 19 ++++++ .../previews/ButtonPreview.tsx | 14 +++++ .../previews/CheckboxPreview.tsx | 13 ++++ 15 files changed, 378 insertions(+), 62 deletions(-) create mode 100644 apps/website/screens/utilities/theme-generator/components/BottomButtons.tsx create mode 100644 apps/website/screens/utilities/theme-generator/components/ComponentPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/components/PreviewArea.tsx create mode 100644 apps/website/screens/utilities/theme-generator/components/SidePanel.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/AccordionPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/AlertPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/AvatarPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/BadgePreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/BreadcrumbsPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/ButtonPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/CheckboxPreview.tsx diff --git a/apps/website/pages/utilities/theme-generator.tsx b/apps/website/pages/utilities/theme-generator.tsx index 707aaf2330..eb7a013206 100644 --- a/apps/website/pages/utilities/theme-generator.tsx +++ b/apps/website/pages/utilities/theme-generator.tsx @@ -1,18 +1,9 @@ import Head from "next/head"; -import { useState } from "react"; import styled from "@emotion/styled"; -import { DxcApplicationLayout, DxcButton, DxcContainer, DxcToastsQueue } from "@dxc-technology/halstack-react"; +import { DxcApplicationLayout, DxcButton, DxcToastsQueue } from "@dxc-technology/halstack-react"; import { dxcLogo } from "@/common/images/dxc_logo"; -import { ThemeSettings } from "screens/utilities/theme-generator/components/ThemeSettings"; import ThemeGeneratorPage from "screens/utilities/theme-generator/ThemeGeneratorPage"; -export type Color = { - name: string; - value: string; -}; - -export type Colors = Color[]; - const MainContent = styled.div` width: 100%; height: 100%; @@ -25,36 +16,7 @@ const MainContent = styled.div` padding-top: var(--spacing-padding-s); `; -const PageWrapper = styled.div` - width: 100%; - height: 100%; - display: flex; - align-items: flex-start; - gap: var(--spacing-gap-ml); -`; - -const PreviewWrapper = styled.div` - width: 100%; - height: 100%; - display: flex; - flex-direction: column; - align-items: flex-start; - gap: var(--spacing-gap-ml); - padding: var(--spacing-padding-l); -`; - const Index = () => { - const [currentStep, setCurrentStep] = useState<0 | 1 | 2>(0); - const [colors, setColors] = useState([ - { name: "primary", value: "#5f249f" }, - { name: "secondary", value: "#0067b3" }, - { name: "tertiary", value: "#c2c2c2" }, - { name: "info", value: "#0067b3" }, - { name: "success", value: "#24a148" }, - { name: "error", value: "#d0011b" }, - { name: "neutral", value: "#000000" }, - ]); - return ( <> @@ -64,20 +26,13 @@ const Index = () => { - - - Sidenav - - - - - - + + diff --git a/apps/website/screens/utilities/theme-generator/ThemeGeneratorPage.tsx b/apps/website/screens/utilities/theme-generator/ThemeGeneratorPage.tsx index be288298a9..d503b20944 100644 --- a/apps/website/screens/utilities/theme-generator/ThemeGeneratorPage.tsx +++ b/apps/website/screens/utilities/theme-generator/ThemeGeneratorPage.tsx @@ -1,5 +1,59 @@ -import { Colors } from "pages/utilities/theme-generator"; +import { ReactNode, useState } from "react"; +import styled from "@emotion/styled"; +import { ThemeSettings } from "screens/utilities/theme-generator/components/ThemeSettings"; +import { BottomButtons } from "screens/utilities/theme-generator/components/BottomButtons"; +import DxcContainer from "../../../../../packages/lib/src/container/Container"; +import { PreviewArea } from "./components/PreviewArea"; +import { DxcFlex } from "@dxc-technology/halstack-react"; -const ThemeGeneratorPage = ({ colors }: { colors: Colors }) => <>Theme generator page; +export type Color = { + name: string; + value: string; +}; + +export type Colors = Color[]; + +const PreviewWrapper = styled.div` + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: var(--spacing-gap-ml); + padding: var(--spacing-padding-l); +`; + +const ThemeGeneratorPage = () => { + const [currentStep, setCurrentStep] = useState<0 | 1 | 2>(0); + const [activeComponents, setActiveComponents] = useState<{ name: string; preview: ReactNode }[]>([]); + const [colors, setColors] = useState([ + { name: "primary", value: "#5f249f" }, + { name: "secondary", value: "#0067b3" }, + { name: "tertiary", value: "#c2c2c2" }, + { name: "info", value: "#0067b3" }, + { name: "success", value: "#24a148" }, + { name: "error", value: "#d0011b" }, + { name: "neutral", value: "#000000" }, + ]); + + return ( + + Sidenav + + + + + + + + + + ); +}; export default ThemeGeneratorPage; diff --git a/apps/website/screens/utilities/theme-generator/components/BottomButtons.tsx b/apps/website/screens/utilities/theme-generator/components/BottomButtons.tsx new file mode 100644 index 0000000000..2d3e6c56fa --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/components/BottomButtons.tsx @@ -0,0 +1,37 @@ +import { DxcButton } from "@dxc-technology/halstack-react"; +import styled from "@emotion/styled"; + +const ButtonsWrapper = styled.div` + width: 100%; + display: flex; + justify-content: flex-end; + align-items: center; + gap: var(--spacing-gap-s); +`; + +export const BottomButtons = ({ + currentStep, + setCurrentStep, +}: { + currentStep: 0 | 1 | 2; + setCurrentStep: React.Dispatch>; +}) => { + const handlePrevious = () => { + setCurrentStep((prev) => (prev > 0 ? ((prev - 1) as 0 | 1 | 2) : prev)); + }; + + const handleNext = () => { + setCurrentStep((prev) => (prev < 2 ? ((prev + 1) as 0 | 1 | 2) : prev)); + }; + + return ( + + + {currentStep === 2 ? ( + + ) : ( + + )} + + ); +}; diff --git a/apps/website/screens/utilities/theme-generator/components/ColorCard.tsx b/apps/website/screens/utilities/theme-generator/components/ColorCard.tsx index f69e32b9e7..af6c8c5dd1 100644 --- a/apps/website/screens/utilities/theme-generator/components/ColorCard.tsx +++ b/apps/website/screens/utilities/theme-generator/components/ColorCard.tsx @@ -1,4 +1,4 @@ -import { useCallback, useState } from "react"; +import { useCallback, useRef, useState } from "react"; import { DxcHeading, DxcPopover, DxcTextInput } from "@dxc-technology/halstack-react"; import styled from "@emotion/styled"; import { SketchPicker } from "react-color"; @@ -21,12 +21,14 @@ const ContentWrapper = styled.div` gap: var(--spacing-gap-xs); `; -const ColorBox = styled.div<{ color: string }>` +const ColorBox = styled.button<{ color: string }>` width: 124px; height: 32px; border-radius: var(--border-radius-s); background-color: ${(props) => props.color}; cursor: pointer; + + border: none; `; const ColorText = styled.div` @@ -48,6 +50,7 @@ export const ColorCard = ({ const [isOpen, setIsOpen] = useState(false); const [inputValue, setInputValue] = useState(color); const [error, setError] = useState(""); + const buttonRef = useRef(null); const handleChange = useCallback( (newColor: { hex: string }) => { @@ -95,11 +98,26 @@ export const ColorCard = ({ setIsOpen(true)} onClose={() => setIsOpen(false)} - popoverContent={} + popoverContent={ + + } + hasTip + side="bottom" + asChild > - + setIsOpen((prev) => !prev)} ref={buttonRef} color={color} /> void; +}) => { + return ( + + + + {component.preview} + + + + ); +}; diff --git a/apps/website/screens/utilities/theme-generator/components/PreviewArea.tsx b/apps/website/screens/utilities/theme-generator/components/PreviewArea.tsx new file mode 100644 index 0000000000..e1b4cb8c80 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/components/PreviewArea.tsx @@ -0,0 +1,59 @@ +import { DxcButton, DxcFlex, DxcHeading, DxcParagraph } from "@dxc-technology/halstack-react"; +import styled from "@emotion/styled"; +import { ReactNode } from "react"; +import { ComponentPreview } from "./ComponentPreview"; + +const PreviewWrapper = styled.div` + min-height: 160px; + min-width: 320px; + display: flex; + flex-direction: column; + align-items: center; + gap: var(--spacing-gap-s); + align-self: stretch; + padding: var(--spacing-padding-l); + + border: var(--border-width-s) var(--border-style-outline) var(--border-color-neutral-dark); + border-radius: var(--border-radius-m); +`; + +export const PreviewArea = ({ + components, + setActiveComponents, +}: { + components: { name: string; preview: ReactNode }[]; + setActiveComponents: React.Dispatch>; +}) => { + const handleRemoveComponent = (name: string) => { + setActiveComponents((prev) => prev.filter((component) => component.name !== name)); + }; + + const handleRemoveAll = () => { + setActiveComponents([]); + }; + + return ( + + + {components.length === 0 ? ( + Click to add the components from the left panel to preview it here. + ) : ( + <> + + + + + + {components.map((component) => ( + handleRemoveComponent(component.name)} + /> + ))} + + )} + + + ); +}; diff --git a/apps/website/screens/utilities/theme-generator/components/SidePanel.tsx b/apps/website/screens/utilities/theme-generator/components/SidePanel.tsx new file mode 100644 index 0000000000..6fb4db34b2 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/components/SidePanel.tsx @@ -0,0 +1,16 @@ +import styled from "@emotion/styled"; + +const PanelWrapper = styled.div` + display: flex; + flex-direction: column; + align-items: flex-start; + gap: var(--spacing-gap-ml); +`; + +export const SidePanel = () => { + return ( + + <> + + ); +}; diff --git a/apps/website/screens/utilities/theme-generator/components/ThemeSettings.tsx b/apps/website/screens/utilities/theme-generator/components/ThemeSettings.tsx index 3675498adc..6304a4036a 100644 --- a/apps/website/screens/utilities/theme-generator/components/ThemeSettings.tsx +++ b/apps/website/screens/utilities/theme-generator/components/ThemeSettings.tsx @@ -2,8 +2,8 @@ import { useState } from "react"; import { DxcBadge, DxcButton, DxcContainer, DxcFileInput, DxcFlex, DxcWizard } from "@dxc-technology/halstack-react"; import styled from "@emotion/styled"; import { FileData } from "../../../../../../packages/lib/src/file-input/types"; -import { Color, Colors } from "pages/utilities/theme-generator"; import { ColorCard } from "./ColorCard"; +import { Color, Colors } from "../ThemeGeneratorPage"; const ThemeSettingsWrapper = styled.div` width: 100%; @@ -39,7 +39,7 @@ const ButtonsWrapper = styled.div` const RightButtonsWrapper = styled.div` display: flex; align-items: center; - gap: var(--spacing-gap-s); + gap: var(--spacing-gap-m); `; const steps = [{ label: "Core colors" }, { label: "Branding" }, { label: "Export" }]; diff --git a/apps/website/screens/utilities/theme-generator/previews/AccordionPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/AccordionPreview.tsx new file mode 100644 index 0000000000..2312aab184 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/AccordionPreview.tsx @@ -0,0 +1,21 @@ +import React from "react"; +import { DxcAccordion, DxcInset, DxcParagraph } from "@dxc-technology/halstack-react"; + +const AccordionPreview = () => { + return ( + + + + To edit your profile you need to go to Settings and click on Profile. + + + + ); +}; + +export default AccordionPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/AlertPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/AlertPreview.tsx new file mode 100644 index 0000000000..0faedb562c --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/AlertPreview.tsx @@ -0,0 +1,38 @@ +import React from "react"; +import { DxcAlert, DxcFlex } from "@dxc-technology/halstack-react"; +const AlertPreview = () => { + return ( + + {} }} + secondaryAction={{ label: "Secondary action", onClick: () => {} }} + semantic="success" + title="Success" + /> + {} }} + secondaryAction={{ label: "Secondary action", onClick: () => {} }} + semantic="info" + title="Information" + /> + {} }} + secondaryAction={{ label: "Secondary action", onClick: () => {} }} + semantic="warning" + title="Warning" + /> + {} }} + secondaryAction={{ label: "Secondary action", onClick: () => {} }} + semantic="error" + title="Error" + /> + + ); +}; + +export default AlertPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/AvatarPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/AvatarPreview.tsx new file mode 100644 index 0000000000..703ea7d3fb --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/AvatarPreview.tsx @@ -0,0 +1,15 @@ +import React from "react"; +import { DxcAvatar } from "@dxc-technology/halstack-react"; + +const AvatarPreview = () => { + return ( + + ); +}; + +export default AvatarPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/BadgePreview.tsx b/apps/website/screens/utilities/theme-generator/previews/BadgePreview.tsx new file mode 100644 index 0000000000..1d8623bd25 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/BadgePreview.tsx @@ -0,0 +1,30 @@ +import React from "react"; +import { DxcBadge, DxcFlex } from "@dxc-technology/halstack-react"; +const BadgePreview = () => { + return ( + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default BadgePreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/BreadcrumbsPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/BreadcrumbsPreview.tsx new file mode 100644 index 0000000000..2e840fe39f --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/BreadcrumbsPreview.tsx @@ -0,0 +1,19 @@ +import React from "react"; +import { DxcInset, DxcBreadcrumbs } from "@dxc-technology/halstack-react"; +const BreadcrumbPreview = () => { + return ( + + + + ); +}; + +export default BreadcrumbPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/ButtonPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/ButtonPreview.tsx new file mode 100644 index 0000000000..a23d5d812a --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/ButtonPreview.tsx @@ -0,0 +1,14 @@ +import React from "react"; +import { DxcButton, DxcFlex } from "@dxc-technology/halstack-react"; +const ButtonPreview = () => { + return ( + + + + + + + ); +}; + +export default ButtonPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/CheckboxPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/CheckboxPreview.tsx new file mode 100644 index 0000000000..5dacdc9436 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/CheckboxPreview.tsx @@ -0,0 +1,13 @@ +import React from "react"; +import { DxcCheckbox, DxcInset } from "@dxc-technology/halstack-react"; +const CheckboxPreview = () => { + return ( + + + + + + ); +}; + +export default CheckboxPreview; From 6b018b679694baaa70319de04d39ca10fe0f450e Mon Sep 17 00:00:00 2001 From: PelayoFelgueroso Date: Fri, 13 Feb 2026 13:22:48 +0100 Subject: [PATCH 3/4] Start preview components and preview area, still Draft --- .../previews/AccordionPreview.tsx | 1 - .../previews/ApplicationPreview.tsx | 0 .../previews/AvatarPreview.tsx | 1 - .../theme-generator/previews/BadgePreview.tsx | 1 - .../previews/BreadcrumbsPreview.tsx | 1 - .../previews/ButtonPreview.tsx | 1 - .../previews/CheckboxPreview.tsx | 1 - .../theme-generator/previews/ChipPreview.tsx | 18 ++ .../previews/ContextualMenuPreview.tsx | 52 ++++++ .../previews/DashboardPreview.tsx | 0 .../previews/DataGridPreview.tsx | 160 ++++++++++++++++++ .../theme-generator/previews/DatePreview.tsx | 34 ++++ .../previews/DividerPreview.tsx | 13 ++ .../previews/DropdownPreview.tsx | 47 +++++ .../previews/FileInputPreview.tsx | 16 ++ .../theme-generator/previews/FormPreview.tsx | 54 ++++++ .../theme-generator/previews/LinkPreview.tsx | 36 ++++ .../theme-generator/previews/LoginPreview.tsx | 0 .../previews/NumberInputPreview.tsx | 15 ++ .../previews/PaginatorPreview.tsx | 21 +++ .../previews/PasswordInputPreview.tsx | 15 ++ .../previews/ProgressBarPreview.tsx | 21 +++ .../previews/QuickNavPreview.tsx | 20 +++ .../theme-generator/previews/RadioPreview.tsx | 21 +++ .../previews/ResultsetTablePreview.tsx | 19 +++ .../previews/SelectPreview.tsx | 39 +++++ .../previews/SliderPreview.tsx | 35 ++++ .../previews/SpinnerPreview.tsx | 17 ++ .../previews/StatusLightPreview.tsx | 19 +++ .../previews/SwitchPreview.tsx | 17 ++ .../theme-generator/previews/TablePreview.tsx | 105 ++++++++++++ .../theme-generator/previews/TabsPreview.tsx | 53 ++++++ .../previews/TextAreaPreview.tsx | 14 ++ .../previews/TextInputPreview.tsx | 24 +++ .../theme-generator/previews/ToastPreview.tsx | 42 +++++ .../previews/TogglePreview.tsx | 34 ++++ .../previews/WizardPreview.tsx | 59 +++++++ 37 files changed, 1020 insertions(+), 6 deletions(-) create mode 100644 apps/website/screens/utilities/theme-generator/previews/ApplicationPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/ChipPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/ContextualMenuPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/DashboardPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/DataGridPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/DatePreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/DividerPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/DropdownPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/FileInputPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/FormPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/LinkPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/LoginPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/NumberInputPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/PaginatorPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/PasswordInputPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/ProgressBarPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/QuickNavPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/RadioPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/ResultsetTablePreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/SelectPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/SliderPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/SpinnerPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/StatusLightPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/SwitchPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/TablePreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/TabsPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/TextAreaPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/TextInputPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/ToastPreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/TogglePreview.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/WizardPreview.tsx diff --git a/apps/website/screens/utilities/theme-generator/previews/AccordionPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/AccordionPreview.tsx index 2312aab184..327c22f005 100644 --- a/apps/website/screens/utilities/theme-generator/previews/AccordionPreview.tsx +++ b/apps/website/screens/utilities/theme-generator/previews/AccordionPreview.tsx @@ -1,4 +1,3 @@ -import React from "react"; import { DxcAccordion, DxcInset, DxcParagraph } from "@dxc-technology/halstack-react"; const AccordionPreview = () => { diff --git a/apps/website/screens/utilities/theme-generator/previews/ApplicationPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/ApplicationPreview.tsx new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/website/screens/utilities/theme-generator/previews/AvatarPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/AvatarPreview.tsx index 703ea7d3fb..9c70b61fe1 100644 --- a/apps/website/screens/utilities/theme-generator/previews/AvatarPreview.tsx +++ b/apps/website/screens/utilities/theme-generator/previews/AvatarPreview.tsx @@ -1,4 +1,3 @@ -import React from "react"; import { DxcAvatar } from "@dxc-technology/halstack-react"; const AvatarPreview = () => { diff --git a/apps/website/screens/utilities/theme-generator/previews/BadgePreview.tsx b/apps/website/screens/utilities/theme-generator/previews/BadgePreview.tsx index 1d8623bd25..4f9f589492 100644 --- a/apps/website/screens/utilities/theme-generator/previews/BadgePreview.tsx +++ b/apps/website/screens/utilities/theme-generator/previews/BadgePreview.tsx @@ -1,4 +1,3 @@ -import React from "react"; import { DxcBadge, DxcFlex } from "@dxc-technology/halstack-react"; const BadgePreview = () => { return ( diff --git a/apps/website/screens/utilities/theme-generator/previews/BreadcrumbsPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/BreadcrumbsPreview.tsx index 2e840fe39f..8846968997 100644 --- a/apps/website/screens/utilities/theme-generator/previews/BreadcrumbsPreview.tsx +++ b/apps/website/screens/utilities/theme-generator/previews/BreadcrumbsPreview.tsx @@ -1,4 +1,3 @@ -import React from "react"; import { DxcInset, DxcBreadcrumbs } from "@dxc-technology/halstack-react"; const BreadcrumbPreview = () => { return ( diff --git a/apps/website/screens/utilities/theme-generator/previews/ButtonPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/ButtonPreview.tsx index a23d5d812a..8e2b890310 100644 --- a/apps/website/screens/utilities/theme-generator/previews/ButtonPreview.tsx +++ b/apps/website/screens/utilities/theme-generator/previews/ButtonPreview.tsx @@ -1,4 +1,3 @@ -import React from "react"; import { DxcButton, DxcFlex } from "@dxc-technology/halstack-react"; const ButtonPreview = () => { return ( diff --git a/apps/website/screens/utilities/theme-generator/previews/CheckboxPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/CheckboxPreview.tsx index 5dacdc9436..7ff727b07e 100644 --- a/apps/website/screens/utilities/theme-generator/previews/CheckboxPreview.tsx +++ b/apps/website/screens/utilities/theme-generator/previews/CheckboxPreview.tsx @@ -1,4 +1,3 @@ -import React from "react"; import { DxcCheckbox, DxcInset } from "@dxc-technology/halstack-react"; const CheckboxPreview = () => { return ( diff --git a/apps/website/screens/utilities/theme-generator/previews/ChipPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/ChipPreview.tsx new file mode 100644 index 0000000000..c39d9ffaf8 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/ChipPreview.tsx @@ -0,0 +1,18 @@ +import { DxcChip, DxcFlex } from "@dxc-technology/halstack-react"; +const ChipPreview = () => { + return ( + + + + + console.log("action clicked") }} + /> + + + ); +}; + +export default ChipPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/ContextualMenuPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/ContextualMenuPreview.tsx new file mode 100644 index 0000000000..b2f135a268 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/ContextualMenuPreview.tsx @@ -0,0 +1,52 @@ +import { DxcInset, DxcContainer, DxcContextualMenu, DxcBadge } from "@dxc-technology/halstack-react"; + +const contextualMenuItems = [ + { + title: "Section 1", + items: [ + { + label: "Grouped Item 1", + icon: "favorite", + items: [ + { label: "Item 1" }, + { + label: "Grouped Item 2", + items: [ + { + label: "Item 2", + icon: "bookmark", + badge: , + }, + { label: "Selected Item 3", selectedByDefault: true }, + ], + }, + ], + badge: , + }, + { label: "Item 4", icon: "key" }, + ], + }, + { + title: "Section 2", + items: [ + { label: "Item 5" }, + { + label: "Grouped Item 6", + items: [{ label: "Item 7" }, { label: "Item 8" }], + }, + { label: "Item 9" }, + ], + }, +]; + +const ContextualPreview = () => { + return ( + + + + + + ); +}; + +export default ContextualPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/DashboardPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/DashboardPreview.tsx new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/website/screens/utilities/theme-generator/previews/DataGridPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/DataGridPreview.tsx new file mode 100644 index 0000000000..70b000fbe5 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/DataGridPreview.tsx @@ -0,0 +1,160 @@ +import { useState } from "react"; +import { DxcDataGrid, DxcInset, DxcContainer } from "@dxc-technology/halstack-react"; + +const actions = [ + { + icon: "filled_edit", + title: "icon", + onClick: () => {}, + }, + { + icon: "filled_delete", + title: "icon", + onClick: () => {}, + disabled: true, + }, +]; + +const columns = [ + { + key: "id", + label: "ID", + resizable: true, + sortable: true, + draggable: false, + alignment: "left" as const, + }, + { + key: "task", + label: "Title", + resizable: true, + sortable: true, + draggable: true, + textEditable: true, + alignment: "left" as const, + }, + { + key: "complete", + label: " % Complete", + resizable: true, + sortable: true, + draggable: true, + alignment: "right" as const, + summaryKey: "label", + }, + { + key: "priority", + label: "Priority", + resizable: true, + draggable: true, + alignment: "center" as const, + summaryKey: "total", + }, + { + key: "actions", + label: "Actions", + alignment: "center" as const, + }, +]; +const expandableRows = [ + { + id: 1, + task: "Task 1", + complete: 46, + priority: "High", + issueType: "Bug", + expandedContent: Custom content 1, + actions: , + }, + { + id: 2, + task: "Task 2", + complete: 51, + priority: "High", + issueType: "Epic", + expandedContent: Custom content 2, + actions: , + }, + { + id: 3, + task: "Task 3", + complete: 40, + priority: "High", + issueType: "Improvement", + expandedContent: Custom content 3, + actions: , + }, + { + id: 4, + task: "Task 4", + complete: 10, + priority: "High", + issueType: "Improvement", + expandedContent: Custom content 4, + actions: , + }, + { + id: 5, + task: "Task 5", + complete: 68, + priority: "High", + issueType: "Improvement", + expandedContent: Custom content 5, + actions: , + }, + { + id: 6, + task: "Task 6", + complete: 37, + priority: "High", + issueType: "Improvement", + expandedContent: Custom content 6, + actions: , + }, + { + id: 7, + task: "Task 7", + complete: 73, + priority: "Medium", + issueType: "Story", + expandedContent: Custom content 7, + actions: , + }, + { + id: 8, + task: "Task 8", + complete: 27, + priority: "Medium", + issueType: "Story", + expandedContent: Custom content 8, + actions: , + }, + { + id: 9, + task: "Task 9", + complete: 36, + priority: "Critical", + issueType: "Epic", + expandedContent: Custom content 9, + actions: , + }, +]; + +const DatagridPreview = () => { + const [selectedRows, setSelectedRows] = useState(() => new Set()); + + return ( + + + + ); +}; + +export default DatagridPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/DatePreview.tsx b/apps/website/screens/utilities/theme-generator/previews/DatePreview.tsx new file mode 100644 index 0000000000..f84c233774 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/DatePreview.tsx @@ -0,0 +1,34 @@ +import { DxcDateInput, DxcFlex } from "@dxc-technology/halstack-react"; + +const DatePreview = () => { + return ( + + + + + + ); +}; + +export default DatePreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/DividerPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/DividerPreview.tsx new file mode 100644 index 0000000000..c3faa99558 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/DividerPreview.tsx @@ -0,0 +1,13 @@ +import { DxcDivider, DxcFlex, DxcTypography } from "@dxc-technology/halstack-react"; + +const DividerPreview = () => { + return ( + + Content above + + Content below + + ); +}; + +export default DividerPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/DropdownPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/DropdownPreview.tsx new file mode 100644 index 0000000000..2acf708d13 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/DropdownPreview.tsx @@ -0,0 +1,47 @@ +import { DxcDropdown, DxcFlex, DxcInset } from "@dxc-technology/halstack-react"; + +const DropdownPreview = () => { + const options = [ + { + value: "1", + label: "Amazon", + }, + { + value: "2", + label: "Ebay", + }, + { + value: "3", + label: "Apple", + }, + ]; + + const iconOptions = [ + { + value: "1", + label: "Android", + icon: "filled_phone_android", + }, + { + value: "2", + label: "Windows", + icon: "desktop_windows", + }, + { + value: "3", + label: "IOS", + icon: "filled_phone_iphone", + }, + ]; + + return ( + + + {}} label="Default Dropdown" /> + {}} icon="download" label="Dropdown with icons" /> + + + ); +}; + +export default DropdownPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/FileInputPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/FileInputPreview.tsx new file mode 100644 index 0000000000..5e87aaad86 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/FileInputPreview.tsx @@ -0,0 +1,16 @@ +import { useState } from "react"; +import { DxcFileInput } from "@dxc-technology/halstack-react"; + +type FileData = { + file: File; + preview?: string; + error?: string; +}; + +const FileInputPreview = () => { + const [files, setFiles] = useState([]); + + return ; +}; + +export default FileInputPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/FormPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/FormPreview.tsx new file mode 100644 index 0000000000..fab0a03ae2 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/FormPreview.tsx @@ -0,0 +1,54 @@ +import React from "react"; +import { + DxcButton, + DxcContainer, + DxcFlex, + DxcTextInput, + DxcHeading, + DxcTypography, +} from "@dxc-technology/halstack-react"; +const FormPreview = () => { + return ( + + +
+ + + + Contact Information + + + + + + + +
+ + {}} /> + {}} /> + +
+
+
+
+
+
+ ); +}; + +export default FormPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/LinkPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/LinkPreview.tsx new file mode 100644 index 0000000000..d9180f7226 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/LinkPreview.tsx @@ -0,0 +1,36 @@ +import { DxcLink, DxcInset, DxcFlex, DxcHeading, DxcParagraph } from "@dxc-technology/halstack-react"; + +const LinkPreview = () => { + return ( + + + + + + This is a text with a{" "} + + Link + {" "} + to another page. + + + This is a text with a{" "} + + Link + {" "} + to another page. + + + This is a text with an{" "} + + Icon after + {" "} + the link. + + + + + ); +}; + +export default LinkPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/LoginPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/LoginPreview.tsx new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/website/screens/utilities/theme-generator/previews/NumberInputPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/NumberInputPreview.tsx new file mode 100644 index 0000000000..26a4689ed1 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/NumberInputPreview.tsx @@ -0,0 +1,15 @@ +import { DxcNumberInput, DxcFlex, DxcHeading } from "@dxc-technology/halstack-react"; + +const NumberInputPreview = () => { + return ( + + + + + + + + ); +}; + +export default NumberInputPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/PaginatorPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/PaginatorPreview.tsx new file mode 100644 index 0000000000..62de8571ac --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/PaginatorPreview.tsx @@ -0,0 +1,21 @@ +import { DxcPaginator, DxcInset, DxcFlex, DxcHeading } from "@dxc-technology/halstack-react"; + +const PaginatorPreview = () => { + return ( + + + + {}} + itemsPerPageOptions={[5, 10, 15]} + showGoToPage + /> + + + ); +}; + +export default PaginatorPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/PasswordInputPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/PasswordInputPreview.tsx new file mode 100644 index 0000000000..c9209c9761 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/PasswordInputPreview.tsx @@ -0,0 +1,15 @@ +import { DxcPasswordInput, DxcFlex, DxcHeading } from "@dxc-technology/halstack-react"; + +const PasswordInputPreview = () => { + return ( + + + + + + + + ); +}; + +export default PasswordInputPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/ProgressBarPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/ProgressBarPreview.tsx new file mode 100644 index 0000000000..e166a73845 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/ProgressBarPreview.tsx @@ -0,0 +1,21 @@ +import { DxcProgressBar, DxcFlex, DxcInset, DxcContainer, DxcHeading } from "@dxc-technology/halstack-react"; + +const ProgressBarPreview = () => { + return ( + + + + + + + + + + + + + + ); +}; + +export default ProgressBarPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/QuickNavPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/QuickNavPreview.tsx new file mode 100644 index 0000000000..f95a0eb26d --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/QuickNavPreview.tsx @@ -0,0 +1,20 @@ +import { DxcQuickNav, DxcInset, DxcFlex, DxcHeading } from "@dxc-technology/halstack-react"; + +const QuickNavPreview = () => { + const links = [ + { label: "Overview", href: "#overview" }, + { label: "Features", href: "#features" }, + { label: "Pricing", href: "#pricing" }, + ]; + + return ( + + + + + + + ); +}; + +export default QuickNavPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/RadioPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/RadioPreview.tsx new file mode 100644 index 0000000000..5fb982a398 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/RadioPreview.tsx @@ -0,0 +1,21 @@ +import { DxcRadioGroup, DxcFlex, DxcHeading } from "@dxc-technology/halstack-react"; + +const RadioPreview = () => { + const options = [ + { label: "Option 1", value: "1" }, + { label: "Option 2", value: "2" }, + { label: "Option 3", value: "3" }, + ]; + + return ( + + + + + + + + ); +}; + +export default RadioPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/ResultsetTablePreview.tsx b/apps/website/screens/utilities/theme-generator/previews/ResultsetTablePreview.tsx new file mode 100644 index 0000000000..87e74ac874 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/ResultsetTablePreview.tsx @@ -0,0 +1,19 @@ +import { DxcResultsetTable, DxcFlex, DxcHeading } from "@dxc-technology/halstack-react"; + +const ResultsetTablePreview = () => { + const columns = [{ displayValue: "Name" }, { displayValue: "Email" }, { displayValue: "Role" }]; + + const rows = [ + [{ displayValue: "John Doe" }, { displayValue: "john@example.com" }, { displayValue: "Developer" }], + [{ displayValue: "Jane Smith" }, { displayValue: "jane@example.com" }, { displayValue: "Designer" }], + ]; + + return ( + + + + + ); +}; + +export default ResultsetTablePreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/SelectPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/SelectPreview.tsx new file mode 100644 index 0000000000..766803e4e0 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/SelectPreview.tsx @@ -0,0 +1,39 @@ +import { DxcSelect, DxcFlex, DxcHeading } from "@dxc-technology/halstack-react"; + +const SelectPreview = () => { + const options = [ + { + value: "1", + label: "3G Mobile", + icon: "3g_mobiledata", + }, + { + value: "2", + label: "Ebay", + icon: "settings_backup_restore", + }, + ]; + const optionsNoIcons = [ + { + value: "1", + label: "Amazon", + }, + { + value: "2", + label: "Ebay", + }, + ]; + + return ( + + + + + + + + + ); +}; + +export default SelectPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/SliderPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/SliderPreview.tsx new file mode 100644 index 0000000000..398ca70635 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/SliderPreview.tsx @@ -0,0 +1,35 @@ +import { useState } from "react"; +import { DxcSlider, DxcFlex, DxcInset, DxcContainer, DxcHeading } from "@dxc-technology/halstack-react"; + +const SliderPreview = () => { + const [value, changeValue] = useState(0); + const onChange = (newValue: number) => { + changeValue(newValue); + }; + + return ( + + + + + + + + + + + + ); +}; + +export default SliderPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/SpinnerPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/SpinnerPreview.tsx new file mode 100644 index 0000000000..aa15e51ce0 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/SpinnerPreview.tsx @@ -0,0 +1,17 @@ +import { DxcSpinner, DxcInset, DxcFlex, DxcHeading } from "@dxc-technology/halstack-react"; + +const SpinnerPreview = () => { + return ( + + + + + + + + + + ); +}; + +export default SpinnerPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/StatusLightPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/StatusLightPreview.tsx new file mode 100644 index 0000000000..5a0e7fa7dd --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/StatusLightPreview.tsx @@ -0,0 +1,19 @@ +import { DxcStatusLight, DxcFlex, DxcInset, DxcHeading } from "@dxc-technology/halstack-react"; + +const StatusLightPreview = () => { + return ( + + + + + + + + + + + + ); +}; + +export default StatusLightPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/SwitchPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/SwitchPreview.tsx new file mode 100644 index 0000000000..8dfd16acc1 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/SwitchPreview.tsx @@ -0,0 +1,17 @@ +import { DxcSwitch, DxcFlex, DxcInset, DxcHeading } from "@dxc-technology/halstack-react"; + +const SwitchPreview = () => { + return ( + + + + + + + + + + ); +}; + +export default SwitchPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/TablePreview.tsx b/apps/website/screens/utilities/theme-generator/previews/TablePreview.tsx new file mode 100644 index 0000000000..6cbee0cc0d --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/TablePreview.tsx @@ -0,0 +1,105 @@ +import { DxcTable, DxcFlex, DxcHeading, DxcResultsetTable, DxcContainer } from "@dxc-technology/halstack-react"; + +const TablePreview = () => { + const columns = [ + { displayValue: "Id", isSortable: false }, + { displayValue: "Name", isSortable: true }, + { displayValue: "City", isSortable: true }, + { displayValue: "Actions", isSortable: false }, + ]; + + const actions = [ + { + icon: "delete", + title: "Delete", + onClick: () => {}, + }, + { + title: "edit", + onClick: (_value: unknown) => {}, + options: [ + { + value: "1", + label: "Edit", + }, + { + value: "2", + label: "Mark as selected", + }, + ], + }, + ]; + + const rows = [ + [ + { displayValue: "001" }, + { displayValue: "Peter" }, + { displayValue: "Miami" }, + { displayValue: }, + ], + [ + { displayValue: "002" }, + { displayValue: "Louis" }, + { displayValue: "London" }, + { displayValue: }, + ], + [ + { displayValue: "003" }, + { displayValue: "Lana" }, + { displayValue: "Amsterdam" }, + { displayValue: }, + ], + [ + { displayValue: "004" }, + { displayValue: "Rick" }, + { displayValue: "London" }, + { displayValue: }, + ], + [ + { displayValue: "005" }, + { displayValue: "Mark" }, + { displayValue: "Miami" }, + { displayValue: }, + ], + [ + { displayValue: "006" }, + { displayValue: "Cris" }, + { displayValue: "Paris" }, + { displayValue: }, + ], + ]; + + return ( + + + + + + + Name + Email + Role + + + + + John Doe + john@example.com + Developer + + + Jane Smith + jane@example.com + Designer + + + + + + + + + ); +}; + +export default TablePreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/TabsPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/TabsPreview.tsx new file mode 100644 index 0000000000..b88acfaa66 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/TabsPreview.tsx @@ -0,0 +1,53 @@ +import { DxcNavTabs, DxcFlex, DxcHeading, DxcTabs } from "@dxc-technology/halstack-react"; + +const TabsPreview = () => { + const handleTabClick = (index: number) => () => { + console.log(`Tab ${index} clicked`); + }; + const mobileIcon = ( + + + + + + + + + + + ); + return ( + + + + + <> + + + <> + + + <> + + + + + + + Tab 1 + + + Tab 2 + + + Tab 3 + + + Tab 4 + + + + ); +}; + +export default TabsPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/TextAreaPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/TextAreaPreview.tsx new file mode 100644 index 0000000000..fa810c2228 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/TextAreaPreview.tsx @@ -0,0 +1,14 @@ +import { DxcTextarea, DxcFlex, DxcHeading } from "@dxc-technology/halstack-react"; +const TextareaPreview = () => { + return ( + + + + + + + + ); +}; + +export default TextareaPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/TextInputPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/TextInputPreview.tsx new file mode 100644 index 0000000000..0a93f94698 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/TextInputPreview.tsx @@ -0,0 +1,24 @@ +import { DxcTextInput, DxcFlex, DxcHeading } from "@dxc-technology/halstack-react"; +const TextInputPreview = () => { + return ( + + + + + + + + ); +}; + +export default TextInputPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/ToastPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/ToastPreview.tsx new file mode 100644 index 0000000000..3f21778196 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/ToastPreview.tsx @@ -0,0 +1,42 @@ +import { DxcButton, DxcInset, DxcFlex, useToast, DxcToastsQueue, DxcHeading } from "@dxc-technology/halstack-react"; + +const ToastButtons = () => { + const toast = useToast(); + + const showSuccessToast = () => { + toast.success({ message: "Success! Operation completed." }); + }; + + const showWarningToast = () => { + toast.warning({ message: "Warning! Please review this." }); + }; + + const showInfoToast = () => { + toast.info({ message: "Info: Here's some information." }); + }; + + return ( + + + + + + + + + + + ); +}; + +// Wrapper component with its own ToastsQueue +// This ensures toasts render within the themed HalstackProvider in PreviewArea +const ToastPreview = () => { + return ( + + + + ); +}; + +export default ToastPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/TogglePreview.tsx b/apps/website/screens/utilities/theme-generator/previews/TogglePreview.tsx new file mode 100644 index 0000000000..93c7bcbec5 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/TogglePreview.tsx @@ -0,0 +1,34 @@ +import { DxcToggleGroup, DxcFlex, DxcInset, DxcHeading } from "@dxc-technology/halstack-react"; + +const TogglePreview = () => { + const options = [ + { label: "Option 1", value: 1 }, + { label: "Option 2", value: 2 }, + { label: "Option 3", value: 3 }, + ]; + const optionsWithIcons = [ + { + value: 1, + label: "Facebook", + icon: "filled_thumb_up", + }, + { + value: 2, + label: "Linkedin", + icon: "filled_work", + }, + ]; + return ( + + + + + + + + + + ); +}; + +export default TogglePreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/WizardPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/WizardPreview.tsx new file mode 100644 index 0000000000..98ceca4936 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/WizardPreview.tsx @@ -0,0 +1,59 @@ +import { DxcWizard, DxcFlex, DxcHeading } from "@dxc-technology/halstack-react"; + +const WizardPreview = () => { + const steps = [ + { + label: "First step", + description: "Not validated step", + valid: false, + }, + { + label: "Second step", + description: "Validated step", + valid: true, + }, + { + label: "Third step", + description: "Another step description", + }, + { + label: "Forth step", + description: "Disable step", + disabled: true, + }, + ]; + const stepsWithIcons = [ + { + label: "First step", + description: "Not validated step", + valid: false, + icon: "person", + }, + { + label: "Second step", + description: "Validated step", + valid: true, + icon: "home", + }, + { + label: "Third step", + description: "Another step description", + icon: "work", + }, + { + label: "Forth step", + description: "Disable step", + disabled: true, + icon: "thumb_up", + }, + ]; + return ( + + + + + + ); +}; + +export default WizardPreview; From 534783356a072da1969c43d657adb23e0db21e66 Mon Sep 17 00:00:00 2001 From: PelayoFelgueroso Date: Mon, 16 Feb 2026 12:57:49 +0100 Subject: [PATCH 4/4] Create ThemeGenerator Context and add application and dashboard previews --- .../theme-generator/ThemeGeneratorPage.tsx | 42 +- .../components/PreviewSidenav.tsx | 72 ++++ .../components/ScaledPreviewContainer.tsx | 45 +++ .../components/ThemeSettings.tsx | 35 +- .../context/ThemeGeneratorContext.tsx | 117 ++++++ .../previews/ApplicationPreview.tsx | 358 ++++++++++++++++++ .../BasicApplicationLayoutPreview.tsx | 126 ++++++ .../previews/DashboardPreview.tsx | 327 ++++++++++++++++ .../theme-generator/previews/LoginPreview.tsx | 96 +++++ 9 files changed, 1165 insertions(+), 53 deletions(-) create mode 100644 apps/website/screens/utilities/theme-generator/components/PreviewSidenav.tsx create mode 100644 apps/website/screens/utilities/theme-generator/components/ScaledPreviewContainer.tsx create mode 100644 apps/website/screens/utilities/theme-generator/context/ThemeGeneratorContext.tsx create mode 100644 apps/website/screens/utilities/theme-generator/previews/BasicApplicationLayoutPreview.tsx diff --git a/apps/website/screens/utilities/theme-generator/ThemeGeneratorPage.tsx b/apps/website/screens/utilities/theme-generator/ThemeGeneratorPage.tsx index d503b20944..b769838c6d 100644 --- a/apps/website/screens/utilities/theme-generator/ThemeGeneratorPage.tsx +++ b/apps/website/screens/utilities/theme-generator/ThemeGeneratorPage.tsx @@ -1,17 +1,10 @@ -import { ReactNode, useState } from "react"; import styled from "@emotion/styled"; import { ThemeSettings } from "screens/utilities/theme-generator/components/ThemeSettings"; import { BottomButtons } from "screens/utilities/theme-generator/components/BottomButtons"; -import DxcContainer from "../../../../../packages/lib/src/container/Container"; import { PreviewArea } from "./components/PreviewArea"; +import { PreviewSidenav } from "./components/PreviewSidenav"; import { DxcFlex } from "@dxc-technology/halstack-react"; - -export type Color = { - name: string; - value: string; -}; - -export type Colors = Color[]; +import { ThemeGeneratorProvider, useThemeGenerator } from "./context/ThemeGeneratorContext"; const PreviewWrapper = styled.div` width: 100%; @@ -23,30 +16,15 @@ const PreviewWrapper = styled.div` padding: var(--spacing-padding-l); `; -const ThemeGeneratorPage = () => { - const [currentStep, setCurrentStep] = useState<0 | 1 | 2>(0); - const [activeComponents, setActiveComponents] = useState<{ name: string; preview: ReactNode }[]>([]); - const [colors, setColors] = useState([ - { name: "primary", value: "#5f249f" }, - { name: "secondary", value: "#0067b3" }, - { name: "tertiary", value: "#c2c2c2" }, - { name: "info", value: "#0067b3" }, - { name: "success", value: "#24a148" }, - { name: "error", value: "#d0011b" }, - { name: "neutral", value: "#000000" }, - ]); +const ThemeGeneratorContent = () => { + const { currentStep, setCurrentStep, activeComponents, setActiveComponents } = useThemeGenerator(); return ( - Sidenav + - + @@ -56,4 +34,12 @@ const ThemeGeneratorPage = () => { ); }; +const ThemeGeneratorPage = () => { + return ( + + + + ); +}; + export default ThemeGeneratorPage; diff --git a/apps/website/screens/utilities/theme-generator/components/PreviewSidenav.tsx b/apps/website/screens/utilities/theme-generator/components/PreviewSidenav.tsx new file mode 100644 index 0000000000..3acf73be55 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/components/PreviewSidenav.tsx @@ -0,0 +1,72 @@ +import { DxcButton, DxcFlex, DxcHeading } from "@dxc-technology/halstack-react"; +import styled from "@emotion/styled"; +import ApplicationPreview from "../previews/ApplicationPreview"; +import { useThemeGenerator } from "../context/ThemeGeneratorContext"; + +const SidenavWrapper = styled.div` + width: 300px; + min-height: 600px; + padding: var(--spacing-padding-l); + background-color: var(--color-grey-100); + border-radius: var(--border-radius-m); + display: flex; + flex-direction: column; + gap: var(--spacing-gap-m); +`; + +const PreviewItemWrapper = styled.div` + display: flex; + flex-direction: column; + gap: var(--spacing-gap-xs); + padding: var(--spacing-padding-m); + border: var(--border-width-s) solid var(--color-grey-300); + border-radius: var(--border-radius-s); + background-color: var(--color-white); +`; + +export const PreviewSidenav = () => { + const { activeComponents, setActiveComponents } = useThemeGenerator(); + + const handleAddApplicationPreview = () => { + const isAlreadyActive = activeComponents.some((component) => component.name === "Application Layout"); + + if (!isAlreadyActive) { + const newComponent = { + name: "Application Layout", + preview: , + }; + + setActiveComponents((prev) => [...prev, newComponent]); + } + }; + + const isApplicationPreviewActive = () => { + return activeComponents.some((component) => component.name === "Application Layout"); + }; + + return ( + + + + + + + +

+ Complete application with header, footer, navigation, and data tables +

+
+ + +
+
+
+ ); +}; diff --git a/apps/website/screens/utilities/theme-generator/components/ScaledPreviewContainer.tsx b/apps/website/screens/utilities/theme-generator/components/ScaledPreviewContainer.tsx new file mode 100644 index 0000000000..6a18f05a94 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/components/ScaledPreviewContainer.tsx @@ -0,0 +1,45 @@ +import { ReactNode } from "react"; +import { DxcFlex } from "@dxc-technology/halstack-react"; + +const ScaledPreviewContainer = ({ + scale = 0.7, + width = 1920, + height = 1300, + background = "#fff", + children, +}: { + scale?: number; + width?: number; + height?: number; + background?: string; + children: ReactNode; +}) => { + return ( + +
+
+ {children} +
+
+
+ ); +}; + +export default ScaledPreviewContainer; diff --git a/apps/website/screens/utilities/theme-generator/components/ThemeSettings.tsx b/apps/website/screens/utilities/theme-generator/components/ThemeSettings.tsx index 6304a4036a..4d507e3b9f 100644 --- a/apps/website/screens/utilities/theme-generator/components/ThemeSettings.tsx +++ b/apps/website/screens/utilities/theme-generator/components/ThemeSettings.tsx @@ -1,9 +1,7 @@ -import { useState } from "react"; import { DxcBadge, DxcButton, DxcContainer, DxcFileInput, DxcFlex, DxcWizard } from "@dxc-technology/halstack-react"; import styled from "@emotion/styled"; -import { FileData } from "../../../../../../packages/lib/src/file-input/types"; import { ColorCard } from "./ColorCard"; -import { Color, Colors } from "../ThemeGeneratorPage"; +import { useThemeGenerator, Color } from "../context/ThemeGeneratorContext"; const ThemeSettingsWrapper = styled.div` width: 100%; @@ -44,20 +42,8 @@ const RightButtonsWrapper = styled.div` const steps = [{ label: "Core colors" }, { label: "Branding" }, { label: "Export" }]; -export const ThemeSettings = ({ - currentStep, - setCurrentStep, - colors, - setColors, -}: { - currentStep: 0 | 1 | 2; - setCurrentStep: React.Dispatch>; - colors: Colors; - setColors: React.Dispatch>; -}) => { - const [mainLogo, setMainLogo] = useState([]); - const [footerLogo, setFooterLogo] = useState([]); - const [favicon, setFavicon] = useState([]); +export const ThemeSettings = () => { + const { currentStep, setCurrentStep, colors, updateColor, getLogoValue, updateLogoValue } = useThemeGenerator(); return ( @@ -74,8 +60,7 @@ export const ThemeSettings = ({ label={color.name} color={color.value} onChange={(newColor) => { - const updatedColors = colors.map((c) => (c.name === color.name ? { ...c, value: newColor } : c)); - setColors(updatedColors); + updateColor(color.name, newColor); }} /> ))} @@ -90,8 +75,8 @@ export const ThemeSettings = ({ accept="image/*" showPreview multiple={false} - callbackFile={setMainLogo} - value={mainLogo} + callbackFile={(files) => updateLogoValue("mainLogo", files)} + value={getLogoValue("mainLogo")} maxSize={4718592} /> @@ -105,8 +90,8 @@ export const ThemeSettings = ({ accept="image/*" showPreview multiple={false} - callbackFile={setFooterLogo} - value={footerLogo} + callbackFile={(files) => updateLogoValue("footerLogo", files)} + value={getLogoValue("footerLogo")} maxSize={4718592} /> @@ -120,8 +105,8 @@ export const ThemeSettings = ({ accept="image/*" showPreview multiple={false} - callbackFile={setFavicon} - value={favicon} + callbackFile={(files) => updateLogoValue("favicon", files)} + value={getLogoValue("favicon")} maxSize={4718592} /> diff --git a/apps/website/screens/utilities/theme-generator/context/ThemeGeneratorContext.tsx b/apps/website/screens/utilities/theme-generator/context/ThemeGeneratorContext.tsx new file mode 100644 index 0000000000..b970a39226 --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/context/ThemeGeneratorContext.tsx @@ -0,0 +1,117 @@ +import { createContext, useContext, useState, ReactNode } from "react"; +import { FileData } from "../../../../../../packages/lib/src/file-input/types"; + +export type Color = { + name: string; + value: string; +}; + +export type Colors = Color[]; + +export type Logo = { + name: string; + value: FileData[]; +}; + +type ThemeGeneratorContextType = { + // Theme settings state + currentStep: 0 | 1 | 2; + setCurrentStep: React.Dispatch>; + + // Colors state + colors: Colors; + setColors: React.Dispatch>; + updateColor: (colorName: string, newValue: string) => void; + + // Logos state + logos: Logo[]; + setLogos: React.Dispatch>; + getLogoValue: (logoName: string) => FileData[]; + updateLogoValue: (logoName: string, newValue: FileData[]) => void; + getLogoUrl: (logoName: string) => string; + + // Active components for preview + activeComponents: { name: string; preview: ReactNode }[]; + setActiveComponents: React.Dispatch>; +}; + +const ThemeGeneratorContext = createContext(undefined); + +export const ThemeGeneratorProvider = ({ children }: { children: ReactNode }) => { + const [currentStep, setCurrentStep] = useState<0 | 1 | 2>(0); + const [activeComponents, setActiveComponents] = useState<{ name: string; preview: ReactNode }[]>([]); + + const [colors, setColors] = useState([ + { name: "primary", value: "#5f249f" }, + { name: "secondary", value: "#0067b3" }, + { name: "tertiary", value: "#c2c2c2" }, + { name: "info", value: "#0067b3" }, + { name: "success", value: "#24a148" }, + { name: "error", value: "#d0011b" }, + { name: "neutral", value: "#000000" }, + ]); + + const [logos, setLogos] = useState([]); + + // Helper functions for colors + const updateColor = (colorName: string, newValue: string) => { + setColors((prev) => prev.map((color) => (color.name === colorName ? { ...color, value: newValue } : color))); + }; + + // Helper functions for logos + const getLogoValue = (logoName: string): FileData[] => { + const logo = logos.find((l) => l.name === logoName); + return logo ? logo.value : []; + }; + + const updateLogoValue = (logoName: string, newValue: FileData[]) => { + const existingLogoIndex = logos.findIndex((l) => l.name === logoName); + + if (existingLogoIndex >= 0) { + // Update existing logo + setLogos((prev) => + prev.map((logo, index) => (index === existingLogoIndex ? { ...logo, value: newValue } : logo)) + ); + } else { + // Add new logo + setLogos((prev) => [...prev, { name: logoName, value: newValue }]); + } + }; + + const getLogoUrl = (logoName: string): string => { + const logo = logos.find((l) => l.name === logoName); + if (logo && logo.value.length > 0) { + const fileData = logo.value[0]; + if (fileData) { + // Use preview URL if available, otherwise create one from the File object + return fileData.preview || URL.createObjectURL(fileData.file); + } + } + return ""; + }; + + const value: ThemeGeneratorContextType = { + currentStep, + setCurrentStep, + colors, + setColors, + updateColor, + logos, + setLogos, + getLogoValue, + updateLogoValue, + getLogoUrl, + activeComponents, + setActiveComponents, + }; + + return {children}; +}; + +export const useThemeGenerator = () => { + const context = useContext(ThemeGeneratorContext); + if (!context) { + throw new Error("useThemeGenerator must be used within a ThemeGeneratorProvider"); + } + return context; +}; diff --git a/apps/website/screens/utilities/theme-generator/previews/ApplicationPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/ApplicationPreview.tsx index e69de29bb2..7911f8cdb8 100644 --- a/apps/website/screens/utilities/theme-generator/previews/ApplicationPreview.tsx +++ b/apps/website/screens/utilities/theme-generator/previews/ApplicationPreview.tsx @@ -0,0 +1,358 @@ +import { useState } from "react"; +import { + DxcApplicationLayout, + DxcFlex, + DxcBadge, + DxcButton, + DxcAvatar, + DxcResultsetTable, + DxcDataGrid, + DxcHeading, + DxcParagraph, + DxcDivider, +} from "@dxc-technology/halstack-react"; +import ScaledPreviewContainer from "../components/ScaledPreviewContainer"; +import { useThemeGenerator } from "../context/ThemeGeneratorContext"; + +const columnsDatagrid = [ + { + key: "policyId", + label: "Policy ID", + sortable: true, + }, + { + key: "memberName", + label: "Member Name", + sortable: true, + }, + { + key: "policyType", + label: "Policy Type", + sortable: true, + }, + { + key: "startDate", + label: "Start Date", + sortable: true, + }, + { + key: "endDate", + label: "End Date", + sortable: true, + }, + { + key: "premium", + label: "Premium", + sortable: true, + }, + { + key: "status", + label: "Status", + sortable: true, + }, +]; + +const rowsDatagrid = [ + { + policyId: "POL-1001", + memberName: "John Doe", + policyType: "Health Insurance", + startDate: "Jan 1, 2022", + endDate: "Jan 1, 2025", + premium: "$450/month", + status: "Active", + childRows: [ + { + policyId: "POL-1001-1", + memberName: "- Basic Coverage", + policyType: "Medical", + startDate: "Jan 1, 2022", + endDate: "Jan 1, 2025", + premium: "$250/month", + status: "Active", + }, + { + policyId: "POL-1001-2", + memberName: "- Dental Coverage", + policyType: "Dental", + startDate: "Jan 1, 2022", + endDate: "Jan 1, 2025", + premium: "$100/month", + status: "Active", + }, + { + policyId: "POL-1001-3", + memberName: "- Vision Coverage", + policyType: "Vision", + startDate: "Jan 1, 2022", + endDate: "Jan 1, 2025", + premium: "$100/month", + status: "Active", + }, + ], + }, + { + policyId: "POL-1002", + memberName: "Jane Doe", + policyType: "Life Insurance", + startDate: "Jun 15, 2021", + endDate: "Jun 15, 2026", + premium: "$125/month", + status: "Active", + childRows: [ + { + policyId: "POL-1002-1", + memberName: "- Term Life", + policyType: "Life", + startDate: "Jun 15, 2021", + endDate: "Jun 15, 2026", + premium: "$125/month", + status: "Active", + }, + ], + }, + { + policyId: "POL-1003", + memberName: "Emily Doe", + policyType: "Auto Insurance", + startDate: "Mar 20, 2023", + endDate: "Mar 20, 2024", + premium: "$180/month", + status: "Active", + childRows: [ + { + policyId: "POL-1003-1", + memberName: "- Liability Coverage", + policyType: "Auto", + startDate: "Mar 20, 2023", + endDate: "Mar 20, 2024", + premium: "$90/month", + status: "Active", + }, + { + policyId: "POL-1003-2", + memberName: "- Collision Coverage", + policyType: "Auto", + startDate: "Mar 20, 2023", + endDate: "Mar 20, 2024", + premium: "$90/month", + status: "Active", + }, + ], + }, + { + policyId: "POL-1004", + memberName: "Michael Doe", + policyType: "Home Insurance", + startDate: "Nov 5, 2022", + endDate: "Nov 5, 2025", + premium: "$200/month", + status: "Pending Renewal", + childRows: [ + { + policyId: "POL-1004-1", + memberName: "- Property Coverage", + policyType: "Home", + startDate: "Nov 5, 2022", + endDate: "Nov 5, 2025", + premium: "$150/month", + status: "Pending Renewal", + }, + { + policyId: "POL-1004-2", + memberName: "- Liability Coverage", + policyType: "Home", + startDate: "Nov 5, 2022", + endDate: "Nov 5, 2025", + premium: "$50/month", + status: "Pending Renewal", + }, + ], + }, + { + policyId: "POL-1005", + memberName: "Sarah Doe", + policyType: "Travel Insurance", + startDate: "Feb 10, 2023", + endDate: "Feb 10, 2024", + premium: "$75/month", + status: "Expired", + }, +]; +const items = [ + { + label: "Policies", + icon: "description", + items: [ + { label: "All Policies", icon: "list", selected: true }, + { label: "Active", icon: "check_circle" }, + { label: "Pending", icon: "schedule" }, + { label: "Expired", icon: "cancel" }, + ], + badge: , + }, + { label: "Claims", icon: "assignment" }, + { label: "Documents", icon: "folder" }, + { label: "Payments", icon: "payment" }, +]; + +const columns = [ + { displayValue: "Name" }, + { displayValue: "Relationship" }, + { displayValue: "Age" }, + { displayValue: "Occupation" }, + { displayValue: "Coverage Amount" }, + { displayValue: "Actions" }, +]; + +const actions = [ + { + icon: "edit", + title: "Edit Member", + onClick: () => {}, + }, + { + icon: "visibility", + title: "View Details", + onClick: () => {}, + }, +]; + +const rows = [ + [ + { displayValue: "John Doe" }, + { displayValue: "Policyholder" }, + { displayValue: "42" }, + { displayValue: "Software Engineer" }, + { displayValue: "$500,000" }, + { displayValue: }, + ], + [ + { displayValue: "Jane Doe" }, + { displayValue: "Spouse" }, + { displayValue: "40" }, + { displayValue: "Teacher" }, + { displayValue: "$300,000" }, + { displayValue: }, + ], + [ + { displayValue: "Emily Doe" }, + { displayValue: "Daughter" }, + { displayValue: "14" }, + { displayValue: "Student" }, + { displayValue: "$100,000" }, + { displayValue: }, + ], + [ + { displayValue: "Michael Doe" }, + { displayValue: "Son" }, + { displayValue: "10" }, + { displayValue: "Student" }, + { displayValue: "$100,000" }, + { displayValue: }, + ], +]; + +const ApplicationPreview = () => { + const [selectedRows, setSelectedRows] = useState(new Set()); + const { getLogoUrl } = useThemeGenerator(); + + const mainLogo = getLogoUrl("mainLogo"); + const footerLogo = getLogoUrl("footerLogo"); + const companyName = "Insurance Portal"; + + const logo = { + src: mainLogo, + alt: "Company logo", + }; + + return ( + + } + header={ + + + + + } + /> + } + > + +
+
+ + + + Manage your family's insurance policies, view coverage details, and track policy status all in one + place. + + + + + + + + View and manage coverage information for all family members + + + + + + + + + + + Complete overview of all insurance policies associated with your family + + + + + + + ({ ...row, childRows: undefined }))} + uniqueRowId="policyId" + selectable + selectedRows={selectedRows} + onSelectRows={setSelectedRows} + /> + +
+
+
+
+
+ ); +}; + +export default ApplicationPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/BasicApplicationLayoutPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/BasicApplicationLayoutPreview.tsx new file mode 100644 index 0000000000..294ab6908d --- /dev/null +++ b/apps/website/screens/utilities/theme-generator/previews/BasicApplicationLayoutPreview.tsx @@ -0,0 +1,126 @@ +import { DxcApplicationLayout, DxcHeading, DxcParagraph, DxcContainer, DxcFlex } from "@dxc-technology/halstack-react"; +import ScaledPreviewContainer from "../components/ScaledPreviewContainer"; +import { useThemeGenerator } from "../context/ThemeGeneratorContext"; + +const sidenavItems = [ + { + label: "Sidenav Content", + icon: "tab", + selected: true, + }, + { + label: "Sidenav Content", + icon: "capture", + }, + { + label: "Sidenav Content", + icon: "folder", + }, + { + label: "Sidenav Content", + icon: "picture_in_picture_mobile", + }, + { + label: "Sidenav Content", + icon: "picture_as_pdf", + }, +]; + +const BasicApplicationLayoutPreview = () => { + const { getLogoUrl } = useThemeGenerator(); + + const mainLogo = getLogoUrl("mainLogo"); + const footerLogo = getLogoUrl("footerLogo"); + const companyName = "Insurance Portal"; + + const logo = { + src: mainLogo, + alt: "Company logo", + }; + + return ( + + + + Application description, version, notes, and contact details can go here for additional information + + + Contact Us: email@dxc.com + + + } + logo={{ src: footerLogo, alt: "Footer logo" }} + /> + } + header={} + sidenav={} + > + + + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc vehicula quam turpis, ac sodales arcu + efficitur quis. Duis ante lacus, dictum eu eleifend ac, iaculis vel lectus. Integer non ante id purus + consectetur luctus. Duis et odio a odio placerat blandit. Cras ultricies ante vel turpis ultricies, a + suscipit velit ultricies. Nam risus leo, laoreet ut augue ac, sagittis iaculis diam. Praesent nec turpis + leo. Aliquam posuere, orci a pharetra convallis, erat est blandit dolor, nec aliquet tortor sapien ac + felis. Maecenas laoreet, nisi a ultrices cursus, leo ipsum rutrum risus, at interdum enim enim non eros. + Donec placerat, ex vitae pulvinar maximus, sapien odio varius massa, vel pulvinar massa ipsum vitae + ipsum. + + + Nullam blandit convallis mi, sit amet pretium sapien auctor ut. Etiam eu magna purus. Quisque + pellentesque mollis libero eget ullamcorper. Vestibulum ante ipsum primis in faucibus orci luctus et + ultrices posuere cubilia curae; Nunc egestas, nisi consequat mollis vestibulum, nulla felis pulvinar + neque, non aliquam eros elit quis diam. Curabitur odio tortor, sagittis at neque sed, faucibus varius + sem. Ut rutrum massa eros, nec luctus orci hendrerit in. Nam hendrerit sed magna in tincidunt. Proin + pretium, orci id placerat maximus, est purus facilisis est, sed euismod turpis urna id enim. Morbi + tristique efficitur hendrerit. Etiam ut viverra est. Vestibulum at ex a nisl vulputate accumsan et nec + elit. Donec sollicitudin justo non odio viverra, sit amet luctus velit facilisis. Nam tortor dui, dictum + vitae sapien fringilla, tempus ullamcorper lectus. + + + Sed quam ipsum, pharetra sed tortor pulvinar, egestas pulvinar quam. Vestibulum mauris mi, iaculis eu + augue id, bibendum fermentum massa. Etiam a purus accumsan, tristique arcu eget, laoreet purus. Morbi in + pellentesque magna, ut condimentum urna. Duis erat nisi, tempor a risus quis, porta commodo ante. Donec + ex sem, viverra a pulvinar a, consectetur nec risus. Nam vitae risus purus. Morbi porta orci a tincidunt + pulvinar. Curabitur eleifend tincidunt eros, vel pretium urna malesuada ac. + + + Integer rutrum faucibus leo. Sed vel tincidunt urna. Pellentesque quis risus vel dui elementum laoreet. + Quisque non ornare nunc. Donec vestibulum mauris et gravida varius. Suspendisse aliquam, libero nec + sollicitudin commodo, sem tellus cursus arcu, quis pellentesque mauris nisl euismod libero. Etiam vitae + sagittis sem. Suspendisse potenti. Integer scelerisque mattis turpis varius rutrum. + + + Praesent faucibus diam metus, eu blandit quam rutrum ut. Maecenas non risus dapibus nulla congue rutrum + at vitae risus. Etiam arcu augue, maximus eu justo ac, ultrices suscipit dui. Pellentesque turpis quam, + accumsan at arcu vel, feugiat ultricies neque. Nullam sit amet ipsum feugiat, facilisis eros sit amet, + bibendum enim. Sed sagittis, mauris at ullamcorper fringilla, lorem nibh pretium magna, ac tristique + turpis nulla id dui. Praesent gravida congue odio, et commodo metus tristique sed. Class aptent taciti + sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Etiam eleifend pretium rhoncus. + Pellentesque id interdum nunc. Mauris sit amet posuere libero. Aenean et eleifend quam. Vestibulum eu ex + vitae nulla efficitur sagittis id vitae elit. Nullam vehicula sollicitudin libero id tristique. Aliquam + pulvinar posuere nibh quis fringilla. Integer placerat massa orci, ut accumsan elit iaculis ac. + + + + + + + ); +}; + +export default BasicApplicationLayoutPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/DashboardPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/DashboardPreview.tsx index e69de29bb2..0b67d2a5b3 100644 --- a/apps/website/screens/utilities/theme-generator/previews/DashboardPreview.tsx +++ b/apps/website/screens/utilities/theme-generator/previews/DashboardPreview.tsx @@ -0,0 +1,327 @@ +import { + DxcApplicationLayout, + DxcContainer, + DxcFlex, + DxcTypography, + DxcHeading, + DxcInset, + DxcBadge, + DxcSpinner, + DxcDivider, + DxcButton, +} from "@dxc-technology/halstack-react"; +import ScaledPreviewContainer from "../components/ScaledPreviewContainer"; +import { useThemeGenerator } from "../context/ThemeGeneratorContext"; + +const DashboardPreview = () => { + const { getLogoUrl } = useThemeGenerator(); + + const mainLogo = getLogoUrl("mainLogo"); + + const logo = { + src: mainLogo, + alt: "Company logo", + }; + + const groupItems = [ + { + title: "Section 1", + items: [ + { + label: "Grouped Item 1", + icon: "favorite", + items: [ + { label: "Item 1", icon: "person" }, + { + label: "Grouped Item 2", + items: [ + { + label: "Item 2", + icon: "bookmark", + badge: , + }, + { label: "Selected Item 3" }, + ], + }, + ], + badge: , + }, + { label: "Item 4", icon: "key" }, + ], + }, + { + title: "Section 2", + items: [ + { label: "Item 5", icon: "person" }, + { + label: "Grouped Item 6", + items: [{ label: "Item 7", icon: "person" }, { label: "Item 8" }], + }, + { label: "Item 9" }, + ], + }, + ]; + + return ( + + }> + + + + + + + + + + + + + + + Uptime over the last 24 hours + + + + + + + + + + 0 + + + Detected outages in the last 24 hours + + + + + + + + +
+ + + + + + + + + N/A + + + 95th pctl. response time + + + + + + + + N/A + + Avg actions per session + + + + N/A + + Bounce rate + + + + N/A + + User sessions + + + + +
+
+
+ + + +
+ + + + + + + + + 3 + + Total users + + + + 0 + + MFA enrollments + + + + 0 + + Login success + + + +
+
+ + +
+ + + + + + + + + N/A + + Secure API calls + + + + N/A + + API calls failed + + + +
+
+ + + + + + + + + STABLE: Ingenium 100% availability with custom version demonstrating 4+ months long-term + stability. July 2025 deployment providing extended operational excellence. Warning-level + performance metrics require monitoring but service reliable. (Analysis ID: + analysis_220fb7ab605e4f03ab6133b2dce1865f). + + + + +
+
+
+
+
+
+ ); +}; + +export default DashboardPreview; diff --git a/apps/website/screens/utilities/theme-generator/previews/LoginPreview.tsx b/apps/website/screens/utilities/theme-generator/previews/LoginPreview.tsx index e69de29bb2..1395b02d15 100644 --- a/apps/website/screens/utilities/theme-generator/previews/LoginPreview.tsx +++ b/apps/website/screens/utilities/theme-generator/previews/LoginPreview.tsx @@ -0,0 +1,96 @@ +import styled from "@emotion/styled"; +import { + DxcFlex, + DxcTypography, + DxcTextInput, + DxcPasswordInput, + DxcButton, + DxcLink, +} from "@dxc-technology/halstack-react"; +import ScaledPreviewContainer from "../components/ScaledPreviewContainer"; +import { useThemeGenerator } from "../context/ThemeGeneratorContext"; +import Image from "@/common/Image"; + +const LoginContainer = styled.div<{ backgroundImage: string }>` + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + background-image: ${(props) => (props.backgroundImage ? `url(${props.backgroundImage})` : "none")}; + background-size: cover; + background-position: center; + background-repeat: no-repeat; + background-color: ${(props) => (props.backgroundImage ? "transparent" : "#f5f5f5")}; + position: relative; +`; + +const LogoContainer = styled.div` + display: flex; + justify-content: center; + align-items: center; + max-width: 150px; + max-height: 50px; + margin: 0 auto; + + img { + max-width: 100%; + max-height: 100%; + object-fit: contain; + } +`; + +const LoginCard = styled.div` + background: white; + border-radius: 4px; + padding: 48px 40px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); + width: 100%; + max-width: 420px; +`; + +const TitleContainer = styled.div` + text-align: center; +`; + +const LoginPreview = () => { + const { getLogoUrl } = useThemeGenerator(); + + const loginBg = getLogoUrl("loginBg"); + const loginLogo = getLogoUrl("loginLogo"); + + return ( + + + + + {loginLogo && ( + + Logo + + )} + + + + Sign in to your account + + + + + + + + + + Forgot password? + + + + + + + + ); +}; + +export default LoginPreview;