import * as React from "react"; import {CssEditorEvents, CssEditorUserData, CssVariable} from "tc-shared/ui/modal/css-editor/Definitions"; import {Registry} from "tc-shared/events"; import {Translatable} from "tc-shared/ui/react-elements/i18n"; import {BoxedInputField, FlatInputField} from "tc-shared/ui/react-elements/InputField"; import {useState} from "react"; import {LoadingDots} from "tc-shared/ui/react-elements/LoadingDots"; import {Checkbox} from "tc-shared/ui/react-elements/Checkbox"; import {Button} from "tc-shared/ui/react-elements/Button"; import {createErrorModal, createInfoModal} from "tc-shared/ui/elements/Modal"; import {AbstractModal} from "tc-shared/ui/react-elements/ModalDefinitions"; const cssStyle = require("./Renderer.scss"); const CssVariableRenderer = React.memo((props: { events: Registry, variable: CssVariable, selected: boolean }) => { const [ selected, setSelected ] = useState(props.selected); const [ override, setOverride ] = useState(props.variable.overwriteValue); const [ overrideColor, setOverrideColor ] = useState(props.variable.customValue); props.events.reactUse("action_select_entry", event => setSelected(event.variable === props.variable)); props.events.reactUse("action_override_toggle", event => { if(event.variableName !== props.variable.name) return; setOverride(event.enabled); if(event.enabled) setOverrideColor(event.value); }); props.events.reactUse("action_change_override_value", event => { if(event.variableName !== props.variable.name) return; setOverrideColor(event.value); }); return (
{ if(selected) return; props.events.fire("action_select_entry", { variable: props.variable }) }} >
{props.variable.name}
); }); const CssVariableListBodyRenderer = (props: { events: Registry }) => { const [ variables, setVariables ] = useState<"loading" | CssVariable[]>(() => { props.events.fire_async("query_css_variables"); return "loading"; }); const [ filter, setFilter ] = useState(undefined); const [ selectedVariable, setSelectedVariable ] = useState(undefined); props.events.reactUse("action_select_entry", event => setSelectedVariable(event.variable)); props.events.reactUse("query_css_variables", () => setVariables("loading")); let content; if(variables === "loading") { content = (
Loading 
); } else { content = []; for(const variable of variables) { if(filter && variable.name.toLowerCase().indexOf(filter) === -1) continue; content.push(); } if(content.length === 0) { content.push( ); } } props.events.reactUse("action_set_filter", event => setFilter(event.filter?.toLowerCase())); props.events.reactUse("notify_css_variables", event => setVariables(event.variables)); return (
{ if(variables === "loading") return; /* TODO: This isn't working since the div isn't focused properly yet */ let offset = 0; if(event.key === "ArrowDown") { offset = 1; } else if(event.key === "ArrowUp") { offset = -1; } if(offset !== 0) { const selectIndex = variables.findIndex(e => e === selectedVariable); if(selectIndex === -1) return; const variable = variables[selectIndex + offset]; if(!variable) return; props.events.fire("action_select_entry", { variable: variable }); } }} tabIndex={0}> {content}
); }; const CssVariableListSearchRenderer = (props: { events: Registry }) => { const [ isLoading, setLoading ] = useState(true); props.events.reactUse("notify_css_variables", () => setLoading(false)); props.events.reactUse("query_css_variables", () => setLoading(true)); return (
Filter variables} labelType={"floating"} className={cssStyle.input} onInput={text => props.events.fire("action_set_filter", { filter: text })} disabled={isLoading} />
); }; const CssVariableListRenderer = (props: { events: Registry }) => (
console.error(event.key)}>
); const SelectedVariableInfo = (props: { events: Registry }) => { const [ selectedVariable, setSelectedVariable ] = useState(undefined); props.events.reactUse("action_select_entry", event => setSelectedVariable(event.variable)); return (<>
Name
Default Value
); }; const OverrideVariableInfo = (props: { events: Registry }) => { const [ selectedVariable, setSelectedVariable ] = useState(undefined); const [ overwriteValue, setOverwriteValue ] = useState(undefined); const [ overwriteEnabled, setOverwriteEnabled ] = useState(false); props.events.reactUse("action_select_entry", event => { setSelectedVariable(event.variable); setOverwriteEnabled(event.variable?.overwriteValue); setOverwriteValue(event.variable?.customValue); }); props.events.reactUse("action_override_toggle", event => { if(event.variableName !== selectedVariable?.name) return; selectedVariable.overwriteValue = event.enabled; setOverwriteEnabled(event.enabled); if(event.enabled) setOverwriteValue(event.value); }); props.events.reactUse("action_change_override_value", event => { if(event.variableName !== selectedVariable?.name) return; setOverwriteValue(event.value); }); return (<>
Override Value { props.events.fire("action_override_toggle", { variableName: selectedVariable.name, value: typeof selectedVariable.customValue === "string" ? selectedVariable.customValue : selectedVariable.defaultValue, enabled: value }); }} />
{ selectedVariable.customValue = text; props.events.fire("action_change_override_value", { value: text, variableName: selectedVariable.name }); }} />
); }; const CssVariableColorPicker = (props: { events: Registry, selectedVariable: CssVariable }) => { const [ overwriteValue, setOverwriteValue ] = useState(undefined); const [ overwriteEnabled, setOverwriteEnabled ] = useState(false); props.events.reactUse("action_override_toggle", event => { if(event.variableName !== props.selectedVariable?.name) return; props.selectedVariable.overwriteValue = event.enabled; setOverwriteEnabled(event.enabled); if(event.enabled) setOverwriteValue(event.value); }); props.events.reactUse("action_change_override_value", event => { if(event.variableName !== props.selectedVariable?.name || 'cpInvoker' in event) return; setOverwriteValue(event.value); }); let currentInput: string; let inputTimeout: number; return ( ) }; const ControlButtons = (props: { events: Registry }) => { return (
) }; const CssVariableEditor = (props: { events: Registry }) => { return ( ) }; const downloadTextAsFile = (text, name) => { const element = document.createElement("a"); element.text = "download"; element.href = "data:test/plain;charset=utf-8," + encodeURIComponent(text); element.download = name; element.style.display = "none"; document.body.appendChild(element); element.click(); element.remove(); }; const requestFileAsText = async (): Promise => { const element = document.createElement("input"); element.style.display = "none"; element.type = "file"; document.body.appendChild(element); element.click(); await new Promise(resolve => { element.onchange = resolve; }); if(element.files.length !== 1) return undefined; const file = element.files[0]; element.remove(); return await file.text(); }; class PopoutConversationUI extends AbstractModal { private readonly events: Registry; private readonly userData: CssEditorUserData; constructor(events: Registry, userData: CssEditorUserData) { super(); this.userData = userData; this.events = events; this.events.on("notify_export_result", event => { createInfoModal(tr("Config exported successfully"), tr("The config has been exported successfully.")).open(); downloadTextAsFile(event.config, "teaweb-style.json"); }); this.events.on("notify_import_result", event => { if(event.success) createInfoModal(tr("Config imported successfully"), tr("The config has been imported successfully.")).open(); else createErrorModal(tr("Config imported failed"), tr("The config import has been failed.")).open(); }) } renderBody() { return (
); } title() { return "CSS Variable editor"; } } export = PopoutConversationUI;