192 lines
5.8 KiB
TypeScript
192 lines
5.8 KiB
TypeScript
// Copyright 2021 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
import React, { useState } from 'react';
|
|
import { Button, ButtonVariant } from './Button';
|
|
import { GradientDial, KnobType } from './GradientDial';
|
|
import { SampleMessageBubbles } from './SampleMessageBubbles';
|
|
import { Slider } from './Slider';
|
|
import { Tabs } from './Tabs';
|
|
import type { CustomColorType } from '../types/Colors';
|
|
import type { LocalizerType } from '../types/Util';
|
|
import { getHSL } from '../util/getHSL';
|
|
import { getCustomColorStyle } from '../util/getCustomColorStyle';
|
|
|
|
export type PropsType = {
|
|
customColor?: CustomColorType;
|
|
i18n: LocalizerType;
|
|
onClose: () => unknown;
|
|
onSave: (color: CustomColorType) => unknown;
|
|
};
|
|
|
|
enum TabViews {
|
|
Solid = 'Solid',
|
|
Gradient = 'Gradient',
|
|
}
|
|
|
|
function getPercentage(value: number, max: number): number {
|
|
return (100 * value) / max;
|
|
}
|
|
|
|
function getValue(percentage: number, max: number): number {
|
|
return Math.round((max / 100) * percentage);
|
|
}
|
|
|
|
const MAX_HUE = 360;
|
|
const ULTRAMARINE_ISH_VALUES = {
|
|
hue: 220,
|
|
saturation: 84,
|
|
};
|
|
const ULTRAMARINE_ISH: CustomColorType = {
|
|
start: ULTRAMARINE_ISH_VALUES,
|
|
deg: 180,
|
|
};
|
|
|
|
export const CustomColorEditor = ({
|
|
customColor = ULTRAMARINE_ISH,
|
|
i18n,
|
|
onClose,
|
|
onSave,
|
|
}: PropsType): JSX.Element => {
|
|
const [color, setColor] = useState<CustomColorType>(customColor);
|
|
const [selectedColorKnob, setSelectedColorKnob] = useState<KnobType>(
|
|
KnobType.start
|
|
);
|
|
|
|
const { hue, saturation } =
|
|
color[selectedColorKnob] || ULTRAMARINE_ISH_VALUES;
|
|
|
|
return (
|
|
<>
|
|
<Tabs
|
|
initialSelectedTab={color.end ? TabViews.Gradient : TabViews.Solid}
|
|
moduleClassName="CustomColorEditor__tabs"
|
|
onTabChange={selectedTab => {
|
|
if (selectedTab === TabViews.Gradient && !color.end) {
|
|
setColor({
|
|
...color,
|
|
end: ULTRAMARINE_ISH_VALUES,
|
|
});
|
|
}
|
|
|
|
if (selectedTab === TabViews.Solid && color.end) {
|
|
setColor({
|
|
...color,
|
|
end: undefined,
|
|
});
|
|
}
|
|
}}
|
|
tabs={[
|
|
{
|
|
id: TabViews.Solid,
|
|
label: i18n('CustomColorEditor__solid'),
|
|
},
|
|
{
|
|
id: TabViews.Gradient,
|
|
label: i18n('CustomColorEditor__gradient'),
|
|
},
|
|
]}
|
|
>
|
|
{({ selectedTab }) => (
|
|
<>
|
|
<div className="CustomColorEditor__messages">
|
|
<SampleMessageBubbles
|
|
backgroundStyle={getCustomColorStyle(color)}
|
|
color="custom"
|
|
i18n={i18n}
|
|
includeAnotherBubble
|
|
/>
|
|
{selectedTab === TabViews.Gradient && (
|
|
<>
|
|
<GradientDial
|
|
deg={color.deg}
|
|
knob1Style={{ backgroundColor: getHSL(color.start) }}
|
|
knob2Style={{
|
|
backgroundColor: getHSL(
|
|
color.end || ULTRAMARINE_ISH_VALUES
|
|
),
|
|
}}
|
|
onChange={deg => {
|
|
setColor({
|
|
...color,
|
|
deg,
|
|
});
|
|
}}
|
|
onClick={knob => setSelectedColorKnob(knob)}
|
|
selectedKnob={selectedColorKnob}
|
|
/>
|
|
</>
|
|
)}
|
|
</div>
|
|
<div className="CustomColorEditor__slider-container">
|
|
{i18n('CustomColorEditor__hue')}
|
|
<Slider
|
|
handleStyle={{
|
|
backgroundColor: getHSL({
|
|
hue,
|
|
saturation: 100,
|
|
}),
|
|
}}
|
|
label={i18n('CustomColorEditor__hue')}
|
|
moduleClassName="CustomColorEditor__hue-slider"
|
|
onChange={(percentage: number) => {
|
|
setColor({
|
|
...color,
|
|
[selectedColorKnob]: {
|
|
...ULTRAMARINE_ISH_VALUES,
|
|
...color[selectedColorKnob],
|
|
hue: getValue(percentage, MAX_HUE),
|
|
},
|
|
});
|
|
}}
|
|
value={getPercentage(hue, MAX_HUE)}
|
|
/>
|
|
</div>
|
|
<div className="CustomColorEditor__slider-container">
|
|
{i18n('CustomColorEditor__saturation')}
|
|
<Slider
|
|
containerStyle={getCustomColorStyle({
|
|
deg: 180,
|
|
start: { hue, saturation: 0 },
|
|
end: { hue, saturation: 100 },
|
|
})}
|
|
handleStyle={{
|
|
backgroundColor: getHSL(
|
|
color[selectedColorKnob] || ULTRAMARINE_ISH_VALUES
|
|
),
|
|
}}
|
|
label={i18n('CustomColorEditor__saturation')}
|
|
moduleClassName="CustomColorEditor__saturation-slider"
|
|
onChange={(value: number) => {
|
|
setColor({
|
|
...color,
|
|
[selectedColorKnob]: {
|
|
...ULTRAMARINE_ISH_VALUES,
|
|
...color[selectedColorKnob],
|
|
saturation: value,
|
|
},
|
|
});
|
|
}}
|
|
value={saturation}
|
|
/>
|
|
</div>
|
|
<div className="CustomColorEditor__footer">
|
|
<Button variant={ButtonVariant.Secondary} onClick={onClose}>
|
|
{i18n('cancel')}
|
|
</Button>
|
|
<Button
|
|
onClick={() => {
|
|
onSave(color);
|
|
onClose();
|
|
}}
|
|
>
|
|
{i18n('save')}
|
|
</Button>
|
|
</div>
|
|
</>
|
|
)}
|
|
</Tabs>
|
|
</>
|
|
);
|
|
};
|