Skip to content

Commit

Permalink
feat: base theme export
Browse files Browse the repository at this point in the history
  • Loading branch information
dgaponov committed Jun 16, 2024
1 parent 63f65ac commit 96c3f44
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 39 deletions.
12 changes: 10 additions & 2 deletions src/components/ColorPickerInput/ColorPickerInput.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,26 @@ $block: '.#{variables.$ns}color-picker';
#{$block} {
--g-border-radius-xl: 8px;
flex-grow: 1;
position: relative;

&__text-input {
z-index: 1;
}

&__preview {
margin-inline-start: var(--g-spacing-2);
margin-inline-end: var(--g-spacing-1);
}

&__input {
width: 100%;
height: 0;
width: 35px;
opacity: 0;
padding: 0;
margin: 0;
border: 0;
position: absolute;
bottom: 0;
right: 0;
z-index: 0;
}
}
1 change: 1 addition & 0 deletions src/components/ColorPickerInput/ColorPickerInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export const ColorPickerInput = ({
return (
<Flex className={b()} direction="column">
<TextInput
className={b('text-input')}
name={name}
value={managedValue}
errorPlacement="inside"
Expand Down
37 changes: 3 additions & 34 deletions src/components/PrivateColorSelect/PrivateColorSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import {ChevronDown, DiamondExclamation, PencilToLine} from '@gravity-ui/icons';
import {ActionTooltip, Button, Flex, Icon, Popup, TextInput} from '@gravity-ui/uikit';
import {ChevronDown, PencilToLine} from '@gravity-ui/icons';
import {Button, Flex, Icon, Popup, TextInput} from '@gravity-ui/uikit';
import React from 'react';

import {block} from '../../utils';
import {ColorPickerInput} from '../ColorPickerInput/ColorPickerInput';
import {ColorPreview} from '../ColorPreview/ColorPreview';
import {createPrivateColorTitle, isPrivateColorToken, parsePrivateColorToken} from '../Theme/utils';
import {isPrivateColorToken} from '../Theme/utils';

import './PrivateColorSelect.scss';
import {PrivateColorSelectPopupContent} from './PrivateColorSelectPopupContent';
Expand All @@ -29,26 +29,6 @@ export const PrivateColorSelect: React.FC<PrivateColorSelectProps> = ({
const containerRef = React.useRef(null);
const [showPopup, toggleShowPopup] = React.useReducer((prev) => !prev, false);
const isCustomValue = !isPrivateColorToken(value);
const isValueDiffersFromDefault = defaultValue && defaultValue !== value;

const defaultValueToken = React.useMemo(() => {
if (!defaultValue) {
return '';
}

const result = parsePrivateColorToken(defaultValue);
if (result) {
return createPrivateColorTitle(result.mainColorToken, result.privateColorCode);
}

return '';
}, [defaultValue]);

const resetToDefault = React.useCallback(() => {
if (defaultValue) {
onChange(defaultValue);
}
}, [onChange, defaultValue]);

const switchMode = React.useCallback(() => {
if (isCustomValue) {
Expand Down Expand Up @@ -85,17 +65,6 @@ export const PrivateColorSelect: React.FC<PrivateColorSelectProps> = ({
<Button view="flat-secondary" onClick={toggleShowPopup}>
<Icon data={ChevronDown} />
</Button>
{isValueDiffersFromDefault && (
<ActionTooltip
title="The value is overriden"
description={`Effective value is \`var(${defaultValueToken});\``}
placement="bottom-end"
>
<Button view="flat-danger" onClick={resetToDefault}>
<Icon data={DiamondExclamation} />
</Button>
</ActionTooltip>
)}
</Flex>
}
controlProps={{
Expand Down
6 changes: 5 additions & 1 deletion src/components/Theme/ThemeCreator/ThemeCreator.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';

import {ThemeOptions} from '../types';
import {initThemeWizard} from '../utils';
import {exportTheme, initThemeWizard} from '../utils';

import {ThemeCreatorContextProvider} from './ThemeCreatorContext';

Expand All @@ -16,6 +16,10 @@ export const ThemeCreator: React.FC<ThemeCreatorProps> = ({theme, children}) =>
updateState(initThemeWizard(theme));
}, [theme]);

React.useEffect(() => {
console.log(exportTheme(state, 'scss'));
}, [state]);

return (
<ThemeCreatorContextProvider
value={{
Expand Down
2 changes: 2 additions & 0 deletions src/components/Theme/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export type ColorsOptions = {
'text-link-visited-hover': string;
};

export type ColorOption = keyof ColorsOptions;

export type BordersOptions = {};

export type TypographyOptions = {};
Expand Down
83 changes: 81 additions & 2 deletions src/components/Theme/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ import lowerCase from 'lodash/lowerCase';

import {
DEFAULT_NEW_COLOR_TITLE,
DEFAULT_PALETTE,
DEFAULT_PALETTE_TOKENS,
DEFAULT_THEME,
THEME_COLOR_VARIABLE_PREFIX,
} from './constants';
import {generatePrivateColors} from './privateColors';
import type {
ColorOption,
ColorsOptions,
Palette,
PaletteTokens,
Expand Down Expand Up @@ -58,10 +61,24 @@ export function parsePrivateColorToken(privateColorToken: string) {
};
}

export function createPrivateColorTitle(mainColorToken: string, privateColorCode: string) {
function createPrivateColorCssVariable(mainColorToken: string, privateColorCode: string) {
return `${THEME_COLOR_VARIABLE_PREFIX}-${mainColorToken}-${privateColorCode}`;
}

function createPrivateColorCssVariableFromToken(privateColorToken: string) {
const result = parsePrivateColorToken(privateColorToken);

if (result) {
return createPrivateColorCssVariable(result.mainColorToken, result.privateColorCode);
}

return '';
}

function createUtilityColorCssVariable(colorName: string) {
return `${THEME_COLOR_VARIABLE_PREFIX}-${colorName}`;
}

function isManuallyCreatedToken(token: string) {
return !DEFAULT_PALETTE_TOKENS.has(token);
}
Expand Down Expand Up @@ -362,7 +379,7 @@ export function getThemeColorOptions({
paletteTokens[token].privateColors[themeVariant]!,
).map(([privateColorCode, color]) => ({
token: createPrivateColorToken(token, privateColorCode),
title: createPrivateColorTitle(token, privateColorCode),
title: createPrivateColorCssVariable(token, privateColorCode),
color,
})),
},
Expand Down Expand Up @@ -417,3 +434,65 @@ export function initThemeWizard(inputTheme: ThemeOptions): ThemeWizardState {
tokens: Object.keys(paletteTokens),
};
}

type ExportType = 'scss' | 'json';

export function exportTheme(themeState: ThemeWizardState, exportType: ExportType = 'scss'): string {
if (exportType === 'json') {
throw new Error('Not implemented');
}

const {paletteTokens} = themeState;

const prepareThemeVariables = (themeVariant: ThemeVariant) => {
let cssVariables = '';
const privateColors: Record<string, string> = {};

themeState.tokens.forEach((token) => {
// Dont export colors that are equals to default
if (DEFAULT_PALETTE[themeVariant][token] === themeState.palette[themeVariant][token]) {
return;
}

if (paletteTokens[token]?.privateColors[themeVariant]) {
Object.entries(paletteTokens[token].privateColors[themeVariant]).forEach(
([privateColorCode, color]) => {
privateColors[createPrivateColorToken(token, privateColorCode)] = color;
cssVariables += `${createPrivateColorCssVariable(
token,
privateColorCode,
)}: ${color};\n`;
},
);
cssVariables += '\n';
}
});

cssVariables += '\n';

Object.entries(themeState.colors[themeVariant]).forEach(
([colorName, colorOrPrivateToken]) => {
// Dont export colors that are equals to default
if (
DEFAULT_THEME.colors[themeVariant][colorName as ColorOption] ===
colorOrPrivateToken
) {
return;
}

const color = isPrivateColorToken(colorOrPrivateToken)
? `var(${createPrivateColorCssVariableFromToken(colorOrPrivateToken)})`
: colorOrPrivateToken;

cssVariables += `${createUtilityColorCssVariable(colorName)}: ${color};\n`;
},
);

return cssVariables;
};

let result = '';
result += '// Light\n' + prepareThemeVariables('light');
result += '\n// Dark\n' + prepareThemeVariables('dark');
return result;
}

0 comments on commit 96c3f44

Please sign in to comment.