Skip to content

Commit

Permalink
chore: allow manually editing the code in the theme creator (#3431)
Browse files Browse the repository at this point in the history
Co-authored-by: Paulo Lagoá <paulo.lagoa@@hitachivantara.com>
  • Loading branch information
plagoa and Paulo Lagoá authored Jun 16, 2023
1 parent 18f67cc commit 7af90e8
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 99 deletions.
3 changes: 3 additions & 0 deletions app/src/generator/CodeEditor/CodeEditor.styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export const styles = {
top: "2px!important",
},
},
".suggest-widget": {
display: "none!important",
},
}),
codeEditorTools: css({
display: "flex",
Expand Down
69 changes: 53 additions & 16 deletions app/src/generator/CodeEditor/CodeEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
useTheme,
} from "@hitachivantara/uikit-react-core";
import { GeneratorContext } from "generator/GeneratorContext";
import { useContext } from "react";
import { useContext, useEffect, useState } from "react";
import debounce from "lodash/debounce";
import {
Download,
Undo,
Expand All @@ -21,26 +22,33 @@ import { HvCodeEditor } from "@hitachivantara/uikit-react-code-editor";
import { IconButton } from "components/common/IconButton";
import { styles } from "./CodeEditor.styles";

export const groupsToShow = ["acce", "atmo", "base", "sema"] as const; // "sup", "cat"

const CodeEditor = ({ themeName, setCopied }): JSX.Element => {
const { activeTheme, selectedTheme } = useTheme();
const { selectedTheme, selectedMode, changeTheme } = useTheme();

const { customTheme, updateCustomTheme, undo, redo, canUndo, canRedo } =
useContext(GeneratorContext);
const {
customTheme,
updateCustomTheme,
undo,
redo,
canUndo,
canRedo,
themeChanges,
} = useContext(GeneratorContext);

const fileName = `${themeName}.ts`;

const fullCode = getThemeCode(
themeName,
selectedTheme,
activeTheme,
customTheme
);
const fullCode = getThemeCode(themeName, selectedTheme, themeChanges);
const encodedCode = encodeURIComponent(fullCode);

const [value, setValue] = useState(fullCode);

useEffect(() => {
const code = getThemeCode(themeName, selectedTheme, themeChanges);
setValue(code);
}, [customTheme]);

const onCopyHandler = () => {
navigator.clipboard.writeText(fullCode);
navigator.clipboard.writeText(value);
setCopied(true);
};

Expand All @@ -52,6 +60,34 @@ const CodeEditor = ({ themeName, setCopied }): JSX.Element => {
updateCustomTheme(newTheme);
};

const codeChangedHandler = (code?: string) => {
if (!code) return;

const snippet = code.substring(
code.indexOf("({") + 1,
code.indexOf("});") + 1
);

const themeJson = snippet.replace(
/(['"])?([a-zA-Z0-9_]+)(['"])?:/g,
'"$2": '
);

try {
const parsed = JSON.parse(themeJson);
if (customTheme.base !== parsed.base) {
changeTheme(parsed.base, selectedMode);
} else {
const newTheme = createTheme(parsed);
updateCustomTheme(newTheme);
}
} catch {
console.log("error processing theme JSON");
}
};

const debouncedHandler = debounce(codeChangedHandler, 1000);

return (
<HvBox css={{ position: "relative" }}>
<HvBox className={styles.codeEditorTools}>
Expand Down Expand Up @@ -95,15 +131,16 @@ const CodeEditor = ({ themeName, setCopied }): JSX.Element => {
<HvCodeEditor
options={{
minimap: { enabled: false },
readOnly: true,
// readOnly: true,
lineDecorationsWidth: 0,
lineNumbersMinChars: 0,
}}
language="typescript"
value={fullCode}
height={260}
value={value}
height={300}
width="100%"
className={styles.codeEditor}
onChange={debouncedHandler}
/>
</HvBox>
);
Expand Down
2 changes: 1 addition & 1 deletion app/src/generator/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const Content = () => {
style={{
width: open ? "calc(100% - 390px)" : "100%",
backgroundColor:
customTheme?.colors?.modes[selectedMode]?.backgroundColor,
customTheme?.colors?.modes?.[selectedMode]?.backgroundColor,
}}
>
<Router basename={import.meta.env.BASE_URL}>
Expand Down
72 changes: 54 additions & 18 deletions app/src/generator/GeneratorContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@ import {
Dispatch,
SetStateAction,
useEffect,
useMemo,
} from "react";
import merge from "lodash/merge";
import { themeDiff } from "./utils";

type GeneratorContextProp = {
customTheme: HvTheme | HvThemeStructure;
updateCustomTheme: (
newTheme: HvThemeStructure | HvTheme,
addToHistory?: boolean
addToHistory?: boolean,
updateThemeChanges?: boolean
) => void;

open?: boolean;
Expand All @@ -28,6 +32,8 @@ type GeneratorContextProp = {
redo?: () => void;
canUndo?: boolean;
canRedo?: boolean;

themeChanges?: Partial<HvTheme | HvThemeStructure>;
};

export const GeneratorContext = createContext<GeneratorContextProp>({
Expand All @@ -46,8 +52,13 @@ const GeneratorProvider = ({ children }) => {
const [historyStep, setHistoryStep] = useState(-1);
const [canUndo, setCanUndo] = useState(false);
const [canRedo, setCanRedo] = useState(false);
const [themeChanges, setThemeChanges] = useState({});

const updateCustomTheme = (newTheme, addToHistory = true) => {
const updateCustomTheme = (
newTheme,
addToHistory = true,
updateThemeChanges = true
) => {
if (addToHistory) {
let newHistory: HvTheme[] = history;
if (history.length - historyStep > 1) {
Expand All @@ -59,6 +70,13 @@ const GeneratorProvider = ({ children }) => {
setHistory([...newHistory, newTheme]);
setHistoryStep((prev) => prev + 1);
}

if (updateThemeChanges) {
setThemeChanges((prev) => {
const diff = themeDiff(customTheme, newTheme);
return merge({}, prev, diff);
});
}
setCustomTheme(newTheme);
};

Expand Down Expand Up @@ -88,23 +106,41 @@ const GeneratorProvider = ({ children }) => {
setHistoryStep((prev) => prev + 1);
};

const value = useMemo(
() => ({
customTheme,
updateCustomTheme,
open,
setOpen,
tutorialOpen,
setTutorialOpen,
currentStep,
setCurrentStep,
undo,
redo,
canUndo,
canRedo,
themeChanges,
}),
[
customTheme,
updateCustomTheme,
open,
setOpen,
tutorialOpen,
setTutorialOpen,
currentStep,
setCurrentStep,
undo,
redo,
canUndo,
canRedo,
themeChanges,
]
);

return (
<GeneratorContext.Provider
value={{
customTheme,
updateCustomTheme,
open,
setOpen,
tutorialOpen,
setTutorialOpen,
currentStep,
setCurrentStep,
undo,
redo,
canUndo,
canRedo,
}}
>
<GeneratorContext.Provider value={value}>
{children}
</GeneratorContext.Provider>
);
Expand Down
9 changes: 1 addition & 8 deletions app/src/generator/Sidebar/Sidebar.styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,9 @@ export const styles = {
...theme.typography.sectionTitle,
textTransform: "uppercase",
}),
themeName: css({
display: "flex",
gap: 10,
alignItems: "center",
}),
themeNameInput: css({
width: "100%",
}),
themeBase: css({
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
gap: 20,
alignItems: "center",
Expand Down
83 changes: 30 additions & 53 deletions app/src/generator/Sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
HvBaseTheme,
HvBox,
HvDropdown,
HvInput,
HvListValue,
HvLoading,
HvSnackbar,
Expand All @@ -15,7 +14,6 @@ import {
} from "@hitachivantara/uikit-react-core";
import { lazy, Suspense, useContext, useEffect, useState } from "react";
import { GeneratorContext } from "generator/GeneratorContext";
import debounce from "lodash/debounce";
import CodeEditor from "generator/CodeEditor";
import {
Bold,
Expand All @@ -36,28 +34,23 @@ const Zindices = lazy(() => import("generator/Zindices"));
const Sizes = lazy(() => import("generator/Sizes"));

const Sidebar = () => {
const { selectedTheme, selectedMode, colorModes, themes, changeTheme } =
const { selectedTheme, selectedMode, colorModes, changeTheme, themes } =
useTheme();

const { updateCustomTheme, open } = useContext(GeneratorContext);
const { customTheme, updateCustomTheme, open, themeChanges } =
useContext(GeneratorContext);

const [themeName, setThemeName] = useState("customTheme");
const [copied, setCopied] = useState(false);
const [tab, setTab] = useState(0);

const nameChangeHandler = (name) => {
setThemeName(name);
};

useEffect(() => {
const newTheme = createTheme({
name: themeName,
name: customTheme.name,
base: selectedTheme as HvBaseTheme,
...themeChanges,
});
updateCustomTheme(newTheme, false);
}, [themeName, selectedTheme]);

const debouncedNameChangeHandler = debounce(nameChangeHandler, 250);
updateCustomTheme(newTheme, false, false);
}, [customTheme.name, selectedTheme]);

const handleClose = (event, reason) => {
if (reason === "clickaway") return;
Expand All @@ -80,48 +73,32 @@ const Sidebar = () => {
<HvBox css={{ display: "flex", justifyContent: "center" }}>
<HvTypography variant="title2">Theme Creator</HvTypography>
</HvBox>
<HvBox className={styles.themeName}>
<HvTypography variant="label">Name: </HvTypography>
<HvBox className={styles.themeNameInput}>
<HvInput
onChange={(event, value) => debouncedNameChangeHandler(value)}
placeholder={themeName}
/>
</HvBox>
</HvBox>
<HvBox className={styles.themeBase}>
<HvBox>
<HvTypography variant="label">Theme: </HvTypography>
<HvDropdown
css={{ width: 100 }}
values={themes.map((name) => ({
value: name,
label: name,
selected: name === selectedTheme,
}))}
onChange={(t) => {
// console.log("new theme is", (t as HvListValue)?.value)
changeTheme((t as HvListValue)?.value, selectedMode);
}}
/>
</HvBox>
<HvBox>
<HvTypography variant="label">Mode: </HvTypography>
<HvDropdown
css={{ width: 120 }}
values={colorModes.map((name) => ({
value: name,
label: name,
selected: name === selectedMode,
}))}
onChange={(mode) =>
changeTheme(selectedTheme, (mode as HvListValue)?.value)
}
/>
</HvBox>
<HvTypography variant="label">Base:</HvTypography>
<HvDropdown
values={themes.map((name) => ({
value: name,
label: name,
selected: name === selectedTheme,
}))}
onChange={(base) => {
changeTheme((base as HvListValue)?.value, selectedMode);
}}
/>
<HvTypography variant="label">Mode:</HvTypography>
<HvDropdown
values={colorModes.map((name) => ({
value: name,
label: name,
selected: name === selectedMode,
}))}
onChange={(mode) =>
changeTheme(selectedTheme, (mode as HvListValue)?.value)
}
/>
</HvBox>
<HvBox>
<CodeEditor themeName={themeName} setCopied={setCopied} />
<CodeEditor themeName={customTheme.name} setCopied={setCopied} />
</HvBox>
<HvBox>
<HvTabs
Expand Down
Loading

0 comments on commit 7af90e8

Please sign in to comment.