import React, { FC, useContext, useCallback, useEffect, useState } from 'react'; import { Button, Col, Collapse, Row, Slider, Space } from 'antd'; import Paragraph from 'antd/lib/typography/Paragraph'; import Title from 'antd/lib/typography/Title'; import { EditCustomStyles } from '../../EditCustomStyles'; import s from './appearance.module.scss'; import { postConfigUpdateToAPI, RESET_TIMEOUT } from '../../../../utils/config-constants'; import { createInputStatus, StatusState, STATUS_ERROR, STATUS_SUCCESS, } from '../../../../utils/input-statuses'; import { ServerStatusContext } from '../../../../utils/server-status-context'; import { FormStatusIndicator } from '../../FormStatusIndicator'; const { Panel } = Collapse; const ENDPOINT = '/appearance'; interface AppearanceVariable { value: string; description: string; } type ColorCollectionProps = { variables: { name; description; value }[]; updateColor: (variable: string, color: string, description: string) => void; }; const chatColorVariables = [ { name: 'theme-color-users-0', description: '' }, { name: 'theme-color-users-1', description: '' }, { name: 'theme-color-users-2', description: '' }, { name: 'theme-color-users-3', description: '' }, { name: 'theme-color-users-4', description: '' }, { name: 'theme-color-users-5', description: '' }, { name: 'theme-color-users-6', description: '' }, { name: 'theme-color-users-7', description: '' }, ]; const componentColorVariables = [ { name: 'theme-color-background-main', description: 'Background' }, { name: 'theme-color-action', description: 'Action' }, { name: 'theme-color-action-hover', description: 'Action Hover' }, { name: 'theme-color-components-primary-button-border', description: 'Primary Button Border' }, { name: 'theme-color-components-primary-button-text', description: 'Primary Button Text' }, { name: 'theme-color-components-chat-background', description: 'Chat Background' }, { name: 'theme-color-components-chat-text', description: 'Text: Chat' }, { name: 'theme-color-components-text-on-dark', description: 'Text: Light' }, { name: 'theme-color-components-text-on-light', description: 'Text: Dark' }, { name: 'theme-color-background-header', description: 'Header/Footer' }, { name: 'theme-color-components-content-background', description: 'Page Content' }, { name: 'theme-color-components-video-status-bar-background', description: 'Video Status Bar Background', }, { name: 'theme-color-components-video-status-bar-foreground', description: 'Video Status Bar Foreground', }, ]; const others = [{ name: 'theme-rounded-corners', description: 'Corner radius' }]; // Create an object so these vars can be indexed by name. const allAvailableValues = [...componentColorVariables, ...chatColorVariables, ...others].reduce( (obj, val) => { // eslint-disable-next-line no-param-reassign obj[val.name] = { name: val.name, description: val.description }; return obj; }, {}, ); // eslint-disable-next-line react/function-component-definition const ColorPicker = React.memo( ({ value, name, description, onChange, }: { value: string; name: string; description: string; onChange: (name: string, value: string, description: string) => void; }) => ( onChange(name, e.target.value, description)} />
{description}
), ); const ColorCollection: FC = ({ variables, updateColor }) => { const cc = variables.map(colorVar => { const { name, description, value } = colorVar; return ( ); }); // eslint-disable-next-line react/jsx-no-useless-fragment return <>{cc}; }; // eslint-disable-next-line react/function-component-definition export default function Appearance() { const serverStatusData = useContext(ServerStatusContext); const { serverConfig, setFieldInConfigState } = serverStatusData; const { instanceDetails } = serverConfig; const { appearanceVariables } = instanceDetails; const [defaultValues, setDefaultValues] = useState>(); const [customValues, setCustomValues] = useState>(); const [submitStatus, setSubmitStatus] = useState(null); let resetTimer = null; const resetStates = () => { setSubmitStatus(null); resetTimer = null; clearTimeout(resetTimer); }; const setDefaults = () => { const c = {}; [...componentColorVariables, ...chatColorVariables, ...others].forEach(color => { const resolvedColor = getComputedStyle(document.documentElement).getPropertyValue( `--${color.name}`, ); c[color.name] = { value: resolvedColor.trim(), description: color.description }; }); setDefaultValues(c); }; useEffect(() => { setDefaults(); }, []); useEffect(() => { if (Object.keys(appearanceVariables).length === 0) return; const c = {}; Object.keys(appearanceVariables).forEach(key => { c[key] = { value: appearanceVariables[key], description: allAvailableValues[key]?.description || '', }; }); setCustomValues(c); }, [appearanceVariables]); const updateColor = useCallback((variable: string, color: string, description: string) => { setCustomValues(oldCustomValues => ({ ...oldCustomValues, [variable]: { value: color, description }, })); }, []); const reset = async () => { await postConfigUpdateToAPI({ apiPath: ENDPOINT, data: { value: {} }, onSuccess: () => { setSubmitStatus(createInputStatus(STATUS_SUCCESS, 'Updated.')); resetTimer = setTimeout(resetStates, RESET_TIMEOUT); setCustomValues({}); }, onError: (message: string) => { setSubmitStatus(createInputStatus(STATUS_ERROR, message)); resetTimer = setTimeout(resetStates, RESET_TIMEOUT); }, }); }; const save = async () => { const c = {}; Object.keys(customValues).forEach(color => { c[color] = customValues[color].value; }); await postConfigUpdateToAPI({ apiPath: ENDPOINT, data: { value: c }, onSuccess: () => { setSubmitStatus(createInputStatus(STATUS_SUCCESS, 'Updated.')); resetTimer = setTimeout(resetStates, RESET_TIMEOUT); setFieldInConfigState({ fieldName: 'appearanceVariables', value: c, path: 'instanceDetails', }); }, onError: (message: string) => { setSubmitStatus(createInputStatus(STATUS_ERROR, message)); resetTimer = setTimeout(resetStates, RESET_TIMEOUT); }, }); }; const onBorderRadiusChange = (value: string) => { const variableName = 'theme-rounded-corners'; updateColor(variableName, `${value.toString()}px`, ''); }; if (!defaultValues) { return
Loading...
; } const transformToColorMap = variables => variables.map(colorVar => { const source = customValues?.[colorVar.name] ? customValues : defaultValues; const { name, description } = colorVar; const { value } = source[name]; return { name, description, value }; }); return ( <> Customize Appearance The following colors are used across the user interface.
Section Colors} key="1">

Certain sections of the interface can be customized by selecting new colors for them.

Chat User Colors} key="2"> Other Settings} key="4"> How rounded should corners be? { onBorderRadiusChange(v); }} value={Number( customValues?.['theme-rounded-corners']?.value?.replace('px', '') ?? defaultValues?.['theme-rounded-corners']?.value?.replace('px', '') ?? 0, )} />
); }