Adding a setting editor
This commit is contained in:
parent
2a8027ec23
commit
3771f40625
13 changed files with 568 additions and 24 deletions
|
@ -4,7 +4,6 @@ import {Sound} from "../sound/Sounds";
|
|||
import {ConnectionHandler} from "../ConnectionHandler";
|
||||
import {server_connections} from "../ui/frames/connection_handlers";
|
||||
import {createErrorModal, createInfoModal, createInputModal} from "../ui/elements/Modal";
|
||||
import {settings} from "../settings";
|
||||
import {spawnConnectModal} from "../ui/modal/ModalConnect";
|
||||
import PermissionType from "../permission/PermissionType";
|
||||
import {spawnQueryCreate} from "../ui/modal/ModalQuery";
|
||||
|
@ -14,6 +13,8 @@ import {CommandResult} from "../connection/ServerConnectionDeclaration";
|
|||
import {spawnSettingsModal} from "../ui/modal/ModalSettings";
|
||||
import {spawnPermissionEditorModal} from "../ui/modal/permission/ModalPermissionEditor";
|
||||
import {tr} from "../i18n/localize";
|
||||
import {spawnGlobalSettingsEditor} from "tc-shared/ui/modal/global-settings-editor/Controller";
|
||||
import {spawnModalCssVariableEditor} from "tc-shared/ui/modal/css-editor/Controller";
|
||||
|
||||
/*
|
||||
function initialize_sounds(event_registry: Registry<ClientGlobalControlEvents>) {
|
||||
|
@ -137,10 +138,18 @@ export function initialize(event_registry: Registry<ClientGlobalControlEvents>)
|
|||
}).open();
|
||||
break;
|
||||
|
||||
case "css-variable-editor":
|
||||
spawnModalCssVariableEditor();
|
||||
break;
|
||||
|
||||
case "settings":
|
||||
spawnSettingsModal();
|
||||
break;
|
||||
|
||||
case "settings-registry":
|
||||
spawnGlobalSettingsEditor();
|
||||
break;
|
||||
|
||||
default:
|
||||
console.warn(tr("Received open window event for an unknown window: %s"), event.window);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ export interface ClientGlobalControlEvents {
|
|||
action_open_window: {
|
||||
window:
|
||||
"settings" | /* use action_open_window_settings! */
|
||||
"settings-registry" |
|
||||
"css-variable-editor" |
|
||||
"bookmark-manage" |
|
||||
"query-manage" |
|
||||
"query-create" |
|
||||
|
|
|
@ -46,6 +46,7 @@ import "./profiles/ConnectionProfile";
|
|||
import "./update/UpdaterWeb";
|
||||
import ContextMenuEvent = JQuery.ContextMenuEvent;
|
||||
import {defaultConnectProfile, findConnectProfile} from "tc-shared/profiles/ConnectionProfile";
|
||||
import {spawnGlobalSettingsEditor} from "tc-shared/ui/modal/global-settings-editor/Controller";
|
||||
|
||||
let preventWelcomeUI = false;
|
||||
async function initialize() {
|
||||
|
@ -151,8 +152,11 @@ export function handle_connect_request(properties: ConnectRequestData, connectio
|
|||
function main() {
|
||||
/* initialize font */
|
||||
{
|
||||
const font = settings.static_global(Settings.KEY_FONT_SIZE, 14); //parseInt(getComputedStyle(document.body).fontSize)
|
||||
const font = settings.static_global(Settings.KEY_FONT_SIZE);
|
||||
$(document.body).css("font-size", font + "px");
|
||||
settings.globalChangeListener(Settings.KEY_FONT_SIZE, value => {
|
||||
$(document.body).css("font-size", value + "px");
|
||||
})
|
||||
}
|
||||
|
||||
/* context menu prevent */
|
||||
|
@ -308,6 +312,7 @@ function main() {
|
|||
modal.close_listener.push(() => settings.changeGlobal(Settings.KEY_USER_IS_NEW, false));
|
||||
}
|
||||
|
||||
spawnGlobalSettingsEditor();
|
||||
//spawnVideoPopout(server_connections.active_connection(), "https://www.youtube.com/watch?v=9683D18fyvs");
|
||||
}
|
||||
|
||||
|
|
|
@ -439,7 +439,7 @@ export class Settings extends StaticSettings {
|
|||
static readonly KEY_FONT_SIZE: ValuedSettingsKey<number> = {
|
||||
key: "font_size",
|
||||
valueType: "number",
|
||||
defaultValue: 14
|
||||
defaultValue: 14 //parseInt(getComputedStyle(document.body).fontSize)
|
||||
};
|
||||
|
||||
static readonly KEY_ICON_SIZE: ValuedSettingsKey<number> = {
|
||||
|
|
|
@ -25,6 +25,7 @@ import {control_bar_instance} from "../../ui/frames/control-bar";
|
|||
import {icon_cache_loader, IconManager, LocalIcon} from "../../file/Icons";
|
||||
import {spawnPermissionEditorModal} from "../../ui/modal/permission/ModalPermissionEditor";
|
||||
import {spawnModalCssVariableEditor} from "../../ui/modal/css-editor/Controller";
|
||||
import {global_client_actions} from "tc-shared/events/GlobalEvents";
|
||||
|
||||
export interface HRItem { }
|
||||
|
||||
|
@ -523,11 +524,16 @@ export function initialize() {
|
|||
menu.append_hr();
|
||||
|
||||
item = menu.append_item(tr("Modify CSS variables"));
|
||||
item.click(() => spawnModalCssVariableEditor());
|
||||
item.click(() => global_client_actions.fire("action_open_window", { window: "css-variable-editor" }));
|
||||
|
||||
item = menu.append_item(tr("Open Registry"));
|
||||
item.click(() => global_client_actions.fire("action_open_window", { window: "settings-registry" }));
|
||||
|
||||
menu.append_hr();
|
||||
|
||||
item = menu.append_item(tr("Settings"));
|
||||
item.icon("client-settings");
|
||||
item.click(() => spawnSettingsModal());
|
||||
item.click(() => global_client_actions.fire("action_open_window_settings"));
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -54,8 +54,16 @@ export const ServerLogRenderer = (props: { events: Registry<ServerLogUIEvents>,
|
|||
});
|
||||
|
||||
props.events.reactUse("notify_log_add", event => {
|
||||
if(logs === "loading")
|
||||
if(logs === "loading") {
|
||||
return;
|
||||
}
|
||||
|
||||
if(__build.mode === "debug") {
|
||||
const index = logs.findIndex(e => e.uniqueId === event.event.uniqueId);
|
||||
if(index !== -1) {
|
||||
debugger;
|
||||
}
|
||||
}
|
||||
|
||||
logs.push(event.event);
|
||||
logs.splice(0, Math.max(0, logs.length - 100));
|
||||
|
|
|
@ -103,17 +103,16 @@ function settings_general_application(container: JQuery, modal: Modal) {
|
|||
const current_size = parseInt(getComputedStyle(document.body).fontSize); //settings.static_global(Settings.KEY_FONT_SIZE, 12);
|
||||
const select = container.find(".option-font-size");
|
||||
|
||||
if (select.find("option[value='" + current_size + "']").length)
|
||||
if (select.find("option[value='" + current_size + "']").length) {
|
||||
select.find("option[value='" + current_size + "']").prop("selected", true);
|
||||
else
|
||||
} else {
|
||||
select.find("option[value='-1']").prop("selected", true);
|
||||
}
|
||||
|
||||
select.on('change', event => {
|
||||
const value = parseInt(select.val() as string);
|
||||
settings.changeGlobal(Settings.KEY_FONT_SIZE, value);
|
||||
console.log("Changed font size to %dpx", value);
|
||||
|
||||
$(document.body).css("font-size", value + "px");
|
||||
});
|
||||
}
|
||||
|
||||
|
|
80
shared/js/ui/modal/global-settings-editor/Controller.tsx
Normal file
80
shared/js/ui/modal/global-settings-editor/Controller.tsx
Normal file
|
@ -0,0 +1,80 @@
|
|||
import {spawnReactModal} from "tc-shared/ui/react-elements/Modal";
|
||||
import {ModalGlobalSettingsEditor} from "tc-shared/ui/modal/global-settings-editor/Renderer";
|
||||
import {Registry} from "tc-shared/events";
|
||||
import {ModalGlobalSettingsEditorEvents, Setting} from "tc-shared/ui/modal/global-settings-editor/Definitions";
|
||||
import {settings, Settings, SettingsKey} from "tc-shared/settings";
|
||||
|
||||
export function spawnGlobalSettingsEditor() {
|
||||
const events = new Registry<ModalGlobalSettingsEditorEvents>();
|
||||
initializeController(events);
|
||||
|
||||
const modal = spawnReactModal(ModalGlobalSettingsEditor, events);
|
||||
modal.show();
|
||||
modal.events.on("destroy", () => {
|
||||
events.fire("notify_destroy");
|
||||
events.destroy();
|
||||
});
|
||||
}
|
||||
|
||||
function initializeController(events: Registry<ModalGlobalSettingsEditorEvents>) {
|
||||
events.on("query_settings", () => {
|
||||
const settingsList: Setting[] = [];
|
||||
|
||||
for(const key of Settings.KEYS) {
|
||||
const setting = Settings[key] as SettingsKey<ConfigValueTypes>;
|
||||
settingsList.push({
|
||||
key: setting.key,
|
||||
description: setting.description,
|
||||
type: setting.valueType,
|
||||
defaultValue: setting.defaultValue
|
||||
});
|
||||
}
|
||||
|
||||
events.fire_async("notify_settings", { settings: settingsList });
|
||||
});
|
||||
|
||||
events.on("action_select_setting", event => {
|
||||
events.fire("notify_selected_setting", { setting: event.setting });
|
||||
});
|
||||
|
||||
events.on("query_setting", event => {
|
||||
const setting = Settings.KEYS.map(setting => Settings[setting] as SettingsKey<ConfigValueTypes>).find(e => e.key === event.setting);
|
||||
if(typeof setting === "undefined") {
|
||||
events.fire("notify_setting", {
|
||||
key: event.setting,
|
||||
status: "not-found"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
events.fire("notify_setting", {
|
||||
setting: event.setting,
|
||||
status: "success",
|
||||
info: {
|
||||
key: setting.key,
|
||||
description: setting.description,
|
||||
type: setting.valueType,
|
||||
defaultValue: setting.defaultValue
|
||||
},
|
||||
value: settings.global(setting)
|
||||
});
|
||||
});
|
||||
|
||||
events.on("action_set_value", event => {
|
||||
const setting = Settings.KEYS.map(setting => Settings[setting] as SettingsKey<ConfigValueTypes>).find(e => e.key === event.setting);
|
||||
if(typeof setting === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
/* the change will may already trigger a notify_setting_value, but just to ensure we're fiering it later as well */
|
||||
settings.changeGlobal(setting, event.value);
|
||||
|
||||
events.fire_async("notify_setting_value", { setting: event.setting, value: event.value });
|
||||
});
|
||||
|
||||
events.on("notify_destroy", settings.events.on("notify_setting_changed", event => {
|
||||
if(event.mode === "global") {
|
||||
events.fire_async("notify_setting_value", { setting: event.setting, value: event.newValue });
|
||||
}
|
||||
}));
|
||||
}
|
36
shared/js/ui/modal/global-settings-editor/Definitions.ts
Normal file
36
shared/js/ui/modal/global-settings-editor/Definitions.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
export interface Setting {
|
||||
key: string;
|
||||
|
||||
type: ConfigValueTypeNames;
|
||||
|
||||
description: string | undefined;
|
||||
defaultValue: string | undefined;
|
||||
}
|
||||
|
||||
export interface ModalGlobalSettingsEditorEvents {
|
||||
action_select_setting: { setting: string }
|
||||
action_set_filter: { filter: string },
|
||||
action_set_value: { setting: string, value: string }
|
||||
|
||||
query_settings: {},
|
||||
query_setting: { setting: string }
|
||||
|
||||
notify_settings: {
|
||||
settings: Setting[]
|
||||
},
|
||||
notify_setting: {
|
||||
setting: string,
|
||||
status: "success" | "not-found",
|
||||
|
||||
info?: Setting,
|
||||
value?: string
|
||||
},
|
||||
notify_selected_setting: {
|
||||
setting: string
|
||||
},
|
||||
notify_setting_value: {
|
||||
setting: string,
|
||||
value: string
|
||||
},
|
||||
notify_destroy: {}
|
||||
}
|
198
shared/js/ui/modal/global-settings-editor/Renderer.scss
Normal file
198
shared/js/ui/modal/global-settings-editor/Renderer.scss
Normal file
|
@ -0,0 +1,198 @@
|
|||
@import "../../../../css/static/mixin";
|
||||
@import "../../../../css/static/properties";
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: stretch;
|
||||
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
|
||||
padding: .5em;
|
||||
|
||||
width: 50em;
|
||||
max-width: 50em;
|
||||
min-width: 20em;
|
||||
|
||||
height: 30em;
|
||||
|
||||
@include user-select(none);
|
||||
|
||||
.subContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: stretch;
|
||||
|
||||
/* allocate as much space as we can get */
|
||||
width: 100vw;
|
||||
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
|
||||
.header {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
|
||||
font-weight: bold;
|
||||
color: #e0e0e0;
|
||||
|
||||
@include text-dotdotdot();
|
||||
}
|
||||
|
||||
.body {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
|
||||
min-height: 5em;
|
||||
}
|
||||
|
||||
&.containerList {
|
||||
max-width: 20em;
|
||||
min-width: 6em;
|
||||
}
|
||||
|
||||
&.containerEdit {
|
||||
min-width: 10em;
|
||||
}
|
||||
}
|
||||
|
||||
.list {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
|
||||
margin-right: 1em;
|
||||
min-height: 6.5em;
|
||||
|
||||
position: relative;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: stretch;
|
||||
|
||||
border: 1px #161616 solid;
|
||||
border-radius: 0.2em;
|
||||
background-color: #28292b;
|
||||
|
||||
.entries {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: stretch;
|
||||
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
|
||||
min-height: 3em;
|
||||
|
||||
@include chat-scrollbar-vertical();
|
||||
|
||||
.entry {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
|
||||
padding-left: .5em;
|
||||
padding-right: .5em;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: stretch;
|
||||
|
||||
height: 1.5em;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: #2c2d2f;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: #1a1a1b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.filter {
|
||||
border-top: 1px #161616 solid;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: stretch;
|
||||
|
||||
.input {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
|
||||
margin: 0;
|
||||
padding: .5em 1em;
|
||||
|
||||
min-width: 3em;
|
||||
}
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: absolute;
|
||||
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
z-index: 1;
|
||||
background-color: #28292b;
|
||||
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
||||
&.shown {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
a {
|
||||
text-align: center;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.editor {
|
||||
.info {
|
||||
flex-shrink: 0;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
|
||||
margin-bottom: 1em;
|
||||
|
||||
.title {
|
||||
text-transform: uppercase;
|
||||
color: var(--modal-query-key);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis
|
||||
}
|
||||
|
||||
.value {
|
||||
user-select: text;
|
||||
@include text-dotdotdot();
|
||||
}
|
||||
}
|
||||
|
||||
.infoDescription {
|
||||
.value {
|
||||
white-space: pre-wrap!important;
|
||||
height: 3.2em!important;
|
||||
}
|
||||
}
|
||||
|
||||
.infoValue {
|
||||
.input {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
196
shared/js/ui/modal/global-settings-editor/Renderer.tsx
Normal file
196
shared/js/ui/modal/global-settings-editor/Renderer.tsx
Normal file
|
@ -0,0 +1,196 @@
|
|||
import {Translatable} from "tc-shared/ui/react-elements/i18n";
|
||||
import * as React from "react";
|
||||
import {InternalModal} from "tc-shared/ui/react-elements/internal-modal/Controller";
|
||||
import {createContext, useContext, useRef, useState} from "react";
|
||||
import {Registry} from "tc-shared/events";
|
||||
import {ModalGlobalSettingsEditorEvents, Setting} from "tc-shared/ui/modal/global-settings-editor/Definitions";
|
||||
import {LoadingDots} from "tc-shared/ui/react-elements/LoadingDots";
|
||||
import {FlatInputField} from "tc-shared/ui/react-elements/InputField";
|
||||
|
||||
const ModalEvents = createContext<Registry<ModalGlobalSettingsEditorEvents>>(undefined);
|
||||
const cssStyle = require("./Renderer.scss");
|
||||
|
||||
const SettingInfoRenderer = (props: { children: [React.ReactNode, React.ReactNode ], className?: string }) => (
|
||||
<div className={cssStyle.info + " " + (props.className || "")}>
|
||||
<div className={cssStyle.title}>{props.children[0]}</div>
|
||||
<div className={cssStyle.value}>{props.children[1]}</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const SettingEditor = () => {
|
||||
const events = useContext(ModalEvents);
|
||||
|
||||
const [ isApplying, setApplying ] = useState(false);
|
||||
const [ currentValue, setCurrentValue ] = useState<string>();
|
||||
const [ currentSetting, setCurrentSetting ] = useState<Setting | "not-found">(false);
|
||||
const currentSettingKey = useRef();
|
||||
|
||||
events.reactUse("notify_selected_setting", event => {
|
||||
if(event.setting === currentSettingKey.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
currentSettingKey.current = event.setting;
|
||||
events.fire("query_setting", { setting: event.setting });
|
||||
});
|
||||
|
||||
events.reactUse("notify_setting", event => {
|
||||
if(event.setting !== currentSettingKey.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
setApplying(false);
|
||||
if(event.status === "not-found") {
|
||||
setCurrentSetting("not-found");
|
||||
} else {
|
||||
setCurrentValue(event.value);
|
||||
setCurrentSetting(event.info);
|
||||
}
|
||||
});
|
||||
|
||||
events.reactUse("action_set_value", event => {
|
||||
if(event.setting !== currentSettingKey.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
setApplying(true);
|
||||
});
|
||||
|
||||
events.reactUse("notify_setting_value", event => {
|
||||
if(event.setting !== currentSettingKey.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
setApplying(false);
|
||||
setCurrentValue(event.value);
|
||||
});
|
||||
|
||||
if(currentSetting === "not-found") {
|
||||
return null;
|
||||
} else if(!currentSetting) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cssStyle.body + " " + cssStyle.editor}>
|
||||
<SettingInfoRenderer>
|
||||
<Translatable>Setting key</Translatable>
|
||||
{currentSetting.key}
|
||||
</SettingInfoRenderer>
|
||||
<SettingInfoRenderer className={cssStyle.infoDescription}>
|
||||
<Translatable>Description</Translatable>
|
||||
{currentSetting.description}
|
||||
</SettingInfoRenderer>
|
||||
<SettingInfoRenderer className={cssStyle}>
|
||||
<Translatable>Default Value</Translatable>
|
||||
{typeof currentSetting.defaultValue !== "undefined" ? (currentSetting.defaultValue + "") : tr("unset")}
|
||||
</SettingInfoRenderer>
|
||||
<SettingInfoRenderer className={cssStyle.infoValue}>
|
||||
<Translatable>Value</Translatable>
|
||||
<FlatInputField
|
||||
className={cssStyle.input}
|
||||
value={isApplying ? "" : currentValue ? currentValue : " "}
|
||||
editable={!isApplying}
|
||||
placeholder={isApplying ? tr("applying...") : tr("setting unset")}
|
||||
onChange={text => {
|
||||
setCurrentValue(text);
|
||||
}}
|
||||
finishOnEnter={true}
|
||||
onBlur={() => {
|
||||
events.fire("action_set_value", { setting: currentSettingKey.current, value: currentValue });
|
||||
}}
|
||||
/>
|
||||
</SettingInfoRenderer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const SettingEntryRenderer = (props: { setting: Setting, selected: boolean }) => {
|
||||
const events = useContext(ModalEvents);
|
||||
|
||||
return (
|
||||
<div className={cssStyle.entry + " " + (props.selected ? cssStyle.selected : "")} onClick={() => events.fire("action_select_setting", { setting: props.setting.key })}>
|
||||
{props.setting.key}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const SettingList = () => {
|
||||
const events = useContext(ModalEvents);
|
||||
const [ settings, setSettings ] = useState<"loading" | Setting[]>(() => {
|
||||
events.fire("query_settings");
|
||||
return "loading";
|
||||
});
|
||||
const [ selectedSetting, setSelectedSetting ] = useState<string>(undefined);
|
||||
const [ filter, setFilter ] = useState<string>(undefined);
|
||||
|
||||
events.reactUse("notify_settings", event => setSettings(event.settings));
|
||||
events.reactUse("notify_selected_setting", event => setSelectedSetting(event.setting));
|
||||
events.reactUse("action_set_filter", event => setFilter((event.filter || "").toLowerCase()));
|
||||
|
||||
return (
|
||||
<div className={cssStyle.body + " " + cssStyle.list}>
|
||||
<div className={cssStyle.entries}>
|
||||
{settings === "loading" ? undefined :
|
||||
settings.map(setting => {
|
||||
filterBlock:
|
||||
if(filter) {
|
||||
if(setting.key.toLowerCase().indexOf(filter) !== -1) {
|
||||
break filterBlock;
|
||||
}
|
||||
|
||||
if(setting.description && setting.description.toLowerCase().indexOf(filter) !== -1) {
|
||||
break filterBlock;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
return <SettingEntryRenderer setting={setting} selected={setting.key === selectedSetting} key={setting.key} />;
|
||||
})
|
||||
}
|
||||
</div>
|
||||
<div className={cssStyle.filter}>
|
||||
<FlatInputField className={cssStyle.input} onInput={text => events.fire("action_set_filter", { filter: text })} placeholder={tr("Filter settings")} />
|
||||
</div>
|
||||
<div className={cssStyle.overlay + " " + (settings === "loading" ? cssStyle.shown : "")}>
|
||||
<a><Translatable>loading</Translatable> <LoadingDots /></a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export class ModalGlobalSettingsEditor extends InternalModal {
|
||||
protected readonly events: Registry<ModalGlobalSettingsEditorEvents>;
|
||||
|
||||
constructor(events: Registry<ModalGlobalSettingsEditorEvents>) {
|
||||
super();
|
||||
|
||||
this.events = events;
|
||||
}
|
||||
|
||||
renderBody(): React.ReactElement {
|
||||
return (
|
||||
<ModalEvents.Provider value={this.events}>
|
||||
<div className={cssStyle.container}>
|
||||
<div className={cssStyle.subContainer + " " + cssStyle.containerList}>
|
||||
<div className={cssStyle.header}>
|
||||
<a><Translatable>Setting list</Translatable></a>
|
||||
</div>
|
||||
<SettingList />
|
||||
</div>
|
||||
<div className={cssStyle.subContainer + " " + cssStyle.containerEdit}>
|
||||
<div className={cssStyle.header}>
|
||||
<a><Translatable>Setting editor</Translatable></a>
|
||||
</div>
|
||||
<SettingEditor />
|
||||
</div>
|
||||
</div>
|
||||
</ModalEvents.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
title(): string | React.ReactElement<Translatable> {
|
||||
return <Translatable>Global settings registry</Translatable>;
|
||||
}
|
||||
}
|
||||
|
|
@ -157,15 +157,15 @@ html:root {
|
|||
.containerFlat {
|
||||
position: relative;
|
||||
|
||||
padding-top: 1.75rem; /* the label above (might be floating) */
|
||||
margin-bottom: 1rem; /* for invalid label/help label */
|
||||
padding-top: 1.75em; /* the label above (might be floating) */
|
||||
margin-bottom: 1em; /* for invalid label/help label */
|
||||
|
||||
label {
|
||||
color: #999999;
|
||||
|
||||
top: 1rem;
|
||||
top: 1em;
|
||||
left: 0;
|
||||
font-size: .75rem;
|
||||
font-size: .75em;
|
||||
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
|
@ -182,13 +182,13 @@ html:root {
|
|||
&.type-floating {
|
||||
will-change: left, top, contents;
|
||||
color: #999999;
|
||||
top: 2.42rem;
|
||||
font-size: 1rem;
|
||||
top: 2.42em;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
&.type-static {
|
||||
top: 1rem;
|
||||
font-size: .75rem;
|
||||
top: 1em;
|
||||
font-size: .75em;
|
||||
}
|
||||
|
||||
@include transition(color $button_hover_animation_time ease-in-out, top $button_hover_animation_time ease-in-out, font-size $button_hover_animation_time ease-in-out);
|
||||
|
@ -199,8 +199,8 @@ html:root {
|
|||
color: #3c74a2;
|
||||
|
||||
&.type-floating {
|
||||
font-size: .75rem;
|
||||
top: 1rem;
|
||||
font-size: .75em;
|
||||
top: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -211,7 +211,7 @@ html:root {
|
|||
height: 2.25em;
|
||||
width: 100%;
|
||||
|
||||
font-size: 1rem;
|
||||
font-size: 1em;
|
||||
line-height: 1.5;
|
||||
|
||||
color: #cdd1d0;
|
||||
|
@ -226,7 +226,7 @@ html:root {
|
|||
box-shadow: none;
|
||||
|
||||
transition: background 0s ease-out;
|
||||
padding: .4375rem 0;
|
||||
padding: .4375em 0;
|
||||
|
||||
@include transition(all .15s ease-in-out);
|
||||
|
||||
|
@ -248,7 +248,7 @@ html:root {
|
|||
position: absolute;
|
||||
opacity: 0;
|
||||
width: 100%;
|
||||
margin-top: .25rem;
|
||||
margin-top: .25em;
|
||||
font-size: 80%;
|
||||
color: #f44336;
|
||||
|
||||
|
@ -274,7 +274,7 @@ html:root {
|
|||
position: absolute;
|
||||
opacity: 0;
|
||||
width: 100%;
|
||||
margin-top: .25rem;
|
||||
margin-top: .25em;
|
||||
|
||||
font-size: .75em;
|
||||
|
||||
|
|
|
@ -111,6 +111,8 @@ export class BoxedInputField extends React.Component<BoxedInputFieldProperties,
|
|||
|
||||
export interface FlatInputFieldProperties {
|
||||
defaultValue?: string;
|
||||
value?: string;
|
||||
|
||||
placeholder?: string;
|
||||
|
||||
className?: string;
|
||||
|
@ -165,6 +167,7 @@ export class FlatInputField extends React.Component<FlatInputFieldProperties, Fl
|
|||
const disabled = typeof this.state.disabled === "boolean" ? this.state.disabled : typeof this.props.disabled === "boolean" ? this.props.disabled : false;
|
||||
const readOnly = typeof this.state.editable === "boolean" ? !this.state.editable : typeof this.props.editable === "boolean" ? !this.props.editable : false;
|
||||
const placeholder = typeof this.state.placeholder === "string" ? this.state.placeholder : typeof this.props.placeholder === "string" ? this.props.placeholder : undefined;
|
||||
|
||||
return (
|
||||
<div className={cssStyle.containerFlat + " " + (this.state.isInvalid ? cssStyle.isInvalid : "") + " " + (this.state.filled ? cssStyle.isFilled : "") + " " + (this.props.className || "")}>
|
||||
{this.props.label ?
|
||||
|
@ -174,6 +177,8 @@ export class FlatInputField extends React.Component<FlatInputFieldProperties, Fl
|
|||
(this.props.labelFloatingClassName && this.state.filled ? this.props.labelFloatingClassName : "")}>{this.props.label}</label> : undefined}
|
||||
<input
|
||||
defaultValue={this.props.defaultValue}
|
||||
value={this.props.value}
|
||||
|
||||
type={"text"}
|
||||
ref={this.refInput}
|
||||
readOnly={readOnly}
|
||||
|
|
Loading…
Add table
Reference in a new issue