From 6e93b760890e85673508ea06007eddba3b981e47 Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Sun, 28 Feb 2021 14:29:06 +0100 Subject: [PATCH 001/128] Fixed linux client start crash when opening too many devices --- shared/js/settings.ts | 7 +- shared/js/ui/modal/settings/Microphone.tsx | 87 +++++++++++++++---- .../ui/modal/settings/MicrophoneRenderer.tsx | 1 + 3 files changed, 75 insertions(+), 20 deletions(-) diff --git a/shared/js/settings.ts b/shared/js/settings.ts index df36f6ef..6718b196 100644 --- a/shared/js/settings.ts +++ b/shared/js/settings.ts @@ -1,4 +1,3 @@ -import * as log from "./log"; import {LogCategory, logError, logTrace} from "./log"; import * as loader from "tc-loader"; import {Stage} from "tc-loader"; @@ -773,6 +772,12 @@ export class Settings { valueType: "boolean", }; + static readonly KEY_MICROPHONE_LEVEL_INDICATOR: RegistryKey = { + key: "microphone_level_indicator", + description: "Enable/disable the microphone level indicator when opening the microphone settings. The default is true, except for the linux native client.", + valueType: "boolean", + }; + static readonly FN_LOG_ENABLED: (category: string) => RegistryKey = category => { return { key: "log." + category.toLowerCase() + ".enabled", diff --git a/shared/js/ui/modal/settings/Microphone.tsx b/shared/js/ui/modal/settings/Microphone.tsx index 1fe07c87..313c3fa5 100644 --- a/shared/js/ui/modal/settings/Microphone.tsx +++ b/shared/js/ui/modal/settings/Microphone.tsx @@ -6,6 +6,8 @@ import {LogCategory, logTrace, logWarn} from "tc-shared/log"; import {defaultRecorder} from "tc-shared/voice/RecorderProfile"; import {DeviceListState, getRecorderBackend, IDevice} from "tc-shared/audio/recorder"; import {Settings, settings} from "tc-shared/settings"; +import {getBackend} from "tc-shared/backend"; +import * as _ from "lodash"; export type MicrophoneSetting = "volume" @@ -48,8 +50,6 @@ export interface MicrophoneSettingsEvents { "action_request_permissions": {}, "action_set_selected_device": { target: SelectedMicrophone }, "action_set_selected_device_result": { - status: "success", - } | { status: "error", reason: string }, @@ -96,6 +96,7 @@ export function initialize_audio_microphone_controller(events: Registry } = {}; const deviceLevelInfo: { [key: string]: any } = {}; let deviceLevelUpdateTask; + let selectedDevice: SelectedMicrophone = { type: "none" }; const destroyLevelIndicators = () => { Object.keys(levelMeterInitializePromises).forEach(e => { @@ -110,39 +111,77 @@ export function initialize_audio_microphone_controller(events: Registry { destroyLevelIndicators(); + let levelMeterEnabled; + { + let defaultValue = true; + if(__build.target === "client" && getBackend("native").getVersionInfo().os_platform === "linux") { + defaultValue = false; + } + + levelMeterEnabled = settings.getValue(Settings.KEY_MICROPHONE_LEVEL_INDICATOR, defaultValue); + } deviceLevelInfo["none"] = {deviceId: "none", status: "success", level: 0}; + const defaultDeviceId = recorderBackend.getDeviceList().getDefaultDeviceId(); for (const device of recorderBackend.getDeviceList().getDevices()) { - let promise = recorderBackend.createLevelMeter(device).then(meter => { - meter.setObserver(level => { + let createLevelMeter; + if(!levelMeterEnabled) { + switch (selectedDevice.type) { + case "default": + createLevelMeter = device.deviceId == defaultDeviceId; + break; + + case "device": + createLevelMeter = device.deviceId == selectedDevice.deviceId; + break; + + case "none": + createLevelMeter = false; + break; + } + } else { + createLevelMeter = true; + } + + if(createLevelMeter) { + let promise = recorderBackend.createLevelMeter(device).then(meter => { + meter.setObserver(level => { + if (levelMeterInitializePromises[device.deviceId] !== promise) { + /* old level meter */ + return; + } + + deviceLevelInfo[device.deviceId] = { + deviceId: device.deviceId, + status: "success", + level: level + }; + }); + return Promise.resolve(meter); + }).catch(error => { if (levelMeterInitializePromises[device.deviceId] !== promise) { /* old level meter */ return; } - deviceLevelInfo[device.deviceId] = { deviceId: device.deviceId, - status: "success", - level: level + status: "error", + + error: error }; + + logWarn(LogCategory.AUDIO, tr("Failed to initialize a level meter for device %s (%s): %o"), device.deviceId, device.driver + ":" + device.name, error); + return Promise.reject(error); }); - return Promise.resolve(meter); - }).catch(error => { - if (levelMeterInitializePromises[device.deviceId] !== promise) { - /* old level meter */ - return; - } + levelMeterInitializePromises[device.deviceId] = promise; + } else { deviceLevelInfo[device.deviceId] = { deviceId: device.deviceId, status: "error", - error: error + error: tr("level meter disabled") }; - - logWarn(LogCategory.AUDIO, tr("Failed to initialize a level meter for device %s (%s): %o"), device.deviceId, device.driver + ":" + device.name, error); - return Promise.reject(error); - }); - levelMeterInitializePromises[device.deviceId] = promise; + } } }; @@ -160,6 +199,7 @@ export function initialize_audio_microphone_controller(events: Registry { + if(_.isEqual(selectedDevice, event.device)) { + return; + } + + selectedDevice = event.device; + updateLevelMeter(); + }); } /* device list */ diff --git a/shared/js/ui/modal/settings/MicrophoneRenderer.tsx b/shared/js/ui/modal/settings/MicrophoneRenderer.tsx index c264d12b..6837513e 100644 --- a/shared/js/ui/modal/settings/MicrophoneRenderer.tsx +++ b/shared/js/ui/modal/settings/MicrophoneRenderer.tsx @@ -52,6 +52,7 @@ const ActivityBar = (props: { events: Registry, device } props.events.reactUse("notify_device_level", event => { + refHider.current.style.width = "100%"; if (event.status === "uninitialized") { if (status.mode === "uninitialized") { return; From f0a79f52bac611c4e9d6a0dd5bbddf4f33c848c0 Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Mon, 1 Mar 2021 15:21:59 +0100 Subject: [PATCH 002/128] Fixed microphone attack/release smooth for the native client and made it actually adjustable --- shared/js/settings.ts | 19 +++++++++++++++++++ shared/js/ui/modal/settings/Microphone.tsx | 1 + shared/js/voice/RecorderProfile.ts | 13 ++++++++++--- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/shared/js/settings.ts b/shared/js/settings.ts index 6718b196..bf3c4a6d 100644 --- a/shared/js/settings.ts +++ b/shared/js/settings.ts @@ -778,6 +778,25 @@ export class Settings { valueType: "boolean", }; + static readonly KEY_MICROPHONE_THRESHOLD_ATTACK_SMOOTH: ValuedRegistryKey = { + key: "microphone_threshold_attack_smooth", + valueType: "number", + defaultValue: .25 + }; + + static readonly KEY_MICROPHONE_THRESHOLD_RELEASE_SMOOTH: ValuedRegistryKey = { + key: "microphone_threshold_release_smooth", + valueType: "number", + defaultValue: .9 + + }; + static readonly KEY_MICROPHONE_THRESHOLD_RELEASE_DELAY: ValuedRegistryKey = { + key: "microphone_threshold_release_delay", + valueType: "number", + description: "Delay for the client to cut of the audio in ms.", + defaultValue: 500 + }; + static readonly FN_LOG_ENABLED: (category: string) => RegistryKey = category => { return { key: "log." + category.toLowerCase() + ".enabled", diff --git a/shared/js/ui/modal/settings/Microphone.tsx b/shared/js/ui/modal/settings/Microphone.tsx index 313c3fa5..75f765d9 100644 --- a/shared/js/ui/modal/settings/Microphone.tsx +++ b/shared/js/ui/modal/settings/Microphone.tsx @@ -115,6 +115,7 @@ export function initialize_audio_microphone_controller(events: Registry Date: Thu, 11 Mar 2021 14:37:57 +0100 Subject: [PATCH 003/128] Some minor cleanups --- shared/js/ui/frames/video/Controller.ts | 7 ------- shared/js/ui/frames/video/Renderer.tsx | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/shared/js/ui/frames/video/Controller.ts b/shared/js/ui/frames/video/Controller.ts index a901142c..4a15bd57 100644 --- a/shared/js/ui/frames/video/Controller.ts +++ b/shared/js/ui/frames/video/Controller.ts @@ -337,13 +337,6 @@ class LocalVideoController extends RemoteClientVideoController { } } } - - /* - protected getBroadcastStream(target: VideoBroadcastType) : MediaStream | undefined { - const videoConnection = this.client.channelTree.client.serverConnection.getVideoConnection(); - return videoConnection.getBroadcastingSource(target)?.getStream(); - } - */ } class ChannelVideoController { diff --git a/shared/js/ui/frames/video/Renderer.tsx b/shared/js/ui/frames/video/Renderer.tsx index ad3c09a2..83555141 100644 --- a/shared/js/ui/frames/video/Renderer.tsx +++ b/shared/js/ui/frames/video/Renderer.tsx @@ -163,7 +163,7 @@ const VideoGeneralAvailableRenderer = (props: { videoId: string, haveScreen: boo const events = useContext(EventContext); const subscribeInfo = useContext(SubscribeContext); - if(props.haveCamera && canSubscribe(subscribeInfo, "camera") || props.haveScreen && canSubscribe(subscribeInfo, "screen")) { + if((props.haveCamera && canSubscribe(subscribeInfo, "camera")) || (props.haveScreen && canSubscribe(subscribeInfo, "screen"))) { return (
From 4394d36383a6e80e7612f9a4decb24156e3e6bec Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Fri, 12 Mar 2021 17:46:27 +0100 Subject: [PATCH 004/128] Adding the new video spotlight mode --- ChangeLog.md | 4 + package-lock.json | 48 +++ package.json | 2 + shared/js/proto.ts | 20 +- shared/js/settings.ts | 7 + shared/js/ui/AppRenderer.tsx | 33 -- shared/js/ui/frames/video/Controller.ts | 31 +- shared/js/ui/frames/video/Definitions.ts | 8 +- shared/js/ui/frames/video/Renderer.scss | 70 +++- shared/js/ui/frames/video/Renderer.tsx | 99 ++--- .../js/ui/frames/video/RendererSpotlight.tsx | 359 ++++++++++++++++++ shared/js/ui/react-elements/ErrorBoundary.tsx | 2 +- shared/js/ui/react-elements/FontSize.tsx | 39 ++ web/app/audio/Recorder.ts | 1 - web/app/audio/sounds.ts | 1 - 15 files changed, 611 insertions(+), 113 deletions(-) create mode 100644 shared/js/ui/frames/video/RendererSpotlight.tsx create mode 100644 shared/js/ui/react-elements/FontSize.tsx diff --git a/ChangeLog.md b/ChangeLog.md index 7165537d..1e6c8bed 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,4 +1,8 @@ # Changelog: +* **12.03.21** + - Added a new video spotlight mode which allows showing multiple videos at the same time as well as + dragging and resizing them + * **20.02.21** - Improved the browser IPC module - Added support for client invite links diff --git a/package-lock.json b/package-lock.json index b7f46275..be69e8a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1529,6 +1529,14 @@ "@types/react": "*" } }, + "@types/react-grid-layout": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/react-grid-layout/-/react-grid-layout-1.1.1.tgz", + "integrity": "sha512-bvPkITzwGGOZKjp01nVSgPrdfGm/uTa5t8Odd8vQRXJsLj7uZLZXSXgWr+TiXBAkUsmHPxhsyswXQCiFeDuZnQ==", + "requires": { + "@types/react": "*" + } + }, "@types/react-transition-group": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.0.tgz", @@ -4111,6 +4119,11 @@ } } }, + "classnames": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", + "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" + }, "clean-css": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", @@ -9138,6 +9151,11 @@ "integrity": "sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI=", "dev": true }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -11456,11 +11474,32 @@ "scheduler": "^0.19.1" } }, + "react-draggable": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.3.tgz", + "integrity": "sha512-jV4TE59MBuWm7gb6Ns3Q1mxX8Azffb7oTtDtBgFkxRvhDp38YAARmRplrj0+XGkhOJB5XziArX+4HUUABtyZ0w==", + "requires": { + "classnames": "^2.2.5", + "prop-types": "^15.6.0" + } + }, "react-fast-compare": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" }, + "react-grid-layout": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/react-grid-layout/-/react-grid-layout-1.2.2.tgz", + "integrity": "sha512-i5/xPkyi0llA6PCEW2B26e7pTY+JLp0zPvs6MYbbEXWaO1FWG0xr6Q/FqPrh6K86glV5ZRU7DEbvnedZVdFglg==", + "requires": { + "classnames": "2.x", + "lodash.isequal": "^4.0.0", + "prop-types": "^15.0.0", + "react-draggable": "^4.0.0", + "react-resizable": "^1.10.0" + } + }, "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -11478,6 +11517,15 @@ "react-fast-compare": "^3.0.1" } }, + "react-resizable": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/react-resizable/-/react-resizable-1.11.1.tgz", + "integrity": "sha512-S70gbLaAYqjuAd49utRHibtHLrHXInh7GuOR+6OO6RO6uleQfuBnWmZjRABfqNEx3C3Z6VPLg0/0uOYFrkfu9Q==", + "requires": { + "prop-types": "15.x", + "react-draggable": "^4.0.3" + } + }, "react-transition-group": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", diff --git a/package.json b/package.json index 9a785300..4c8ac6e7 100644 --- a/package.json +++ b/package.json @@ -91,6 +91,7 @@ }, "homepage": "https://www.teaspeak.de", "dependencies": { + "@types/react-grid-layout": "^1.1.1", "@types/react-transition-group": "^4.4.0", "broadcastchannel-polyfill": "^1.0.1", "detect-browser": "^5.2.0", @@ -104,6 +105,7 @@ "moment": "^2.24.0", "react": "^16.13.1", "react-dom": "^16.13.1", + "react-grid-layout": "^1.2.2", "react-player": "^2.5.0", "react-transition-group": "^4.4.1", "remarkable": "^2.0.1", diff --git a/shared/js/proto.ts b/shared/js/proto.ts index e64e2df4..c4d8d404 100644 --- a/shared/js/proto.ts +++ b/shared/js/proto.ts @@ -19,7 +19,19 @@ declare global { last?(): T; pop_front(): T | undefined; + + /** + * @param entry The entry to toggle + * @returns `true` if the entry has been inserted and false if the entry has been deleted + */ toggle(entry: T) : boolean; + + /** + * @param entry The entry to toggle + * @param insert Whatever the entry should be in the array or not + * @returns `true` if the array has been modified + */ + toggle(entry: T, insert: boolean); } interface JSON { @@ -173,14 +185,16 @@ if (!Array.prototype.pop_front) { } if (!Array.prototype.toggle) { - Array.prototype.toggle = function(element: T): boolean { + Array.prototype.toggle = function(element: T, insert?: boolean): boolean { const index = this.findIndex(e => e === element); - if(index === -1) { + if((index !== -1) === insert) { + return false; + } else if(index === -1) { this.push(element); return true; } else { this.splice(index, 1); - return false; + return typeof insert === "boolean"; } } } diff --git a/shared/js/settings.ts b/shared/js/settings.ts index bf3c4a6d..0b8f6fb5 100644 --- a/shared/js/settings.ts +++ b/shared/js/settings.ts @@ -758,6 +758,13 @@ export class Settings { valueType: "boolean", }; + static readonly KEY_VIDEO_SPOTLIGHT_MODE: ValuedRegistryKey = { + key: "video_spotlight_mode", + defaultValue: 1, + description: "Select the video spotlight mode.\n0: Single video\n1: Video grid", + valueType: "number", + }; + static readonly KEY_INVITE_SHORT_URL: ValuedRegistryKey = { key: "invite_short_url", defaultValue: true, diff --git a/shared/js/ui/AppRenderer.tsx b/shared/js/ui/AppRenderer.tsx index d10976f3..529ca799 100644 --- a/shared/js/ui/AppRenderer.tsx +++ b/shared/js/ui/AppRenderer.tsx @@ -21,39 +21,6 @@ import {ChannelTreeUIEvents} from "tc-shared/ui/tree/Definitions"; const cssStyle = require("./AppRenderer.scss"); -/* -
-
- -
-
-
-
-
-
-
-
- -
-
-
-
- -
- -
-
-
-
-
- -
-
-
-
- */ - const VideoFrame = React.memo((props: { events: Registry }) => { const refElement = React.useRef(); const [ container, setContainer ] = useState(() => { diff --git a/shared/js/ui/frames/video/Controller.ts b/shared/js/ui/frames/video/Controller.ts index 4a15bd57..c1193248 100644 --- a/shared/js/ui/frames/video/Controller.ts +++ b/shared/js/ui/frames/video/Controller.ts @@ -354,7 +354,7 @@ class ChannelVideoController { private localVideoController: LocalVideoController; private clientVideos: {[key: number]: RemoteClientVideoController} = {}; - private currentSpotlight: string; + private currentSpotlights: string[]; constructor(events: Registry, connection: ConnectionHandler) { this.events = events; @@ -366,6 +366,8 @@ class ChannelVideoController { this.localVideoController = new LocalVideoController(connection.getClient(), this.events); this.localVideoController.callbackBroadcastStateChanged = () => this.notifyVideoList(); }); + + this.currentSpotlights = []; this.currentlyVisible = false; this.expended = false; } @@ -395,8 +397,8 @@ class ChannelVideoController { this.events.fire_react("notify_expended", { expended: this.expended }); }); - this.events.on("action_set_spotlight", event => { - this.setSpotlight(event.videoId); + this.events.on("action_toggle_spotlight", event => { + this.toggleSpotlight(event.videoIds, event.enabled); if(!this.isExpended()) { this.events.fire("action_toggle_expended", { expended: true }); } @@ -554,13 +556,13 @@ class ChannelVideoController { events.push(settings.globalChangeListener(Settings.KEY_VIDEO_FORCE_SHOW_OWN_VIDEO, () => this.notifyVideoList())); } - setSpotlight(videoId: string | undefined) { - if(this.currentSpotlight === videoId) { return; } + toggleSpotlight(videoId: string[], enabled: boolean) { + const updated = videoId.map(entry => this.currentSpotlights.toggle(entry, enabled)).find(updated => updated); + if(!updated) { + return; + } - /* TODO: test if the video event exists? */ - - this.currentSpotlight = videoId; - this.notifySpotlight() + this.notifySpotlight(); this.notifyVideoList(); } @@ -597,7 +599,7 @@ class ChannelVideoController { } private resetClientVideos() { - this.currentSpotlight = undefined; + this.currentSpotlights = []; for(const clientId of Object.keys(this.clientVideos)) { this.destroyClientVideo(parseInt(clientId)); } @@ -614,10 +616,7 @@ class ChannelVideoController { video.destroy(); delete this.clientVideos[clientId]; - if(video.videoId === this.currentSpotlight) { - this.currentSpotlight = undefined; - this.notifySpotlight(); - } + this.toggleSpotlight([ video.videoId ], false); return true; } else { return false; @@ -635,7 +634,7 @@ class ChannelVideoController { } private notifySpotlight() { - this.events.fire_react("notify_spotlight", { videoId: this.currentSpotlight }); + this.events.fire_react("notify_spotlight", { videoId: this.currentSpotlights }); } private notifyVideoList() { @@ -677,7 +676,7 @@ class ChannelVideoController { this.updateVisibility(videoStreamingCount !== 0); if(this.expended) { - videoIds.remove(this.currentSpotlight); + this.currentSpotlights.forEach(entry => videoIds.remove(entry)); } this.events.fire_react("notify_videos", { diff --git a/shared/js/ui/frames/video/Definitions.ts b/shared/js/ui/frames/video/Definitions.ts index a0140d11..b19b2d76 100644 --- a/shared/js/ui/frames/video/Definitions.ts +++ b/shared/js/ui/frames/video/Definitions.ts @@ -69,7 +69,11 @@ export type LocalVideoState = "muted" | "unset" | "empty"; export interface ChannelVideoEvents { action_toggle_expended: { expended: boolean }, action_video_scroll: { direction: "left" | "right" }, - action_set_spotlight: { videoId: string | undefined, expend: boolean }, + action_toggle_spotlight: { + videoIds: string[], + enabled: boolean, + expend: boolean + }, action_focus_spotlight: {}, action_set_fullscreen: { videoId: string | undefined }, action_set_pip: { videoId: string | undefined, broadcastType: VideoBroadcastType }, @@ -108,7 +112,7 @@ export interface ChannelVideoEvents { right: boolean }, notify_spotlight: { - videoId: string | undefined + videoId: string[] }, notify_video_statistics: { videoId: string | undefined, diff --git a/shared/js/ui/frames/video/Renderer.scss b/shared/js/ui/frames/video/Renderer.scss index 5621221b..46d4f41c 100644 --- a/shared/js/ui/frames/video/Renderer.scss +++ b/shared/js/ui/frames/video/Renderer.scss @@ -24,12 +24,22 @@ $small_height: 10em; .panel { height: 0; + transition: none; /* else the whole spotlight will be triggered N times */ + } + } + + .heightProvider { + height: 100%; /* the footer size (version etc) */ + + .spotlight { + margin-left: 0; + margin-right: 0; } } &.expended { .panel { - height: calc(100% - 1.5em); /* the footer size (version etc) */ + height: 100%; /* the footer size (version etc) */ border-bottom-left-radius: 0; border-bottom-right-radius: 0; } @@ -62,6 +72,24 @@ $small_height: 10em; @include transition(all .3s ease-in-out); } +.heightProvider { + position: absolute; + + top: 0; + left: 0; + + width: 100%; + + display: flex; + flex-direction: column; + justify-content: stretch; + + height: $small_height; + flex-shrink: 0; + + pointer-events: none; +} + .expendArrow { position: absolute; @@ -122,8 +150,15 @@ $small_height: 10em; height: ($small_height - 1em); width: ($small_height * 16 / 9); + margin-top: .5em; + margin-bottom: .5em; + flex-shrink: 0; flex-grow: 0; + + &:not(:last-of-type) { + margin-right: .5em; + } } } @@ -181,11 +216,14 @@ $small_height: 10em; flex-direction: column; justify-content: stretch; + position: relative; + min-height: 5em; min-width: 5em; margin-left: .5em; margin-right: .5em; + margin-bottom: .5em; flex-shrink: 1; flex-grow: 1; @@ -198,20 +236,21 @@ $small_height: 10em; max-width: 25% !important; max-height: 25%!important; } + + &.grid { + /* if we're in grid mode we don't need any margins (will already be applied via the grid itself) */ + margin-left: 0; + margin-right: 0; + } } -.videoContainer { +.videoContainer, :global(.react-grid-item.react-grid-placeholder) { + /* Note: don't use margin here since it might */ position: relative; - margin-top: .5em; - margin-bottom: .5em; - flex-shrink: 1; flex-grow: 1; - background-color: #2e2e2e; - box-shadow: inset 0 0 5px #00000040; - border-radius: .2em; overflow: hidden; @@ -219,8 +258,19 @@ $small_height: 10em; flex-direction: column; justify-content: center; - &:not(:last-of-type) { - margin-right: .5em; + &.outlined, &:global(.react-grid-item.react-grid-placeholder) { + background-color: #2e2e2e; + box-shadow: inset 0 0 5px #00000040; + } + + &:global(.react-grid-item.react-grid-placeholder) { + background-color: #242424; + } + + :global .react-resizable-handle { + &::after { + border-color: #66666666; + } } .video { diff --git a/shared/js/ui/frames/video/Renderer.tsx b/shared/js/ui/frames/video/Renderer.tsx index 83555141..d5f5052b 100644 --- a/shared/js/ui/frames/video/Renderer.tsx +++ b/shared/js/ui/frames/video/Renderer.tsx @@ -11,24 +11,29 @@ import { makeVideoAutoplay, VideoStreamState, VideoSubscribeInfo -} from "tc-shared/ui/frames/video/Definitions"; +} from "./Definitions"; import {Translatable} from "tc-shared/ui/react-elements/i18n"; import {LoadingDots} from "tc-shared/ui/react-elements/LoadingDots"; import {ClientTag} from "tc-shared/ui/tree/EntryTags"; import ResizeObserver from "resize-observer-polyfill"; -import {LogCategory, logWarn} from "tc-shared/log"; +import {LogCategory, logTrace, logWarn} from "tc-shared/log"; import {spawnContextMenu} from "tc-shared/ui/ContextMenu"; import {VideoBroadcastType} from "tc-shared/connection/VideoConnection"; import {ErrorBoundary} from "tc-shared/ui/react-elements/ErrorBoundary"; import {useTr} from "tc-shared/ui/react-elements/Helper"; +import {Spotlight, SpotlightDimensions, SpotlightDimensionsContext} from "./RendererSpotlight"; +import * as _ from "lodash"; + const SubscribeContext = React.createContext(undefined); const EventContext = React.createContext>(undefined); const HandlerIdContext = React.createContext(undefined); +export const RendererVideoEventContext = EventContext; + const cssStyle = require("./Renderer.scss"); -const ExpendArrow = () => { +const ExpendArrow = React.memo(() => { const events = useContext(EventContext); const [ expended, setExpended ] = useState(() => { @@ -43,7 +48,7 @@ const ExpendArrow = () => {
) -}; +}); const VideoInfo = React.memo((props: { videoId: string }) => { const events = useContext(EventContext); @@ -368,7 +373,7 @@ const VideoControlButtons = React.memo((props: { if(props.isSpotlight) { events.fire("action_set_fullscreen", { videoId: props.fullscreenMode === "set" ? undefined : props.videoId }); } else { - events.fire("action_set_spotlight", { videoId: props.videoId, expend: true }); + events.fire("action_toggle_spotlight", { videoIds: [ props.videoId ], expend: true, enabled: true }); events.fire("action_focus_spotlight", { }); } }} @@ -380,7 +385,7 @@ const VideoControlButtons = React.memo((props: { ); }); -const VideoContainer = React.memo((props: { videoId: string, isSpotlight: boolean }) => { +export const VideoContainer = React.memo((props: { videoId: string, isSpotlight: boolean }) => { const events = useContext(EventContext); const refContainer = useRef(); const fullscreenCapable = "requestFullscreen" in HTMLElement.prototype; @@ -438,14 +443,14 @@ const VideoContainer = React.memo((props: { videoId: string, isSpotlight: boolea return (
{ if(isFullscreen) { events.fire("action_set_fullscreen", { videoId: undefined }); } else if(props.isSpotlight) { events.fire("action_set_fullscreen", { videoId: props.videoId }); } else { - events.fire("action_set_spotlight", { videoId: props.videoId, expend: true }); + events.fire("action_toggle_spotlight", { videoIds: [ props.videoId ], expend: true, enabled: true }); events.fire("action_focus_spotlight", { }); } }} @@ -479,7 +484,7 @@ const VideoContainer = React.memo((props: { videoId: string, isSpotlight: boolea label: props.isSpotlight ? tr("Release spotlight") : tr("Put client in spotlight"), icon: ClientIcon.Fullscreen, click: () => { - events.fire("action_set_spotlight", { videoId: props.isSpotlight ? undefined : props.videoId, expend: true }); + events.fire("action_toggle_spotlight", { videoIds: [ props.videoId ], expend: true, enabled: !props.isSpotlight }); events.fire("action_focus_spotlight", { }); } } @@ -514,7 +519,7 @@ const VideoBarArrow = React.memo((props: { direction: "left" | "right", containe ); }); -const VideoBar = () => { +const VideoBar = React.memo(() => { const events = useContext(EventContext); const refVideos = useRef(); const refArrowRight = useRef(); @@ -594,51 +599,53 @@ const VideoBar = () => {
) -}; +}); -const Spotlight = () => { - const events = useContext(EventContext); - const refContainer = useRef(); - const [ videoId, setVideoId ] = useState(() => { - events.fire("query_spotlight"); - return undefined; - }); - events.reactUse("notify_spotlight", event => setVideoId(event.videoId), undefined, []); - events.reactUse("action_focus_spotlight", () => refContainer.current?.focus(), undefined, []); +const PanelContainer = (props: { children }) => { + const refSpotlightContainer = useRef(); + const [ spotlightDimensions, setSpotlightDimensions ] = useState({ width: 1200, height: 900 }); - let body; - if(videoId) { - body = ; - } else { - body = ( -
-
No spotlight selected
-
- ); - } + useEffect(() => { + const resizeObserver = new ResizeObserver(entries => { + const entry = entries.last(); + const newDimensions = { height: entry.contentRect.height, width: entry.contentRect.width }; + + if(newDimensions.width === 0) { + /* div most likely got removed or something idk... */ + return; + } + + if(_.isEqual(newDimensions, spotlightDimensions)) { + return; + } + + setSpotlightDimensions(newDimensions); + logTrace(LogCategory.VIDEO, tr("New spotlight dimensions: %o"), entry.contentRect); + }); + + resizeObserver.observe(refSpotlightContainer.current); + return () => resizeObserver.disconnect(); + }, []); return ( -
{ - if(event.key === "Escape") { - events.fire("action_set_spotlight", { videoId: undefined, expend: false }); - } - }} - tabIndex={0} - ref={refContainer} - > - {body} -
- ) -}; + +
+ {props.children} +
+
+
+
+
+ + ); +} export const ChannelVideoRenderer = (props: { handlerId: string, events: Registry }) => { return ( -
+ @@ -646,7 +653,7 @@ export const ChannelVideoRenderer = (props: { handlerId: string, events: Registr -
+
); diff --git a/shared/js/ui/frames/video/RendererSpotlight.tsx b/shared/js/ui/frames/video/RendererSpotlight.tsx new file mode 100644 index 00000000..7b78a67b --- /dev/null +++ b/shared/js/ui/frames/video/RendererSpotlight.tsx @@ -0,0 +1,359 @@ +import * as React from "react"; +import {useContext, useMemo, useRef, useState} from "react"; +import {Translatable} from "tc-shared/ui/react-elements/i18n"; +import {Layout} from "react-grid-layout"; +import * as GridLayout from "react-grid-layout"; +import {ErrorBoundary} from "tc-shared/ui/react-elements/ErrorBoundary"; +import * as _ from "lodash"; +import {FontSizeObserver} from "tc-shared/ui/react-elements/FontSize"; +import {RendererVideoEventContext, VideoContainer} from "tc-shared/ui/frames/video/Renderer"; + +import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!react-resizable/css/styles.css"; +import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!react-grid-layout/css/styles.css"; +import {useGlobalSetting} from "tc-shared/ui/react-elements/Helper"; +import {Settings} from "tc-shared/settings"; + +export type SpotlightDimensions = { width: number, height: number }; +export const SpotlightDimensionsContext = React.createContext(undefined); + +const cssStyle = require("./Renderer.scss"); + +const SpotlightSingle = () => { + const events = useContext(RendererVideoEventContext); + const refContainer = useRef(); + + const [ videoId, setVideoId ] = useState(() => { + events.fire("query_spotlight"); + return undefined; + }); + events.reactUse("notify_spotlight", event => { + setVideoId(event.videoId.last()); + const dropped = event.videoId.slice(0, event.videoId.length - 1); + if(dropped.length > 0) { + events.fire("action_toggle_spotlight", { expend: false, enabled: false, videoIds: dropped }); + } + }, undefined, []); + events.reactUse("action_focus_spotlight", () => refContainer.current?.focus(), undefined, []); + + let body; + if(videoId) { + body = ; + } else { + body = ( +
+
No spotlight selected
+
+ ); + } + + return ( +
{ + if(event.key === "Escape") { + events.fire("action_toggle_spotlight", { videoIds: [ videoId ], expend: false, enabled: false }); + } + }} + tabIndex={0} + ref={refContainer} + > + {body} +
+ ) +}; + +type Rectangle = { x: number, y: number, w: number, h: number }; +const largestRectangleInHistogram = (histogram: number[]) : Rectangle => { + const len = histogram.length; + const stack = []; + let max = 0, maxH, maxW, maxX; + let h, w; + + for (let i = 0; i <= len; i++) { + while (stack.length && (i === len || histogram[i] <= histogram[stack[stack.length - 1]])) { + h = histogram[stack.pop()]; + w = stack.length === 0 ? i : i - stack[stack.length - 1] - 1; + + if(h * w > max) { + maxH = h; + maxW = w; + max = h * w; + maxX = i; + + while(maxX > 0 && histogram[maxX - 1] >= h) { + maxX --; + } + } + } + + stack.push(i); + } + + return { x: maxX, y: maxH, h: maxH, w: maxW }; +}; + +const largestRectangle = (matrix: boolean[][]) : Rectangle | undefined => { + let result: Rectangle & { area: number } = { w: -1, h: -1, x: 0, y: 0, area: -1 }; + + let histogram = []; + for(const _ of matrix[0]) { histogram.push(0); } + + for(let row = 0; row < matrix.length; row++) { + for(let column = 0; column < matrix[row].length; column++) { + if(matrix[row][column]) { + histogram[column] += 1; + } else { + histogram[column] = 0; + } + } + + const rectangle = largestRectangleInHistogram(histogram); + const area = rectangle.w * rectangle.h; + if(area > result.area) { + result = { + area, + w: rectangle.w, + h: rectangle.h, + x: rectangle.x, + y: row - rectangle.y + 1 + }; + } + } + + return result.area === -1 ? undefined : result; +} + +/* Numbers given in em units, its a 16:9 ratio */ +const kVideoMinWidth = 17.77778; +const kVideoMinHeight = 9; + +const kGridScaleFactor = 16; + +class SpotlightGridController extends React.PureComponent<{ fontSize: number }, { layout: Layout[] }> { + private currentLayout: Layout[] = []; + private columnCount: number; + private rowCount: number; + + constructor(props) { + super(props); + + this.state = { layout: [] }; + } + + render() { + return ( + + {events => ( + + {containerDimensions => { + this.columnCount = Math.floor(Math.max(containerDimensions.width / (kVideoMinWidth * this.props.fontSize), 1)) * kGridScaleFactor; + this.rowCount = Math.floor(Math.max(containerDimensions.height / (kVideoMinHeight * this.props.fontSize), 1)) * kGridScaleFactor; + + this.currentLayout.forEach(entry => { + entry.minW = kGridScaleFactor; + entry.minH = kGridScaleFactor; + }); + + //error("Column count: %o, Row count: %o, Layout: %o", this.columnCount, this.rowCount, this.state.layout); + return ( +
+ { + this.currentLayout = newLayout; + events.fire("action_toggle_spotlight", { + videoIds: newLayout.filter(entry => entry.x >= this.columnCount || entry.y >= this.rowCount).map(entry => entry.i), + enabled: false, + expend: false + }); + }} + + layout={this.state.layout} + + margin={[this.props.fontSize * .5, this.props.fontSize * .5]} + autoSize={false} + compactType={"vertical"} + + resizeHandles={["ne", "nw", "se", "sw"]} + > + {this.state.layout.map(entry => ( +
+ + + +
+ ))} +
+
+ ); + }} +
+ )} +
+ ); + } + + updateBoxes(keys: string[]) { + const deletedKeys = this.currentLayout.filter(entry => keys.indexOf(entry.i) === -1); + const newKeys = keys.filter(entry => this.currentLayout.findIndex(el => el.i === entry) === -1); + + deletedKeys.forEach(key => this.removeBox(key.i)); + newKeys.forEach(key => this.addBox(key)); + } + + addBox(key: string) { + const newLayout = _.cloneDeep(this.currentLayout); + + let newTile: Layout = { i: key, w: kGridScaleFactor, h: kGridScaleFactor, x: 0, y: 0 }; + + calculateNewTile: + if(newLayout.length === 0) { + /* Trivial case */ + newTile.x = 0; + newTile.y = 0; + newTile.w = this.columnCount; + newTile.h = this.rowCount; + } else { + /* 1. try to find an empty spot */ + { + let matrix = []; + for(let row = 0; row < this.rowCount; row++) { + let col = []; + + columnLoop: + for(let column = 0; column < this.columnCount; column++) { + for(const entry of newLayout) { + if(entry.x > column || column >= entry.x + entry.w) { + continue; + } + + if(entry.y > row || row >= entry.y + entry.h) { + continue; + } + + col.push(false); + continue columnLoop; + } + + col.push(true); + } + + matrix.push(col); + } + + const rectangle = largestRectangle(matrix); + if(rectangle && rectangle.w >= Math.floor(kGridScaleFactor / 2) && rectangle.h >= Math.floor(kGridScaleFactor / 2)) { + /* TODO: Try to find neighbors which have the same border length and see if they've space on the opposite site */ + + newTile.x = rectangle.x; + newTile.y = rectangle.y; + newTile.w = rectangle.w; + newTile.h = rectangle.h; + break calculateNewTile; + } + } + + /* 2. No spot found. Break up a big tile into peaces */ + { + let biggest: Layout = newLayout[0]; + for(const entry of newLayout) { + if(entry.w * entry.h > biggest.w * biggest.h) { + biggest = entry; + } + } + + if(biggest.h / kVideoMinWidth * kVideoMinHeight > biggest.w) { + /* split it by height */ + newTile.h = biggest.h; + biggest.h = Math.floor(biggest.h / 2); + newTile.h -= biggest.h; + + newTile.w = biggest.w; + + newTile.x = biggest.x; + newTile.y = biggest.y + biggest.h; + } else { + /* split it by width */ + newTile.w = biggest.w; + biggest.w = Math.floor(biggest.w / 2); + newTile.w -= biggest.w; + + newTile.h = biggest.h; + + newTile.x = biggest.x + biggest.w; + newTile.y = biggest.y; + } + } + } + + newLayout.push(newTile); + this.currentLayout = newLayout; + this.setState({ layout: newLayout }); + } + + removeBox(key: string) { + const newLayout = _.cloneDeep(this.currentLayout); + const index = newLayout.findIndex(entry => entry.i === key); + if(index === -1) { + return; + } + + const [ removedEntry ] = newLayout.splice(index, 1); + for(const entry of newLayout) { + if(removedEntry.h === entry.h && removedEntry.y === entry.y) { + if(removedEntry.x === entry.x + entry.w) { + entry.w += removedEntry.w; + } else if(removedEntry.x + removedEntry.w === entry.x) { + entry.x -= removedEntry.w; + entry.w += removedEntry.w; + } + } else if(removedEntry.w === entry.w && removedEntry.x === entry.x) { + if(removedEntry.y === entry.y + entry.h) { + entry.h += removedEntry.h; + } else if(removedEntry.y + removedEntry.h === entry.y) { + entry.y -= removedEntry.h; + entry.h += removedEntry.h; + } + } + } + + this.currentLayout = newLayout; + this.setState({ layout: newLayout }); + } +} + +const SpotlightGrid = (props: { fontSize: number }) => { + const refSpotlight = useRef(); + + const events = useContext(RendererVideoEventContext); + events.reactUse("notify_spotlight", event => refSpotlight.current?.updateBoxes(event.videoId), undefined, []); + useMemo(() => events.fire("query_spotlight"), []); + + return ( + + ); +}; + +export const Spotlight = () => { + const mode = useGlobalSetting(Settings.KEY_VIDEO_SPOTLIGHT_MODE); + switch (mode) { + case 1: + return ( + + {fontSize => } + + ); + + case 0: + default: + return ; + } +}; \ No newline at end of file diff --git a/shared/js/ui/react-elements/ErrorBoundary.tsx b/shared/js/ui/react-elements/ErrorBoundary.tsx index e3022f7f..73e50890 100644 --- a/shared/js/ui/react-elements/ErrorBoundary.tsx +++ b/shared/js/ui/react-elements/ErrorBoundary.tsx @@ -6,7 +6,7 @@ interface ErrorBoundaryState { errorOccurred: boolean } -export class ErrorBoundary extends React.Component<{}, ErrorBoundaryState> { +export class ErrorBoundary extends React.PureComponent<{}, ErrorBoundaryState> { constructor(props) { super(props); diff --git a/shared/js/ui/react-elements/FontSize.tsx b/shared/js/ui/react-elements/FontSize.tsx new file mode 100644 index 00000000..c815be33 --- /dev/null +++ b/shared/js/ui/react-elements/FontSize.tsx @@ -0,0 +1,39 @@ +import * as React from "react"; +import {CSSProperties, useEffect, useRef, useState} from "react"; +import ResizeObserver from "resize-observer-polyfill"; + +const SpanCssProperties: CSSProperties = { + position: "absolute", + fontSize: "inherit", + top: 0, + left: 0, + width: "1em", + height: 1, + translate: "none", + transition: "none", + transform: "none" +}; + +export const FontSizeObserver = React.memo((props: { children: (fontSize: number) => React.ReactNode | React.ReactNode[] }) => { + const refContainer = useRef(); + const [ fontSize, setFontSize ] = useState(() => { + return parseFloat(window.getComputedStyle(document.body, null).getPropertyValue('font-size')); + }); + + useEffect(() => { + const resizeObserver = new ResizeObserver(entries => { + const entry = entries.last(); + setFontSize(entry.contentRect.width); + }); + + resizeObserver.observe(refContainer.current); + return () => resizeObserver.disconnect(); + }) + + return ( + +   + {props.children(fontSize)} + + ) +}); \ No newline at end of file diff --git a/web/app/audio/Recorder.ts b/web/app/audio/Recorder.ts index b5de313d..71b2752a 100644 --- a/web/app/audio/Recorder.ts +++ b/web/app/audio/Recorder.ts @@ -11,7 +11,6 @@ import { LevelMeter, NodeInputConsumer } from "tc-shared/voice/RecorderBase"; -import * as log from "tc-shared/log"; import {LogCategory, logDebug, logWarn} from "tc-shared/log"; import * as aplayer from "./player"; import {JAbstractFilter, JStateFilter, JThresholdFilter} from "./RecorderFilter"; diff --git a/web/app/audio/sounds.ts b/web/app/audio/sounds.ts index daf95807..656c6ccb 100644 --- a/web/app/audio/sounds.ts +++ b/web/app/audio/sounds.ts @@ -1,5 +1,4 @@ import {LogCategory, logError, logWarn} from "tc-shared/log"; -import * as log from "tc-shared/log"; import {SoundFile} from "tc-shared/sound/Sounds"; import * as aplayer from "./player"; import { tr } from "tc-shared/i18n/localize"; From 7f6af3c30480b1718de5848d2c93dd43b4165a1b Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Fri, 12 Mar 2021 18:12:23 +0100 Subject: [PATCH 005/128] Fixed some minor permission related ui issues --- ChangeLog.md | 2 + shared/js/ui/modal/ModalGroupCreate.tsx | 4 +- .../permission/ModalPermissionEditor.tsx | 78 ++++++++++--------- shared/js/ui/modal/permission/TabHandler.tsx | 18 ++--- 4 files changed, 55 insertions(+), 47 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 1e6c8bed..126b5e5b 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -2,6 +2,8 @@ * **12.03.21** - Added a new video spotlight mode which allows showing multiple videos at the same time as well as dragging and resizing them + - Fixed a minor bug within the permission editor + - Fixed the creation of channel groups * **20.02.21** - Improved the browser IPC module diff --git a/shared/js/ui/modal/ModalGroupCreate.tsx b/shared/js/ui/modal/ModalGroupCreate.tsx index c4254181..01089892 100644 --- a/shared/js/ui/modal/ModalGroupCreate.tsx +++ b/shared/js/ui/modal/ModalGroupCreate.tsx @@ -328,13 +328,13 @@ function initializeGroupCreateController(connection: ConnectionHandler, events: let promise: Promise; if(event.source <= 0) { /* real group create */ - promise = connection.serverConnection.send_command("servergroupadd", { + promise = connection.serverConnection.send_command(target + "groupadd", { name: event.name, type: event.target === "query" ? 2 : event.target === "template" ? 0 : 1 }); } else { /* group copy */ - promise = connection.serverConnection.send_command("servergroupcopy", { + promise = connection.serverConnection.send_command(target + "groupcopy", { ssgid: event.source, name: event.name, type: event.target === "query" ? 2 : event.target === "template" ? 0 : 1 diff --git a/shared/js/ui/modal/permission/ModalPermissionEditor.tsx b/shared/js/ui/modal/permission/ModalPermissionEditor.tsx index 0c89e753..935874da 100644 --- a/shared/js/ui/modal/permission/ModalPermissionEditor.tsx +++ b/shared/js/ui/modal/permission/ModalPermissionEditor.tsx @@ -104,7 +104,7 @@ export interface PermissionModalEvents { } action_set_permission_editor_subject: { - mode: PermissionEditorSubject; + mode: PermissionEditorSubject | undefined; groupId?: number; channelId?: number; @@ -160,42 +160,27 @@ export interface PermissionModalEvents { query_groups: { target: "server" | "channel", }, - query_groups_result: { - target: "server" | "channel", - groups: GroupProperties[] - }, query_group_clients: { id: number }, - query_group_clients_result: { - id: number, - status: "success" | "error" | "no-permissions", - error?: string; - clients?: { - name: string; - databaseId: number; - uniqueId: string; - }[] - }, - query_channels: {}, - query_channels_result: { - channels: ChannelInfo[] - } - - query_client_permissions: {}, /* will cause the notify_client_permissions */ + query_client_permissions: {}, query_client_info: { client: number | string; /* client database id or unique id */ }, - query_client_info_result: { + + + notify_channels: { + channels: ChannelInfo[] + }, + notify_client_info: { client: number | string; state: "success" | "error" | "no-such-client" | "no-permission"; error?: string; info?: { name: string, uniqueId: string, databaseId: number }, failedPermission?: string; - } - + }, notify_group_updated: { target: "server" | "channel"; id: number; @@ -210,8 +195,21 @@ export interface PermissionModalEvents { target: "server" | "channel"; groups: number[] }, - - notify_groups_reset: {} + notify_group_clients: { + id: number, + status: "success" | "error" | "no-permissions", + error?: string; + clients?: { + name: string; + databaseId: number; + uniqueId: string; + }[] + }, + notify_groups_reset: {}, + notify_groups: { + target: "server" | "channel", + groups: GroupProperties[] + }, notify_client_permissions: { permissionModifyPower: number; @@ -417,7 +415,7 @@ const stringifyError = error => { function initializePermissionModalController(connection: ConnectionHandler, events: Registry) { events.on("query_groups", event => { const groups = event.target === "server" ? connection.groups.serverGroups : connection.groups.channelGroups; - events.fire_react("query_groups_result", { + events.fire_react("notify_groups", { target: event.target, groups: groups.map(group => { return { id: group.id, @@ -613,6 +611,14 @@ function initializePermissionModalController(connection: ConnectionHandler, even clientPermissionList: connection.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_CLIENT_PERMISSION_LIST).granted(1), clientChannelPermissionList: connection.permissions.neededPermission(PermissionType.B_VIRTUALSERVER_CHANNELCLIENT_PERMISSION_LIST).granted(1), }); + + /* Update the permission subject (we may now have or not have any more the permissions to edit him) */ + events.fire("action_set_permission_editor_subject", { + channelId: undefined, + clientDatabaseId: undefined, + groupId: undefined, + mode: undefined + }); }; events.on("query_client_permissions", () => sendClientPermissions()); @@ -621,7 +627,7 @@ function initializePermissionModalController(connection: ConnectionHandler, even events.on("query_group_clients", event => { connection.serverConnection.command_helper.requestClientsByServerGroup(event.id).then(clients => { - events.fire("query_group_clients_result", { + events.fire("notify_group_clients", { id: event.id, status: "success", clients: clients.map(e => { return { name: e.client_nickname, @@ -632,12 +638,12 @@ function initializePermissionModalController(connection: ConnectionHandler, even }); }).catch(error => { if (error instanceof CommandResult && error.id === ErrorCode.SERVER_INSUFFICIENT_PERMISSIONS) { - events.fire("query_group_clients_result", {id: event.id, status: "no-permissions"}); + events.fire("notify_group_clients", {id: event.id, status: "no-permissions"}); return; } logWarn(LogCategory.PERMISSIONS, tr("Failed to request server group client list: %o"), error); - events.fire("query_group_clients_result", {id: event.id, status: "error", error: stringifyError(error)}); + events.fire("notify_group_clients", {id: event.id, status: "error", error: stringifyError(error)}); }); }); @@ -713,7 +719,7 @@ function initializePermissionModalController(connection: ConnectionHandler, even })); events.on("query_channels", () => { - events.fire_react("query_channels_result", { + events.fire_react("notify_channels", { channels: connection.channelTree.channelsOrdered().map(e => { return { id: e.channelId, @@ -734,13 +740,13 @@ function initializePermissionModalController(connection: ConnectionHandler, even } promise.then(result => { if (result.length === 0) { - events.fire("query_client_info_result", { + events.fire("notify_client_info", { client: event.client, state: "no-such-client" }); return; } - events.fire("query_client_info_result", { + events.fire("notify_client_info", { client: event.client, state: "success", info: { @@ -751,7 +757,7 @@ function initializePermissionModalController(connection: ConnectionHandler, even }); }).catch(error => { if (error instanceof CommandResult) { - events.fire("query_client_info_result", { + events.fire("notify_client_info", { client: event.client, state: "no-permission", failedPermission: connection.permissions.resolveInfo(parseInt(error.json["failed_permid"]))?.name || tr("unknwon") @@ -760,7 +766,7 @@ function initializePermissionModalController(connection: ConnectionHandler, even } logWarn(LogCategory.PERMISSIONS, tr("Failed to query client info for %o: %o"), event.client, error); - events.fire("query_client_info_result", { + events.fire("notify_client_info", { client: event.client, state: "error", error: stringifyError(error) @@ -849,7 +855,7 @@ function initializePermissionEditor(connection: ConnectionHandler, modalEvents: clientDatabaseId = typeof event.clientDatabaseId === "number" ? event.clientDatabaseId : clientDatabaseId; groupId = typeof event.groupId === "number" ? event.groupId : groupId; - mode = event.mode; + mode = event.mode || mode; let editorMode: "unset" | "normal" = "unset"; switch (mode) { diff --git a/shared/js/ui/modal/permission/TabHandler.tsx b/shared/js/ui/modal/permission/TabHandler.tsx index d02302ef..decd8fea 100644 --- a/shared/js/ui/modal/permission/TabHandler.tsx +++ b/shared/js/ui/modal/permission/TabHandler.tsx @@ -323,8 +323,8 @@ class GroupsList extends React.Component<{ connection: ConnectionHandler, events this.groups.splice(0, this.groups.length); } - @EventHandler("query_groups_result") - private handleQueryResult(event: PermissionModalEvents["query_groups_result"]) { + @EventHandler("notify_groups") + private handleQueryResult(event: PermissionModalEvents["notify_groups"]) { if (event.target !== this.props.target) return; @@ -585,8 +585,8 @@ class ServerClientList extends React.Component<{ connection: ConnectionHandler, this.setState({state: "loading"}); } - @EventHandler("query_group_clients_result") - private handleQueryClientsResult(event: PermissionModalEvents["query_group_clients_result"]) { + @EventHandler("notify_group_clients") + private handleQueryClientsResult(event: PermissionModalEvents["notify_group_clients"]) { if (event.id !== this.state.selectedGroupId) return; @@ -642,8 +642,8 @@ class ServerClientList extends React.Component<{ connection: ConnectionHandler, }); } - @EventHandler("query_groups_result") - private handleQueryResult(event: PermissionModalEvents["query_groups_result"]) { + @EventHandler("notify_groups") + private handleQueryResult(event: PermissionModalEvents["notify_groups"]) { if (event.target !== "server") return; @@ -862,8 +862,8 @@ class ChannelList extends React.Component<{ connection: ConnectionHandler, event this.props.events.fire("query_channels"); } - @EventHandler("query_channels_result") - private handleQueryChannelsResult(event: PermissionModalEvents["query_channels_result"]) { + @EventHandler("notify_channels") + private handleQueryChannelsResult(event: PermissionModalEvents["notify_channels"]) { this.channels = event.channels.slice(0); if (this.channels.length > 0 && this.channels.findIndex(e => e.id === this.state.selectedChanelId) === -1) this.setState({selectedChanelId: this.channels[0].id}); @@ -988,7 +988,7 @@ const ClientSelect = (props: { events: Registry, tabTarge props.events.fire("action_set_permission_editor_subject", {mode: props.tabTarget, clientDatabaseId: 0}); }); - props.events.reactUse("query_client_info_result", event => { + props.events.reactUse("notify_client_info", event => { if (event.client !== clientIdentifier) return; From 3e42c7027f6ed91eeba98b057fce092c04771ffe Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Fri, 12 Mar 2021 18:24:43 +0100 Subject: [PATCH 006/128] Properly parse empty setting value for booleans and integers --- shared/js/settings.ts | 24 ++++++++++++++++++------ shared/js/ui/react-elements/Helper.ts | 7 ++++--- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/shared/js/settings.ts b/shared/js/settings.ts index 0b8f6fb5..8e078e67 100644 --- a/shared/js/settings.ts +++ b/shared/js/settings.ts @@ -80,19 +80,31 @@ function resolveKey( ) : ValueType | DefaultType { let value = resolver(key.key); - if(typeof value === "string") { - return decodeValueFromString(value, key.valueType); + const keys = [key.key]; + if(Array.isArray(key.fallbackKeys)) { + keys.push(...key.fallbackKeys); } - /* trying fallback values */ - for(const fallback of key.fallbackKeys || []) { - value = resolver(fallback); + for(const resolveKey of keys) { + value = resolver(resolveKey); if(typeof value !== "string") { continue; } + switch (key.valueType) { + case "number": + case "boolean": + if(value.length === 0) { + continue; + } + break; + + default: + break; + } + if(key.fallbackImports) { - const fallbackValueImporter = key.fallbackImports[fallback]; + const fallbackValueImporter = key.fallbackImports[resolveKey]; if(fallbackValueImporter) { return fallbackValueImporter(value); } diff --git a/shared/js/ui/react-elements/Helper.ts b/shared/js/ui/react-elements/Helper.ts index efbfc54a..10c17518 100644 --- a/shared/js/ui/react-elements/Helper.ts +++ b/shared/js/ui/react-elements/Helper.ts @@ -34,10 +34,11 @@ export function joinClassList(...classes: any[]) : string { return classes.filter(value => typeof value === "string" && value.length > 0).join(" "); } -export function useGlobalSetting(key: RegistryKey, defaultValue: DV) : V | DV; export function useGlobalSetting(key: ValuedRegistryKey, defaultValue?: V) : V; -export function useGlobalSetting(key: RegistryKey, defaultValue: DV) : V | DV { - const [ value, setValue ] = useState(settings.getValue(key, defaultValue)); +export function useGlobalSetting(key: RegistryKey, defaultValue: DV) : V | DV; + +export function useGlobalSetting(key, defaultValue) { + const [ value, setValue ] = useState(arguments.length > 1 ? settings.getValue(key, defaultValue) : settings.getValue(key)); useEffect(() => settings.globalChangeListener(key, value => setValue(value)), []); return value; From 82cbfd9e4579d068e6370046cd051eff91d04410 Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Sat, 13 Mar 2021 20:10:00 +0100 Subject: [PATCH 007/128] fixed some minor bugs --- shared/js/ui/utils/Variable.ts | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/shared/js/ui/utils/Variable.ts b/shared/js/ui/utils/Variable.ts index 656e740c..3b37075c 100644 --- a/shared/js/ui/utils/Variable.ts +++ b/shared/js/ui/utils/Variable.ts @@ -1,5 +1,7 @@ import {useEffect, useState} from "react"; import * as _ from "lodash"; +import {ReadonlyKeys, WritableKeys} from "tc-shared/proto"; +import {useDependentState} from "tc-shared/ui/react-elements/Helper"; /* * To deliver optimized performance, we only promisify the values we need. @@ -10,18 +12,6 @@ import * as _ from "lodash"; export type UiVariable = Transferable | undefined | null | number | string | object; export type UiVariableMap = { [key: string]: any }; //UiVariable | Readonly -type IfEquals = - (() => T extends X ? 1 : 2) extends - (() => T extends Y ? 1 : 2) ? A : B; - -type WritableKeys = { - [P in keyof T]-?: IfEquals<{ [Q in P]: T[P] }, { -readonly [Q in P]: T[P] }, P, never> -}[keyof T]; - -type ReadonlyKeys = { - [P in keyof T]: IfEquals<{ [Q in P]: T[P] }, { -readonly [Q in P]: T[P] }, never, P> -}[keyof T]; - export type ReadonlyVariables = Pick> export type WriteableVariables = Pick> @@ -247,7 +237,7 @@ export abstract class UiVariableConsumer { const haveDefaultValue = arguments.length >= 3; const cacheEntry = this.getOrCreateVariable(variable as string, customData); - const [ localValue, setLocalValue ] = useState(() => { + const [ localValue, setLocalValue ] = useDependentState(() => { /* Variable constructor */ cacheEntry.useCount++; @@ -266,7 +256,7 @@ export abstract class UiVariableConsumer { status: "unset" }; } - }); + }, [ variable, customData ]); const [, setRemoteVersion ] = useState(0); @@ -274,7 +264,7 @@ export abstract class UiVariableConsumer { /* Initial rendered */ if(cacheEntry.status === "loaded" && localValue.status !== "set") { /* Update the local value to the current state */ - setLocalValue(cacheEntry.currentValue); + setLocalValue({ status: "set", value: cacheEntry.currentValue }); } let listener; @@ -291,7 +281,7 @@ export abstract class UiVariableConsumer { cacheEntry.updateListener.remove(listener); this.derefVariable(cacheEntry); }; - }, []); + }, [ variable, customData ]); if(cacheEntry.status === "loading") { return { @@ -379,7 +369,7 @@ export abstract class UiVariableConsumer { cacheEntry.updateListener.remove(listener); this.derefVariable(cacheEntry); }; - }, []); + }, [ variable, customData ]); if(arguments.length >= 3) { return cacheEntry.status === "loaded" ? cacheEntry.currentValue : defaultValue; From 439ba5488e324769628b805061a618225fd693a2 Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Sun, 14 Mar 2021 12:25:02 +0100 Subject: [PATCH 008/128] Fixed some modal flaws (will break because of ts inter op which hasn't been commited) --- .../ui/react-elements/external-modal/PopoutEntrypoint.ts | 2 +- shared/js/ui/react-elements/internal-modal/Controller.ts | 3 +-- shared/js/ui/react-elements/internal-modal/Modal.scss | 2 ++ shared/js/ui/react-elements/internal-modal/Renderer.tsx | 2 +- shared/js/ui/react-elements/modal/Definitions.ts | 5 +++++ shared/js/ui/react-elements/modal/Registry.ts | 8 +++++++- shared/js/ui/react-elements/modal/index.ts | 2 +- 7 files changed, 18 insertions(+), 6 deletions(-) diff --git a/shared/js/ui/react-elements/external-modal/PopoutEntrypoint.ts b/shared/js/ui/react-elements/external-modal/PopoutEntrypoint.ts index 07955647..c05b9708 100644 --- a/shared/js/ui/react-elements/external-modal/PopoutEntrypoint.ts +++ b/shared/js/ui/react-elements/external-modal/PopoutEntrypoint.ts @@ -75,7 +75,7 @@ loader.register_task(Stage.JAVASCRIPT_INITIALIZING, { throw "missing handler"; } - modalClass = await registeredModal.classLoader(); + modalClass = (await registeredModal.classLoader()).default; } catch(error) { loader.critical_error("Failed to load modal", "Lookup the console for more detail"); console.error("Failed to load modal %s: %o", modalTarget, error); diff --git a/shared/js/ui/react-elements/internal-modal/Controller.ts b/shared/js/ui/react-elements/internal-modal/Controller.ts index 7d1c47ee..206f5e21 100644 --- a/shared/js/ui/react-elements/internal-modal/Controller.ts +++ b/shared/js/ui/react-elements/internal-modal/Controller.ts @@ -50,8 +50,7 @@ export class InternalModalController implements ModalController { this.refModal = React.createRef(); this.domElement = document.createElement("div"); - this.modalInstance = new (await this.modalType.classLoader())(...this.constructorArguments); - console.error(this.modalInstance); + this.modalInstance = new (await this.modalType.classLoader()).default(...this.constructorArguments); const element = React.createElement(InternalModalRenderer, { ref: this.refModal, modal: this.modalInstance, diff --git a/shared/js/ui/react-elements/internal-modal/Modal.scss b/shared/js/ui/react-elements/internal-modal/Modal.scss index aaaa3537..0cccb4d4 100644 --- a/shared/js/ui/react-elements/internal-modal/Modal.scss +++ b/shared/js/ui/react-elements/internal-modal/Modal.scss @@ -141,6 +141,7 @@ html:root { justify-content: stretch; padding: .25em; + @include user-select(none); .icon, .button { flex-grow: 0; @@ -155,6 +156,7 @@ html:root { border-radius: .2em; cursor: pointer; + display: flex; -webkit-app-region: no-drag; pointer-events: all; diff --git a/shared/js/ui/react-elements/internal-modal/Renderer.tsx b/shared/js/ui/react-elements/internal-modal/Renderer.tsx index 59a882cf..c83a464d 100644 --- a/shared/js/ui/react-elements/internal-modal/Renderer.tsx +++ b/shared/js/ui/react-elements/internal-modal/Renderer.tsx @@ -26,7 +26,7 @@ export const InternalModalContentRenderer = React.memo((props: {
- {tr("Modal + {tr("Modal
diff --git a/shared/js/ui/react-elements/modal/Definitions.ts b/shared/js/ui/react-elements/modal/Definitions.ts index f5336015..892b9e9e 100644 --- a/shared/js/ui/react-elements/modal/Definitions.ts +++ b/shared/js/ui/react-elements/modal/Definitions.ts @@ -8,6 +8,7 @@ import {InviteUiEvents, InviteUiVariables} from "tc-shared/ui/modal/invite/Defin import {ReactElement} from "react"; import * as React from "react"; import {IpcVariableDescriptor} from "tc-shared/ui/utils/IpcVariable"; +import {ModalBookmarkEvents, ModalBookmarkVariables} from "tc-shared/ui/modal/bookmarks/Definitions"; export type ModalType = "error" | "warning" | "info" | "none"; export type ModalRenderType = "page" | "dialog"; @@ -132,5 +133,9 @@ export interface ModalConstructorArguments { /* events */ IpcRegistryDescription, /* variables */ IpcVariableDescriptor, /* serverName */ string + ], + "modal-bookmarks": [ + /* events */ IpcRegistryDescription, + /* variables */ IpcVariableDescriptor, ] } \ No newline at end of file diff --git a/shared/js/ui/react-elements/modal/Registry.ts b/shared/js/ui/react-elements/modal/Registry.ts index 833294ed..1f442669 100644 --- a/shared/js/ui/react-elements/modal/Registry.ts +++ b/shared/js/ui/react-elements/modal/Registry.ts @@ -3,7 +3,7 @@ import {ModalConstructorArguments} from "tc-shared/ui/react-elements/modal/Defin export interface RegisteredModal { modalId: T, - classLoader: () => Promise AbstractModal>, + classLoader: () => Promise<{ default: new (...args: ModalConstructorArguments[T]) => AbstractModal }>, popoutSupported: boolean } @@ -73,3 +73,9 @@ registerModal({ popoutSupported: true }); +registerModal({ + modalId: "modal-bookmarks", + classLoader: async () => await import("tc-shared/ui/modal/bookmarks/Renderer"), + popoutSupported: true +}); + diff --git a/shared/js/ui/react-elements/modal/index.ts b/shared/js/ui/react-elements/modal/index.ts index c9dec036..57b85908 100644 --- a/shared/js/ui/react-elements/modal/index.ts +++ b/shared/js/ui/react-elements/modal/index.ts @@ -22,7 +22,7 @@ export function spawnReactModal(modalClass: ne return new InternalModalController({ popoutSupported: false, modalId: "__internal__unregistered", - classLoader: async () => modalClass + classLoader: async () => ({ default: modalClass }) }, args); } From 6ff210be079b1efe54584efbec51d0663cb3ac4d Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Sun, 14 Mar 2021 19:39:08 +0100 Subject: [PATCH 009/128] Added the new bookmark system and updated the bookmark UI --- ChangeLog.md | 18 +- file.ts | 2 +- package-lock.json | 88 ++ package.json | 2 + shared/css/load-css.tsx | 1 - shared/css/static/mixin.scss | 12 +- shared/css/static/modal-bookmarks.scss | 498 ----------- shared/html/templates.html | 167 ---- .../img/client-icons/bookmark_edit_name.svg | 4 + shared/js/bookmarks.ts | 749 ++++++++++------ shared/js/connection/HandshakeHandler.ts | 2 - shared/js/connectionlog/History.ts | 16 +- .../js/events/ClientGlobalControlHandler.ts | 8 +- shared/js/file/Icons.ts | 4 + shared/js/file/Utils.ts | 37 + shared/js/global.d.ts | 4 + shared/js/main.tsx | 21 +- shared/js/proto.ts | 16 +- shared/js/text/bbcode/emoji.tsx | 4 +- shared/js/text/bbcode/highlight.tsx | 2 +- shared/js/tree/Server.ts | 16 - shared/js/ui/elements/Modal.ts | 8 +- shared/js/ui/frames/HostBannerRenderer.tsx | 4 +- shared/js/ui/frames/control-bar/Button.scss | 10 +- shared/js/ui/frames/control-bar/Controller.ts | 90 +- shared/js/ui/frames/menu-bar/MainMenu.ts | 94 ++- .../js/ui/frames/video/RendererSpotlight.tsx | 2 +- shared/js/ui/jsrender.ts | 2 +- shared/js/ui/modal/ModalAvatarList.ts | 2 +- shared/js/ui/modal/ModalBanList.ts | 2 +- shared/js/ui/modal/ModalBookmarks.ts | 421 --------- shared/js/ui/modal/ModalClientInfo.ts | 2 +- shared/js/ui/modal/ModalPoke.ts | 2 +- shared/js/ui/modal/ModalServerInfo.ts | 2 +- shared/js/ui/modal/ModalSettings.tsx | 3 +- .../modal/bookmarks-add-server/Controller.ts | 5 + .../modal/bookmarks-add-server/Definitions.ts | 7 + .../modal/bookmarks-add-server/Renderer.scss | 0 .../modal/bookmarks-add-server/Renderer.tsx | 13 + shared/js/ui/modal/bookmarks/Controller.ts | 568 +++++++++++++ shared/js/ui/modal/bookmarks/Definitions.ts | 77 ++ shared/js/ui/modal/bookmarks/Renderer.scss | 670 +++++++++++++++ shared/js/ui/modal/bookmarks/Renderer.tsx | 797 ++++++++++++++++++ .../ui/modal/bookmarks/header_background.png} | Bin shared/js/ui/modal/bookmarks/serverinfo.png | Bin 0 -> 80844 bytes shared/js/ui/modal/connect/Controller.ts | 2 +- shared/js/ui/modal/connect/Renderer.scss | 11 - shared/js/ui/modal/connect/Renderer.tsx | 10 +- shared/js/ui/modal/css-editor/Renderer.tsx | 31 +- shared/js/ui/modal/invite/Renderer.tsx | 2 +- .../ui/modal/transfer/FileBrowserRenderer.tsx | 6 +- shared/js/ui/react-elements/Checkbox.scss | 5 +- shared/js/ui/react-elements/CountryIcon.scss | 10 + shared/js/ui/react-elements/CountryIcon.tsx | 15 + shared/js/ui/react-elements/InputField.tsx | 5 +- shared/js/ui/react-elements/Tooltip.scss | 5 + shared/js/ui/react-elements/Tooltip.tsx | 4 +- shared/js/ui/utils/Variable.ts | 44 +- shared/svg-sprites/client-icons.d.ts | 5 +- shared/tsconfig/tsconfig.declarations.json | 1 + shared/tsconfig/tsconfig.json | 1 + tsconfig.json | 1 + webpack.config.ts | 6 +- 63 files changed, 3078 insertions(+), 1538 deletions(-) delete mode 100644 shared/css/static/modal-bookmarks.scss create mode 100644 shared/img/client-icons/bookmark_edit_name.svg create mode 100644 shared/js/file/Utils.ts create mode 100644 shared/js/global.d.ts delete mode 100644 shared/js/ui/modal/ModalBookmarks.ts create mode 100644 shared/js/ui/modal/bookmarks-add-server/Controller.ts create mode 100644 shared/js/ui/modal/bookmarks-add-server/Definitions.ts create mode 100644 shared/js/ui/modal/bookmarks-add-server/Renderer.scss create mode 100644 shared/js/ui/modal/bookmarks-add-server/Renderer.tsx create mode 100644 shared/js/ui/modal/bookmarks/Controller.ts create mode 100644 shared/js/ui/modal/bookmarks/Definitions.ts create mode 100644 shared/js/ui/modal/bookmarks/Renderer.scss create mode 100644 shared/js/ui/modal/bookmarks/Renderer.tsx rename shared/{img/bookmark_background.png => js/ui/modal/bookmarks/header_background.png} (100%) create mode 100644 shared/js/ui/modal/bookmarks/serverinfo.png create mode 100644 shared/js/ui/react-elements/CountryIcon.scss create mode 100644 shared/js/ui/react-elements/CountryIcon.tsx diff --git a/ChangeLog.md b/ChangeLog.md index 126b5e5b..a68ba5dc 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,4 +1,12 @@ # Changelog: +* **14.03.21** + - Enchanted the bookmark system + - Added support for auto connect on startup + - Cleaned and simplified up the bookmark UI + - Added support for importing/exporting bookmarks + - Added support for duplicating bookmarks + - Adding support for default channels and passwords + * **12.03.21** - Added a new video spotlight mode which allows showing multiple videos at the same time as well as dragging and resizing them @@ -150,7 +158,7 @@ - Fixed invalid channel tree unique id assignment for the initial server entry ([#F2986](https://forum.teaspeak.de/index.php?threads/2986)) * **27.09.20** - - Middle clicking on bookmarks now directly connects in a new tab + - Middle clicking on bookmarksOld now directly connects in a new tab * **26.09.20** - Updating group prefix/suffixes when the group naming mode changes @@ -320,7 +328,7 @@ - Fixed channel tree deletions - Removed layout recalculate bottleneck on connection handler switching - Fixed empty channel tree on tab change, if the tree has some scroll offset - - Added the ability to duplicate bookmarks + - Added the ability to duplicate bookmarksOld - Fixed issue [#106](https://github.com/TeaSpeak/TeaWeb/issues/106) - Fixed issue [#90](https://github.com/TeaSpeak/TeaWeb/issues/90) @@ -350,7 +358,7 @@ * **21.04.20** - Clicking on the music bot does not longer results in the insufficient permission sound when the client has no permissions - Fixed permission editor overflow - - Fixed the bookmark edit window (bookmarks have failed to save) + - Fixed the bookmark edit window (bookmarksOld have failed to save) * **18.04.20** - Recoded the channel tree using React @@ -447,7 +455,7 @@ - Improved the server info modal experience (Correctly showing no permissions) - Improved "About" modal overflow behaviour - Allow the client to use the scroll bar without closing the modal within modals - - Improved bookmarks modal for smaller devices + - Improved bookmarksOld modal for smaller devices - Fixed invalid white space representation * **10.12.19** @@ -637,7 +645,7 @@ - Added query account management (since server 1.2.32b) * **18.12.18** - - Added bookmarks and bookmarks management + - Added bookmarksOld and bookmarksOld management - Added query user visibility button and creation (Query management will follow soon) - Fixed overflow within the group assignment dialog diff --git a/file.ts b/file.ts index a2867ad6..03143b7a 100644 --- a/file.ts +++ b/file.ts @@ -40,7 +40,7 @@ const APP_FILE_LIST_SHARED_SOURCE: ProjectResource[] = [ }, { /* javascript files as manifest.json */ "type": "js", - "search-pattern": /.*\.(js|json|svg)$/, + "search-pattern": /.*\.(js|json|svg|png)$/, "build-target": "dev|rel", "path": "js/", diff --git a/package-lock.json b/package-lock.json index be69e8a7..6809714d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8912,6 +8912,11 @@ } } }, + "jsonschema": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.0.tgz", + "integrity": "sha512-/YgW6pRMr6M7C+4o8kS+B/2myEpHCrxO4PEWnqJNBFMjn7EWXqlQ4tGwL6xTHeRplwuZmcAncdvfOad1nT2yMw==" + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -14431,6 +14436,89 @@ } } }, + "url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "@types/json-schema": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", + "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "mime-db": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", + "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.29", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", + "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", + "dev": true, + "requires": { + "mime-db": "1.46.0" + } + }, + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, "url-parse-lax": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", diff --git a/package.json b/package.json index 4c8ac6e7..54275896 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "ts-loader": "^6.2.2", "tsd": "^0.13.1", "typescript": "^3.7.0", + "url-loader": "^4.1.1", "wabt": "^1.0.13", "webpack": "^4.42.1", "webpack-bundle-analyzer": "^3.6.1", @@ -101,6 +102,7 @@ "highlight.js": "^10.1.1", "ip-regex": "^4.2.0", "jquery": "^3.5.1", + "jsonschema": "^1.4.0", "jsrender": "^1.0.7", "moment": "^2.24.0", "react": "^16.13.1", diff --git a/shared/css/load-css.tsx b/shared/css/load-css.tsx index e691b1cd..5d600bb8 100644 --- a/shared/css/load-css.tsx +++ b/shared/css/load-css.tsx @@ -14,7 +14,6 @@ import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/m import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-avatar.scss" import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-banclient.scss" import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-banlist.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-bookmarks.scss" import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-channelinfo.scss" import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-clientinfo.scss" import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-connect.scss" diff --git a/shared/css/static/mixin.scss b/shared/css/static/mixin.scss index 0199d98b..0da9d333 100644 --- a/shared/css/static/mixin.scss +++ b/shared/css/static/mixin.scss @@ -66,29 +66,29 @@ user-select: $mode; } -@mixin chat-scrollbar() { +@mixin chat-scrollbar($width: .5em) { & { /* for moz */ scrollbar-color: #353535 #555; - scrollbarWidth: .5em; + scrollbarWidth: $width; } &::-webkit-scrollbar-track { - border-radius: .25em; + border-radius: $width / 2; background-color: transparent; cursor: pointer; } &::-webkit-scrollbar { - width: .5em; - height: .5em; + width: $width; + height: $width; background-color: transparent; cursor: pointer; } &::-webkit-scrollbar-thumb { - border-radius: .25em; + border-radius: $width / 2; background-color: #555; } diff --git a/shared/css/static/modal-bookmarks.scss b/shared/css/static/modal-bookmarks.scss deleted file mode 100644 index fc341e00..00000000 --- a/shared/css/static/modal-bookmarks.scss +++ /dev/null @@ -1,498 +0,0 @@ -@import "properties"; -@import "mixin"; - -.modal .modal-bookmark-create { - .property { - margin-top: 5px; - - display: flex; - flex-direction: row; - justify-content: stretch; - - .key { - flex-grow: 0; - flex-shrink: 0; - - width: 150px; - } - - select, input { - flex-grow: 1; - flex-shrink: 1; - } - } - - .buttons { - text-align: right; - - button { - min-width: 200px; - } - - margin-bottom: 5px; - } -} - -.modal-body.modal-bookmarks { - padding: 0!important; - - display: flex!important; - flex-direction: row!important; - justify-content: stretch!important; - - min-width: 30em!important; - height: 45em; - width: 80em; - - @include user-select(none); - - .container-tooltip { - flex-shrink: 0; - flex-grow: 0; - - position: relative; - width: 1.6em; - margin-left: .5em; - font-size: .9em; - - display: flex; - flex-direction: column; - justify-content: center; - - img { - height: 1em; - width: 1em; - - align-self: center; - font-size: 1.2em; - } - - .tooltip { - display: none; - } - } - - .input-boxed { - height: 2em; - } - - .left { - min-width: 12em; - width: 30%; - - flex-grow: 1; - flex-shrink: 1; - - padding: .5em; - background-color: #212125; - - display: flex; - flex-direction: column; - justify-content: stretch; - - .title { - flex-shrink: 0; - flex-grow: 0; - - text-align: center; - - font-size: 1.5em; - color: #557edc; - text-transform: uppercase; - - @include text-dotdotdot(); - } - - .container-bookmarks { - flex-shrink: 1; - flex-grow: 1; - - min-height: 6em; - - display: flex; - flex-direction: column; - justify-content: stretch; - - overflow: auto; - @include chat-scrollbar-vertical(); - @include chat-scrollbar-horizontal(); - - .bookmark, .directory { - flex-grow: 0; - flex-shrink: 0; - - display: flex; - flex-direction: row; - justify-content: stretch; - - border-radius: $border_radius_middle; - padding: .25em .5em; - - cursor: pointer; - - .icon-container { - flex-grow: 0; - flex-shrink: 0; - - align-self: center; - margin-right: .5em; - } - - .name { - flex-grow: 1; - flex-shrink: 1; - - min-width: 5em; - align-self: center; - - @include text-dotdotdot(); - } - - &:hover { - background-color: #2c2d2f; - } - - &.selected { - background-color: #1a1a1b; - } - - .link { - flex-grow: 0; - flex-shrink: 0; - - position: relative; - width: 1.5em; - - $line_width: 2px; - $color: hsla(0, 0%, 35%, 1); - &:not(.hidden) { - &:before { - content: ""; - position: absolute; - - height: 2.25em; /* connect with the previous one */ - width: .75em; - - left: .5em; /* icons have a width of 1em */ - bottom: calc(.75em - #{$line_width / 2}); - - border-left: $line_width solid $color; - } - - &.connected { - &:before { - border-bottom: $line_width solid $color; - - border-bottom-left-radius: .3em; - } - } - } - } - } - - .link-start { - .link.connected { - &:before { - height: 1.25em; - } - } - } - - .directory { - .name { - //color: #557edc; - } - } - } - - .buttons { - flex-shrink: 0; - flex-grow: 0; - - display: flex; - flex-direction: row; - justify-content: space-between; - - padding-top: .5em; - - button { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - - &:not(:first-of-type) { - margin-left: .5em; - } - } - } - } - - .right { - min-width: 25em; - width: 30%; - - flex-grow: 1; - flex-shrink: 1; - - background-color: #2f2f35; - - display: flex; - flex-direction: column; - justify-content: flex-start; - - .header { - flex-grow: 0; - flex-shrink: 0; - - height: 10em; - - background: url('../../../img/bookmark_background.png'), url('../../img/bookmark_background.png'), url('img/bookmark_background.png') no-repeat; - - display: flex; - flex-direction: column; - justify-content: flex-end; - - padding: .5em; - - .container-name { - font-size: 2em; - color: #fcfcfc; - - @include text-dotdotdot(); - } - - .container-address { - font-size: 1.5em; - color: #fcfcfc; - - @include text-dotdotdot(); - } - } - - .container-settings { - flex-grow: 1; - flex-shrink: 1; - min-height: 10em; - - padding: .5em; - - display: flex; - flex-direction: column; - justify-content: flex-start; - - overflow-y: auto; - overflow-x: hidden; - @include chat-scrollbar-vertical(); - - .group { - padding: .5em; - - border-radius: .2em; - border: 1px solid #1f2122; - - background-color: #28292b; - - display: flex; - flex-direction: column; - justify-content: flex-start; - - > .row { - display: flex; - flex-direction: row; - justify-content: stretch; - - .key { - flex-grow: 0; - flex-shrink: 1; - - width: 15em; - min-width: 2em; - - align-self: center; - - color: #557edc; - - text-transform: uppercase; - - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - .value { - flex-grow: 1; - flex-shrink: 1; - - min-width: 2em; - - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - &:not(:first-of-type) { - margin-top: 1em; - } - } - - &:not(:first-of-type) { - margin-top: 1em; - } - - &.info { - flex-direction: row; - } - - .container-image { - flex-grow: 1; - flex-shrink: 1; - - max-width: 15em; - max-height: 9em; /* minus one padding */ - width: 15em; - - display: flex; - flex-direction: column; - justify-content: center; - - img { - object-fit: contain; - max-height: 100%; - max-width: 100%; - } - - @include transition(.25s ease-in-out); - } - - .container-properties { - flex-shrink: 1; - flex-grow: 1; - - min-width: 23em; - - display: flex; - flex-direction: column; - justify-content: flex-start; - - height: inherit; - - .row { - flex-grow: 0; - flex-shrink: 0; - - height: 1.8em; - - display: flex; - flex-direction: row; - justify-content: flex-start; - - .key { - flex-shrink: 0; - flex-grow: 0; - - color: #557edc; - text-transform: uppercase; - align-self: center; - - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - - width: 15em; - } - - .value { - color: #d6d6d7; - align-self: center; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - - &.server-region { - > div { - display: inline-block; - } - - .country { - margin-right: .25em; - } - } - - .connect-count, .connect-never { - display: inline-block; - - color: #7a3131; - } - } - } - - .container-network { - display: flex; - flex-direction: row; - justify-content: center; - - .container-button { - margin-right: 1em; - - flex-shrink: 1; - min-width: 5em; - - display: flex; - flex-direction: column; - justify-content: flex-end; - - button { - height: 2.5em; - width: 12em; - - max-width: 100%; - - @include text-dotdotdot(); - } - } - - .right { - flex-grow: 1; - } - } - } - } - } - - .buttons { - padding: .5em; - display: flex; - flex-direction: row; - justify-content: flex-start; - - .button-duplicate { - margin-right: auto; - } - - button { - flex-shrink: 1; - flex-grow: 1; - - min-width: 2em; - - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - - &:not(:first-of-type) { - margin-left: .5em; - } - } - } - } -} - - -@media all and (max-width: 50em) { - .modal-body.modal-bookmarks { - .container-image { - margin: 0!important; - max-width: 0!important; - } - } -} \ No newline at end of file diff --git a/shared/html/templates.html b/shared/html/templates.html index e15a1694..35f5d824 100644 --- a/shared/html/templates.html +++ b/shared/html/templates.html @@ -2035,173 +2035,6 @@
- -
- - - - - - - - - '; - } else { - const script = fs.readFileSync(path.join(compilation.compiler.outputPath, file)); - return ``; - } - }); - return tags.join("\n"); - } - - private async generateEntryCssTag() { - if(this.options.embedInitialCSSFile) { - const style = await util.promisify(fs.readFile)(this.options.initialCSSFile.localFile); - return `` - } else { - return `` - } - } - - apply(compiler: webpack.Compiler) { - compiler.hooks.afterEmit.tapPromise(this.constructor.name, async compilation => { - const input = await util.promisify(fs.readFile)(this.options.input); - const variables = Object.assign({}, this.options.variables); - - variables["initial_script"] = await this.generateEntryJsTag(compilation); - variables["initial_css"] = await this.generateEntryCssTag(); - - let generated = await ejs.render(input.toString(), variables, { - beautify: false, /* uglify is a bit dump and does not understands ES6 */ - context: this - }); - - if(this.options.minify) { - generated = minifier.minify(generated, { - html5: true, - - collapseWhitespace: true, - removeComments: true, - removeRedundantAttributes: true, - removeScriptTypeAttributes: true, - removeTagWhitespace: true, - minifyCSS: true, - minifyJS: true, - minifyURLs: true, - }); - } - - await util.promisify(fs.writeFile)(this.options.output, generated); - }); - - compiler.hooks.afterCompile.tapPromise(this.constructor.name, async compilation => { - const file = path.resolve(this.options.input); - if(compilation.fileDependencies.has(file)) - return; - - console.log("Adding additional watch to %s", file); - compilation.fileDependencies.add(file); - }); - } -} - -export = EJSGenerator; \ No newline at end of file diff --git a/webpack/ManifestPlugin.ts b/webpack/ManifestPlugin.ts index 6aefde2d..3d8874ab 100644 --- a/webpack/ManifestPlugin.ts +++ b/webpack/ManifestPlugin.ts @@ -1,65 +1,64 @@ import * as webpack from "webpack"; -import * as fs from "fs-extra"; import * as path from "path"; interface Options { - file?: string; - base: string; + outputFileName?: string; + context: string; } class ManifestGenerator { - private manifest_content; + private readonly options: Options; - readonly options: Options; constructor(options: Options) { - this.options = options || { base: __dirname }; + this.options = options || { context: __dirname }; } apply(compiler: webpack.Compiler) { - compiler.hooks.afterCompile.tap(this.constructor.name, compilation => { - const chunks_data = {}; + compiler.hooks.emit.tap(this.constructor.name, compilation => { + const chunkData = {}; for(const chunkGroup of compilation.chunkGroups) { const fileJs = []; const filesCss = []; const modules = []; for(const chunk of chunkGroup.chunks) { - if(!chunk.files.length) + if(!chunk.files.size) { continue; - - /* - if(chunk.files.length !== 1) { - console.error("Expected only one file per chunk but got " + chunk.files.length); - chunk.files.forEach(e => console.log(" - %s", e)); - throw "expected only one file per chunk"; } - */ for(const file of chunk.files) { const extension = path.extname(file); - if(extension === ".js") { - fileJs.push({ - hash: chunk.hash, - file: file - }); - } else if(extension === ".css") { - filesCss.push({ - hash: chunk.hash, - file: file - }); - } else if(extension === ".wasm") { - /* do nothing */ - } else { - throw "Unknown chunk file with extension " + extension; + switch (extension) { + case ".js": + fileJs.push({ + hash: chunk.hash, + file: file + }); + break; + + case ".css": + filesCss.push({ + hash: chunk.hash, + file: file + }); + break; + + case ".wasm": + break; + + default: + throw "Unknown chunk file with extension " + extension; } } - for(const module of chunk.getModules()) { - if(!module.type.startsWith("javascript/")) + for(const module of chunk.getModules() as any[]) { + if(!module.type.startsWith("javascript/")) { continue; + } - if(!module.context) + if(!module.context) { continue; + } if(module.context.startsWith("svg-sprites/")) { /* custom svg sprite handler */ @@ -71,37 +70,39 @@ class ManifestGenerator { continue; } - if(!module.resource) + if(!module.resource) { continue; + } - if(module.context !== path.dirname(module.resource)) + if(module.context !== path.dirname(module.resource)) { throw "invalid context/resource relation"; + } modules.push({ id: module.id, - context: path.relative(this.options.base, module.context).replace(/\\/g, "/"), + context: path.relative(this.options.context, module.context).replace(/\\/g, "/"), resource: path.basename(module.resource) }); } } - chunks_data[chunkGroup.options.name] = { + chunkData[chunkGroup.options.name] = { files: fileJs, css_files: filesCss, modules: modules }; } - this.manifest_content = { + const payload = JSON.stringify({ version: 2, - chunks: chunks_data - }; - }); + chunks: chunkData + }); - compiler.hooks.done.tap(this.constructor.name, () => { - const file = this.options.file || "manifest.json"; - fs.mkdirpSync(path.dirname(file)); - fs.writeFileSync(this.options.file || "manifest.json", JSON.stringify(this.manifest_content)); + const fileName = this.options.outputFileName || "manifest.json"; + compilation.assets[fileName] = { + size() { return payload.length; }, + source() { return payload; } + } as any; }); } } diff --git a/webpack/WatLoader.ts b/webpack/WatLoader.ts index 7597d523..65d6eb7b 100644 --- a/webpack/WatLoader.ts +++ b/webpack/WatLoader.ts @@ -1,12 +1,7 @@ -import * as webpack from "webpack"; -import {RawSourceMap} from "source-map"; -import LoaderContext = webpack.loader.LoaderContext; - const wabt = require("wabt")(); - const filename = "module.wast"; -export default function loader(this: LoaderContext, source: string | Buffer, sourceMap?: RawSourceMap): string | Buffer | void | undefined { +export default function loader(source: string | Buffer): string | Buffer | void | undefined { this.cacheable(); const module = wabt.parseWat(filename, source); From 503ca5db8bd65853914a99a0682e2adc6fdd8bfa Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Wed, 17 Mar 2021 13:41:01 +0100 Subject: [PATCH 018/128] Correctly inlining the global loader style --- loader/app/css/index.ts | 6 +- loader/app/css/loader.scss | 227 +++++++++++++++-------------- loader/app/css/overlay.scss | 100 ++++++------- package.json | 1 - webpack.config.ts | 4 +- webpack/HtmlWebpackInlineSource.ts | 138 ++++++++++++++++++ 6 files changed, 311 insertions(+), 165 deletions(-) create mode 100644 webpack/HtmlWebpackInlineSource.ts diff --git a/loader/app/css/index.ts b/loader/app/css/index.ts index 035afdf9..bfe4b056 100644 --- a/loader/app/css/index.ts +++ b/loader/app/css/index.ts @@ -1,3 +1,3 @@ -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./index.scss"; -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./loader.scss"; -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./overlay.css"; \ No newline at end of file +import "./index.scss"; +import "./loader.scss"; +import "./overlay.css"; \ No newline at end of file diff --git a/loader/app/css/loader.scss b/loader/app/css/loader.scss index eda8d424..af9eabd8 100644 --- a/loader/app/css/loader.scss +++ b/loader/app/css/loader.scss @@ -1,138 +1,162 @@ -$setup-time-normal: 80s / 24; /* 24 frames / sec; the initial sequence is 80 frames */ -$setup-time-halloween: 323s / 24; -$loop-time-halloween: 25s / 24; +:global { + $setup-time-normal: 80s / 24; /* 24 frames / sec; the initial sequence is 80 frames */ + $setup-time-halloween: 323s / 24; + $loop-time-halloween: 25s / 24; -#loader-overlay { - position: absolute; - overflow: hidden; - - top: 0; - left: 0; - right: 0; - bottom: 0; - - background: #1e1e1e; - - user-select: none; - - z-index: 10000000; - - display: flex; - flex-direction: column; - justify-content: center; - - -webkit-app-region: drag; - - .container { - flex-shrink: 0; - - display: block; - position: relative; - - width: 1000px; - height: 1000px; - - align-self: center; - margin-bottom: 10vh; - - transition-duration: .5s; - - img { - user-select: none; - } - } - - .setup, .idle { + #loader-overlay { position: absolute; + overflow: hidden; top: 0; left: 0; right: 0; bottom: 0; - display: none; + background: #1e1e1e; + + user-select: none; + + z-index: 10000000; + + display: flex; + flex-direction: column; + justify-content: center; + + -webkit-app-region: drag; + + .container { + flex-shrink: 0; - &.visible { display: block; - } - } + position: relative; - .setup.visible { - &.normal { - animation: loader-initial-sequence 0s cubic-bezier(.81,.01,.65,1.16) $setup-time-normal forwards; + width: 1000px; + height: 1000px; + + align-self: center; + margin-bottom: 10vh; + + transition-duration: .5s; + + img { + user-select: none; + } } - &.halloween { - animation: loader-initial-sequence 0s cubic-bezier(.81,.01,.65,1.16) $setup-time-halloween forwards; - } - } - - .idle.animation-normal { - img { - position: absolute; - } - - .steam { + .setup, .idle { position: absolute; - top: 282px; - left: 380px; + top: 0; + left: 0; + right: 0; + bottom: 0; - width: 249px; - height: 125px; - background: url("../images/steam.png") 0 0; + display: none; - animation: sprite-steam 2.5s steps(50) forwards infinite; + &.visible { + display: block; + } } - } - &.finishing { - .idle { + .setup.visible { + &.normal { + animation: loader-initial-sequence 0s cubic-bezier(.81,.01,.65,1.16) $setup-time-normal forwards; + } + + &.halloween { + animation: loader-initial-sequence 0s cubic-bezier(.81,.01,.65,1.16) $setup-time-halloween forwards; + } + } + + .idle.animation-normal { + img { + position: absolute; + } + .steam { - display: none; - } + position: absolute; - .bowl { - animation: swipe-out-bowl .5s both; - } + top: 282px; + left: 380px; - .text { - animation: swipe-out-text .5s .12s both; + width: 249px; + height: 125px; + background: url("../images/steam.png") 0 0; + + animation: sprite-steam 2.5s steps(50) forwards infinite; } } - pointer-events: none; - animation: overlay-fade .3s .2s both; + &.finishing { + .idle { + .steam { + display: none; + } + + .bowl { + animation: swipe-out-bowl .5s both; + } + + .text { + animation: swipe-out-text .5s .12s both; + } + } + + pointer-events: none; + animation: overlay-fade .3s .2s both; + } + + .loader-stage { + position: absolute; + + left: 5px; + bottom: 5px; + + font-size: 12px; + font-family: monospace; + + color: #999; + } } - .loader-stage { - position: absolute; + /* Automated loader timeout */ + #loader-overlay:not(.initialized) + #critical-load:not(.shown) { + display: block !important; + opacity: 0; - left: 5px; - bottom: 5px; + animation: loader-setup-timeout 0s ease-in $setup-time-normal forwards; - font-size: 12px; - font-family: monospace; + .error::before { + content: 'Failed to startup loader!'; + } - color: #999; + .detail::before { + content: 'Lookup the console for more details'; + } } } @media all and (max-width: 850px) { - #loader-overlay .container { - transform: scale(.5); + :global { + #loader-overlay .container { + transform: scale(.5); + } } } @media all and (max-height: 700px) { - #loader-overlay .container { - transform: scale(.5); + :global { + #loader-overlay .container { + transform: scale(.5); + } } } @media all and (max-width: 400px) { - #loader-overlay .container { - transform: scale(.3); + :global { + #loader-overlay .container { + transform: scale(.3); + } } } @@ -192,23 +216,6 @@ $loop-time-halloween: 25s / 24; } } -/* Automated loader timeout */ -#loader-overlay:not(.initialized) + #critical-load:not(.shown) { - display: block !important; - opacity: 0; - - animation: loader-setup-timeout 0s ease-in $setup-time-normal forwards; - - .error::before { - content: 'Failed to startup loader!'; - } - - .detail::before { - content: 'Lookup the console for more details'; - } -} - - @keyframes loader-setup-timeout { to { opacity: 1; diff --git a/loader/app/css/overlay.scss b/loader/app/css/overlay.scss index 3e76ba17..d285c96d 100644 --- a/loader/app/css/overlay.scss +++ b/loader/app/css/overlay.scss @@ -1,64 +1,66 @@ -#overlay-no-js, #critical-load { - z-index: 100000000; - display: none; - position: fixed; +:global { + #overlay-no-js, #critical-load { + z-index: 100000000; + display: none; + position: fixed; - top: 0; - bottom: 0; - left: 0; - right: 0; + top: 0; + bottom: 0; + left: 0; + right: 0; - background: #1e1e1e; - text-align: center; + background: #1e1e1e; + text-align: center; - -webkit-app-region: drag; + -webkit-app-region: drag; - h1, h3, a { - -webkit-app-region: no-drag; - } + h1, h3, a { + -webkit-app-region: no-drag; + } - .container { - position: relative; - display: inline-block; + .container { + position: relative; + display: inline-block; - top: 20%; - } + top: 20%; + } - &.shown { - display: block; - } -} - -#critical-load { - img { - height: 12em - } - - .error { - color: #bd1515; - margin-bottom: 0 - } - - .detail { - color: #696363; - margin-top: .5em - } -} - - -@media (max-height: 750px) { - #critical-load .container { - top: unset; + &.shown { + display: block; + } } #critical-load { - font-size: .8rem; + img { + height: 12em + } - flex-direction: column; - justify-content: center; + .error { + color: #bd1515; + margin-bottom: 0 + } + + .detail { + color: #696363; + margin-top: .5em + } } - #critical-load.shown { - display: flex; + + @media (max-height: 750px) { + #critical-load .container { + top: unset; + } + + #critical-load { + font-size: .8rem; + + flex-direction: column; + justify-content: center; + } + + #critical-load.shown { + display: flex; + } } } \ No newline at end of file diff --git a/package.json b/package.json index d49e298e..d0282a73 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,6 @@ "node-sass": "^4.14.1", "potpack": "^1.0.1", "raw-loader": "^4.0.0", - "react-dev-utils": "^11.0.4", "sass": "1.22.10", "sass-loader": "^8.0.2", "sha256": "^0.2.0", diff --git a/webpack.config.ts b/webpack.config.ts index 29260b19..83654405 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -11,7 +11,7 @@ const webpack = require("webpack"); import { Plugin as SvgSpriteGenerator } from "webpack-svg-sprite-generator"; const ManifestGenerator = require("./webpack/ManifestPlugin"); -const InlineChunkHtmlPlugin = require("react-dev-utils/InlineChunkHtmlPlugin"); +const HtmlWebpackInlineSourcePlugin = require("./webpack/HtmlWebpackInlineSource"); import HtmlWebpackPlugin from "html-webpack-plugin"; const MiniCssExtractPlugin = require('mini-css-extract-plugin'); @@ -155,7 +155,7 @@ export const config = async (target: "web" | "client"): Promise !!e), module: { diff --git a/webpack/HtmlWebpackInlineSource.ts b/webpack/HtmlWebpackInlineSource.ts new file mode 100644 index 00000000..d25c705f --- /dev/null +++ b/webpack/HtmlWebpackInlineSource.ts @@ -0,0 +1,138 @@ +const escapeRegex = require('escape-string-regexp'); +const path = require('path'); +const slash = require('slash'); +const sourceMapUrl = require('source-map-url'); + +function HtmlWebpackInlineSourcePlugin (htmlWebpackPlugin) { + this.htmlWebpackPlugin = htmlWebpackPlugin; +} + +HtmlWebpackInlineSourcePlugin.prototype.apply = function (compiler) { + const self = this; + + // Hook into the html-webpack-plugin processing + compiler.hooks.compilation.tap('html-webpack-inline-source-plugin', compilation => { + self.htmlWebpackPlugin + .getHooks(compilation) + .alterAssetTagGroups.tapAsync('html-webpack-inline-source-plugin', (htmlPluginData, callback) => { + if (!htmlPluginData.plugin.options.inlineSource) { + return callback(null, htmlPluginData); + } + + const regexStr = htmlPluginData.plugin.options.inlineSource; + const result = self.processTags(compilation, regexStr, htmlPluginData); + callback(null, result); + }); + }); +}; + +HtmlWebpackInlineSourcePlugin.prototype.processTags = function (compilation, regexStr, pluginData) { + const self = this; + + const bodyTags = []; + const headTags = []; + + const regex = new RegExp(regexStr); + const filename = pluginData.plugin.options.filename; + + pluginData.headTags.forEach(function (tag) { + headTags.push(self.processTag(compilation, regex, tag, filename)); + }); + + pluginData.bodyTags.forEach(function (tag) { + bodyTags.push(self.processTag(compilation, regex, tag, filename)); + }); + + return { headTags: headTags, bodyTags: bodyTags, plugin: pluginData.plugin, outputName: pluginData.outputName }; +}; + +HtmlWebpackInlineSourcePlugin.prototype.resolveSourceMaps = function (compilation, assetName, asset) { + let source = asset.source(); + const out = compilation.outputOptions; + // Get asset file absolute path + const assetPath = path.join(out.path, assetName); + // Extract original sourcemap URL from source string + if (typeof source !== 'string') { + source = source.toString(); + } + const mapUrlOriginal = sourceMapUrl.getFrom(source); + // Return unmodified source if map is unspecified, URL-encoded, or already relative to site root + if (!mapUrlOriginal || mapUrlOriginal.indexOf('data:') === 0 || mapUrlOriginal.indexOf('/') === 0) { + return source; + } + // Figure out sourcemap file path *relative to the asset file path* + const assetDir = path.dirname(assetPath); + const mapPath = path.join(assetDir, mapUrlOriginal); + const mapPathRelative = path.relative(out.path, mapPath); + // Starting with Node 6, `path` module throws on `undefined` + const publicPath = out.publicPath || ''; + // Prepend Webpack public URL path to source map relative path + // Calling `slash` converts Windows backslashes to forward slashes + const mapUrlCorrected = slash(path.join(publicPath, mapPathRelative)); + // Regex: exact original sourcemap URL, possibly '*/' (for CSS), then EOF, ignoring whitespace + const regex = new RegExp(escapeRegex(mapUrlOriginal) + '(\\s*(?:\\*/)?\\s*$)'); + // Replace sourcemap URL and (if necessary) preserve closing '*/' and whitespace + return source.replace(regex, function (match, group) { + return mapUrlCorrected + group; + }); +}; + +HtmlWebpackInlineSourcePlugin.prototype.processTag = function (compilation, regex, tag, filename) { + let assetUrl; + let preTag = tag; + + // inline js + if (tag.tagName === 'script' && tag.attributes && regex.test(tag.attributes.src)) { + assetUrl = tag.attributes.src; + tag = { + tagName: 'script', + closeTag: true, + attributes: { + type: 'text/javascript' + } + }; + + // inline css + } else if (tag.tagName === 'link' && regex.test(tag.attributes.href)) { + assetUrl = tag.attributes.href; + tag = { + tagName: 'style', + closeTag: true, + attributes: { + type: 'text/css' + } + }; + } + + if (assetUrl) { + // Strip public URL prefix from asset URL to get Webpack asset name + const publicUrlPrefix = compilation.outputOptions.publicPath || ''; + // if filename is in subfolder, assetUrl should be prepended folder path + if (path.basename(filename) !== filename) { + assetUrl = path.dirname(filename) + '/' + assetUrl; + } + const assetName = path.posix.relative(publicUrlPrefix, assetUrl); + const asset = getAssetByName(compilation.assets, assetName); + if (compilation.assets[assetName] !== undefined) { + const updatedSource = this.resolveSourceMaps(compilation, assetName, asset); + tag.innerHTML = (tag.tagName === 'script') ? updatedSource.replace(/(<)(\/script>)/g, '\\x3C$2') : updatedSource; + }else{ + return preTag; + } + } + + return tag; +}; + +function getAssetByName (assests, assetName) { + for (let key in assests) { + if (assests.hasOwnProperty(key)) { + let processedKey = path.posix.relative('', key); + if (processedKey === assetName) { + return assests[key]; + } + } + } +} + +module.exports = HtmlWebpackInlineSourcePlugin; \ No newline at end of file From ff610bf3eeef9e1d0221a12074a796383fdbeab2 Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Wed, 17 Mar 2021 14:00:35 +0100 Subject: [PATCH 019/128] Fixed some minor project setup issues --- babel.config.ts | 4 +- loader/app/css/index.ts | 2 +- loader/app/css/overlay.scss | 4 +- setup_devel_environment.md | 5 --- webpack.config.ts | 79 +++++++++++++------------------------ 5 files changed, 34 insertions(+), 60 deletions(-) diff --git a/babel.config.ts b/babel.config.ts index e6e6d3bc..bdcb598f 100644 --- a/babel.config.ts +++ b/babel.config.ts @@ -4,7 +4,7 @@ export = api => { [ "@babel/preset-env", { - "corejs": { "version":3 }, + "corejs": {"version": 3}, "useBuiltIns": "usage", "targets": { "edge": "17", @@ -16,10 +16,12 @@ export = api => { } ] ]; + const plugins = [ ["@babel/transform-runtime"], ["@babel/plugin-transform-modules-commonjs"] ]; + return { presets, plugins diff --git a/loader/app/css/index.ts b/loader/app/css/index.ts index bfe4b056..36ac23e4 100644 --- a/loader/app/css/index.ts +++ b/loader/app/css/index.ts @@ -1,3 +1,3 @@ import "./index.scss"; import "./loader.scss"; -import "./overlay.css"; \ No newline at end of file +import "./overlay.scss"; \ No newline at end of file diff --git a/loader/app/css/overlay.scss b/loader/app/css/overlay.scss index d285c96d..be486a87 100644 --- a/loader/app/css/overlay.scss +++ b/loader/app/css/overlay.scss @@ -45,9 +45,11 @@ margin-top: .5em } } +} - @media (max-height: 750px) { +@media (max-height: 750px) { + :global { #critical-load .container { top: unset; } diff --git a/setup_devel_environment.md b/setup_devel_environment.md index 8ba98aac..4ecac232 100644 --- a/setup_devel_environment.md +++ b/setup_devel_environment.md @@ -5,7 +5,6 @@ The following tools or applications are required to develop the web client: - [1.2 NodeJS](#12-nodejs) - [1.2.2 NPM](#122-npm) - [1.3 Git bash](#13-git-bash) -- [1.4 Rust (Options)](#14-rust-optional-will-be-installed-automatically) ### 1.1 IDE It does not matter which IDE you use, @@ -27,10 +26,6 @@ IMPORTANT: NPM must be available within the PATH environment variable! For using the `.sh` build scripts you require Git Bash. A minimum of 4.2 is recommend, but in general every modern version should work. -### 1.4 Rust (Optional, will be installed automatically) -For building the web client audio library, you may want to install rust in advance. -Since it will be installed when executing the install libraries script, I'm not going into more detail here. - ## 2.0 Project initialization ### 2.1 Cloning the WebClient diff --git a/webpack.config.ts b/webpack.config.ts index 83654405..1069183c 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -3,11 +3,9 @@ import * as fs from "fs"; import trtransformer from "./tools/trgen/ts_transformer"; import {exec} from "child_process"; import * as util from "util"; +import * as path from "path"; -import {Configuration} from "webpack"; - -const path = require('path'); -const webpack = require("webpack"); +import { DefinePlugin, Configuration } from "webpack"; import { Plugin as SvgSpriteGenerator } from "webpack-svg-sprite-generator"; const ManifestGenerator = require("./webpack/ManifestPlugin"); @@ -53,17 +51,7 @@ const generateDefinitions = async (target: string) => { timestamp: timestamp, entry_chunk_name: JSON.stringify(target === "web" ? "shared-app" : "client-app") } as BuildDefinitions - }; -}; - -const isLoaderFile = (file: string) => { - if(file.startsWith(__dirname)) { - const path = file.substr(__dirname.length).replace(/\\/g, "/"); - if(path.startsWith("/loader/")) { - return true; - } - } - return false; + } as any; }; const generateIndexPlugin = (target: "web" | "client"): HtmlWebpackPlugin => { @@ -102,21 +90,23 @@ export const config = async (target: "web" | "client"): Promise !!e), module: { @@ -189,12 +182,18 @@ export const config = async (target: "web" | "client"): Promise module.match(/\.tsx?$/) && !isLoaderFile(module), + test: /\.tsx?$/, exclude: /node_modules/, use: [ { - loader: 'ts-loader', + loader: "babel-loader", + options: { + presets: ["@babel/preset-env"] + } + }, + { + loader: "ts-loader", options: { context: __dirname, colors: true, @@ -212,52 +211,28 @@ export const config = async (target: "web" | "client"): Promise module.match(/\.tsx?$/) && isLoaderFile(module), - exclude: /(node_modules|bower_components)/, - - use: [ - { - loader: "babel-loader", - options: { - presets: ["@babel/preset-env"] //Preset used for env setup - } - }, - { - loader: "ts-loader", - options: { - transpileOnly: true - } - } - ] - }, { test: /\.was?t$/, use: [ "./webpack/WatLoader.js" ] }, + { + test: /ChangeLog\.md$|\.html$/i, + type: "asset/source", + }, { test: /\.svg$/, use: 'svg-inline-loader' }, - { - test: /ChangeLog\.md$|\.html$/i, - use: { - loader: "raw-loader", - options: { - esModule: false - } - }, - }, { test: /\.(png|jpg|jpeg|gif)?$/, - use: 'file-loader', + type: "asset/resource" }, ] } as any, resolve: { - extensions: ['.tsx', '.ts', '.js', ".scss", ".css", ".wasm"], + extensions: ['.tsx', '.ts', '.js', ".scss"], alias: { "vendor/xbbcode": path.resolve(__dirname, "vendor/xbbcode/src"), "tc-events": path.resolve(__dirname, "vendor/TeaEventBus/src/index.ts"), From 29639ca836c0c41572fbbb77b82156eef40a9865 Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Wed, 17 Mar 2021 15:38:56 +0100 Subject: [PATCH 020/128] Improved the translation generator. It now generates a up2date translation list --- ...er_generator.ts => JsRendererGenerator.ts} | 21 +- tools/trgen/JsRendererTranslationLoader.ts | 19 + tools/trgen/TsGenerator.ts | 415 ++++++++++++++++ tools/trgen/TsTransformer.ts | 52 ++ tools/trgen/WebpackPlugin.ts | 55 +++ tools/trgen/compiler.ts | 6 +- tools/trgen/index.ts | 11 +- tools/trgen/ts_generator.ts | 459 ------------------ tools/trgen/ts_transformer.ts | 75 --- tools/trgen/tsconfig.json | 5 +- webpack.config.ts | 352 +++++++------- webpack/ManifestPlugin.ts | 2 +- 12 files changed, 742 insertions(+), 730 deletions(-) rename tools/trgen/{jsrender_generator.ts => JsRendererGenerator.ts} (70%) create mode 100644 tools/trgen/JsRendererTranslationLoader.ts create mode 100644 tools/trgen/TsGenerator.ts create mode 100644 tools/trgen/TsTransformer.ts create mode 100644 tools/trgen/WebpackPlugin.ts delete mode 100644 tools/trgen/ts_generator.ts delete mode 100644 tools/trgen/ts_transformer.ts diff --git a/tools/trgen/jsrender_generator.ts b/tools/trgen/JsRendererGenerator.ts similarity index 70% rename from tools/trgen/jsrender_generator.ts rename to tools/trgen/JsRendererGenerator.ts index 24ef1947..18381ed1 100644 --- a/tools/trgen/jsrender_generator.ts +++ b/tools/trgen/JsRendererGenerator.ts @@ -1,8 +1,5 @@ import {TranslationEntry} from "./generator"; -export interface Configuration { - -} export interface File { content: string; name: string; @@ -11,15 +8,15 @@ export interface File { /* Well my IDE hates me and does not support groups. By default with ES6 groups are supported... nvm */ //const regex = /{{ *tr *(?(("([^"]|\\")*")|('([^']|\\')*')|(`([^`]|\\`)+`)|( *\+ *)?)+) *\/ *}}/; const regex = /{{ *tr *((("([^"]|\\")*")|('([^']|\\')*')|(`([^`]|\\`)+`)|([\n ]*\+[\n ]*)?)+) *\/ *}}/; -export function generate(config: Configuration, file: File) : TranslationEntry[] { +export function extractJsRendererTranslations(file: File) : TranslationEntry[] { let result: TranslationEntry[] = []; const lines = file.content.split('\n'); let match: RegExpExecArray; - let base_index = 0; + let baseIndex = 0; - while(match = regex.exec(file.content.substr(base_index))) { - let expression = ((match).groups || {})["message_expression"] || match[1]; + while(match = regex.exec(file.content.substr(baseIndex))) { + let expression = (match.groups || {})["message_expression"] || match[1]; //expression = expression.replace(/\n/g, "\\n"); let message; @@ -27,16 +24,18 @@ export function generate(config: Configuration, file: File) : TranslationEntry[] message = eval(expression); } catch (error) { console.error("Failed to evaluate expression:\n%s", expression); - base_index += match.index + match[0].length; + baseIndex += match.index + match[0].length; continue; } - let character = base_index + match.index; + let character = baseIndex + match.index; let line; for(line = 0; line < lines.length; line++) { const length = lines[line].length + 1; - if(length > character) break; + if(length > character) { + break; + } character -= length; } @@ -48,7 +47,7 @@ export function generate(config: Configuration, file: File) : TranslationEntry[] type: "js-template" }); - base_index += match.index + match[0].length; + baseIndex += match.index + match[0].length; } return result; } \ No newline at end of file diff --git a/tools/trgen/JsRendererTranslationLoader.ts b/tools/trgen/JsRendererTranslationLoader.ts new file mode 100644 index 00000000..32d97850 --- /dev/null +++ b/tools/trgen/JsRendererTranslationLoader.ts @@ -0,0 +1,19 @@ +import {extractJsRendererTranslations} from "./JsRendererGenerator"; +import {deltaTranslations} from "./TsTransformer"; + +export default function (source) { + const options = this.getOptions({ + translations: { type: "array" } + }); + source = typeof source === "object" ? source.toString() : source; + + const timestampBegin = Date.now(); + const translations = extractJsRendererTranslations({ + name: this.resourcePath, + content: source + }); + const timestampEnd = Date.now(); + + deltaTranslations(options.translations, this.resourcePath, timestampEnd - timestampBegin, translations); + return source; +}; \ No newline at end of file diff --git a/tools/trgen/TsGenerator.ts b/tools/trgen/TsGenerator.ts new file mode 100644 index 00000000..028cc3d3 --- /dev/null +++ b/tools/trgen/TsGenerator.ts @@ -0,0 +1,415 @@ +import * as ts from "typescript"; +import sha256 from "sha256"; +import {SyntaxKind} from "typescript"; +import {TranslationEntry} from "./generator"; + +const getSourceLocation = (node: ts.Node) => { + const sf = node.getSourceFile(); + let { line, character } = sf ? sf.getLineAndCharacterOfPosition(node.getStart()) : {line: -1, character: -1}; + return `${(sf || {fileName: "unknown"}).fileName} (${line + 1},${character + 1})`; +}; + +function report(node: ts.Node, message: string) { + console.log(`${getSourceLocation(node)}: ${message}`); +} + +function generateUniqueCheck(config: Configuration, source_file: ts.SourceFile, variable: ts.Expression, variables: { name: string, node: ts.Node }[]) : ts.Node[] { + const nodes: ts.Node[] = [], blockedNodes: ts.Statement[] = []; + + const nodePath = (node: ts.Node) => { + const sf = node.getSourceFile(); + let { line, character } = sf ? sf.getLineAndCharacterOfPosition(node.getStart()) : {line: -1, character: -1}; + return `${(sf || {fileName: "unknown"}).fileName} (${line + 1},${character + 1})`; + }; + + const createError = (variable_name: ts.Expression, variable_path: ts.Expression, other_path: ts.Expression) => { + return [ + ts.createLiteral("Translation with generated name \""), + variable_name, + ts.createLiteral("\" already exists!\nIt has been already defined here: "), + other_path, + ts.createLiteral("\nAttempted to redefine here: "), + variable_path, + ts.createLiteral("\nRegenerate and/or fix your program!") + ].reduce((a, b) => ts.createBinary(a, SyntaxKind.PlusToken, b)); + }; + + let declarationsFile: ts.Expression; + const uniqueCheckLabelName = "unique_translation_check"; + + /* initialization */ + { + const declarations = ts.createElementAccess(variable, ts.createLiteral(config.variables.declarations)); + nodes.push(ts.createAssignment(declarations, ts.createBinary(declarations, SyntaxKind.BarBarToken, ts.createAssignment(declarations, ts.createObjectLiteral())))); + + declarationsFile = ts.createElementAccess(variable, ts.createLiteral(config.variables.declareFiles)); + nodes.push(ts.createAssignment(declarationsFile, ts.createBinary(declarationsFile, SyntaxKind.BarBarToken, ts.createAssignment(declarationsFile, ts.createObjectLiteral())))); + + variable = declarations; + } + + /* test file already loaded */ + { + const uniqueId = sha256(source_file.fileName + " | " + (Date.now() / 1000)); + const property = ts.createElementAccess(declarationsFile, ts.createLiteral(uniqueId)); + + const ifCondition = ts.createBinary(property, SyntaxKind.ExclamationEqualsEqualsToken, ts.createIdentifier("undefined")); + // + let ifThen: ts.Block; + { + const elements: ts.Statement[] = []; + + const console = ts.createIdentifier("console.warn"); + elements.push(ts.createCall(console, [], [ts.createLiteral("This file has already been loaded!\nAre you executing scripts twice?") as any]) as any); + elements.push(ts.createBreak(uniqueCheckLabelName)); + + ifThen = ts.createBlock(elements); + } + + const ifElse = ts.createAssignment(property, ts.createLiteral(uniqueId)); + blockedNodes.push(ts.createIf(ifCondition, ifThen, ifElse as any)); + } + + /* test if variable has been defined somewhere else */ + { + const forVariableName = ts.createLoopVariable(); + const forVariablePath = ts.createLoopVariable(); + const forDeclaration = ts.createVariableDeclarationList([ts.createVariableDeclaration(ts.createObjectBindingPattern([ + ts.createBindingElement(undefined, config.optimized ? "n": "name", forVariableName, undefined), + ts.createBindingElement(undefined, config.optimized ? "p": "path", forVariablePath, undefined)]) + , undefined, undefined)]); + + let forBlock: ts.Statement; + { //Create the for block + const elements: ts.Statement[] = []; + + + const property = ts.createElementAccess(variable, forVariableName); + const ifCondition = ts.createBinary(property, SyntaxKind.ExclamationEqualsEqualsToken, ts.createIdentifier("undefined")); + + // + const ifThen = ts.createThrow(createError(forVariableName, forVariablePath, property)); + const ifElse = ts.createAssignment(property, forVariablePath); + const ifValid = ts.createIf(ifCondition, ifThen, ifElse as any); + + elements.push(ifValid); + + forBlock = ts.createBlock(elements); + } + + let block = ts.createForOf(undefined, + forDeclaration, ts.createArrayLiteral( + [...variables.map(e => ts.createObjectLiteral([ + ts.createPropertyAssignment(config.optimized ? "n": "name", ts.createLiteral(e.name)), + ts.createPropertyAssignment(config.optimized ? "p": "path", ts.createLiteral(nodePath(e.node))) + ])) + ]) + , forBlock); + block = ts.addSyntheticLeadingComment(block, SyntaxKind.MultiLineCommentTrivia, "Auto generated helper for testing if the translation keys are unique", true); + blockedNodes.push(block); + } + return [...nodes, ts.createLabel(uniqueCheckLabelName, ts.createBlock(blockedNodes))]; +} + +let globalIdIndex = 0, globalIdTimestamp = Date.now(); +export function transform(config: Configuration, context: ts.TransformationContext, sourceFile: ts.SourceFile) : TransformResult { + const cache: VolatileTransformConfig = {} as any; + cache.translations = []; + + config.variables = (config.variables || {}) as any; + config.variables.base = config.variables.base || (config.optimized ? "__tr" : "_translations"); + config.variables.declareFiles = config.variables.declareFiles || (config.optimized ? "f" : "declare_files"); + config.variables.declarations = config.variables.declarations || (config.optimized ? "d" : "definitions"); + + //Initialize nodes + const extraNodes = []; + { + cache.nodes = {} as any; + if(config.useWindow) { + const window = ts.createIdentifier("window"); + const translationMap = ts.createPropertyAccess(window, ts.createIdentifier(config.variables.base)); + const newTranslations = ts.createAssignment(translationMap, ts.createObjectLiteral()); + + extraNodes.push(ts.createParen( + ts.createBinary(translationMap, ts.SyntaxKind.BarBarToken, newTranslations) + )); + + cache.nodes = { + translationMap: translationMap + }; + } else if(config.module) { + cache.nodes = { + translationMap: ts.createIdentifier(config.variables.base) + }; + + extraNodes.push(( + ts.createVariableDeclarationList([ + ts.createVariableDeclaration(config.variables.base, undefined, ts.createObjectLiteral()) + ], ts.NodeFlags.Const) + ), ts.createToken(SyntaxKind.SemicolonToken)); + } else { + const variableMap = ts.createIdentifier(config.variables.base); + const inlineIf = ts.createBinary( + ts.createBinary( + ts.createTypeOf(variableMap), + SyntaxKind.ExclamationEqualsEqualsToken, + ts.createLiteral("undefined") + ), + ts.SyntaxKind.BarBarToken, + ts.createAssignment(variableMap, ts.createObjectLiteral()) + ); + + cache.nodes = { + translationMap: variableMap, + }; + + extraNodes.push(inlineIf); + } + } + + const generatedNames: { name: string, node: ts.Node }[] = []; + let generatorBase = 0; + + const generateUniqueName = config => { + if(config.module) { + return "_" + generatorBase++; + } else { + return "_" + globalIdTimestamp + "-" + ++globalIdIndex; + } + }; + + cache.nameGenerator = (config, node) => { + const name = generateUniqueName(config); + generatedNames.push({name: name, node: node}); + return name; + }; + + cache.tsxNameGenerator = generateUniqueName; + + function visit(node: ts.Node): ts.Node { + node = ts.visitEachChild(node, visit, context); + return visitNode(config, cache, node, sourceFile); + } + + sourceFile = ts.visitNode(sourceFile, visit); + if(!config.module) { + /* we don't need a unique check because we're just in our scope */ + extraNodes.push(...generateUniqueCheck(config, sourceFile, cache.nodes.translationMap, generatedNames)); + } + + if(!config.cacheTranslations) { + sourceFile = ts.updateSourceFileNode(sourceFile, [ + ...extraNodes, + ...sourceFile.statements + ], sourceFile.isDeclarationFile, sourceFile.referencedFiles, sourceFile.typeReferenceDirectives, sourceFile.hasNoDefaultLib, sourceFile.referencedFiles); + } + + return { + node: sourceFile, + translations: cache.translations + }; +} + +const generateJsxCacheKey = (cache: VolatileTransformConfig, config: Configuration, element: ts.JsxElement) => ts.updateJsxElement( + element, + ts.updateJsxOpeningElement( + element.openingElement, + element.openingElement.tagName, + element.openingElement.typeArguments, + ts.updateJsxAttributes(element.openingElement.attributes, [ + ...element.openingElement.attributes.properties, + ts.createJsxAttribute(ts.createIdentifier("__cacheKey"), ts.createStringLiteral(cache.tsxNameGenerator(config))) + ]) + ), + element.children, + element.closingElement +); + +export function visitNode(config: Configuration, cache: VolatileTransformConfig, node: ts.Node, sourceFile: ts.SourceFile) : ts.Node { + if(config.verbose) { + console.log("Process %s", SyntaxKind[node.kind]); + } + + if(!node.getSourceFile()) { + /* Node is already artificial */ + return node; + } + + if(ts.isCallExpression(node)) { + const call = node as ts.CallExpression; + const callName = call.expression["escapedText"] as string; + if(callName !== "tr" && callName !== "useTr") { + return node; + } + + if(call.arguments.length > 1) { + throw new Error(getSourceLocation(call) + ": tr(...) has been called with an invalid arguments (" + (call.arguments.length === 0 ? "too few" : "too many") + ")"); + } + + const fullText = call.getFullText(sourceFile); + if(fullText && fullText.indexOf("@tr-ignore") !== -1) { + return node; + } + + const object = call.arguments[0]; + if(object.kind != SyntaxKind.StringLiteral) { + if(call.getSourceFile()) { + throw new Error(getSourceLocation(call) + ": Ignoring tr call because given argument isn't of type string literal. (" + SyntaxKind[object.kind] + ")"); + } + + report(call, "Ignoring tr call because given argument isn't of type string literal. (" + SyntaxKind[object.kind] + ")"); + } + + if(config.verbose) { + console.log("Message: %o", object.text || object.getText(sourceFile)); + } + + let { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); + cache.translations.push({ + message: object.text || object.getText(sourceFile), + line: line, + character: character, + filename: sourceFile.fileName, + type: "call" + }); + + if(!config.cacheTranslations) { + return node; + } + + const variableName = ts.createIdentifier(cache.nameGenerator(config, node, object.text || object.getText(sourceFile))); + const variableInit = ts.createPropertyAccess(cache.nodes.translationMap, variableName); + + const variable = ts.createPropertyAccess(cache.nodes.translationMap, variableName); + const newVariable = ts.createAssignment(variable, call); + + return ts.createBinary(variableInit, ts.SyntaxKind.BarBarToken, newVariable); + } else if(node.kind === SyntaxKind.JsxElement) { + const element = node as ts.JsxElement; + const tag = element.openingElement.tagName as ts.Identifier; + + if(tag.kind !== SyntaxKind.Identifier) { + return node; + } + + const properties: any = {}; + element.openingElement.attributes.properties.forEach((e: ts.JsxAttribute) => { + if(e.kind !== SyntaxKind.JsxAttribute) { + throw new Error(getSourceLocation(e) + ": Invalid jsx attribute kind " + SyntaxKind[e.kind]); + } + + if(e.name.kind !== SyntaxKind.Identifier) { + throw new Error(getSourceLocation(e) + ": Key isn't an identifier"); + } + + properties[e.name.escapedText as string] = e.initializer; + }); + + if(tag.escapedText === "Translatable") { + if('trIgnore' in properties && properties.trIgnore.kind === SyntaxKind.JsxExpression) { + const ignoreAttribute = properties.trIgnore as ts.JsxExpression; + if(ignoreAttribute.expression.kind === SyntaxKind.TrueKeyword) { + return node; + } else if(ignoreAttribute.expression.kind !== SyntaxKind.FalseKeyword) { + throw new Error(getSourceLocation(ignoreAttribute) + ": Invalid attribute value of type " + SyntaxKind[ignoreAttribute.expression.kind]); + } + } + + if(element.children.length < 1) { + throw new Error(getSourceLocation(element) + ": Element has been called with an invalid arguments (too few)"); + } + + let text = element.children.map(element => { + if(element.kind === SyntaxKind.JsxText) { + return element.text; + } else if(element.kind === SyntaxKind.JsxSelfClosingElement) { + if(element.tagName.kind !== SyntaxKind.Identifier) { + throw new Error(getSourceLocation(element.tagName) + ": Expected a JsxSelfClosingElement, but received " + SyntaxKind[element.tagName.kind]); + } + + if(element.tagName.escapedText !== "br") { + throw new Error(getSourceLocation(element.tagName) + ": Expected a br element, but received " + element.tagName.escapedText); + } + + return "\n"; + } + }).join(""); + + let { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); + cache.translations.push({ + message: text, + line: line, + character: character, + filename: sourceFile.fileName, + type: "jsx-translatable" + }); + + if(!config.cacheTranslations) { + return node; + } + + return generateJsxCacheKey(cache, config, element); + } else if(tag.escapedText === "VariadicTranslatable") { + if(!('text' in properties)) { + throw new Error(getSourceLocation(element) + ": Missing text to translate"); + } + + const textAttribute = properties["text"] as ts.JsxExpression; + if(textAttribute.kind !== SyntaxKind.JsxExpression) { + throw new Error(getSourceLocation(element) + ": Text attribute has an invalid type. Expected JsxExpression but received " + SyntaxKind[textAttribute.kind]); + } + + if(textAttribute.expression.kind !== SyntaxKind.StringLiteral) { + throw new Error(getSourceLocation(element) + ": Text attribute value isn't a string literal. Expected StringLiteral but received " + SyntaxKind[textAttribute.expression.kind]); + } + + const literal = textAttribute.expression as ts.StringLiteral; + + let { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); + cache.translations.push({ + message: literal.text, + line: line, + character: character, + filename: sourceFile.fileName, + type: "jsx-variadic-translatable" + }); + + if(!config.cacheTranslations) { + return node; + } + + return generateJsxCacheKey(cache, config, element); + } + } + + return node; +} +export interface Configuration { + useWindow?: boolean; + cacheTranslations?: boolean; + verbose?: boolean; + + optimized?: boolean; + module?: boolean; + + variables?: { + base: string, + declarations: string, + declareFiles: string + } +} + +export interface TransformResult { + node: ts.SourceFile; + translations: TranslationEntry[]; +} + +interface VolatileTransformConfig { + nodes: { + translationMap: ts.Expression; + }; + + nameGenerator: (config: Configuration, node: ts.Node, message: string) => string; + tsxNameGenerator: (config: Configuration) => string; + translations: TranslationEntry[]; +} \ No newline at end of file diff --git a/tools/trgen/TsTransformer.ts b/tools/trgen/TsTransformer.ts new file mode 100644 index 00000000..0411fca8 --- /dev/null +++ b/tools/trgen/TsTransformer.ts @@ -0,0 +1,52 @@ +import * as ts from "typescript"; +import * as ts_generator from "./TsGenerator"; +import {TranslationEntry} from "./generator"; + +export interface TransformerConfig { + verbose: boolean; + optimized: boolean; + + /** + * Output array for all gathered translations. + */ + translations?: TranslationEntry[]; +} + +export const deltaTranslations = (result: TranslationEntry[], fileName: string, processSpeed: number, newTranslations: TranslationEntry[]) => { + let deletedTranslations = 0; + for(let index = 0; index < result.length; index++) { + if(result[index].filename === fileName) { + result.splice(index, 1); + index--; + deletedTranslations++; + } + } + + result.push(...newTranslations); + if(deletedTranslations === 0 && newTranslations.length === 0) { + console.log("Processed %s (%dms). No translations found.", fileName, processSpeed); + } else if(deletedTranslations === 0) { + console.log("Processed %s (%dms). Found %d translations", fileName, processSpeed, newTranslations.length); + } else if(newTranslations.length === 0) { + console.log("Processed %s (%dms). %d translations deleted.", fileName, processSpeed, deletedTranslations); + } else { + console.log("Processed %s (%dms). Old translation count: %d New translation count: %d", fileName, processSpeed, deletedTranslations, newTranslations.length); + } +} + +export const createTransformer = (program: ts.Program, config: TransformerConfig) : ts.TransformerFactory => { + return ctx => sourceFile => { + const timestampBegin = Date.now(); + const result = ts_generator.transform({ + module: true, + useWindow: false, + /* Note: Even though caching might cause less method calls but if the tr method is performant developed it's faster than having the cache lookup */ + cacheTranslations: false, + optimized: config.optimized, + }, ctx, sourceFile); + const timestampEnd = Date.now(); + + deltaTranslations(config.translations || [], sourceFile.fileName, timestampEnd - timestampBegin, result.translations); + return result.node; + }; +} \ No newline at end of file diff --git a/tools/trgen/WebpackPlugin.ts b/tools/trgen/WebpackPlugin.ts new file mode 100644 index 00000000..6f1a41f9 --- /dev/null +++ b/tools/trgen/WebpackPlugin.ts @@ -0,0 +1,55 @@ +import * as ts from "typescript"; +import {createTransformer, deltaTranslations, TransformerConfig} from "./TsTransformer"; +import * as webpack from "webpack"; +import {extractJsRendererTranslations} from "./JsRendererGenerator"; +import * as path from "path"; + +export interface TranslateableWebpackPluginConfig { + assetName: string, +} + +export class TranslateableWebpackPlugin { + private readonly config: TranslateableWebpackPluginConfig; + private readonly transformerConfig: TransformerConfig; + + constructor(config: TranslateableWebpackPluginConfig) { + this.config = config; + this.transformerConfig = { + optimized: true, + translations: [], + verbose: true + }; + } + + createTypeScriptTransformer(program: ts.Program) : ts.TransformerFactory { + return createTransformer(program, this.transformerConfig); + } + + createTemplateLoader() { + return { + loader: path.join(__dirname, "JsRendererTranslationLoader.js"), + options: { + translations: this.transformerConfig.translations + } + }; + } + + apply(compiler: webpack.Compiler) { + compiler.hooks.emit.tap("TranslateableWebpackPlugin", compilation => { + const payload = JSON.stringify(this.transformerConfig.translations); + compilation.assets[this.config.assetName] = { + size() { return payload.length; }, + source() { return payload; } + } as any; + }); + + /* + compiler.hooks.normalModuleFactory.tap("TranslateableWebpackPlugin", normalModuleFactory => { + normalModuleFactory.hooks.resolve.tap("TranslateableWebpackPlugin", resolveData => { + if(resolveData.request === "generated-translations") { + } + }); + }); + */ + } +} \ No newline at end of file diff --git a/tools/trgen/compiler.ts b/tools/trgen/compiler.ts index ae2c5cfa..012b32b2 100644 --- a/tools/trgen/compiler.ts +++ b/tools/trgen/compiler.ts @@ -1,5 +1,5 @@ import * as ts from "typescript"; -import * as generator from "./ts_generator"; +import * as generator from "./TsGenerator"; import {readFileSync} from "fs"; import * as glob from "glob"; @@ -7,8 +7,8 @@ import * as path from "path"; const transformer = (context: ts.TransformationContext) => (rootNode: T) => { return generator.transform({ - use_window: false, - replace_cache: true, + useWindow: false, + cacheTranslations: true, verbose: true }, context, rootNode as any).node; }; diff --git a/tools/trgen/index.ts b/tools/trgen/index.ts index 7ec42a7a..b6f8bf8b 100644 --- a/tools/trgen/index.ts +++ b/tools/trgen/index.ts @@ -1,6 +1,6 @@ import * as ts from "typescript"; -import * as ts_generator from "./ts_generator"; -import * as jsrender_generator from "./jsrender_generator"; +import * as ts_generator from "./TsGenerator"; +import * as jsrender_generator from "./JsRendererGenerator"; import {readFileSync, writeFileSync} from "fs"; import * as path from "path"; import * as glob from "glob"; @@ -119,10 +119,11 @@ config.source_files.forEach(file => { ); console.log("Compile " + _file); - const messages = ts_generator.generate(source, {}); - translations.push(...messages); + throw "not supported"; + //const messages = ts_generator.generate(source, {}); + //translations.push(...messages); } else if(file_type == ".html") { - const messages = jsrender_generator.generate({}, { + const messages = jsrender_generator.extractJsRendererTranslations({ content: readFileSync(_file).toString(), name: _file }); diff --git a/tools/trgen/ts_generator.ts b/tools/trgen/ts_generator.ts deleted file mode 100644 index fa0911b4..00000000 --- a/tools/trgen/ts_generator.ts +++ /dev/null @@ -1,459 +0,0 @@ -import * as ts from "typescript"; -import {SyntaxKind} from "typescript"; -import sha256 from "sha256"; -import {TranslationEntry} from "./generator"; - -export function generate(file: ts.SourceFile, config: Configuration) : TranslationEntry[] { - let result: TranslationEntry[] = []; - - file.forEachChild(n => _generate(config, n, result)); - - return result; -} - -const source_location = (node: ts.Node) => { - const sf = node.getSourceFile(); - let { line, character } = sf ? sf.getLineAndCharacterOfPosition(node.getStart()) : {line: -1, character: -1}; - return `${(sf || {fileName: "unknown"}).fileName} (${line + 1},${character + 1})`; -}; - -function report(node: ts.Node, message: string) { - console.log(`${source_location(node)}: ${message}`); -} - -function _generate(config: Configuration, node: ts.Node, result: TranslationEntry[]) { - //console.log("Node: %s", SyntaxKind[node.kind]); - - call_analize: - if(ts.isCallExpression(node)) { - const call = node as ts.CallExpression; - const call_name = call.expression["escapedText"] as string; - - if(call_name != "tr") { - break call_analize; - } - - console.dir(call_name); - console.log("Parameters: %o", call.arguments.length); - if(call.arguments.length > 1) { - report(call, "Invalid argument count"); - break call_analize; - } - - const object = call.arguments[0]; - if(object.kind != SyntaxKind.StringLiteral) { - report(call, "Invalid argument: " + SyntaxKind[object.kind]); - break call_analize; - } - - console.log("Message: %o", object.text); - - //FIXME - if(config.replace_cache) { - console.log("Update!"); - ts.updateCall(call, call.expression, call.typeArguments, [ts.createLiteral("PENIS!")]); - } - - const { line, character } = node.getSourceFile().getLineAndCharacterOfPosition(node.getStart()); - result.push({ - filename: node.getSourceFile().fileName, - line: line, - character: character, - message: object.text, - type: "call" - }); - } else if(node.kind === SyntaxKind.JsxElement) { - const element = node as ts.JsxElement; - const tag = element.openingElement.tagName as ts.Identifier; - - if(tag.kind !== SyntaxKind.Identifier) - break call_analize; - - if(tag.escapedText === "Translatable") { - if(element.children.length !== 1) { - report(element, "Invalid child count: " + element.children.length); - break call_analize; - } - - const text = element.children[0] as ts.JsxText; - if(text.kind != SyntaxKind.JsxText) { - report(element, "Invalid child type " + SyntaxKind[text.kind]); - break call_analize; - } - - const { line, character } = node.getSourceFile().getLineAndCharacterOfPosition(node.getStart()); - result.push({ - filename: node.getSourceFile().fileName, - line: line, - character: character, - message: text.text, - type: "jsx-translatable" - }); - } else if(tag.escapedText === "VariadicTranslatable") { - - } - } - - node.forEachChild(n => _generate(config, n, result)); -} -function generateUniqueCheck(config: Configuration, source_file: ts.SourceFile, variable: ts.Expression, variables: { name: string, node: ts.Node }[]) : ts.Node[] { - const nodes: ts.Node[] = [], blocked_nodes: ts.Statement[] = []; - - const node_path = (node: ts.Node) => { - const sf = node.getSourceFile(); - let { line, character } = sf ? sf.getLineAndCharacterOfPosition(node.getStart()) : {line: -1, character: -1}; - return `${(sf || {fileName: "unknown"}).fileName} (${line + 1},${character + 1})`; - }; - - const create_error = (variable_name: ts.Expression, variable_path: ts.Expression, other_path: ts.Expression) => { - return [ - ts.createLiteral("Translation with generated name \""), - variable_name, - ts.createLiteral("\" already exists!\nIt has been already defined here: "), - other_path, - ts.createLiteral("\nAttempted to redefine here: "), - variable_path, - ts.createLiteral("\nRegenerate and/or fix your program!") - ].reduce((a, b) => ts.createBinary(a, SyntaxKind.PlusToken, b)); - }; - - let declarations_file: ts.Expression; - const unique_check_label_name = "unique_translation_check"; - - /* initialization */ - { - const declarations = ts.createElementAccess(variable, ts.createLiteral(config.variables.declarations)); - nodes.push(ts.createAssignment(declarations, ts.createBinary(declarations, SyntaxKind.BarBarToken, ts.createAssignment(declarations, ts.createObjectLiteral())))); - - declarations_file = ts.createElementAccess(variable, ts.createLiteral(config.variables.declare_files)); - nodes.push(ts.createAssignment(declarations_file, ts.createBinary(declarations_file, SyntaxKind.BarBarToken, ts.createAssignment(declarations_file, ts.createObjectLiteral())))); - - variable = declarations; - } - - /* test file already loaded */ - { - const unique_id = sha256(source_file.fileName + " | " + (Date.now() / 1000)); - const property = ts.createElementAccess(declarations_file, ts.createLiteral(unique_id)); - - const if_condition = ts.createBinary(property, SyntaxKind.ExclamationEqualsEqualsToken, ts.createIdentifier("undefined")); - // - let if_then: ts.Block; - { - const elements: ts.Statement[] = []; - - const console = ts.createIdentifier("console.warn"); - elements.push(ts.createCall(console, [], [ts.createLiteral("This file has already been loaded!\nAre you executing scripts twice?") as any]) as any); - elements.push(ts.createBreak(unique_check_label_name)); - - if_then = ts.createBlock(elements); - } - - const if_else = ts.createAssignment(property, ts.createLiteral(unique_id)); - blocked_nodes.push(ts.createIf(if_condition, if_then, if_else as any)); - } - - /* test if variable has been defined somewhere else */ - { - const for_variable_name = ts.createLoopVariable(); - const for_variable_path = ts.createLoopVariable(); - const for_declaration = ts.createVariableDeclarationList([ts.createVariableDeclaration(ts.createObjectBindingPattern([ - ts.createBindingElement(undefined, config.optimized ? "n": "name", for_variable_name, undefined), - ts.createBindingElement(undefined, config.optimized ? "p": "path", for_variable_path, undefined)]) - , undefined, undefined)]); - - let for_block: ts.Statement; - { //Create the for block - const elements: ts.Statement[] = []; - - - const property = ts.createElementAccess(variable, for_variable_name); - const if_condition = ts.createBinary(property, SyntaxKind.ExclamationEqualsEqualsToken, ts.createIdentifier("undefined")); - - // - const if_then = ts.createThrow(create_error(for_variable_name, for_variable_path, property)); - const if_else = ts.createAssignment(property, for_variable_path); - const if_valid = ts.createIf(if_condition, if_then, if_else as any); - - elements.push(if_valid); - - for_block = ts.createBlock(elements); - } - - let block = ts.createForOf(undefined, - for_declaration, ts.createArrayLiteral( - [...variables.map(e => ts.createObjectLiteral([ - ts.createPropertyAssignment(config.optimized ? "n": "name", ts.createLiteral(e.name)), - ts.createPropertyAssignment(config.optimized ? "p": "path", ts.createLiteral(node_path(e.node))) - ])) - ]) - , for_block); - block = ts.addSyntheticLeadingComment(block, SyntaxKind.MultiLineCommentTrivia, "Auto generated helper for testing if the translation keys are unique", true); - blocked_nodes.push(block); - } - return [...nodes, ts.createLabel(unique_check_label_name, ts.createBlock(blocked_nodes))]; -} - -let globalIdIndex = 0, globalIdTimestamp = Date.now(); -export function transform(config: Configuration, context: ts.TransformationContext, source_file: ts.SourceFile) : TransformResult { - const cache: VolatileTransformConfig = {} as any; - cache.translations = []; - - config.variables = (config.variables || {}) as any; - config.variables.base = config.variables.base || (config.optimized ? "__tr" : "_translations"); - config.variables.declare_files = config.variables.declare_files || (config.optimized ? "f" : "declare_files"); - config.variables.declarations = config.variables.declarations || (config.optimized ? "d" : "definitions"); - - //Initialize nodes - const extra_nodes: ts.Node[] = []; - { - cache.nodes = {} as any; - if(config.use_window) { - const window = ts.createIdentifier("window"); - let translation_map = ts.createPropertyAccess(window, ts.createIdentifier(config.variables.base)); - const new_translations = ts.createAssignment(translation_map, ts.createObjectLiteral()); - - let translation_map_init: ts.Expression = ts.createBinary(translation_map, ts.SyntaxKind.BarBarToken, new_translations); - translation_map_init = ts.createParen(translation_map_init); - - extra_nodes.push(translation_map_init); - cache.nodes = { - translation_map: translation_map - }; - } else if(config.module) { - cache.nodes = { - translation_map: ts.createIdentifier(config.variables.base) - }; - - extra_nodes.push(ts.createVariableDeclarationList([ - ts.createVariableDeclaration(config.variables.base, undefined, ts.createObjectLiteral()) - ], ts.NodeFlags.Const), ts.createToken(SyntaxKind.SemicolonToken)); - } else { - const variable_map = ts.createIdentifier(config.variables.base); - const inline_if = ts.createBinary(ts.createBinary(ts.createTypeOf(variable_map), SyntaxKind.ExclamationEqualsEqualsToken, ts.createLiteral("undefined")), ts.SyntaxKind.BarBarToken, ts.createAssignment(variable_map, ts.createObjectLiteral())); - - cache.nodes = { - translation_map: variable_map, - }; - - extra_nodes.push(inline_if); - } - } - - const generated_names: { name: string, node: ts.Node }[] = []; - let generator_base = 0; - - const generate_unique_name = config => { - if(config.module) { - return "_" + generator_base++; - } else { - return "_" + globalIdTimestamp + "-" + ++globalIdIndex; - } - }; - - cache.name_generator = (config, node, message) => { - const name = generate_unique_name(config); - generated_names.push({name: name, node: node}); - return name; - }; - - cache.tsx_name_generator = generate_unique_name; - - function visit(node: ts.Node): ts.Node { - node = ts.visitEachChild(node, visit, context); - return replace_processor(config, cache, node, source_file); - } - source_file = ts.visitNode(source_file, visit); - if(!config.module) { - /* we don't need a unique check because we're just in our scope */ - extra_nodes.push(...generateUniqueCheck(config, source_file, cache.nodes.translation_map, generated_names)); - } - - source_file = ts.updateSourceFileNode(source_file, [...(extra_nodes as any[]), ...source_file.statements], source_file.isDeclarationFile, source_file.referencedFiles, source_file.typeReferenceDirectives, source_file.hasNoDefaultLib, source_file.referencedFiles); - - const result: TransformResult = {} as any; - result.node = source_file; - result.translations = cache.translations; - return result; -} - -const generate_jsx_cache_key = (cache: VolatileTransformConfig, config: Configuration, element: ts.JsxElement) => ts.updateJsxElement( - element, - ts.updateJsxOpeningElement( - element.openingElement, - element.openingElement.tagName, - element.openingElement.typeArguments, - ts.updateJsxAttributes(element.openingElement.attributes, [ - ...element.openingElement.attributes.properties, - ts.createJsxAttribute(ts.createIdentifier("__cacheKey"), ts.createStringLiteral(cache.tsx_name_generator(config))) - ]) - ), - element.children, - element.closingElement -); - -export function replace_processor(config: Configuration, cache: VolatileTransformConfig, node: ts.Node, source_file: ts.SourceFile) : ts.Node { - if(config.verbose) - console.log("Process %s", SyntaxKind[node.kind]); - - if(!node.getSourceFile()) - return node; - - if(ts.isCallExpression(node)) { - const call = node; - const call_name = call.expression["escapedText"] as string; - if(call_name != "tr") return node; - if(config.verbose) { - console.dir(call_name); - console.log("Parameters: %o", call.arguments.length); - } - - if(call.arguments.length > 1) - throw new Error(source_location(call) + ": tr(...) has been called with an invalid arguments (" + (call.arguments.length === 0 ? "too few" : "too many") + ")"); - - const fullText = call.getFullText(source_file); - if(fullText && fullText.indexOf("@tr-ignore") !== -1) - return node; - - const object = call.arguments[0]; - if(object.kind != SyntaxKind.StringLiteral) { - if(call.getSourceFile()) - throw new Error(source_location(call) + ": Ignoring tr call because given argument isn't of type string literal. (" + SyntaxKind[object.kind] + ")"); - report(call, "Ignoring tr call because given argument isn't of type string literal. (" + SyntaxKind[object.kind] + ")"); - } - - if(config.verbose) - console.log("Message: %o", object.text || object.getText(source_file)); - - const variable_name = ts.createIdentifier(cache.name_generator(config, node, object.text || object.getText(source_file))); - const variable_init = ts.createPropertyAccess(cache.nodes.translation_map, variable_name); - - const variable = ts.createPropertyAccess(cache.nodes.translation_map, variable_name); - const new_variable = ts.createAssignment(variable, call); - - let { line, character } = source_file.getLineAndCharacterOfPosition(node.getStart()); - - cache.translations.push({ - message: object.text || object.getText(source_file), - line: line, - character: character, - filename: (source_file || {fileName: "unknown"}).fileName, - type: "call" - }); - - return ts.createBinary(variable_init, ts.SyntaxKind.BarBarToken, new_variable); - } else if(node.kind === SyntaxKind.JsxElement) { - const element = node as ts.JsxElement; - const tag = element.openingElement.tagName as ts.Identifier; - - if(tag.kind !== SyntaxKind.Identifier) - return node; - - const properties = {} as any; - - element.openingElement.attributes.properties.forEach((e: ts.JsxAttribute) => { - if(e.kind !== SyntaxKind.JsxAttribute) - throw new Error(source_location(e) + ": Invalid jsx attribute kind " + SyntaxKind[e.kind]); - - if(e.name.kind !== SyntaxKind.Identifier) - throw new Error(source_location(e) + ": Key isn't an identifier"); - - properties[e.name.escapedText as string] = e.initializer; - }); - - if(tag.escapedText === "Translatable") { - if('trIgnore' in properties && properties.trIgnore.kind === SyntaxKind.JsxExpression) { - const ignoreAttribute = properties.trIgnore as ts.JsxExpression; - if(ignoreAttribute.expression.kind === SyntaxKind.TrueKeyword) - return node; - else if(ignoreAttribute.expression.kind !== SyntaxKind.FalseKeyword) - throw new Error(source_location(ignoreAttribute) + ": Invalid attribute value of type " + SyntaxKind[ignoreAttribute.expression.kind]); - } - - if(element.children.length < 1) { - throw new Error(source_location(element) + ": Element has been called with an invalid arguments (too few)"); - } - - let text = element.children.map(element => { - if(element.kind === SyntaxKind.JsxText) { - return element.text; - } else if(element.kind === SyntaxKind.JsxSelfClosingElement) { - if(element.tagName.kind !== SyntaxKind.Identifier) { - throw new Error(source_location(element.tagName) + ": Expected a JsxSelfClosingElement, but received " + SyntaxKind[element.tagName.kind]); - } - - if(element.tagName.escapedText !== "br") { - throw new Error(source_location(element.tagName) + ": Expected a br element, but received " + element.tagName.escapedText); - } - - return "\n"; - } - }).join(""); - - let { line, character } = source_file.getLineAndCharacterOfPosition(node.getStart()); - cache.translations.push({ - message: text, - line: line, - character: character, - filename: (source_file || {fileName: "unknown"}).fileName, - type: "jsx-translatable" - }); - - return generate_jsx_cache_key(cache, config, element); - } else if(tag.escapedText === "VariadicTranslatable") { - if(!('text' in properties)) - throw new Error(source_location(element) + ": Missing text to translate"); - - const textAttribute = properties["text"] as ts.JsxExpression; - if(textAttribute.kind !== SyntaxKind.JsxExpression) - throw new Error(source_location(element) + ": Text attribute has an invalid type. Expected JsxExpression but received " + SyntaxKind[textAttribute.kind]); - - if(textAttribute.expression.kind !== SyntaxKind.StringLiteral) - throw new Error(source_location(element) + ": Text attribute value isn't a string literal. Expected StringLiteral but received " + SyntaxKind[textAttribute.expression.kind]); - - const literal = textAttribute.expression as ts.StringLiteral; - - let { line, character } = source_file.getLineAndCharacterOfPosition(node.getStart()); - cache.translations.push({ - message: literal.text, - line: line, - character: character, - filename: (source_file || {fileName: "unknown"}).fileName, - type: "jsx-variadic-translatable" - }); - - return generate_jsx_cache_key(cache, config, element); - } - } - - return node; -} -export interface Configuration { - use_window?: boolean; - replace_cache?: boolean; - verbose?: boolean; - - optimized?: boolean; - module?: boolean; - - variables?: { - base: string, - declarations: string, - declare_files: string - } -} - -export interface TransformResult { - node: ts.SourceFile; - translations: TranslationEntry[]; -} - -interface VolatileTransformConfig { - nodes: { - translation_map: ts.Expression; - }; - - name_generator: (config: Configuration, node: ts.Node, message: string) => string; - tsx_name_generator: (config: Configuration) => string; - translations: TranslationEntry[]; -} \ No newline at end of file diff --git a/tools/trgen/ts_transformer.ts b/tools/trgen/ts_transformer.ts deleted file mode 100644 index 096c2ec2..00000000 --- a/tools/trgen/ts_transformer.ts +++ /dev/null @@ -1,75 +0,0 @@ -import * as ts from "typescript"; -import * as ts_generator from "./ts_generator"; -import * as path from "path"; -import * as mkdirp from "mkdirp"; - -import {writeFileSync} from "fs"; -import {TranslationEntry} from "./generator"; - -export interface Config { - target_file?: string; - verbose?: boolean; - optimized?: boolean; -} - -let process_config: Config; -export default function(program: ts.Program, config?: Config) : (context: ts.TransformationContext) => (sourceFile: ts.SourceFile) => ts.SourceFile { - process_config = config as any || {}; - - const base_path = path.dirname(program.getCompilerOptions().project || program.getCurrentDirectory()); - if(process_config.verbose) { - console.log("TRGen transformer called"); - console.log("Base path: %s", base_path); - } - - process.on('exit', function () { - if(!process_config.target_file) return; - - const target = path.isAbsolute(process_config.target_file) ? process_config.target_file : path.join(base_path, process_config.target_file); - if(process_config.target_file) { - if(process_config.verbose) { - console.log("Writing translation file to " + target); - } - - mkdirp.sync(path.dirname(target)); - writeFileSync(target, JSON.stringify(translations, null, 2)); - } - }); - - return ctx => transformer(ctx) as any; -} - -let processed = []; -const translations: TranslationEntry[] = []; -const transformer = (context: ts.TransformationContext) => (rootNode: ts.Node) => { - const handler = (rootNode: ts.Node) => { - if(rootNode.kind == ts.SyntaxKind.Bundle) { - const bundle = rootNode as ts.Bundle; - const result = []; - for(const file of bundle.sourceFiles) - result.push(handler(file)); - return ts.updateBundle(bundle, result as any, bundle.prepends as any); - } else if(rootNode.kind == ts.SyntaxKind.SourceFile) { - const file = rootNode as ts.SourceFile; - - if(processed.findIndex(e => e === file.fileName) !== -1) { - console.log("Skipping %s (already processed)", file.fileName); - return rootNode; - } - processed.push(file.fileName); - console.log("Processing " + file.fileName); - const result = ts_generator.transform({ - use_window: false, - replace_cache: true, - module: true, - optimized: process_config.optimized - }, context, file); - translations.push(...result.translations); - return result.node; - } else { - console.warn("Invalid transform input: %s", ts.SyntaxKind[rootNode.kind]); - } - }; - - return handler(rootNode); -}; \ No newline at end of file diff --git a/tools/trgen/tsconfig.json b/tools/trgen/tsconfig.json index d4815f28..eb3b1f72 100644 --- a/tools/trgen/tsconfig.json +++ b/tools/trgen/tsconfig.json @@ -14,7 +14,8 @@ "generator.ts", "index.ts", "compiler.ts", - "jsrender_generator.ts", - "ts_generator.ts" + "JsRendererGenerator.ts", + "TsGenerator.ts", + "JsRendererTranslationLoader.ts" ] } \ No newline at end of file diff --git a/webpack.config.ts b/webpack.config.ts index 1069183c..6d247a99 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -1,9 +1,7 @@ -import * as ts from "typescript"; import * as fs from "fs"; -import trtransformer from "./tools/trgen/ts_transformer"; -import {exec} from "child_process"; import * as util from "util"; import * as path from "path"; +import * as child_process from "child_process"; import { DefinePlugin, Configuration } from "webpack"; @@ -12,6 +10,7 @@ const ManifestGenerator = require("./webpack/ManifestPlugin"); const HtmlWebpackInlineSourcePlugin = require("./webpack/HtmlWebpackInlineSource"); import HtmlWebpackPlugin from "html-webpack-plugin"; +import {TranslateableWebpackPlugin} from "./tools/trgen/WebpackPlugin"; const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); const TerserPlugin = require('terser-webpack-plugin'); @@ -33,7 +32,7 @@ const generateDefinitions = async (target: string) => { let timestamp; try { - const { stdout } = await util.promisify(exec)("git show -s --format=%ct"); + const { stdout } = await util.promisify(child_process.exec)("git show -s --format=%ct"); timestamp = parseInt(stdout.toString()); if(isNaN(timestamp)) { throw "failed to parse timestamp '" + stdout.toString() + "'"; @@ -83,189 +82,194 @@ const generateIndexPlugin = (target: "web" | "client"): HtmlWebpackPlugin => { return new HtmlWebpackPlugin(options); } -export const config = async (target: "web" | "client"): Promise => ({ - entry: { - "loader": ["./loader/app/index.ts"], - "modal-external": ["./shared/js/ui/react-elements/external-modal/PopoutEntrypoint.ts"], - //"devel-main": "./shared/js/devel_main.ts" - }, +export const config = async (target: "web" | "client"): Promise => { + const translateablePlugin = new TranslateableWebpackPlugin({ assetName: "translations.json" }); - devtool: isDevelopment ? "inline-source-map" : "source-map", - mode: isDevelopment ? "development" : "production", - plugins: [ - new CleanWebpackPlugin(), - new DefinePlugin(await generateDefinitions(target)), + return { + entry: { + "loader": ["./loader/app/index.ts"], + "modal-external": ["./shared/js/ui/react-elements/external-modal/PopoutEntrypoint.ts"], + //"devel-main": "./shared/js/devel_main.ts" + }, - new MiniCssExtractPlugin({ - filename: isDevelopment ? "[name].[contenthash].css" : "[contenthash].css", - chunkFilename: isDevelopment ? "[name].[contenthash].css" : "[contenthash].css", - ignoreOrder: true - }), + devtool: isDevelopment ? "inline-source-map" : "source-map", + mode: isDevelopment ? "development" : "production", + plugins: [ + new CleanWebpackPlugin(), + new DefinePlugin(await generateDefinitions(target)), - new ManifestGenerator({ - outputFileName: "manifest.json", - context: __dirname - }), + new MiniCssExtractPlugin({ + filename: isDevelopment ? "[name].[contenthash].css" : "[contenthash].css", + chunkFilename: isDevelopment ? "[name].[contenthash].css" : "[contenthash].css", + ignoreOrder: true + }), - new SvgSpriteGenerator({ - dtsOutputFolder: path.join(__dirname, "shared", "svg-sprites"), - publicPath: "js/", - configurations: { - "client-icons": { - folder: path.join(__dirname, "shared", "img", "client-icons"), - cssClassPrefix: "client-", - cssOptions: [ - { - scale: 1, - selector: ".icon", - unit: "px" - }, - { - scale: 1.5, - selector: ".icon_x24", - unit: "px" - }, - { - scale: 2, - selector: ".icon_x32", - unit: "px" - }, - { - scale: 1, - selector: ".icon_em", - unit: "em" + new ManifestGenerator({ + outputFileName: "manifest.json", + context: __dirname + }), + + new SvgSpriteGenerator({ + dtsOutputFolder: path.join(__dirname, "shared", "svg-sprites"), + publicPath: "js/", + configurations: { + "client-icons": { + folder: path.join(__dirname, "shared", "img", "client-icons"), + cssClassPrefix: "client-", + cssOptions: [ + { + scale: 1, + selector: ".icon", + unit: "px" + }, + { + scale: 1.5, + selector: ".icon_x24", + unit: "px" + }, + { + scale: 2, + selector: ".icon_x32", + unit: "px" + }, + { + scale: 1, + selector: ".icon_em", + unit: "em" + } + ], + dtsOptions: { + enumName: "ClientIcon", + classUnionName: "ClientIconClass", + module: false } - ], - dtsOptions: { - enumName: "ClientIcon", - classUnionName: "ClientIconClass", - module: false } } - } - }), + }), - generateIndexPlugin(target), - new HtmlWebpackInlineSourcePlugin(HtmlWebpackPlugin), + generateIndexPlugin(target), + new HtmlWebpackInlineSourcePlugin(HtmlWebpackPlugin), - //new BundleAnalyzerPlugin(), - ].filter(e => !!e), + translateablePlugin + //new BundleAnalyzerPlugin(), + ].filter(e => !!e), - module: { - rules: [ - { - test: /\.(s[ac]|c)ss$/, - use: [ - //'style-loader', - { - loader: MiniCssExtractPlugin.loader, - options: { - esModule: false + module: { + rules: [ + { + test: /\.(s[ac]|c)ss$/, + use: [ + //'style-loader', + { + loader: MiniCssExtractPlugin.loader, + options: { + esModule: false + } + }, + { + loader: 'css-loader', + options: { + modules: { + mode: "local", + localIdentName: isDevelopment ? "[path][name]__[local]--[hash:base64:5]" : "[hash:base64]", + }, + sourceMap: isDevelopment + } + }, + { + loader: 'sass-loader', + options: { + sourceMap: isDevelopment + } } - }, - { - loader: 'css-loader', - options: { - modules: { - mode: "local", - localIdentName: isDevelopment ? "[path][name]__[local]--[hash:base64:5]" : "[hash:base64]", - }, - sourceMap: isDevelopment - } - }, - { - loader: 'sass-loader', - options: { - sourceMap: isDevelopment - } - } - ] - }, - { - test: /\.tsx?$/, - exclude: /node_modules/, + ] + }, + { + test: /\.tsx?$/, + exclude: /node_modules/, - use: [ - { - loader: "babel-loader", - options: { - presets: ["@babel/preset-env"] + use: [ + { + loader: "babel-loader", + options: { + presets: ["@babel/preset-env"] + } + }, + { + loader: "ts-loader", + options: { + context: __dirname, + colors: true, + + getCustomTransformers: program => ({ + before: [translateablePlugin.createTypeScriptTransformer(program)] + }), + transpileOnly: isDevelopment + } } - }, - { - loader: "ts-loader", - options: { - context: __dirname, - colors: true, - getCustomTransformers: (prog: ts.Program) => { - return { - before: [trtransformer(prog, { - optimized: false, - verbose: true, - target_file: path.join(__dirname, "dist", "translations.json") - })] - }; - }, - transpileOnly: isDevelopment - } - } - ] + ] + }, + { + test: /\.was?t$/, + use: [ + "./webpack/WatLoader.js" + ] + }, + { + test: /\.html$/i, + use: [translateablePlugin.createTemplateLoader()], + type: "asset/source", + }, + { + test: /ChangeLog\.md$/i, + type: "asset/source", + }, + { + test: /\.svg$/, + use: 'svg-inline-loader' + }, + { + test: /\.(png|jpg|jpeg|gif)?$/, + type: "asset/resource" + }, + ] + } as any, + resolve: { + extensions: ['.tsx', '.ts', '.js', ".scss"], + alias: { + "vendor/xbbcode": path.resolve(__dirname, "vendor/xbbcode/src"), + "tc-events": path.resolve(__dirname, "vendor/TeaEventBus/src/index.ts"), + "tc-services": path.resolve(__dirname, "vendor/TeaClientServices/src/index.ts"), }, - { - test: /\.was?t$/, - use: [ - "./webpack/WatLoader.js" - ] - }, - { - test: /ChangeLog\.md$|\.html$/i, - type: "asset/source", - }, - { - test: /\.svg$/, - use: 'svg-inline-loader' - }, - { - test: /\.(png|jpg|jpeg|gif)?$/, - type: "asset/resource" - }, - ] - } as any, - resolve: { - extensions: ['.tsx', '.ts', '.js', ".scss"], - alias: { - "vendor/xbbcode": path.resolve(__dirname, "vendor/xbbcode/src"), - "tc-events": path.resolve(__dirname, "vendor/TeaEventBus/src/index.ts"), - "tc-services": path.resolve(__dirname, "vendor/TeaClientServices/src/index.ts"), }, - }, - externals: [ - {"tc-loader": "window loader"} - ], - output: { - filename: isDevelopment ? "[name].[contenthash].js" : "[contenthash].js", - chunkFilename: isDevelopment ? "[name].[contenthash].js" : "[contenthash].js", - path: path.resolve(__dirname, 'dist'), - publicPath: "js/" - }, - performance: { - hints: false - }, - optimization: { - splitChunks: { - chunks: "all", - maxSize: 512 * 1024 + externals: [ + {"tc-loader": "window loader"} + ], + output: { + filename: isDevelopment ? "[name].[contenthash].js" : "[contenthash].js", + chunkFilename: isDevelopment ? "[name].[contenthash].js" : "[contenthash].js", + path: path.resolve(__dirname, 'dist'), + publicPath: "js/" }, - minimize: !isDevelopment, - minimizer: [ - new TerserPlugin(), - new CssMinimizerPlugin() - ] - }, - devServer: { - publicPath: "/", - contentBase: path.join(__dirname, 'dist'), - writeToDisk: true, - compress: true - }, -}); \ No newline at end of file + performance: { + hints: false + }, + optimization: { + splitChunks: { + chunks: "all", + maxSize: 512 * 1024 + }, + minimize: !isDevelopment, + minimizer: [ + new TerserPlugin(), + new CssMinimizerPlugin() + ] + }, + devServer: { + publicPath: "/", + contentBase: path.join(__dirname, 'dist'), + writeToDisk: true, + compress: true + }, + }; +}; \ No newline at end of file diff --git a/webpack/ManifestPlugin.ts b/webpack/ManifestPlugin.ts index 3d8874ab..fc6c59c8 100644 --- a/webpack/ManifestPlugin.ts +++ b/webpack/ManifestPlugin.ts @@ -14,7 +14,7 @@ class ManifestGenerator { } apply(compiler: webpack.Compiler) { - compiler.hooks.emit.tap(this.constructor.name, compilation => { + compiler.hooks.emit.tap("ManifestGenerator", compilation => { const chunkData = {}; for(const chunkGroup of compilation.chunkGroups) { const fileJs = []; From 5b289b15d774662913c1c65b2d040e164a68ac9d Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Wed, 17 Mar 2021 16:02:06 +0100 Subject: [PATCH 021/128] Properly import the old global css styles --- shared/css/load-css.tsx | 65 +- shared/css/static/general.scss | 323 +- shared/css/static/hostbanner.scss | 83 - shared/css/static/htmltags.scss | 10 +- shared/css/static/main-layout.scss | 110 +- shared/css/static/menu-bar.scss | 133 - shared/css/static/modal-about.scss | 102 +- shared/css/static/modal-avatar.scss | 474 +- shared/css/static/modal-banclient.scss | 466 +- shared/css/static/modal-banlist.scss | 1420 +++--- shared/css/static/modal-channelinfo.scss | 240 +- shared/css/static/modal-clientinfo.scss | 972 ++--- shared/css/static/modal-connect.scss | 353 -- shared/css/static/modal-group-assignment.scss | 160 +- shared/css/static/modal-icons.scss | 904 ++-- shared/css/static/modal-identity.scss | 286 +- shared/css/static/modal-invite.scss | 112 +- shared/css/static/modal-keyselect.scss | 80 +- shared/css/static/modal-latency.scss | 140 +- shared/css/static/modal-musicmanage.scss | 1110 ++--- shared/css/static/modal-newcomer.scss | 268 +- shared/css/static/modal-poke.scss | 118 +- shared/css/static/modal-query.scss | 588 +-- shared/css/static/modal-server.scss | 1958 ++++----- shared/css/static/modal-serverinfo.scss | 390 +- .../css/static/modal-serverinfobandwidth.scss | 274 +- shared/css/static/modal-settings.scss | 3840 +++++++++-------- shared/css/static/modal.scss | 1701 ++++---- shared/css/static/modals.scss | 52 +- shared/css/static/overlay-image-preview.scss | 146 +- shared/css/static/scroll.scss | 41 - shared/css/static/server-log.scss | 63 - shared/css/static/ts/country.scss | 1518 +++---- shared/css/static/ts/tab.scss | 154 +- shared/generate_i18n_gtranslate.ts | 2 +- shared/generate_translations.sh | 9 - .../external-modal/ModalRenderer.scss | 6 +- 37 files changed, 9027 insertions(+), 9644 deletions(-) delete mode 100644 shared/css/static/hostbanner.scss delete mode 100644 shared/css/static/menu-bar.scss delete mode 100644 shared/css/static/modal-connect.scss delete mode 100644 shared/css/static/scroll.scss delete mode 100644 shared/css/static/server-log.scss delete mode 100644 shared/generate_translations.sh diff --git a/shared/css/load-css.tsx b/shared/css/load-css.tsx index 5d600bb8..888a082c 100644 --- a/shared/css/load-css.tsx +++ b/shared/css/load-css.tsx @@ -1,36 +1,31 @@ -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/properties.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/main-layout.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/general.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/frame-chat.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/server-log.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/scroll.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/hostbanner.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/htmltags.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/menu-bar.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/mixin.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modals.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-about.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-avatar.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-banclient.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-banlist.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-channelinfo.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-clientinfo.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-connect.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-group-assignment.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-icons.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-identity.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-newcomer.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-invite.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-keyselect.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-poke.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-query.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-server.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-musicmanage.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-serverinfobandwidth.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-serverinfo.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/modal-settings.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/overlay-image-preview.scss" +import "./static/properties.scss" +import "./static/main-layout.scss" +import "./static/general.scss" +import "./static/frame-chat.scss" +import "./static/htmltags.scss" +import "./static/mixin.scss" +import "./static/modal.scss" +import "./static/modals.scss" +import "./static/modal-about.scss" +import "./static/modal-avatar.scss" +import "./static/modal-banclient.scss" +import "./static/modal-banlist.scss" +import "./static/modal-channelinfo.scss" +import "./static/modal-clientinfo.scss" +import "./static/modal-group-assignment.scss" +import "./static/modal-icons.scss" +import "./static/modal-identity.scss" +import "./static/modal-newcomer.scss" +import "./static/modal-invite.scss" +import "./static/modal-keyselect.scss" +import "./static/modal-poke.scss" +import "./static/modal-query.scss" +import "./static/modal-server.scss" +import "./static/modal-musicmanage.scss" +import "./static/modal-serverinfobandwidth.scss" +import "./static/modal-serverinfo.scss" +import "./static/modal-settings.scss" +import "./static/overlay-image-preview.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/ts/tab.scss" -import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!./static/ts/country.scss" \ No newline at end of file +import "./static/ts/tab.scss" +import "./static/ts/country.scss" \ No newline at end of file diff --git a/shared/css/static/general.scss b/shared/css/static/general.scss index d514b03b..4fbf8662 100644 --- a/shared/css/static/general.scss +++ b/shared/css/static/general.scss @@ -1,187 +1,188 @@ @import "mixin"; +:global { + /* Avatar/Icon loading animations */ + .icon_loading { + border: 2px solid #f3f3f3; /* Light grey */ + border-top: 2px solid #3498db; /* Blue */ + border-radius: 50%; + animation: loading_spin 2s linear infinite; -/* Avatar/Icon loading animations */ -.icon_loading { - border: 2px solid #f3f3f3; /* Light grey */ - border-top: 2px solid #3498db; /* Blue */ - border-radius: 50%; - animation: loading_spin 2s linear infinite; - - width: 14px !important; - height: 14px !important; -} - -.avatar_loading { - border: 2px solid #f3f3f3; /* Light grey */ - border-top: 2px solid #3498db; /* Blue */ - border-radius: 50%; - animation: loading_spin 2s linear infinite; - - width: 14px !important; - height: 14px !important; -} - -@keyframes loading_spin { - 0% { - transform: rotate(0deg); + width: 14px !important; + height: 14px !important; } - 100% { - transform: rotate(360deg); + + .avatar_loading { + border: 2px solid #f3f3f3; /* Light grey */ + border-top: 2px solid #3498db; /* Blue */ + border-radius: 50%; + animation: loading_spin 2s linear infinite; + + width: 14px !important; + height: 14px !important; } -} -@viewport { - width: device-width; - user-zoom: fixed; -} + @keyframes loading_spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } + } + + @viewport { + width: device-width; + user-zoom: fixed; + } -html:root { - --text: #999; -} + html:root { + --text: #999; + } -html { - font-family: sans-serif; - line-height: 1.15; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; - -ms-overflow-style: scrollbar; - -webkit-tap-highlight-color: transparent; - background-color: gray; -} + html { + font-family: sans-serif; + line-height: 1.15; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; + -ms-overflow-style: scrollbar; + -webkit-tap-highlight-color: transparent; + background-color: gray; + } -body { - height: 100vh; - width: 100vw; - top: 0; - left: 0; - right: 0; - padding: 0; - margin: 0; + body { + height: 100vh; + width: 100vw; + top: 0; + left: 0; + right: 0; + padding: 0; + margin: 0; - font-family: Roboto, Helvetica, Arial, sans-serif; - font-size: 1rem; - line-height: 1.5; - color: #212529; - text-align: left; - background-color: #fafafa; + font-family: Roboto, Helvetica, Arial, sans-serif; + font-size: 1rem; + line-height: 1.5; + color: #212529; + text-align: left; + background-color: #fafafa; - font-weight: 400; -} + font-weight: 400; + } -button, input, optgroup, select, textarea { - margin: 0; - font-family: inherit; - font-size: inherit; - line-height: inherit; -} + button, input, optgroup, select, textarea { + margin: 0; + font-family: inherit; + font-size: inherit; + line-height: inherit; + } -select { - -webkit-border-radius: 1px!important; - outline: none; + select { + -webkit-border-radius: 1px!important; + outline: none; - option { + option { + color: #999999; + } + + &:focus { + outline: none !important; + } + } + + + fieldset { + border: unset; + display: unset; + } + + code { + padding: 2px; + } + + + /* bootstrap materialize fix */ + .form-row { + margin-left: 0 !important; + margin-right: 0 !important; + } + + /* New design */ + a[href] { + color: #4d7bff; + text-decoration: none; + + &:hover { + color: #8aa8ff; + } + + &:visited { + color: #2752cd; + } + } + + /* tooltip */ + #global-tooltip { color: #999999; + background-color: #232222; + + position: fixed; + z-index: 1000000; + + pointer-events: none; + + padding: .25em; + transform: translate(-50%, -100%); /* translate up, center */ + + text-align: center; + border-right: 3px; + + display: flex; + flex-direction: column; + justify-content: space-around; + + opacity: 0; + @include transition(opacity .5s ease-in-out); + + &:after { + content: ''; + position: absolute; + + width: 0; + height: 0; + + left: calc(50% - .5em); + bottom: -.4em; + + border-style: solid; + border-width: .5em .5em 0 .5em; + border-color: #232222 transparent transparent transparent; + } + + &.shown { + opacity: 1; + } } - &:focus { - outline: none !important; - } -} + /* colored letters */ + a.rainbow-letter { + background-image: url('data:img/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAV/klEQVR4nM1dbY7j1hFsauSsk2CBAPkXBPkZ5Ca+QY6V+wS5SA5g569jrGN7d0diMCNRahar+uNRY7sDmeR7j++rqqublHYyffWPv39jNr+3V5tte8QyVZ4d120ms9fPYpM74vlUKF8+h2Idtjsk5f7aknGij1qjBceVzQSKKnTb44ejmf3pMtRs/GhQ5yFT97B2fC10kaSd7y1rW+lzj7H+I0BZO9U2unezjfvAf/m8P5hNH+IpVKaJ00X/tk17tRa2zq6hkzzC2IqYMm1Xyu8bWlT1WCHK5fzDoQ5wpw0uVW2Nnqtaiy9nhFd9jVjVkysWuUjJ+6MFsSiN10IdDr3pVKYaqUI870gFEHTVLjLVtguwqot2EetbfUceXZN62f5Q83JWVlWHDkm26+3I+V6CjBqushMgy14feUvUNiGLU4BoaiPqYKW6jgqw+7p1lfu9RUlbxaPZvZWx6GS7SV+h/lAHvKsOWSioq4AvY+vKPL+bYI4kaVPwYe0s3YEiy7vgw4YdttOOprnH83V9pm7VMPBo+VerHInrUd6AY73aYExPwYe2SQjISNDx/Gi5WgW6Up8lypFlIFXL1T2ZC8lJvxH4xRDw6Hq+VVUVUGGA7Rvrp2tV8CMdbRMoyu7VeRV8+ATvAfaQoNv2ch3F/cywXUcdKhatspIzlL2/kt2z8xEiWPoeYJQE2VJVGrRWA2UR0I8CvuK1FRVQ99P6itcrj1Z12A7KyXuADrCqHpdYinhyzZW1Zn1VrRrXKyqQEaJMgkeBT/pthABGDrb8KoHqKlANAdl5tT81M6zP6qJ+Q+nvyLmqUwkTtIEQEAGPZWxJXeD74OOasj1U12gVyceZZrRn3l/yenau2nRVAdoETwEZcBkJsu2KjBOhQoZO/oDWlfisDtux883EokUrMLGMtRGfo57+7KatztkKJtIH1rHraXWsjKhG3/ZWAwkt8n5cqTkyDHm/EfCMXEfyPpAfHDUIFpzjChjo7FoBj+ObJAJaB9gKEbJQwMDPVECSIPP6ild37iFtj3zZ2VZ1QDcAFesVrDUVmDd3Pcb7fZ94ngVG5f2p9O8BPyNDrgAViyDJQMc2CJ0J2LQKKNpmWqZmrCwiAZuHVeoUKNF1Rgosi8aZKQGUJFfyhGilEVHYuL5mur0jVBSzlELr8zmZeRa/I/BL3o9g+/PM60fAzwnQkfwRQlSh82V3KKMAgj2OerkyJvPqXJGBmgJ+BPz9BOhaJxSMlHs/ttU51vjNZnfvAV/1z0hgCRFWk1MAYZtR8PcRIBJPv3SkcJUEbFsiReAqwHqO4n8k+xUQ1diZ94fSX/H4EfADwAkB1NIMgJ7g7m7sr9arUHCvU96Ps4tAr1gUzyOShON1PL5KEFaPZTj29UjeA+DMKrE/Wm1GAiv6tW7Nykdmm2XzmANgeZr4KQXYS4AM8F4IqFpF9lm0ZqZCg7m6XAWY/LN9YBZJuIrp5aSvAqQFbV7sXLy/4PW+TBCg4j8ILgN7VDWwz5oKYGsWAjIisL6NkIEpALalS1Pgnd1xRAlYHS74sQrAVveovrDPWAUwSO2ZSSWut3KDyMsXq4KfqUAEuqhrECCS8wl6fitbgJ9u//V7qRSgOrNM0qNsnxoOzEhQAf8RXt8jQCbnWM98bnKr22PMr+fVyEbAz54vIkKg1DP5z9psBs48uwt+FBIsOXf14lWwAjRTAFz1YUAVIkjvdV4LcF1MAXzvbEYqtrN2WZvVQNlnFPyMDLjYWAFmt5wuYOyePSHh4HZFbe98+6/K+lmSWJ1NFNujJPB23yPBP8PkO2pgpA7Oj2vg9xDBb9novb4PZWt451tGsFzfj0wBOqNmRMB6ah3wu/kALjS6Zufbx8AKETArn0Wd2uJzIT+IPH89Bht9mylsCYLnOHIU11UucOs080wEeE8OgE8GOB6rc0fxbeCjFIFF4wMckf7mwgDubD0k4LnBCjKaKiKoBPDWaRdspQRVrx8EHgigAI48nJ1jXYc0CHp2fR9rduNEe4F7wozJegq8Hzz6eGC7wO/xfrbw6/Xgi6CRMFCR/wx0Bs+8GhN1gu1btCojQLMymvipQSPwFehYrvpViyyqQECAiuxXwPdqUJV/X+ZJoNOuBX4MOjgjtaLokU95PpV+Bi4eO0SIFKADPCMo/y4gi/8ZyHidkciAEAz4g1MPP6Zt+o+UUO1HN96niR8DmZGgmwyqsdjC2Tk5NhSgI/WsXbZLizHgl36YGtzLmAqYmCWbtT/PgN9IP1uSAr/j+dH7f0vOsR7L1wSIJL+bDBoAr/rzQLOVnR3A6jgDfPNm7Wrv1EqNgC7jvgJYnTPg98g/LhTnZsFRK8CepwIGPFMBC3IBDzau4gwhwRPB6BdF2f75WVY/m86r4Kt8oEIEBnZ0zshg6/bJ7wGqqpDlBUwV2OoPwfn5/ucMNuBPEArmdA/ZajbyLv4m8GpT0ZO7RGAEMOcLLAQgqBVvF8RoKAB6eFQege7vY9l/tCpPAhNEuPSdkUDZ5HpMwUfgGegdBZgT4B8Euj8Xr4KtWKaOBsArz8cQUNUztLODaE4JwKhoBOww9iPoEQnwvEKALvAV0ElZ8z3ASJkiRfSZ3A5VCIB2bqtA9VGQPrpViJB5fwR8BjpeF8G3LQFm44SoAI9plwoJ5yIRCrNfmVeU6UoAoyTAGXnZDwlQBb1CAlQCcyRAMrBzVVbZNk2AStLnge7kBcv5wd1fIcDkSIN5A9oJ+ucEiDTEx3//fyJx69IDe0quR57/cWssOUdQG+BbHAKsQYjKUamC+qgwIMUZ2l4Sw7kYClTidwMfgT0REpwI8NXkrwv6IOBYF7wKZpa9H2BhQK2mEgYYuc4EeGXzLRfwD5NnsgoE3R830u/BZwRg4FeAHwW9ATha4dtAJe+sjrXxbdnK/DUGwWXXojDgyYBqMF+DwJoEOGoIvgnQUQFQ/hXweI3bwMCtSH50HtQn/zjUb3JGAg+wuleFAazD4xnKPFwnd32Sq57tRPfeBPg3AnhQn4EACvzqI98er4/OszpX3gwBqp1KDKMytmK2K/jU4OE6O+CZkr20f7qeXTQAsTGg1JMjwGuDBehncR7F/4wAagtwiywoU21UPZQXFcCKxFDgG6yIPSUoMmCugOD7sBAlh2fqoIsdEHwDwJ8JEZAAFdnH5bGlG5yPeH1WrkOAknJmrG2kDGxVKugpZWDv/88FAlw+Z1ABg8e+GwEQ/GcgwkkAHz3ndyQ/OlfwVAnh6smLoMWUCrCeWY7g2ylSVI/4mVw653ceYdwS4Xz7rGf05D63eP/5+lnOUQE6Md8SwB8JfFbu6o8cnOSuMjlU30wRTOwK20H8BdEsSMBDwen1f/dniYMD/7X1AvgnIMFCgOiRj30MlqGucZuja9amWufsgf86eDGlBoupHMEIAbCMEYIR4OmK0JOL7Pcxz9dnAk+A4/VzA/7l85EQgCV8UZzHc7U8PO+WKUvaJn8ihlklR6i+TGLkiM4ZGSI1eAYS3H9P8GyfXmvNg3+6gv7T9fMJpB9jfgV4XM6Ip6M9qs2YAlTDhXosY3UqTLA2SkcZCY4uYC8wX0jwEgg+X98b/GYhwI9m9r/r8SMBP5L6aIpqSWx51fKuiX4GCBCBNHqvmkPHXRQZls8LzO883PbRvns9fvnyn+/N7L9XAnjwTwOgV6ef2aPAD+y47/Y9+UP13q7bROHiBcnfmtnvzex31xzgOzu+gP/NlQSfRIxX3XemO2pvSIQ3SAIfbW81vz+a2V/sr//81y+3tF+B/coI8KC5KBFYkrhPV6n/2uzf9pX97TXj+/rl/039qv8nl+0pzcdzNoFH2dtJQBACfmXKkIV/f46qf3Zv8T5ewf/W7PDt5ZaP9qW9sz9fk4Dvr48A/tlvhphgghRv8Rxnje9n+vbLKkDHgaI4zECfXSxfXux8vGb431+c/d319h9fU8MvbbI/mNkXZvYDvATAFwAsI1QJabSAzqZ0XtFXbd6bBILteT6t5HMGe6u83X9B49/q/XRF+wezw/Nd/pbqd5fngeuj4hfujdAzeQWILwLYhNjk1YLxUTgjQrRxzFi7qUCAPf1X2mR7knn7DFic4Yucz0CAq7o/ufi3NDu+vjL6zbXUvyD+HHwNyL79wYniAtRi/Xn0HiVrx4yHkeMur+20q5BfyTzzenwNi7/OeQYCfLyr+uHsXwmtU4SDHWx69X5zXzo9kW+D2BcCODkDQlhACvV63LervGaPNn9LlhoBsv6j+koorEi8CWdDycevcT+Dkp/gFz/k1uP1RyQX8z9AeXa/Qjq57xyQBH6i7B+/sMVHGxN9qVYxfc82BDxCyllZdJ7JvAkHY56/fD6Tr3RfwJ+33wzMcPul7gk2HYnw5FojEw+ECErKKgRQZZEiKEDWKhArQBVoNVd1Hh3VHjEnQwLgr3Y+OyU4rb3/AKKLPLrA7ZXA4JeDJ3etfhF6GCABhgNzZQggaxvZtq0mwN54rs4jb8frDvhM/p/XIfsAfuyn6btbYHta5QCL+R4O7g71jwIiErCFs81Rv52Ifmij3h2sSdRTgM511dst2RsG/Ex+j4cEgIR9Oq9hm2DLkFfnG8yeKgbhAH+PuL27TgJFALVpqAgM+OxHOj4HyMDN2lTCVkR4BbryfAT/DMA/r0nCwGe/GmSRfFr9oQo0Hw5OAPwZgFILZJvANg69mhHCCmpwvz6u+ojAVuAyoNnc1XnX+zP5J4/p07xN43BZOOTysVsAwLtMgO+BnwgBznAdqQAD3h+xXAOdvwcYARzngzuK9ZHHZ8AzEigCQD6Ggm3g/UaGmh2MFzWY4LnBm++VfWahBCws4AapzWP9KkAW26rEOgfYe85Aj9YTAZ+BjwRg9fPa+/GffWEOgMPiE/x0uwuTQn+ONMMcwStBpAKRAjAyGLRVxFibVoCqx1c9PwOfveRBEjCgo3+bR8BXCoBL8BCttxL/XpEHn/WGJEBtqRDAz2wi5wgEkgDL7u05ARQZOqDjbuI17rQFj3sjCjBvY38UBhgHkQh32Fk+4Dffg+7Lz7AZVRLg5jESZGTA84vlBIjqFeA43xHvZ8DPAeAkgCvw2ROAwRQxBKyfCjzQHTLg0QMXEYFtXkSCKDlct4kJUAU9Aj8CnhFAqUD0IX1WvN5bNDWM1HbLB1Q4MAc2ux7ZKJYvsNxAkYE9BUyEAF3Q3wL8SAWKZMDUzAgZmGXgz6s+kVr4J+zwfaMnAsp/pgQmZqS9u0KG7XuAKhFUWRX4igIoAkT7FMR9Rgpv1anrpPAMRDiTR8do49izh/+ov6+U5QTe1uVrAnS9P1MAVs6AizwfCaBIch1nmtc+ybwfwR/hrbl+7z12gccRqzOwQAkQfEWIaYAA6pzNO1tLJP0Z+OqR0c0/Any9BeslI8A9AphTgLM4qo3LvL9CBEvAz0JA1+tHgFdEyOI/O4cxo8e+KBwwy6Y9uaWuSeDVAEkwJ2W4Md587pARoR4S6gSIgM9At+QhO/N+bBe5JAG3m/x1/G89Jo6CJMCyCHymBuxLqY4CbMuO9MkkO46QQIEekaDyjmTOvZ+RomKK/0iAdd84kiIBAxrrO1SMiIBkuZt+DMxUIAPeCgAqImTlRP5x+xX4HSVgy878jffOvN6AFCbIoKwSCnCGBmXRewC2wRnwrGyPArC2ZJzI27NHP28znKtlRVFVk4CFBgtAr6iA7zsignpCUO8BHun9FihBVQFYmcEcYZuzpI89AeB5tsS156NlI6IamCPGROrUGKwNi/n8PE8CO7vR+UQqwMrEGCrejySC0RbgJ1cBNJT7xVQYMKEC+CTg21cSQlvNXhMg2gm2MwavujMPVnVROzWuWxaL95kvKiNDSBVA24aCORhZkUO19aPi46EvZ7OLQkCFDJnXWy97fwTgzPuVt7OcgC3Zmx9ePWFrq9Jtj/xnv1lkVL7YkW44HrskGAW/EhaunynwfgZyRf7VsvGjiMO2fjujyJT8qxdATA2Et9DZzYQAuHoT53uJUAGb9QtLYLKPW54pAVq2fb5++xh4b2NDJGAWeXhkeViIQ0CHBL6O5QJnqK8SBW1ef+HjDcGvJn7KIgXAo8F0fdl2/D1kYH2xDVM5wLqOhwDUthGPNwd65ZGw83HLUO8AVOKnCFH1L0UCvr04FlJlDxHi2K7br8tyAmSK8KiPuX7ZeG4ZatuybL/yCIhDKu9HH1H5fhwKuD7k5jN/ZpH0q6eALuhsdx7xMZi7QEbJvMoJujYLeLBMqQCOP4ck6Mx0AV/lBdFscCbqy6Aq4KzsrUhRADcixV5TCqDlfr2tfA4jRJib4MdqwL8LYBoXgfPGwCvv99dZWBhJBlH6zZ3j0WDKOD4PBQz00bAwZsfVSnHVUd2jwFc7B+XM+1WZFQgRGYJuUMaOUd+MQOs72GjVHivlfrz1Zh9DQDKwWVlVKXCt2T3JlmTL3mOZAvCt3Y7P4YmeDCIisN4iuef36CQwUwBL3v2rtla4B9Yfef+ICkTGfLEj/1keoNtFNFFg45NANHucwaW+/hRQVYWqoijQbX3tX/lmgLIEkZFBgTQCPgLKVIBBux6L0any/KFeBSvbEoK/CRy5jry4Cjq7r+Dh6ulAPSVULALfoNzc1CtPAjoUoFZUSJAlkDPsyHrjx14EZR6d1VnSJ2wYs47MszbRfRn4ka9GCoD9befBRlU9VK8n2FyVA1gAIF5HIEflqh/cPeL9VaD3ZP9okT+hr6pxYsDZGFWaVa+53ix1eQjA8lHwM0LYekzltdEH27F+Rojgp5ZFa+R0FDoiaDTNqqRgM9+2O/zs4FsynjsfyeZHPZ2d41QtmC67D/uMtndtKqOJzrM63u4oZ1cJDRnIbIWZ9Cfer4wlgo/2dtbGwLeYjeT4+7KQSruLHW51jwS/6vHK3RIJV5xWhn11iRF5P7tWfYhoJ/vlweyRSjBdQ0AGLK5ASTfew67xngd4/2jbzCqy7q+romgh6GpVeBwhwbbs0AI8onBVFfBeshuZ92fblJVlVgW+AjCW9Qmh9OsxJNgmgWymkVdnyqHa42qTn3lhmVqiurfSdwZM5LUKWNU36y8nAbOe5GObdQ7QCQPsPpz9Dq/PwIvqWELYtUyaI0/ORFNtSWzKk3GFVYUwkgPgDKvg42oqwOOuNZb/c1s0/czzo2UG/hD0WQ0JrGyrEHkOYAH4VryPnbtjZUkGZartW5GkwuFIHCsqUA8FjyJBlgNEK1MrUaFAWdH7o/IO6FnbzrRVfTcX6Fk3DJggASrAHvAzSrOypvePePajcwEGeiVXYPeOq4AJXTTq4VndPQnEWXVkHlcR9ZmvTlpF5kdUoWsqD1Cyn5EmU5I8H8CyOgnqIQBXizPMyBFMPxOzyjIzT+8QYr9M6367PqUt2jVWrp4CzN7vlvlo5oPeXwVxr8SPGvN0ZqpN1etroWDk+HrP+5cvg/5js72/jaKkPZN8toJAAzupDJ53LFIQnHY0xrIE1UYBytr7sXy/ag5LOa/3NZWju8/sw/8BT1vrMTgvQV8AAAAASUVORK5CYII='); + background-size: 100% 100%; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; -fieldset { - border: unset; - display: unset; -} - -code { - padding: 2px; -} - - -/* bootstrap materialize fix */ -.form-row { - margin-left: 0 !important; - margin-right: 0 !important; -} - -/* New design */ -a[href] { - color: #4d7bff; - text-decoration: none; - - &:hover { - color: #8aa8ff; + font-weight: bold; + border-bottom: 1px solid #ab4788; + line-height: 1em; } - &:visited { - color: #2752cd; - } -} - -/* tooltip */ -#global-tooltip { - color: #999999; - background-color: #232222; - - position: fixed; - z-index: 1000000; - - pointer-events: none; - - padding: .25em; - transform: translate(-50%, -100%); /* translate up, center */ - - text-align: center; - border-right: 3px; - - display: flex; - flex-direction: column; - justify-content: space-around; - - opacity: 0; - @include transition(opacity .5s ease-in-out); - - &:after { - content: ''; - position: absolute; - - width: 0; - height: 0; - - left: calc(50% - .5em); - bottom: -.4em; - - border-style: solid; - border-width: .5em .5em 0 .5em; - border-color: #232222 transparent transparent transparent; + iframe { + border-radius: .2em; + border: none; } - &.shown { - opacity: 1; + select, input { + -webkit-appearance: none; } -} - -/* colored letters */ -a.rainbow-letter { - background-image: url('data:img/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAV/klEQVR4nM1dbY7j1hFsauSsk2CBAPkXBPkZ5Ca+QY6V+wS5SA5g569jrGN7d0diMCNRahar+uNRY7sDmeR7j++rqqublHYyffWPv39jNr+3V5tte8QyVZ4d120ms9fPYpM74vlUKF8+h2Idtjsk5f7aknGij1qjBceVzQSKKnTb44ejmf3pMtRs/GhQ5yFT97B2fC10kaSd7y1rW+lzj7H+I0BZO9U2unezjfvAf/m8P5hNH+IpVKaJ00X/tk17tRa2zq6hkzzC2IqYMm1Xyu8bWlT1WCHK5fzDoQ5wpw0uVW2Nnqtaiy9nhFd9jVjVkysWuUjJ+6MFsSiN10IdDr3pVKYaqUI870gFEHTVLjLVtguwqot2EetbfUceXZN62f5Q83JWVlWHDkm26+3I+V6CjBqushMgy14feUvUNiGLU4BoaiPqYKW6jgqw+7p1lfu9RUlbxaPZvZWx6GS7SV+h/lAHvKsOWSioq4AvY+vKPL+bYI4kaVPwYe0s3YEiy7vgw4YdttOOprnH83V9pm7VMPBo+VerHInrUd6AY73aYExPwYe2SQjISNDx/Gi5WgW6Up8lypFlIFXL1T2ZC8lJvxH4xRDw6Hq+VVUVUGGA7Rvrp2tV8CMdbRMoyu7VeRV8+ATvAfaQoNv2ch3F/cywXUcdKhatspIzlL2/kt2z8xEiWPoeYJQE2VJVGrRWA2UR0I8CvuK1FRVQ99P6itcrj1Z12A7KyXuADrCqHpdYinhyzZW1Zn1VrRrXKyqQEaJMgkeBT/pthABGDrb8KoHqKlANAdl5tT81M6zP6qJ+Q+nvyLmqUwkTtIEQEAGPZWxJXeD74OOasj1U12gVyceZZrRn3l/yenau2nRVAdoETwEZcBkJsu2KjBOhQoZO/oDWlfisDtux883EokUrMLGMtRGfo57+7KatztkKJtIH1rHraXWsjKhG3/ZWAwkt8n5cqTkyDHm/EfCMXEfyPpAfHDUIFpzjChjo7FoBj+ObJAJaB9gKEbJQwMDPVECSIPP6ild37iFtj3zZ2VZ1QDcAFesVrDUVmDd3Pcb7fZ94ngVG5f2p9O8BPyNDrgAViyDJQMc2CJ0J2LQKKNpmWqZmrCwiAZuHVeoUKNF1Rgosi8aZKQGUJFfyhGilEVHYuL5mur0jVBSzlELr8zmZeRa/I/BL3o9g+/PM60fAzwnQkfwRQlSh82V3KKMAgj2OerkyJvPqXJGBmgJ+BPz9BOhaJxSMlHs/ttU51vjNZnfvAV/1z0hgCRFWk1MAYZtR8PcRIBJPv3SkcJUEbFsiReAqwHqO4n8k+xUQ1diZ94fSX/H4EfADwAkB1NIMgJ7g7m7sr9arUHCvU96Ps4tAr1gUzyOShON1PL5KEFaPZTj29UjeA+DMKrE/Wm1GAiv6tW7Nykdmm2XzmANgeZr4KQXYS4AM8F4IqFpF9lm0ZqZCg7m6XAWY/LN9YBZJuIrp5aSvAqQFbV7sXLy/4PW+TBCg4j8ILgN7VDWwz5oKYGsWAjIisL6NkIEpALalS1Pgnd1xRAlYHS74sQrAVveovrDPWAUwSO2ZSSWut3KDyMsXq4KfqUAEuqhrECCS8wl6fitbgJ9u//V7qRSgOrNM0qNsnxoOzEhQAf8RXt8jQCbnWM98bnKr22PMr+fVyEbAz54vIkKg1DP5z9psBs48uwt+FBIsOXf14lWwAjRTAFz1YUAVIkjvdV4LcF1MAXzvbEYqtrN2WZvVQNlnFPyMDLjYWAFmt5wuYOyePSHh4HZFbe98+6/K+lmSWJ1NFNujJPB23yPBP8PkO2pgpA7Oj2vg9xDBb9novb4PZWt451tGsFzfj0wBOqNmRMB6ah3wu/kALjS6Zufbx8AKETArn0Wd2uJzIT+IPH89Bht9mylsCYLnOHIU11UucOs080wEeE8OgE8GOB6rc0fxbeCjFIFF4wMckf7mwgDubD0k4LnBCjKaKiKoBPDWaRdspQRVrx8EHgigAI48nJ1jXYc0CHp2fR9rduNEe4F7wozJegq8Hzz6eGC7wO/xfrbw6/Xgi6CRMFCR/wx0Bs+8GhN1gu1btCojQLMymvipQSPwFehYrvpViyyqQECAiuxXwPdqUJV/X+ZJoNOuBX4MOjgjtaLokU95PpV+Bi4eO0SIFKADPCMo/y4gi/8ZyHidkciAEAz4g1MPP6Zt+o+UUO1HN96niR8DmZGgmwyqsdjC2Tk5NhSgI/WsXbZLizHgl36YGtzLmAqYmCWbtT/PgN9IP1uSAr/j+dH7f0vOsR7L1wSIJL+bDBoAr/rzQLOVnR3A6jgDfPNm7Wrv1EqNgC7jvgJYnTPg98g/LhTnZsFRK8CepwIGPFMBC3IBDzau4gwhwRPB6BdF2f75WVY/m86r4Kt8oEIEBnZ0zshg6/bJ7wGqqpDlBUwV2OoPwfn5/ucMNuBPEArmdA/ZajbyLv4m8GpT0ZO7RGAEMOcLLAQgqBVvF8RoKAB6eFQege7vY9l/tCpPAhNEuPSdkUDZ5HpMwUfgGegdBZgT4B8Euj8Xr4KtWKaOBsArz8cQUNUztLODaE4JwKhoBOww9iPoEQnwvEKALvAV0ElZ8z3ASJkiRfSZ3A5VCIB2bqtA9VGQPrpViJB5fwR8BjpeF8G3LQFm44SoAI9plwoJ5yIRCrNfmVeU6UoAoyTAGXnZDwlQBb1CAlQCcyRAMrBzVVbZNk2AStLnge7kBcv5wd1fIcDkSIN5A9oJ+ucEiDTEx3//fyJx69IDe0quR57/cWssOUdQG+BbHAKsQYjKUamC+qgwIMUZ2l4Sw7kYClTidwMfgT0REpwI8NXkrwv6IOBYF7wKZpa9H2BhQK2mEgYYuc4EeGXzLRfwD5NnsgoE3R830u/BZwRg4FeAHwW9ATha4dtAJe+sjrXxbdnK/DUGwWXXojDgyYBqMF+DwJoEOGoIvgnQUQFQ/hXweI3bwMCtSH50HtQn/zjUb3JGAg+wuleFAazD4xnKPFwnd32Sq57tRPfeBPg3AnhQn4EACvzqI98er4/OszpX3gwBqp1KDKMytmK2K/jU4OE6O+CZkr20f7qeXTQAsTGg1JMjwGuDBehncR7F/4wAagtwiywoU21UPZQXFcCKxFDgG6yIPSUoMmCugOD7sBAlh2fqoIsdEHwDwJ8JEZAAFdnH5bGlG5yPeH1WrkOAknJmrG2kDGxVKugpZWDv/88FAlw+Z1ABg8e+GwEQ/GcgwkkAHz3ndyQ/OlfwVAnh6smLoMWUCrCeWY7g2ylSVI/4mVw653ceYdwS4Xz7rGf05D63eP/5+lnOUQE6Md8SwB8JfFbu6o8cnOSuMjlU30wRTOwK20H8BdEsSMBDwen1f/dniYMD/7X1AvgnIMFCgOiRj30MlqGucZuja9amWufsgf86eDGlBoupHMEIAbCMEYIR4OmK0JOL7Pcxz9dnAk+A4/VzA/7l85EQgCV8UZzHc7U8PO+WKUvaJn8ihlklR6i+TGLkiM4ZGSI1eAYS3H9P8GyfXmvNg3+6gv7T9fMJpB9jfgV4XM6Ip6M9qs2YAlTDhXosY3UqTLA2SkcZCY4uYC8wX0jwEgg+X98b/GYhwI9m9r/r8SMBP5L6aIpqSWx51fKuiX4GCBCBNHqvmkPHXRQZls8LzO883PbRvns9fvnyn+/N7L9XAnjwTwOgV6ef2aPAD+y47/Y9+UP13q7bROHiBcnfmtnvzex31xzgOzu+gP/NlQSfRIxX3XemO2pvSIQ3SAIfbW81vz+a2V/sr//81y+3tF+B/coI8KC5KBFYkrhPV6n/2uzf9pX97TXj+/rl/039qv8nl+0pzcdzNoFH2dtJQBACfmXKkIV/f46qf3Zv8T5ewf/W7PDt5ZaP9qW9sz9fk4Dvr48A/tlvhphgghRv8Rxnje9n+vbLKkDHgaI4zECfXSxfXux8vGb431+c/d319h9fU8MvbbI/mNkXZvYDvATAFwAsI1QJabSAzqZ0XtFXbd6bBILteT6t5HMGe6u83X9B49/q/XRF+wezw/Nd/pbqd5fngeuj4hfujdAzeQWILwLYhNjk1YLxUTgjQrRxzFi7qUCAPf1X2mR7knn7DFic4Yucz0CAq7o/ufi3NDu+vjL6zbXUvyD+HHwNyL79wYniAtRi/Xn0HiVrx4yHkeMur+20q5BfyTzzenwNi7/OeQYCfLyr+uHsXwmtU4SDHWx69X5zXzo9kW+D2BcCODkDQlhACvV63LervGaPNn9LlhoBsv6j+koorEi8CWdDycevcT+Dkp/gFz/k1uP1RyQX8z9AeXa/Qjq57xyQBH6i7B+/sMVHGxN9qVYxfc82BDxCyllZdJ7JvAkHY56/fD6Tr3RfwJ+33wzMcPul7gk2HYnw5FojEw+ECErKKgRQZZEiKEDWKhArQBVoNVd1Hh3VHjEnQwLgr3Y+OyU4rb3/AKKLPLrA7ZXA4JeDJ3etfhF6GCABhgNzZQggaxvZtq0mwN54rs4jb8frDvhM/p/XIfsAfuyn6btbYHta5QCL+R4O7g71jwIiErCFs81Rv52Ifmij3h2sSdRTgM511dst2RsG/Ex+j4cEgIR9Oq9hm2DLkFfnG8yeKgbhAH+PuL27TgJFALVpqAgM+OxHOj4HyMDN2lTCVkR4BbryfAT/DMA/r0nCwGe/GmSRfFr9oQo0Hw5OAPwZgFILZJvANg69mhHCCmpwvz6u+ojAVuAyoNnc1XnX+zP5J4/p07xN43BZOOTysVsAwLtMgO+BnwgBznAdqQAD3h+xXAOdvwcYARzngzuK9ZHHZ8AzEigCQD6Ggm3g/UaGmh2MFzWY4LnBm++VfWahBCws4AapzWP9KkAW26rEOgfYe85Aj9YTAZ+BjwRg9fPa+/GffWEOgMPiE/x0uwuTQn+ONMMcwStBpAKRAjAyGLRVxFibVoCqx1c9PwOfveRBEjCgo3+bR8BXCoBL8BCttxL/XpEHn/WGJEBtqRDAz2wi5wgEkgDL7u05ARQZOqDjbuI17rQFj3sjCjBvY38UBhgHkQh32Fk+4Dffg+7Lz7AZVRLg5jESZGTA84vlBIjqFeA43xHvZ8DPAeAkgCvw2ROAwRQxBKyfCjzQHTLg0QMXEYFtXkSCKDlct4kJUAU9Aj8CnhFAqUD0IX1WvN5bNDWM1HbLB1Q4MAc2ux7ZKJYvsNxAkYE9BUyEAF3Q3wL8SAWKZMDUzAgZmGXgz6s+kVr4J+zwfaMnAsp/pgQmZqS9u0KG7XuAKhFUWRX4igIoAkT7FMR9Rgpv1anrpPAMRDiTR8do49izh/+ov6+U5QTe1uVrAnS9P1MAVs6AizwfCaBIch1nmtc+ybwfwR/hrbl+7z12gccRqzOwQAkQfEWIaYAA6pzNO1tLJP0Z+OqR0c0/Any9BeslI8A9AphTgLM4qo3LvL9CBEvAz0JA1+tHgFdEyOI/O4cxo8e+KBwwy6Y9uaWuSeDVAEkwJ2W4Md587pARoR4S6gSIgM9At+QhO/N+bBe5JAG3m/x1/G89Jo6CJMCyCHymBuxLqY4CbMuO9MkkO46QQIEekaDyjmTOvZ+RomKK/0iAdd84kiIBAxrrO1SMiIBkuZt+DMxUIAPeCgAqImTlRP5x+xX4HSVgy878jffOvN6AFCbIoKwSCnCGBmXRewC2wRnwrGyPArC2ZJzI27NHP28znKtlRVFVk4CFBgtAr6iA7zsignpCUO8BHun9FihBVQFYmcEcYZuzpI89AeB5tsS156NlI6IamCPGROrUGKwNi/n8PE8CO7vR+UQqwMrEGCrejySC0RbgJ1cBNJT7xVQYMKEC+CTg21cSQlvNXhMg2gm2MwavujMPVnVROzWuWxaL95kvKiNDSBVA24aCORhZkUO19aPi46EvZ7OLQkCFDJnXWy97fwTgzPuVt7OcgC3Zmx9ePWFrq9Jtj/xnv1lkVL7YkW44HrskGAW/EhaunynwfgZyRf7VsvGjiMO2fjujyJT8qxdATA2Et9DZzYQAuHoT53uJUAGb9QtLYLKPW54pAVq2fb5++xh4b2NDJGAWeXhkeViIQ0CHBL6O5QJnqK8SBW1ef+HjDcGvJn7KIgXAo8F0fdl2/D1kYH2xDVM5wLqOhwDUthGPNwd65ZGw83HLUO8AVOKnCFH1L0UCvr04FlJlDxHi2K7br8tyAmSK8KiPuX7ZeG4ZatuybL/yCIhDKu9HH1H5fhwKuD7k5jN/ZpH0q6eALuhsdx7xMZi7QEbJvMoJujYLeLBMqQCOP4ck6Mx0AV/lBdFscCbqy6Aq4KzsrUhRADcixV5TCqDlfr2tfA4jRJib4MdqwL8LYBoXgfPGwCvv99dZWBhJBlH6zZ3j0WDKOD4PBQz00bAwZsfVSnHVUd2jwFc7B+XM+1WZFQgRGYJuUMaOUd+MQOs72GjVHivlfrz1Zh9DQDKwWVlVKXCt2T3JlmTL3mOZAvCt3Y7P4YmeDCIisN4iuef36CQwUwBL3v2rtla4B9Yfef+ICkTGfLEj/1keoNtFNFFg45NANHucwaW+/hRQVYWqoijQbX3tX/lmgLIEkZFBgTQCPgLKVIBBux6L0any/KFeBSvbEoK/CRy5jry4Cjq7r+Dh6ulAPSVULALfoNzc1CtPAjoUoFZUSJAlkDPsyHrjx14EZR6d1VnSJ2wYs47MszbRfRn4ka9GCoD9befBRlU9VK8n2FyVA1gAIF5HIEflqh/cPeL9VaD3ZP9okT+hr6pxYsDZGFWaVa+53ix1eQjA8lHwM0LYekzltdEH27F+Rojgp5ZFa+R0FDoiaDTNqqRgM9+2O/zs4FsynjsfyeZHPZ2d41QtmC67D/uMtndtKqOJzrM63u4oZ1cJDRnIbIWZ9Cfer4wlgo/2dtbGwLeYjeT4+7KQSruLHW51jwS/6vHK3RIJV5xWhn11iRF5P7tWfYhoJ/vlweyRSjBdQ0AGLK5ASTfew67xngd4/2jbzCqy7q+romgh6GpVeBwhwbbs0AI8onBVFfBeshuZ92fblJVlVgW+AjCW9Qmh9OsxJNgmgWymkVdnyqHa42qTn3lhmVqiurfSdwZM5LUKWNU36y8nAbOe5GObdQ7QCQPsPpz9Dq/PwIvqWELYtUyaI0/ORFNtSWzKk3GFVYUwkgPgDKvg42oqwOOuNZb/c1s0/czzo2UG/hD0WQ0JrGyrEHkOYAH4VryPnbtjZUkGZartW5GkwuFIHCsqUA8FjyJBlgNEK1MrUaFAWdH7o/IO6FnbzrRVfTcX6Fk3DJggASrAHvAzSrOypvePePajcwEGeiVXYPeOq4AJXTTq4VndPQnEWXVkHlcR9ZmvTlpF5kdUoWsqD1Cyn5EmU5I8H8CyOgnqIQBXizPMyBFMPxOzyjIzT+8QYr9M6367PqUt2jVWrp4CzN7vlvlo5oPeXwVxr8SPGvN0ZqpN1etroWDk+HrP+5cvg/5js72/jaKkPZN8toJAAzupDJ53LFIQnHY0xrIE1UYBytr7sXy/ag5LOa/3NZWju8/sw/8BT1vrMTgvQV8AAAAASUVORK5CYII='); - background-size: 100% 100%; - - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - - font-weight: bold; - border-bottom: 1px solid #ab4788; - line-height: 1em; -} - -iframe { - border-radius: .2em; - border: none; -} - -select, input { - -webkit-appearance: none; } \ No newline at end of file diff --git a/shared/css/static/hostbanner.scss b/shared/css/static/hostbanner.scss deleted file mode 100644 index 079c6cb6..00000000 --- a/shared/css/static/hostbanner.scss +++ /dev/null @@ -1,83 +0,0 @@ -@import "mixin"; - -html:root { - --hostbanner-background: #2e2e2e; -} - -.hostbanner { - .container-hostbanner { - position: relative; - - overflow: hidden; - height: 1000px; /* allocate some height to be truncated by the flex :) */ - - display: flex; - flex-direction: column; - justify-content: stretch; - - cursor: pointer; - - &:not(.no-background) { - background-color: var(--hostbanner-background); - border-top-left-radius: 5px; - border-top-right-radius: 5px; - -moz-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.25); - -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.25); - box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.25); - padding-bottom: 5px; - } - - &.disabled { - padding-bottom: 0; - height: 0; - } - - @include transition(height 0.5s ease-in-out); - - .hostbanner-image-container { - height: 100%; - width: 100%; - - flex-grow: 1; - flex-shrink: 1; - min-height: 0; - - text-align: center; - - &.hostbanner-mode-0 { - /* do not adjust */ - display: block; - } - - &.hostbanner-mode-1 { - /* do adjust and ignore ration */ - display: flex; - - height: 100%; - width: 100%; - - > img { - width: 100%; - height: 100%; - } - } - - &.hostbanner-mode-2 { - display: flex; - flex-direction: row; - justify-content: space-around; - - > img { - object-fit: contain; - max-height: 100%; - - /* "Normal" third more */ - //max-width: 100%; - - /* better adoptable mode */ - width: min-content; - } - } - } - } -} \ No newline at end of file diff --git a/shared/css/static/htmltags.scss b/shared/css/static/htmltags.scss index afe59076..94ce09ba 100644 --- a/shared/css/static/htmltags.scss +++ b/shared/css/static/htmltags.scss @@ -1,5 +1,7 @@ -.htmltag-client, .htmltag-channel { - color: var(--text); - font-weight: bold; - cursor: pointer; +:global { + .htmltag-client, .htmltag-channel { + color: var(--text); + font-weight: bold; + cursor: pointer; + } } \ No newline at end of file diff --git a/shared/css/static/main-layout.scss b/shared/css/static/main-layout.scss index ec1c50a4..09521d9f 100644 --- a/shared/css/static/main-layout.scss +++ b/shared/css/static/main-layout.scss @@ -16,77 +16,85 @@ html:root { --channel-chat-seperator: #1e1e1e; --channel-chat-seperator-selected: #707070; + + --server-log-text: #6e6e6e; + --server-log-error: #e62222; + --server-log-tree-entry: #d8d8d8; + + --hostbanner-background: #2e2e2e; } -.hide-small { - opacity: 1; - transition: opacity $animation_length linear; -} - -.show-small { - display: none; - - opacity: 0; - transition: opacity $animation_length linear; -} - -.app-container { - right: 0; - left: 0; - top: 0; - - overflow: auto; - padding: 0; -} - -@media only screen and (max-width: $small_device) { +:global { .hide-small { - display: none; - opacity: 0; + opacity: 1; transition: opacity $animation_length linear; } .show-small { - display: block !important; + display: none; - opacity: 1 !important; + opacity: 0; transition: opacity $animation_length linear; } -} -$animation_seperator_length: .1s; -.container-seperator { - @include transition(all $animation_seperator_length ease-in-out); - background: var(--channel-chat-seperator); + .app-container { + right: 0; + left: 0; + top: 0; - flex-grow: 0; - flex-shrink: 0; - - &.horizontal { - height: $separator_thickness; - width: 100%; - - cursor: row-resize; + overflow: auto; + padding: 0; } - &.vertical { - width: $separator_thickness; - height: 100%; + @media only screen and (max-width: $small_device) { + .hide-small { + display: none; + opacity: 0; + transition: opacity $animation_length linear; + } - cursor: col-resize; + .show-small { + display: block !important; + + opacity: 1 !important; + transition: opacity $animation_length linear; + } } - &.seperator-selected { + $animation_seperator_length: .1s; + .container-seperator { @include transition(all $animation_seperator_length ease-in-out); + background: var(--channel-chat-seperator); - background-color: var(--channel-chat-seperator-selected); + flex-grow: 0; + flex-shrink: 0; + + &.horizontal { + height: $separator_thickness; + width: 100%; + + cursor: row-resize; + } + + &.vertical { + width: $separator_thickness; + height: 100%; + + cursor: col-resize; + } + + &.seperator-selected { + @include transition(all $animation_seperator_length ease-in-out); + + background-color: var(--channel-chat-seperator-selected); + } } -} -html, body { - overflow: hidden; -} + html, body { + overflow: hidden; + } -body { - background: var(--app-background)!important; + body { + background: var(--app-background)!important; + } } \ No newline at end of file diff --git a/shared/css/static/menu-bar.scss b/shared/css/static/menu-bar.scss deleted file mode 100644 index a1530f9c..00000000 --- a/shared/css/static/menu-bar.scss +++ /dev/null @@ -1,133 +0,0 @@ -@import "mixin"; - -.top-menu-bar { - @include user-select(none); - - height: 1.5em; - width: 100%; - - background: #fafafa; - - display: flex; - flex-direction: row; - justify-content: flex-start; - - position: fixed; - top: 0; - z-index: 201; - - font-family: Arial, serif; - - .container-menu-item { - position: relative; - - .menu-item { - cursor: pointer; - - padding-left: .4em; - padding-right: .4em; - - height: 100%; - - display: flex; - flex-direction: row; - width: max-content; - - > * { - vertical-align: middle; - } - - .container-icon { - height: 1.2em; - width: 1.2em; - padding: .1em; - font-size: 1em; - - margin-right: .2em; - display: inline-block; - } - - .container-label { - display: inline-block; - align-self: center; - - a { - white-space: nowrap; - } - } - } - - &:hover:not(.disabled) { - background-color: rgba(0, 0, 0, 0.27); - } - - &.disabled { - background-color: rgba(0, 0, 0, 0.13); - } - - &.hidden { - display: none; - } - - .sub-menu { - z-index: 1000; - display: none; - - background: white; - position: absolute; - - top: 100%; - border: 1px solid black; - - > .container-menu-item { - padding-right: .5em; - } - } - - &.type-side { - &.sub-entries:after { - position: absolute; - - display: block; - content: '>'; - - top: 0; - bottom: 0; - - right: .4em; - } - - > .sub-menu { - top: -1px; /* border */ - left: 100%; - } - - &:hover { - > .sub-menu { - display: block; - } - } - } - - &.active { - background-color: rgba(0, 0, 0, 0.27); - - > .sub-menu { - display: block; - } - } - } - - > .container-menu-item { - > .menu-item { - .container-icon { - display: none; - } - } - } - - hr { - margin-top: .125em; - margin-bottom: .125em; - } -} \ No newline at end of file diff --git a/shared/css/static/modal-about.scss b/shared/css/static/modal-about.scss index 6c0999e0..76395463 100644 --- a/shared/css/static/modal-about.scss +++ b/shared/css/static/modal-about.scss @@ -1,59 +1,61 @@ -.modal-about { - display: flex!important; - flex-direction: row!important; +:global { + .modal-about { + display: flex!important; + flex-direction: row!important; - text-align: center; - color: #999999; + text-align: center; + color: #999999; - .container-left { - display: flex; - flex-direction: column; - justify-content: center; - } - - .container-right { - text-align: left; - padding-left: 2em; - - h1 { - font-size: 1.5em; - margin-block-start: 0.35em; - margin-block-end: 0.35em; + .container-left { + display: flex; + flex-direction: column; + justify-content: center; } - h2 { - font-size: 1.25em; - margin-block-start: 0.10em; - margin-block-end: 0.10em; - } - - p { - margin-block-start: .25em; - margin-block-end: .25em; - } - } - - .version { - width: 100%; - display: flex; - flex-direction: row; - justify-content: stretch; - - a { - width: 50%; - - flex-grow: 1; - flex-shrink: 1; - - text-align: right; - } - .value { - padding-left: .25em; - + .container-right { text-align: left; + padding-left: 2em; - flex-grow: 1; - flex-shrink: 1; + h1 { + font-size: 1.5em; + margin-block-start: 0.35em; + margin-block-end: 0.35em; + } + + h2 { + font-size: 1.25em; + margin-block-start: 0.10em; + margin-block-end: 0.10em; + } + + p { + margin-block-start: .25em; + margin-block-end: .25em; + } + } + + .version { + width: 100%; + display: flex; + flex-direction: row; + justify-content: stretch; + + a { + width: 50%; + + flex-grow: 1; + flex-shrink: 1; + + text-align: right; + } + .value { + padding-left: .25em; + + text-align: left; + + flex-grow: 1; + flex-shrink: 1; + } } } } \ No newline at end of file diff --git a/shared/css/static/modal-avatar.scss b/shared/css/static/modal-avatar.scss index bd6f4e10..29942ba1 100644 --- a/shared/css/static/modal-avatar.scss +++ b/shared/css/static/modal-avatar.scss @@ -1,289 +1,291 @@ -.modal-avatar-list { - display: flex!important;; - flex-direction: row!important;; +:global { + .modal-avatar-list { + display: flex!important;; + flex-direction: row!important;; - .container-list { - width: 50%; + .container-list { + width: 50%; - margin-top: 5px; + margin-top: 5px; - display: flex; - flex-direction: column; - justify-content: stretch; - - .column { - &.column-username { - width: calc(50% - 100px); - overflow: hidden; - text-overflow: ellipsis; - } - - &.column-unique-id { - width: calc(50% - 100px); - overflow: hidden; - text-overflow: ellipsis; - } - - &.column-size { - width: 75px; - flex-grow: 0; - flex-shrink: 0; - - text-align: center; - } - - &.column-timestamp { - width: 150px; - flex-grow: 0; - flex-shrink: 0; - - text-align: center; - } - } - - .list-header { - flex-grow: 0; - flex-shrink: 0; - display: flex; - flex-direction: row; - - .column { - border: 1px solid lightgray; - text-align: center; - } - } - - .list-entries-container { - flex-grow: 1; display: flex; flex-direction: column; - justify-content: start; - overflow-y: auto; - min-height: 250px; + justify-content: stretch; - .entry { + .column { + &.column-username { + width: calc(50% - 100px); + overflow: hidden; + text-overflow: ellipsis; + } + + &.column-unique-id { + width: calc(50% - 100px); + overflow: hidden; + text-overflow: ellipsis; + } + + &.column-size { + width: 75px; + flex-grow: 0; + flex-shrink: 0; + + text-align: center; + } + + &.column-timestamp { + width: 150px; + flex-grow: 0; + flex-shrink: 0; + + text-align: center; + } + } + + .list-header { + flex-grow: 0; + flex-shrink: 0; display: flex; flex-direction: row; .column { - margin-left: 2px; - } - - cursor: pointer; - - &.selected { - background-color: lightblue; + border: 1px solid lightgray; + text-align: center; } } - &.scrollbar { - .column-username { - width: calc(50% - 100px + 30px) - } - - .column-unique-id { - width: calc(50% - 100px + 30px) - } - } - } - } - - .container-info { - margin-left: 10px; - - position: relative; - width: 50%; - - .container-data { - width: 100%; - } - - .container-preview { - display: flex; - flex-direction: row; - justify-content: stretch; - - .container-image { - flex-shrink: 0; - flex-grow: 0; - - width: 302px; - height: 302px; - - background-color: whitesmoke; - border: 1px solid black; - border-radius: 2px; - - position: relative; - overflow: hidden; - - > div { - top: 0; - bottom: 0; - left: 0; - right: 0; - - position: absolute; - } - } - - .container-image-data { - margin-left: 10px; - - flex-shrink: 1; + .list-entries-container { flex-grow: 1; + display: flex; + flex-direction: column; + justify-content: start; + overflow-y: auto; + min-height: 250px; + + .entry { + display: flex; + flex-direction: row; + + .column { + margin-left: 2px; + } + + cursor: pointer; + + &.selected { + background-color: lightblue; + } + } + + &.scrollbar { + .column-username { + width: calc(50% - 100px + 30px) + } + + .column-unique-id { + width: calc(50% - 100px + 30px) + } + } + } + } + + .container-info { + margin-left: 10px; + + position: relative; + width: 50%; + + .container-data { + width: 100%; + } + + .container-preview { + display: flex; + flex-direction: row; + justify-content: stretch; + + .container-image { + flex-shrink: 0; + flex-grow: 0; + + width: 302px; + height: 302px; + + background-color: whitesmoke; + border: 1px solid black; + border-radius: 2px; + + position: relative; + overflow: hidden; + + > div { + top: 0; + bottom: 0; + left: 0; + right: 0; + + position: absolute; + } + } + + .container-image-data { + margin-left: 10px; + + flex-shrink: 1; + flex-grow: 1; + + a { + text-align: center; + } + + .form-group { + width: 100%; + margin-bottom: 0px; + } + } + } + + .container-buttons { + width: 100%; + margin-top: 20px; + + display: flex; + flex-direction: row; + justify-content: space-between; + } + + .disabled-overlay { + position: absolute; + + top: 0; + bottom: 0; + left: 0; + right: 0; + + background-color: gray; + + display: flex; + flex-direction: column; + justify-content: space-around; a { text-align: center; } - - .form-group { - width: 100%; - margin-bottom: 0px; - } - } - } - - .container-buttons { - width: 100%; - margin-top: 20px; - - display: flex; - flex-direction: row; - justify-content: space-between; - } - - .disabled-overlay { - position: absolute; - - top: 0; - bottom: 0; - left: 0; - right: 0; - - background-color: gray; - - display: flex; - flex-direction: column; - justify-content: space-around; - - a { - text-align: center; } } } -} - -.modal-avatar-upload { - display: flex; - flex-direction: column; - justify-content: stretch; - - .container-upload { - flex-grow: 0; - flex-shrink: 0; - - display: flex; - flex-direction: row; - justify-content: space-between; - - .bmd-form-group { - padding-top: 0; - } - - input[type="file"] { - display: none; - } - } - - .container-preview { - flex-grow: 1; - flex-shrink: 1; + .modal-avatar-upload { display: flex; flex-direction: column; justify-content: stretch; - .title { - font-size: 1.2em; - font-weight: bold; - - border-bottom: 1px solid gray; - } - - .previews { + .container-upload { flex-grow: 0; flex-shrink: 0; display: flex; flex-direction: row; - justify-content: space-evenly; + justify-content: space-between; - align-self: center; + .bmd-form-group { + padding-top: 0; + } - .preview { - flex-shrink: 1; - flex-grow: 1; + input[type="file"] { + display: none; + } + } - width: 11rem; - min-width: 11rem; - max-width: 11rem; + .container-preview { + flex-grow: 1; + flex-shrink: 1; - height: 13rem; - min-height: 13rem; - max-height: 13rem; + display: flex; + flex-direction: column; + justify-content: stretch; - text-align: center; + .title { + font-size: 1.2em; + font-weight: bold; + + border-bottom: 1px solid gray; + } + + .previews { + flex-grow: 0; + flex-shrink: 0; display: flex; - flex-direction: column; - justify-content: flex-end; + flex-direction: row; + justify-content: space-evenly; + + align-self: center; + + .preview { + flex-shrink: 1; + flex-grow: 1; + + width: 11rem; + min-width: 11rem; + max-width: 11rem; + + height: 13rem; + min-height: 13rem; + max-height: 13rem; + + text-align: center; - .container-avatar { display: flex; - flex-direction: row; - justify-content: space-around; + flex-direction: column; + justify-content: flex-end; - .avatar { - position: relative; + .container-avatar { + display: flex; + flex-direction: row; + justify-content: space-around; - height: 1em; - width: 1em; + .avatar { + position: relative; - overflow: hidden; - border-radius: 50%; + height: 1em; + width: 1em; - > img { - position: absolute; + overflow: hidden; + border-radius: 50%; - top: 0; - left: 0; + > img { + position: absolute; - height: 100%; - width: 100%; + top: 0; + left: 0; + + height: 100%; + width: 100%; + } } } - } - > a { - margin-top: 1em; - } - - &.preview-client-info { - .container-avatar { - font-size: 10rem; + > a { + margin-top: 1em; } - } - &.preview-chat { - .container-avatar { - font-size: 2.5rem; + &.preview-client-info { + .container-avatar { + font-size: 10rem; + } } - } - &.preview-chat-entry { - .container-avatar { - font-size: 2rem; + &.preview-chat { + .container-avatar { + font-size: 2.5rem; + } + } + + &.preview-chat-entry { + .container-avatar { + font-size: 2rem; + } } } } @@ -292,7 +294,9 @@ } @media all and (max-width: 40rem) { - .modal-avatar-upload .container-preview .previews { - flex-direction: column; + :global { + .modal-avatar-upload .container-preview .previews { + flex-direction: column; + } } } \ No newline at end of file diff --git a/shared/css/static/modal-banclient.scss b/shared/css/static/modal-banclient.scss index f64b8c56..0c5c44e4 100644 --- a/shared/css/static/modal-banclient.scss +++ b/shared/css/static/modal-banclient.scss @@ -1,293 +1,295 @@ @import "mixin"; @import "properties"; -//TODO: Resize style! -.modal-body.modal-ban-client { - padding: 0!important; +:global { + //TODO: Resize style! + .modal-body.modal-ban-client { + padding: 0!important; - display: flex!important; - flex-direction: column!important; - justify-content: stretch!important; + display: flex!important; + flex-direction: column!important; + justify-content: stretch!important; - //min-width: 30em!important; - max-height: calc(100vh - 10em); - width: 40em; + //min-width: 30em!important; + max-height: calc(100vh - 10em); + width: 40em; - min-height: 20em; + min-height: 20em; - .container-tooltip { - flex-shrink: 0; - flex-grow: 0; + .container-tooltip { + flex-shrink: 0; + flex-grow: 0; - position: relative; - width: 1.6em; + position: relative; + width: 1.6em; - margin-left: .5em; - margin-right: .25em; + margin-left: .5em; + margin-right: .25em; - font-size: .9em; + font-size: .9em; - display: flex; - flex-direction: column; - justify-content: center; + display: flex; + flex-direction: column; + justify-content: center; - img { - height: 1em; - width: 1em; + img { + height: 1em; + width: 1em; - align-self: center; - font-size: 1.2em; + align-self: center; + font-size: 1.2em; + } + + .tooltip { + display: none; + } } - .tooltip { - display: none; + .container-info { + flex-shrink: 0; + flex-grow: 0; + + padding: .5em; + + display: flex; + flex-direction: row; + justify-content: stretch; + + .container { + flex-grow: 1; + flex-shrink: 1; + + min-width: 4em; + width: 10em; + + display: flex; + flex-direction: column; + justify-content: stretch; + + .title { + text-transform: uppercase; + color: #557edc; + + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + .value { + flex-grow: 1; + flex-shrink: 1; + min-height: 2em; + + padding: .5em; + + border-radius: 0.2em; + border: 1px solid #111112; + background-color: #121213; + + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + + @include chat-scrollbar-vertical(); + } + } } - } - .container-info { - flex-shrink: 0; - flex-grow: 0; + .container-duration { + margin: 1em; + margin-top: 0em; - padding: .5em; + display: flex; + flex-direction: column; + justify-content: flex-start; - display: flex; - flex-direction: row; - justify-content: stretch; + > a { + flex-grow: 0; + flex-shrink: 0; + } - .container { - flex-grow: 1; + .container-value { + flex-grow: 0; + flex-shrink: 0; + + display: flex; + flex-direction: row; + justify-content: stretch; + + .input-boxed.value { + flex-grow: 1; + flex-shrink: 1; + + min-width: 6em; + + margin-right: 1em; + } + + select { + width: 7em; + padding-left: .5em; + } + } + } + + .container-reason { + margin: 1em; + margin-top: 0em; + position: relative; + + flex-grow: 0; flex-shrink: 1; - min-width: 4em; - width: 10em; + min-height: 5em; + max-height: 22.5em; + + border-radius: .2em; + border: 1px solid #111112; + + overflow: hidden; display: flex; flex-direction: column; justify-content: stretch; - .title { - text-transform: uppercase; - color: #557edc; + .toolbar { + flex-shrink: 0; + flex-grow: 0; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; + display: flex; + flex-direction: row; + justify-content: flex-start; + + width: 100%; + height: 2.5em; + + background-color: #17171a; + font-size: .8em; + + padding: .25em; + + .button { + cursor: pointer; + + padding: .5em; + &:not(:first-child) { + margin-left: .25em; + } + + border-radius: .2em; + border: 1px solid #111112; + + background-color: #121213; + + height: 2em; + width: 2em; + + display: flex; + flex-direction: column; + justify-content: center; + + text-align: center; + align-self: center; + + &.button-bold { + font-weight: bold; + } + + &.button-italic { + font-style: italic; + } + + &.button-underline { + text-decoration: underline; + } + + &.button-color { + input { + position: absolute; + width: 0; + height: 0; + opacity: 0; + } + } + + &:hover { + background-color: #0f0f0f; + @include transition(background-color $button_hover_animation_time); + } + } } - .value { - flex-grow: 1; + > .input-boxed { flex-shrink: 1; - min-height: 2em; + flex-grow: 1; - padding: .5em; + min-height: 2.5em; + height: 5em; + max-height: 20em; - border-radius: 0.2em; - border: 1px solid #111112; - background-color: #121213; + border: none; + border-radius: 0; + border-top: 1px solid #111112; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; + + overflow-x: hidden;; + overflow-y: auto; + + resize: vertical; @include chat-scrollbar-vertical(); } - } - } - .container-duration { - margin: 1em; - margin-top: 0em; - - display: flex; - flex-direction: column; - justify-content: flex-start; - - > a { - flex-grow: 0; - flex-shrink: 0; - } - - .container-value { - flex-grow: 0; - flex-shrink: 0; - - display: flex; - flex-direction: row; - justify-content: stretch; - - .input-boxed.value { - flex-grow: 1; - flex-shrink: 1; - - min-width: 6em; - - margin-right: 1em; - } - - select { - width: 7em; - padding-left: .5em; + &:focus-within { + background-color: #131b22; + //border-color: #284262; } } - } - .container-reason { - margin: 1em; - margin-top: 0em; - position: relative; + .container-criteria { + margin: 1em; + margin-top: 0em; + padding: .5em; - flex-grow: 0; - flex-shrink: 1; - - min-height: 5em; - max-height: 22.5em; - - border-radius: .2em; - border: 1px solid #111112; - - overflow: hidden; - - display: flex; - flex-direction: column; - justify-content: stretch; - - .toolbar { - flex-shrink: 0; - flex-grow: 0; - - display: flex; - flex-direction: row; - justify-content: flex-start; - - width: 100%; - height: 2.5em; - - background-color: #17171a; - font-size: .8em; - - padding: .25em; - - .button { - cursor: pointer; - - padding: .5em; - &:not(:first-child) { - margin-left: .25em; - } - - border-radius: .2em; - border: 1px solid #111112; - - background-color: #121213; - - height: 2em; - width: 2em; + border-radius: 0.2em; + border: 1px solid #111112; + background-color: #121213; + .criteria { display: flex; - flex-direction: column; - justify-content: center; + flex-direction: row; + justify-content: space-between; - text-align: center; - align-self: center; + a { + flex-shrink: 1; + min-width: 4em; - &.button-bold { - font-weight: bold; + text-transform: uppercase; + color: #557edc; + + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; } - &.button-italic { - font-style: italic; - } + label { - &.button-underline { - text-decoration: underline; - } - - &.button-color { - input { - position: absolute; - width: 0; - height: 0; - opacity: 0; - } - } - - &:hover { - background-color: #0f0f0f; - @include transition(background-color $button_hover_animation_time); } } } - > .input-boxed { - flex-shrink: 1; - flex-grow: 1; - - min-height: 2.5em; - height: 5em; - max-height: 20em; - - border: none; - border-radius: 0; - border-top: 1px solid #111112; - - - overflow-x: hidden;; - overflow-y: auto; - - resize: vertical; - - @include chat-scrollbar-vertical(); - } - - &:focus-within { - background-color: #131b22; - //border-color: #284262; - } - } - - .container-criteria { - margin: 1em; - margin-top: 0em; - padding: .5em; - - border-radius: 0.2em; - border: 1px solid #111112; - background-color: #121213; - - .criteria { + .container-buttons { display: flex; flex-direction: row; - justify-content: space-between; + justify-content: flex-end; - a { - flex-shrink: 1; - min-width: 4em; + margin: 1em; + margin-top: 0em; - text-transform: uppercase; - color: #557edc; - - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; + button:not(:first-of-type) { + margin-left: 1em; + width: 6em; } - - label { - - } - } - } - - .container-buttons { - display: flex; - flex-direction: row; - justify-content: flex-end; - - margin: 1em; - margin-top: 0em; - - button:not(:first-of-type) { - margin-left: 1em; - width: 6em; } } } \ No newline at end of file diff --git a/shared/css/static/modal-banlist.scss b/shared/css/static/modal-banlist.scss index 84f9bfe9..45228a54 100644 --- a/shared/css/static/modal-banlist.scss +++ b/shared/css/static/modal-banlist.scss @@ -3,111 +3,180 @@ $category_slide_animation_length: .25s; -.modal-body.modal-ban-list { - padding: 0!important; +:global { + .modal-body.modal-ban-list { + padding: 0!important; - display: flex!important; - flex-direction: row!important; - justify-content: stretch!important; + display: flex!important; + flex-direction: row!important; + justify-content: stretch!important; - //min-width: 30em!important; - max-height: calc(100vh - 10em); - height: 50em; - width: 80em; + //min-width: 30em!important; + max-height: calc(100vh - 10em); + height: 50em; + width: 80em; - min-height: 20em; + min-height: 20em; - .container-tooltip { - flex-shrink: 0; - flex-grow: 0; - - position: relative; - width: 1.6em; - - margin-left: .5em; - margin-right: .25em; - - font-size: .9em; - - display: flex; - flex-direction: column; - justify-content: center; - - img { - height: 1em; - width: 1em; - - align-self: center; - font-size: 1.2em; - } - - .tooltip { - display: none; - } - } - - /* general for shrink */ - input { - min-width: 4em; - } - - .left, .right { - flex-grow: 1; - flex-shrink: 1; - - display: flex; - flex-direction: column; - justify-content: stretch; - } - - .container-seperator { - width: 3px; - height: unset!important; - background-color: #222224!important; - - .top { - height: 3.75em; - background-color: #303036; - - opacity: 0; - - @include transition($category_slide_animation_length ease-in-out); - } - } - - .left { - background-color: #222226; - min-width: 15em; - - .head { - flex-grow: 0; + .container-tooltip { flex-shrink: 0; + flex-grow: 0; - height: 2.5em; - font-size: 1.5em; + position: relative; + width: 1.6em; + + margin-left: .5em; + margin-right: .25em; + + font-size: .9em; display: flex; - flex-direction: row; + flex-direction: column; + justify-content: center; + + img { + height: 1em; + width: 1em; + + align-self: center; + font-size: 1.2em; + } + + .tooltip { + display: none; + } + } + + /* general for shrink */ + input { + min-width: 4em; + } + + .left, .right { + flex-grow: 1; + flex-shrink: 1; + + display: flex; + flex-direction: column; justify-content: stretch; + } - background-color: #303036; + .container-seperator { + width: 3px; + height: unset!important; + background-color: #222224!important; - .category { + .top { + height: 3.75em; + background-color: #303036; + + opacity: 0; + + @include transition($category_slide_animation_length ease-in-out); + } + } + + .left { + background-color: #222226; + min-width: 15em; + + .head { + flex-grow: 0; + flex-shrink: 0; + + height: 2.5em; + font-size: 1.5em; + + display: flex; + flex-direction: row; + justify-content: stretch; + + background-color: #303036; + + .category { + flex-grow: 1; + flex-shrink: 1; + + display: flex; + flex-direction: column; + justify-content: center; + + cursor: pointer; + + text-align: center; + color: #fefefe; + + position: relative; + + .background { + position: absolute; + + top: 0; + left: 0; + right: 0; + bottom: 0; + + background-color: #222226; + + @include transition($category_slide_animation_length ease-in-out); + } + + a { + z-index: 1; + } + + &.disabled { + color: #454545; + pointer-events: none!important; + } + } + + .category-edit { + .background { + right: 100%; + } + + &.selected { + .background { + right: 0; + } + } + } + + .category-add { + .background { + left: 100%; + } + + &.selected { + .background { + left: 0; + } + } + } + } + + .body { flex-grow: 1; flex-shrink: 1; + min-height: 6em; + display: flex; flex-direction: column; - justify-content: center; - - cursor: pointer; - - text-align: center; - color: #fefefe; + justify-content: stretch; position: relative; + overflow: hidden; + + .container-add, .container-edit { + flex-grow: 1; + flex-shrink: 1; + + min-height: 6em; + overflow-y: auto; + overflow-x: hidden; - .background { position: absolute; top: 0; @@ -115,221 +184,605 @@ $category_slide_animation_length: .25s; right: 0; bottom: 0; - background-color: #222226; + padding: .5em; - @include transition($category_slide_animation_length ease-in-out); - } + .container-no-permissions { + position: absolute; - a { - z-index: 1; - } - - &.disabled { - color: #454545; - pointer-events: none!important; - } - } - - .category-edit { - .background { - right: 100%; - } - - &.selected { - .background { - right: 0; - } - } - } - - .category-add { - .background { - left: 100%; - } - - &.selected { - .background { + top: 0; left: 0; - } - } - } - } + right: -1em; /* due to the translateX the padding gets a bit miscalculated */ + bottom: 0; - .body { - flex-grow: 1; - flex-shrink: 1; + z-index: 10; - min-height: 6em; + display: flex; + flex-direction: column; + justify-content: center; - display: flex; - flex-direction: column; - justify-content: stretch; + background-color: #222226; - position: relative; - overflow: hidden; - - .container-add, .container-edit { - flex-grow: 1; - flex-shrink: 1; - - min-height: 6em; - overflow-y: auto; - overflow-x: hidden; - - position: absolute; - - top: 0; - left: 0; - right: 0; - bottom: 0; - - padding: .5em; - - .container-no-permissions { - position: absolute; - - top: 0; - left: 0; - right: -1em; /* due to the translateX the padding gets a bit miscalculated */ - bottom: 0; - - z-index: 10; - - display: flex; - flex-direction: column; - justify-content: center; - - background-color: #222226; - - a { - align-self: center; - color: hsla(0, 0%, 30%, 1);; - } - } - - .group { - flex-grow: 0; - flex-shrink: 0; - - > a { - color: #557edc; - text-transform: uppercase; - } - - .input-boxed { - height: 2em; - } - - &:not(:first-of-type) { - margin-top: .5em; - } - - &.group-reason { - textarea { - flex-shrink: 1; - height: 6em; /* show by default 3 rows */ - max-height: 12em; /* 6 rows */ + a { + align-self: center; + color: hsla(0, 0%, 30%, 1);; } } - &.group-duration { - .container-value { - display: flex; - flex-direction: row; - justify-content: stretch; - - .value { - flex-grow: 2; - flex-shrink: 2; - } - - select { - flex-grow: 1; - flex-shrink: 1; - - margin-left: .5em; - min-width: 2em; - } - } - } - } - - .group-enforcements, .group-creator { - flex-grow: 0; - flex-shrink: 0; - - display: flex; - flex-direction: row; - justify-content: stretch; - - height: 2.5em; - padding-top: .5em; - - .key { + .group { flex-grow: 0; - flex-shrink: 1; + flex-shrink: 0; - min-width: 6em; + > a { + color: #557edc; + text-transform: uppercase; + } - color: #557edc; - text-transform: uppercase; + .input-boxed { + height: 2em; + } - align-self: center; + &:not(:first-of-type) { + margin-top: .5em; + } - margin-right: .5em; + &.group-reason { + textarea { + flex-shrink: 1; + height: 6em; /* show by default 3 rows */ + max-height: 12em; /* 6 rows */ + } + } - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; + &.group-duration { + .container-value { + display: flex; + flex-direction: row; + justify-content: stretch; + + .value { + flex-grow: 2; + flex-shrink: 2; + } + + select { + flex-grow: 1; + flex-shrink: 1; + + margin-left: .5em; + min-width: 2em; + } + } + } } - .value { - flex-grow: 1; - flex-shrink: 1; + .group-enforcements, .group-creator { + flex-grow: 0; + flex-shrink: 0; display: flex; flex-direction: row; - justify-content: flex-end; + justify-content: stretch; - min-width: 4em; + height: 2.5em; + padding-top: .5em; - align-self: center; + .key { + flex-grow: 0; + flex-shrink: 1; + + min-width: 6em; + + color: #557edc; + text-transform: uppercase; - button { - height: 2em; - font-size: .8em; align-self: center; + margin-right: .5em; + overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } - a { - align-self: center; - margin-right: .5em; - } + .value { + flex-grow: 1; + flex-shrink: 1; - .htmltag-client { - color: #999999!important; - font-weight: normal!important; + display: flex; + flex-direction: row; + justify-content: flex-end; + + min-width: 4em; + + align-self: center; + + button { + height: 2em; + font-size: .8em; + align-self: center; + + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + a { + align-self: center; + margin-right: .5em; + } + + .htmltag-client { + color: #999999!important; + font-weight: normal!important; + } } } + + .group-global { + flex-grow: 0; + flex-shrink: 0; + + display: flex; + flex-direction: row; + justify-content: stretch; + + height: 2.5em; + padding-top: .5em; + + .checkbox { + align-self: center; + } + + a { + flex-grow: 1; + flex-shrink: 1; + + min-width: 2em; + + align-self: center; + margin-left: .5em; + + color: #557edc; + text-transform: uppercase; + + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + } + + + @include transition($category_slide_animation_length ease-in-out); + + @include transform(translateX(0)); } - .group-global { - flex-grow: 0; + .container-add.hidden { + @include transform(translateX(100%)); + } + + .container-edit.hidden { + @include transform(translateX(-100%)); + } + } + + .buttons { + flex-grow: 0; + flex-shrink: 0; + + padding: .5em; + + display: flex; + flex-direction: row; + justify-content: flex-end; + } + } + + .right { + position: relative; + + display: flex; + flex-direction: column; + justify-content: stretch; + + min-width: 30em; + + .container-filter { + flex-shrink: 0; + flex-grow: 0; + + display: flex; + flex-direction: row; + justify-content: stretch; + + /* well this is shit, but thats how it works */ + .form-group { + margin-top: -1em; + margin-left: .25em; + margin-right: .25em; + + margin-bottom: .5em; + + flex-grow: 1; + flex-shrink: 1; + + min-width: 5em; + } + + .container-close { + cursor: pointer; + flex-shrink: 0; + flex-grow: 0; + + font-size: 5em; + opacity: 0.3; + + align-self: center; + position: relative; + + margin-right: .125em; + margin-left: .125em; + + width: .5em; + height: .5em; + + &:hover { + opacity: 1; + } + @include transition(opacity $button_hover_animation_time ease-in-out); + + &:before, &:after { + position: absolute; + left: .25em; + content: ' '; + height: .5em; + width: .05em; + background-color: #5a5a5a; + } + + &:before { + transform: rotate(45deg); + } + + &:after { + transform: rotate(-45deg); + } + } + } + + .container-list { + flex-shrink: 1; + flex-grow: 1; + + min-height: 10em; + padding: .25em; + + display: flex; + flex-direction: column; + justify-content: stretch; + + .entry { + flex-shrink: 0; + flex-grow: 0; display: flex; flex-direction: row; justify-content: stretch; - height: 2.5em; - padding-top: .5em; + &.header { + color: #557edc; + + margin-right: .5em; /* scroll bar */ + -moz-margin-end: 12px; /* moz scroll bar */ + } + + .column { + padding: .25em; + + &:not(:first-of-type) { + border-left: 0.125em solid transparent; + } + } + } + + .body { + flex-shrink: 1; + flex-grow: 1; + + min-height: 6em; + + overflow-x: hidden; + overflow-y: scroll; + + position: relative; + + display: flex; + flex-direction: column; + justify-content: flex-start; + + @include chat-scrollbar-vertical(); + + .entry { + cursor: pointer; + + border: 0.125em solid #222425; + border-radius: $border_radius_large; + + background-color: #292a2c; + + &:not(:first-of-type) { + margin-top: .3em; + } + + .column { + border-left-color: #222425; + } + + @include transition($button_hover_animation_time ease-in-out); + } + + .container-empty, .container-error { + position: absolute; + + top: 0; + left: 0; + right: 0; + bottom: 0; + + z-index: 2; + + display: flex; + flex-direction: column; + justify-content: center; + + text-align: center; + + background-color: #303036; + color: hsla(0, 0%, 30%, 1); + + font-size: 1.8em; + + > a { + margin-top: -1em; /* looks better then totally centered */ + align-self: center; + } + + &.container-error { + a { + color: red; + } + } + } + } + } + + /* for the ban list only */ + .container-banlist { + position: absolute; + + top: 0; + bottom: 0; + left: 0; + right: 0; + + display: flex; + flex-direction: column; + justify-content: stretch; + + background-color: #303036; + + .entry { + .column-key { + flex-shrink: 1; + flex-grow: 0; + + display: flex; + flex-direction: column; + justify-content: center; + + > * { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + min-width: 4em; + width: 20em; /* UUID length */ + } + + .column-reason { + flex-shrink: 1; + flex-grow: 1; + + min-width: 12em; + //width: calc(100% - 28em); + } + + .column-expires { + flex-shrink: 0; + flex-grow: 0; + + width: 10em; + + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + .column-delete { + flex-shrink: 0; + flex-grow: 0; + + display: flex; + flex-direction: column; + justify-content: center; + + width: 1.75em; + + .button-delete { + width: 1.25em; + height: 1.25em; + + cursor: pointer; + align-self: center; + + display: flex; + flex-direction: column; + justify-content: center; + + > div { + align-self: center; + } + + &:hover { + background-color: #393c40; + border-radius: $border_radius_middle; + + @include transition($button_hover_animation_time ease-in-out); + } + } + } + } + + .body { + .entry { + &.selected { + background-color: #18191b; + } + + &:hover { + background-color: #333539; + } + + &.global { + background-color: #3b2626; + border-color: #7d3536; + + &.selected { + background-color: #221717; + } + + &:hover { + background-color: #4e3434; + } + } + + &.highlight { + border-color: #328f33; + } + } + } + + } + + /* for the trigger list only */ + .container-triggerlist { + position: absolute; + + top: 0; + bottom: 0; + left: 0; + right: 0; + + display: flex; + flex-direction: column; + justify-content: stretch; + + background-color: #303036; + + .entry { + .column-properties { + flex-shrink: 1; + flex-grow: 1; + + display: flex; + flex-direction: column; + justify-content: center; + + > * { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + min-width: 4em; + width: 20em; + + .property { + display: flex; + flex-direction: row; + justify-content: stretch; + + .key, .value { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + .key { + flex-grow: 0; + flex-shrink: 4; + + width: 9em; + } + + .value { + flex-grow: 1; + flex-shrink: 1; + } + + @include transition($button_hover_animation_time ease-in-out); + } + } + + .column-timestamp { + flex-shrink: 0; + flex-grow: 0; + + display: flex; + flex-direction: column; + justify-content: center; + + width: 10em; + text-align: center; + } + } + + .container-list.highlight { + .property.highlighted { + color: #328f33; + } + } + } + + .container-options { + flex-shrink: 0; + flex-grow: 0; + + padding: .5em; //TODO: May use .25 from the list above? + + min-width: 14em; + + display: flex; + flex-direction: row; + justify-content: space-between; + + background-color: #222224; + + .container-option { + display: flex; + flex-direction: row; + justify-content: stretch; + + min-width: 4em; .checkbox { + flex-grow: 0; + flex-shrink: 0; + align-self: center; + margin-right: .25em; } a { @@ -339,7 +792,6 @@ $category_slide_animation_length: .25s; min-width: 2em; align-self: center; - margin-left: .5em; color: #557edc; text-transform: uppercase; @@ -350,459 +802,9 @@ $category_slide_animation_length: .25s; } } - - @include transition($category_slide_animation_length ease-in-out); - - @include transform(translateX(0)); - } - - .container-add.hidden { - @include transform(translateX(100%)); - } - - .container-edit.hidden { - @include transform(translateX(-100%)); - } - } - - .buttons { - flex-grow: 0; - flex-shrink: 0; - - padding: .5em; - - display: flex; - flex-direction: row; - justify-content: flex-end; - } - } - - .right { - position: relative; - - display: flex; - flex-direction: column; - justify-content: stretch; - - min-width: 30em; - - .container-filter { - flex-shrink: 0; - flex-grow: 0; - - display: flex; - flex-direction: row; - justify-content: stretch; - - /* well this is shit, but thats how it works */ - .form-group { - margin-top: -1em; - margin-left: .25em; - margin-right: .25em; - - margin-bottom: .5em; - - flex-grow: 1; - flex-shrink: 1; - - min-width: 5em; - } - - .container-close { - cursor: pointer; - - flex-shrink: 0; - flex-grow: 0; - - font-size: 5em; - opacity: 0.3; - - align-self: center; - position: relative; - - margin-right: .125em; - margin-left: .125em; - - width: .5em; - height: .5em; - - &:hover { - opacity: 1; + button { + height: 2em; } - @include transition(opacity $button_hover_animation_time ease-in-out); - - &:before, &:after { - position: absolute; - left: .25em; - content: ' '; - height: .5em; - width: .05em; - background-color: #5a5a5a; - } - - &:before { - transform: rotate(45deg); - } - - &:after { - transform: rotate(-45deg); - } - } - } - - .container-list { - flex-shrink: 1; - flex-grow: 1; - - min-height: 10em; - padding: .25em; - - display: flex; - flex-direction: column; - justify-content: stretch; - - .entry { - flex-shrink: 0; - flex-grow: 0; - - display: flex; - flex-direction: row; - justify-content: stretch; - - &.header { - color: #557edc; - - margin-right: .5em; /* scroll bar */ - -moz-margin-end: 12px; /* moz scroll bar */ - } - - .column { - padding: .25em; - - &:not(:first-of-type) { - border-left: 0.125em solid transparent; - } - } - } - - .body { - flex-shrink: 1; - flex-grow: 1; - - min-height: 6em; - - overflow-x: hidden; - overflow-y: scroll; - - position: relative; - - display: flex; - flex-direction: column; - justify-content: flex-start; - - @include chat-scrollbar-vertical(); - - .entry { - cursor: pointer; - - border: 0.125em solid #222425; - border-radius: $border_radius_large; - - background-color: #292a2c; - - &:not(:first-of-type) { - margin-top: .3em; - } - - .column { - border-left-color: #222425; - } - - @include transition($button_hover_animation_time ease-in-out); - } - - .container-empty, .container-error { - position: absolute; - - top: 0; - left: 0; - right: 0; - bottom: 0; - - z-index: 2; - - display: flex; - flex-direction: column; - justify-content: center; - - text-align: center; - - background-color: #303036; - color: hsla(0, 0%, 30%, 1); - - font-size: 1.8em; - - > a { - margin-top: -1em; /* looks better then totally centered */ - align-self: center; - } - - &.container-error { - a { - color: red; - } - } - } - } - } - - /* for the ban list only */ - .container-banlist { - position: absolute; - - top: 0; - bottom: 0; - left: 0; - right: 0; - - display: flex; - flex-direction: column; - justify-content: stretch; - - background-color: #303036; - - .entry { - .column-key { - flex-shrink: 1; - flex-grow: 0; - - display: flex; - flex-direction: column; - justify-content: center; - - > * { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - - min-width: 4em; - width: 20em; /* UUID length */ - } - - .column-reason { - flex-shrink: 1; - flex-grow: 1; - - min-width: 12em; - //width: calc(100% - 28em); - } - - .column-expires { - flex-shrink: 0; - flex-grow: 0; - - width: 10em; - - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - - .column-delete { - flex-shrink: 0; - flex-grow: 0; - - display: flex; - flex-direction: column; - justify-content: center; - - width: 1.75em; - - .button-delete { - width: 1.25em; - height: 1.25em; - - cursor: pointer; - align-self: center; - - display: flex; - flex-direction: column; - justify-content: center; - - > div { - align-self: center; - } - - &:hover { - background-color: #393c40; - border-radius: $border_radius_middle; - - @include transition($button_hover_animation_time ease-in-out); - } - } - } - } - - .body { - .entry { - &.selected { - background-color: #18191b; - } - - &:hover { - background-color: #333539; - } - - &.global { - background-color: #3b2626; - border-color: #7d3536; - - &.selected { - background-color: #221717; - } - - &:hover { - background-color: #4e3434; - } - } - - &.highlight { - border-color: #328f33; - } - } - } - - } - - /* for the trigger list only */ - .container-triggerlist { - position: absolute; - - top: 0; - bottom: 0; - left: 0; - right: 0; - - display: flex; - flex-direction: column; - justify-content: stretch; - - background-color: #303036; - - .entry { - .column-properties { - flex-shrink: 1; - flex-grow: 1; - - display: flex; - flex-direction: column; - justify-content: center; - - > * { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - - min-width: 4em; - width: 20em; - - .property { - display: flex; - flex-direction: row; - justify-content: stretch; - - .key, .value { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - - .key { - flex-grow: 0; - flex-shrink: 4; - - width: 9em; - } - - .value { - flex-grow: 1; - flex-shrink: 1; - } - - @include transition($button_hover_animation_time ease-in-out); - } - } - - .column-timestamp { - flex-shrink: 0; - flex-grow: 0; - - display: flex; - flex-direction: column; - justify-content: center; - - width: 10em; - text-align: center; - } - } - - .container-list.highlight { - .property.highlighted { - color: #328f33; - } - } - } - - .container-options { - flex-shrink: 0; - flex-grow: 0; - - padding: .5em; //TODO: May use .25 from the list above? - - min-width: 14em; - - display: flex; - flex-direction: row; - justify-content: space-between; - - background-color: #222224; - - .container-option { - display: flex; - flex-direction: row; - justify-content: stretch; - - min-width: 4em; - - .checkbox { - flex-grow: 0; - flex-shrink: 0; - - align-self: center; - margin-right: .25em; - } - - a { - flex-grow: 1; - flex-shrink: 1; - - min-width: 2em; - - align-self: center; - - color: #557edc; - text-transform: uppercase; - - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - } - - button { - height: 2em; } } } diff --git a/shared/css/static/modal-channelinfo.scss b/shared/css/static/modal-channelinfo.scss index c9c121d9..92c7b36b 100644 --- a/shared/css/static/modal-channelinfo.scss +++ b/shared/css/static/modal-channelinfo.scss @@ -1,161 +1,163 @@ @import "mixin"; @import "properties"; -.modal-body.modal-channel-info { - display: flex!important; - flex-direction: column!important; - justify-content: stretch!important; +:global { + .modal-body.modal-channel-info { + display: flex!important; + flex-direction: column!important; + justify-content: stretch!important; - min-width: 30em!important; - max-height: calc(100vh - 10em)!important; - padding: 0 !important; + min-width: 30em!important; + max-height: calc(100vh - 10em)!important; + padding: 0 !important; - .row { - flex-grow: 0; - flex-shrink: 0; + .row { + flex-grow: 0; + flex-shrink: 0; - display: flex; - flex-direction: row; - justify-content: stretch; + display: flex; + flex-direction: row; + justify-content: stretch; - padding-top: 1em; - padding-left: .5em; - padding-right: .5em; + padding-top: 1em; + padding-left: .5em; + padding-right: .5em; - .column { + .column { + flex-grow: 1; + flex-shrink: 1; + + min-width: 6em; + width: 10em; + + margin-right: .5em; + margin-left: .5em; + + .title { + text-transform: uppercase; + color: #557edc; + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .value { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + &.audio-encrypted { + /* looks better */ + .value { + height: 1.6em; + overflow: visible; + } + } + } + } + + .container-description { flex-grow: 1; flex-shrink: 1; - min-width: 6em; - width: 10em; + min-height: 8em; /* description plus title */ - margin-right: .5em; - margin-left: .5em; + display: flex; + flex-direction: column; + justify-content: stretch; + + padding-top: 1em; + padding-left: 1em; + padding-right: 1em; .title { + display: flex; + flex-direction: row; + justify-content: flex-start; + + flex-grow: 0; + flex-shrink: 0; + text-transform: uppercase; color: #557edc; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + + .button-copy { + display: flex; + flex-direction: column; + justify-content: center; + + margin-top: .1em; /* looks a bit better */ + margin-left: .5em; + border-radius: .2em; + + width: 1.3em; + height: 1.3em; + + cursor: pointer; + + div { + align-self: center; + } + + &:hover { + background-color: #313135; + } + + @include transition($button_hover_animation_time ease-in-out); + } } .value { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + display: block; + flex-grow: 1; + flex-shrink: 1; + + border-radius: 0.2em; + border: 1px solid #212324; + background-color: #3a3b3f; + + padding: .5em; + + height: max-content; + min-height: 6em; + max-height: 40em; + + overflow-y: auto; + overflow-x: hidden; + @include chat-scrollbar-vertical(); } - &.audio-encrypted { - /* looks better */ - .value { - height: 1.6em; - overflow: visible; - } - } - } - } + .no-value { + flex-grow: 0; + flex-shrink: 0; - .container-description { - flex-grow: 1; - flex-shrink: 1; + font-size: 1.25em; + height: (6em / 1.25); /* min value height and a bit more */ - min-height: 8em; /* description plus title */ - - display: flex; - flex-direction: column; - justify-content: stretch; - - padding-top: 1em; - padding-left: 1em; - padding-right: 1em; - - .title { - display: flex; - flex-direction: row; - justify-content: flex-start; - - flex-grow: 0; - flex-shrink: 0; - - text-transform: uppercase; - color: #557edc; - - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - - .button-copy { display: flex; flex-direction: column; justify-content: center; - margin-top: .1em; /* looks a bit better */ - margin-left: .5em; - border-radius: .2em; - - width: 1.3em; - height: 1.3em; - - cursor: pointer; - - div { - align-self: center; - } - - &:hover { - background-color: #313135; - } - - @include transition($button_hover_animation_time ease-in-out); + text-align: center; + color: #666666; } } - .value { - display: block; - flex-grow: 1; - flex-shrink: 1; - - border-radius: 0.2em; - border: 1px solid #212324; - background-color: #3a3b3f; - - padding: .5em; - - height: max-content; - min-height: 6em; - max-height: 40em; - - overflow-y: auto; - overflow-x: hidden; - @include chat-scrollbar-vertical(); - } - - .no-value { + .container-buttons { flex-grow: 0; flex-shrink: 0; - font-size: 1.25em; - height: (6em / 1.25); /* min value height and a bit more */ - display: flex; - flex-direction: column; - justify-content: center; + flex-direction: row; + justify-content: flex-end; - text-align: center; - color: #666666; + padding: 1em; } } - - .container-buttons { - flex-grow: 0; - flex-shrink: 0; - - display: flex; - flex-direction: row; - justify-content: flex-end; - - padding: 1em; - } } \ No newline at end of file diff --git a/shared/css/static/modal-clientinfo.scss b/shared/css/static/modal-clientinfo.scss index 6d281273..c31e6f2c 100644 --- a/shared/css/static/modal-clientinfo.scss +++ b/shared/css/static/modal-clientinfo.scss @@ -1,612 +1,614 @@ @import "mixin"; @import "properties"; -.modal-body.modal-client-info { - padding: 0!important; +:global { + .modal-body.modal-client-info { + padding: 0!important; - $avatar_size: 12em; - .head { - flex-shrink: 0; - flex-grow: 0; - - z-index: 1; - - height: 7em; - background-color: #212125; - - .status-row { + $avatar_size: 12em; + .head { flex-shrink: 0; flex-grow: 0; - display: flex; - flex-direction: row; - justify-content: flex-start; + z-index: 1; - .status-entry { - font-size: 1.5em; + height: 7em; + background-color: #212125; - margin: .25em; + .status-row { + flex-shrink: 0; + flex-grow: 0; - width: 1em; - height: 1em; - } - } + display: flex; + flex-direction: row; + justify-content: flex-start; - .container-away-message { - $offset_left: (.25em) * 1.5 /* 1.5 is the font size of the icons */; + .status-entry { + font-size: 1.5em; - position: relative; - margin-left: $offset_left; - margin-top: .25em; + margin: .25em; - background-color: #1c1c1c; - border: 1px solid #161515; - border-radius: 3px; - - max-width: calc(50% - #{$avatar_size / 2 + $offset_left + 1em}); /* do actual 1em space to the avatar */ - max-height: 4em; /* else it will overflow the header */ - - display: flex; - flex-direction: column; - justify-content: start; - - width: max-content; - padding: .15em; - - overflow: hidden; - - //A verry long away message, because I want to tell a story. There was a child.... - a { - font-size: .85em; + width: 1em; + height: 1em; + } } - &:hover { - max-height: 200em; - } + .container-away-message { + $offset_left: (.25em) * 1.5 /* 1.5 is the font size of the icons */; - @include transition(.5s ease-in-out); - } - } + position: relative; + margin-left: $offset_left; + margin-top: .25em; - .body { - flex-shrink: 1; - flex-grow: 0; + background-color: #1c1c1c; + border: 1px solid #161515; + border-radius: 3px; - //TODO: Min height here! + max-width: calc(50% - #{$avatar_size / 2 + $offset_left + 1em}); /* do actual 1em space to the avatar */ + max-height: 4em; /* else it will overflow the header */ - display: flex; - flex-direction: column; - justify-content: stretch; + display: flex; + flex-direction: column; + justify-content: start; - background-color: #2f2f35; + width: max-content; + padding: .15em; - .container-avatar { - z-index: 2; /* overlay the header */ - - flex-grow: 0; - flex-shrink: 0; - - position: relative; - display: inline-block; - margin: calc(#{$avatar_size} / -2) 0.75em 0.5em 0.5em; - align-self: center; - - .avatar { - height: $avatar_size; - width: $avatar_size; - - border-radius: 50%; overflow: hidden; + + //A verry long away message, because I want to tell a story. There was a child.... + a { + font-size: .85em; + } + + &:hover { + max-height: 200em; + } + + @include transition(.5s ease-in-out); } } - .container-name { + .body { + flex-shrink: 1; flex-grow: 0; - flex-shrink: 0; - display: flex; - flex-direction: row; - justify-content: center; - - .htmltag-client { - text-align: center; - font-size: 1.5em; - color: #cccccc; - font-weight: bold; - } - } - - .container-description { - flex-grow: 0; - flex-shrink: 0; - - padding-right: calc(10em / 2); - padding-left: calc(10em / 2); - - text-align: center; + //TODO: Min height here! display: flex; flex-direction: column; justify-content: stretch; - .client-description { - color: #6f6f6f; - max-width: 100%; - flex-shrink: 1; - flex-grow: 1; - overflow-wrap: break-word; + background-color: #2f2f35; + + .container-avatar { + z-index: 2; /* overlay the header */ + + flex-grow: 0; + flex-shrink: 0; + + position: relative; + display: inline-block; + margin: calc(#{$avatar_size} / -2) 0.75em 0.5em 0.5em; + align-self: center; + + .avatar { + height: $avatar_size; + width: $avatar_size; + + border-radius: 50%; + overflow: hidden; + } } - } - - - .container-categories { - margin-top: 1em; - - display: flex; - flex-direction: column; - justify-content: stretch; - - min-height: 14em; - - .categories { - height: 2.5em; + .container-name { flex-grow: 0; flex-shrink: 0; display: flex; flex-direction: row; - justify-content: stretch; - - padding-left: 2.5em; - padding-right: 2.5em; - - border-bottom: 1px solid #1d1d1d; - - .entry { - padding: .5em; + justify-content: center; + .htmltag-client { text-align: center; - - flex-grow: 1; - flex-shrink: 1; - - cursor: pointer; - - &:hover { - color: #b6c4d6; - } - - &.selected { - border-bottom: 3px solid #245184; - margin-bottom: -2px; - - color: #245184; - } - - @include transition(color $button_hover_animation_time, border-bottom-color $button_hover_animation_time); + font-size: 1.5em; + color: #cccccc; + font-weight: bold; } } - .bodies { - position: relative; + .container-description { + flex-grow: 0; + flex-shrink: 0; - flex-shrink: 1; - flex-grow: 1; + padding-right: calc(10em / 2); + padding-left: calc(10em / 2); + + text-align: center; display: flex; + flex-direction: column; justify-content: stretch; - padding-left: .5em; - padding-right: .5em; + .client-description { + color: #6f6f6f; + max-width: 100%; + flex-shrink: 1; + flex-grow: 1; + overflow-wrap: break-word; + } + } - min-height: 10em; - height: 21em; /* body size 20 + .5 padding */ - .container-tooltip { - flex-shrink: 0; + .container-categories { + margin-top: 1em; + + display: flex; + flex-direction: column; + justify-content: stretch; + + min-height: 14em; + + .categories { + height: 2.5em; + flex-grow: 0; - - font-size: .8em; /* shrink the tip a bit */ - - position: relative; - width: 1.6em; - margin-left: .5em; + flex-shrink: 0; display: flex; - flex-direction: column; - justify-content: center; + flex-direction: row; + justify-content: stretch; - img { - height: 1em; - width: 1em; + padding-left: 2.5em; + padding-right: 2.5em; - align-self: center; - font-size: 1.2em; - } + border-bottom: 1px solid #1d1d1d; - .tooltip { - display: none; + .entry { + padding: .5em; + + text-align: center; + + flex-grow: 1; + flex-shrink: 1; + + cursor: pointer; + + &:hover { + color: #b6c4d6; + } + + &.selected { + border-bottom: 3px solid #245184; + margin-bottom: -2px; + + color: #245184; + } + + @include transition(color $button_hover_animation_time, border-bottom-color $button_hover_animation_time); } } - .body { - position: absolute; + .bodies { + position: relative; - top: 0; - left: 0; - right: 0; - bottom: 0; - - padding: .5em; + flex-shrink: 1; + flex-grow: 1; display: flex; justify-content: stretch; - overflow: auto; /* else the tooltip will trigger the scrollbar */ - @include chat-scrollbar-vertical(); + padding-left: .5em; + padding-right: .5em; - &.hidden { - display: none; - } + min-height: 10em; + height: 21em; /* body size 20 + .5 padding */ - &.container-basic { - flex-direction: row; + .container-tooltip { + flex-shrink: 0; + flex-grow: 0; - .spacer { - flex-grow: 0; - flex-shrink: 0; + font-size: .8em; /* shrink the tip a bit */ + + position: relative; + width: 1.6em; + margin-left: .5em; + + display: flex; + flex-direction: column; + justify-content: center; + + img { + height: 1em; width: 1em; + + align-self: center; + font-size: 1.2em; } - .left, .right { - height: 20em; - width: calc(50% - .5em); /* the spacer in the middle thats why -.5 em */ + .tooltip { + display: none; + } + } - flex-grow: 1; - flex-shrink: 1; + .body { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; - border-radius: .2em; - border: 1px solid #1f2122; - background-color: #28292b; - padding: .5em; + padding: .5em; - .property { - flex-shrink: 0; + display: flex; + justify-content: stretch; + + overflow: auto; /* else the tooltip will trigger the scrollbar */ + @include chat-scrollbar-vertical(); + + &.hidden { + display: none; + } + + &.container-basic { + flex-direction: row; + + .spacer { flex-grow: 0; - - display: flex; - flex-direction: column; - justify-content: flex-start; - - .title, .value { - display: flex; - flex-direction: row; - justify-content: stretch; - - white-space: nowrap; - overflow: hidden; - - > * { - flex-shrink: 0; - flex-grow: 0; - - align-self: center; - } - - a { - flex-shrink: 1; - - overflow: hidden; - text-overflow: ellipsis; - } - } - - .title { - color: #254d7b; - text-transform: uppercase; - } - - .value { - color: #bdbdbd; - - a, a:visited { - color: #bdbdbd!important; - } - - .button { - width: 1.6em; - height: 1.6em; - - display: flex; - flex-direction: column; - justify-content: space-around; - - cursor: pointer; - opacity: .5; - - > div { - align-self: center; - } - - &:hover { - opacity: 1; - } - - @include transition($button_hover_animation_time ease-in-out); - } - - .country { - margin-right: .25em; - } - } - - &:not(:first-of-type) { - margin-top: .5em; - } - - &.property-unique-id, &.property-ip { - .value { - justify-content: space-between; - } - } - - &.property-version { - .a-on { - flex-shrink: 0; - flex-grow: 0; - margin-left: .25em; - margin-right: .25em; - } - } - } - } - } - - &.container-packets { - flex-direction: row; - - .spacer { - flex-grow: 0; - flex-shrink: 0; - width: 1em; - } - - .left, .right { - height: 20em; - width: calc(50% - .5em); /* the spacer in the middle thats why -.5 em */ - - flex-grow: 1; - flex-shrink: 1; - - - border-radius: .2em; - border: 1px solid #1f2122; - background-color: #28292b; - padding: .5em; - - .statistic { flex-shrink: 0; - flex-grow: 0; - - display: flex; - flex-direction: column; - justify-content: flex-start; - - .title, .upstream, .downstream { - display: flex; - flex-direction: row; - justify-content: stretch; - - white-space: nowrap; - overflow: hidden; - - > * { - flex-shrink: 0; - flex-grow: 0; - - align-self: center; - } - - a { - flex-shrink: 1; - - overflow: hidden; - text-overflow: ellipsis; - } - } - - .title { - color: #254d7b; - text-transform: uppercase; - } - - .upstream, .downstream { - padding-top: .25em; - - - display: flex; - flex-direction: row; - justify-content: space-between; - - > a { - align-self: center; - } - } - - .upstream { - color: #fd3913; - } - - .downstream { - color: #0e8afd; - } - - &:not(:first-of-type) { - margin-top: .5em; - } - } - } - } - - &.container-groups { - flex-direction: row; - - .spacer { - flex-grow: 0; - flex-shrink: 0; - width: 1em; - } - - .left, .right { - height: 20em; - width: calc(50% - .5em); /* the spacer in the middle thats why -.5 em */ - - flex-grow: 1; - flex-shrink: 1; - - .title { - align-self: center; - color: #254d7b; - text-transform: uppercase; + width: 1em; } - .container { - margin-top: .5em; - } - } - - .left { - display: flex; - flex-direction: column; - justify-content: stretch; - - .container { - border-radius: .2em .2em 0 0; - border: 1px solid #1f2122; - border-bottom: 0; - - padding: 0!important; - background-color: #28292b; + .left, .right { + height: 20em; + width: calc(50% - .5em); /* the spacer in the middle thats why -.5 em */ flex-grow: 1; flex-shrink: 1; - overflow-y: auto; - min-height: 4em; - position: relative; - @include chat-scrollbar-vertical(); + border-radius: .2em; + border: 1px solid #1f2122; + background-color: #28292b; + padding: .5em; - .entries { - flex-grow: 1; - flex-shrink: 1; + .property { + flex-shrink: 0; + flex-grow: 0; - min-height: 4em; + display: flex; + flex-direction: column; + justify-content: flex-start; - .entry { + .title, .value { display: flex; flex-direction: row; justify-content: stretch; - height: 1.6em; - padding-left: .5em; - padding-right: .5em; - - &:hover { - background-color: #232425; - } + white-space: nowrap; + overflow: hidden; > * { + flex-shrink: 0; + flex-grow: 0; + align-self: center; } - .icon-container { - margin-right: .25em; - } - - .name { - flex-grow: 1; + a { flex-shrink: 1; - min-width: 1em; - line-height: normal; - overflow: hidden; - white-space: nowrap; text-overflow: ellipsis; } + } - .button-delete { - height: 1.3em; - width: 1.3em; + .title { + color: #254d7b; + text-transform: uppercase; + } - cursor: pointer; - border-radius: .2em; + .value { + color: #bdbdbd; - &:hover { - background-color: #2c2d2e; - } + a, a:visited { + color: #bdbdbd!important; + } + + .button { + width: 1.6em; + height: 1.6em; display: flex; - flex-direction: row; + flex-direction: column; justify-content: space-around; + cursor: pointer; + opacity: .5; + > div { align-self: center; } + &:hover { + opacity: 1; + } + @include transition($button_hover_animation_time ease-in-out); } + + .country { + margin-right: .25em; + } } - } - .container-default-groups { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - display: flex; - flex-direction: column; - justify-content: center; - - a { - align-self: center; - font-size: 1.25em; - color: hsla(0, 0%, 30%, 1); + &:not(:first-of-type) { + margin-top: .5em; } - } - } - .buttons { - flex-grow: 0; - flex-shrink: 0; + &.property-unique-id, &.property-ip { + .value { + justify-content: space-between; + } + } - border-radius: 0 0 .2em .2em; - border: 1px solid #1f2122; - background-color: #28292b; - - padding: .5em; - - display: flex; - flex-direction: row; - justify-content: space-around; - - .button { - align-self: center; + &.property-version { + .a-on { + flex-shrink: 0; + flex-grow: 0; + margin-left: .25em; + margin-right: .25em; + } + } } } } - .right { - .container { - padding: 0!important; + &.container-packets { + flex-direction: row; - select { - font-size: .8em; - width: 100%; + .spacer { + flex-grow: 0; + flex-shrink: 0; + width: 1em; + } + + .left, .right { + height: 20em; + width: calc(50% - .5em); /* the spacer in the middle thats why -.5 em */ + + flex-grow: 1; + flex-shrink: 1; + + + border-radius: .2em; + border: 1px solid #1f2122; + background-color: #28292b; + padding: .5em; + + .statistic { + flex-shrink: 0; + flex-grow: 0; + + display: flex; + flex-direction: column; + justify-content: flex-start; + + .title, .upstream, .downstream { + display: flex; + flex-direction: row; + justify-content: stretch; + + white-space: nowrap; + overflow: hidden; + + > * { + flex-shrink: 0; + flex-grow: 0; + + align-self: center; + } + + a { + flex-shrink: 1; + + overflow: hidden; + text-overflow: ellipsis; + } + } + + .title { + color: #254d7b; + text-transform: uppercase; + } + + .upstream, .downstream { + padding-top: .25em; + + + display: flex; + flex-direction: row; + justify-content: space-between; + + > a { + align-self: center; + } + } + + .upstream { + color: #fd3913; + } + + .downstream { + color: #0e8afd; + } + + &:not(:first-of-type) { + margin-top: .5em; + } + } + } + } + + &.container-groups { + flex-direction: row; + + .spacer { + flex-grow: 0; + flex-shrink: 0; + width: 1em; + } + + .left, .right { + height: 20em; + width: calc(50% - .5em); /* the spacer in the middle thats why -.5 em */ + + flex-grow: 1; + flex-shrink: 1; + + .title { + align-self: center; + color: #254d7b; + text-transform: uppercase; + } + + .container { + margin-top: .5em; + } + } + + .left { + display: flex; + flex-direction: column; + justify-content: stretch; + + .container { + border-radius: .2em .2em 0 0; + border: 1px solid #1f2122; + border-bottom: 0; + + padding: 0!important; + background-color: #28292b; + + flex-grow: 1; + flex-shrink: 1; + overflow-y: auto; + + min-height: 4em; + position: relative; + + @include chat-scrollbar-vertical(); + + .entries { + flex-grow: 1; + flex-shrink: 1; + + min-height: 4em; + + .entry { + display: flex; + flex-direction: row; + justify-content: stretch; + + height: 1.6em; + padding-left: .5em; + padding-right: .5em; + + &:hover { + background-color: #232425; + } + + > * { + align-self: center; + } + + .icon-container { + margin-right: .25em; + } + + .name { + flex-grow: 1; + flex-shrink: 1; + + min-width: 1em; + line-height: normal; + + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + .button-delete { + height: 1.3em; + width: 1.3em; + + cursor: pointer; + border-radius: .2em; + + &:hover { + background-color: #2c2d2e; + } + + display: flex; + flex-direction: row; + justify-content: space-around; + + > div { + align-self: center; + } + + @include transition($button_hover_animation_time ease-in-out); + } + } + } + + .container-default-groups { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + flex-direction: column; + justify-content: center; + + a { + align-self: center; + font-size: 1.25em; + color: hsla(0, 0%, 30%, 1); + } + } + } + + .buttons { + flex-grow: 0; + flex-shrink: 0; + + border-radius: 0 0 .2em .2em; + border: 1px solid #1f2122; + background-color: #28292b; + + padding: .5em; + + display: flex; + flex-direction: row; + justify-content: space-around; + + .button { + align-self: center; + } + } + } + + .right { + .container { + padding: 0!important; + + select { + font-size: .8em; + width: 100%; + } } } } diff --git a/shared/css/static/modal-connect.scss b/shared/css/static/modal-connect.scss deleted file mode 100644 index 4b7918fa..00000000 --- a/shared/css/static/modal-connect.scss +++ /dev/null @@ -1,353 +0,0 @@ -@import "mixin"; - -.modal .modal-connect { - @include user-select(none); - - font-size: 1rem; - max-width: 100000px; /* max 100000px width, else we shrink the modal */ - padding: 0!important; /* override the default padding */ - - display: flex!important; - flex-direction: column!important; - justify-content: stretch!important; - - .container-connect-input { - flex-grow: 0; - flex-shrink: 0; - - /* apply the default padding */ - padding: .75em 24px; - - border-left: 2px solid #0073d4; - overflow: hidden; - - > .row { - display: flex; - flex-direction: row; - justify-content: stretch; - - > *:not(:last-of-type) { - margin-right: 3em; - } - } - - .container-address-password { - .container-address { - flex-grow: 1; - flex-shrink: 1; - } - - .container-password { - flex-grow: 0; - flex-shrink: 4; - - min-width: 21.5em; - } - } - - .container-profile-manage { - flex-grow: 0; - flex-shrink: 4; - - display: flex; - flex-direction: row; - justify-content: stretch; - - .container-select-profile { - flex-grow: 1; - flex-shrink: 1; - - min-width: 14em; - - > .invalid-feedback { - width: max-content; /* allow overflow here */ - } - } - - .container-manage { - flex-grow: 0; - flex-shrink: 4; - - margin-left: 15px; - } - - .button-manage-profiles { - min-width: 7em; - margin-left: 0.5em; - } - } - - .container-nickname { - flex-grow: 1; - flex-shrink: 1; - } - - .container-buttons { - padding-top: 1em; - - display: flex; - flex-direction: row; - justify-content: space-between; - - .container-buttons-connect { - display: flex; - flex-direction: row; - - flex-shrink: 1; - min-width: 6em; - } - - .button-right { - min-width: 7em; - margin-left: 0.5em; - } - - .button-left { - min-width: 14em; - } - } - - .arrow { - border-color: #7a7a7a; - margin-left: .5em; - } - } - - .container-last-servers { - flex-grow: 0; - flex-shrink: 1; - - display: flex; - flex-direction: column; - justify-content: stretch; - - max-height: 0; - opacity: 0; - overflow: hidden; - padding: 0; - - min-width: 0; - - - border: none; - border-left: 2px solid #7a7a7a; - - @include transition(max-height .5s ease-in-out, opacity .5s ease-in-out, padding .5s ease-in-out); - &.shown { - /* apply the default padding */ - padding: 0 24px 24px; - - max-height: 100%; - opacity: 1; - - @include transition(max-height .5s ease-in-out, opacity .5s ease-in-out, padding .5s ease-in-out) - } - - hr { - height: 0; - width: calc(100% + 46px); - min-width: 0; - - margin: 0 0 0 -23px; - - padding: 0; - - border: none; - border-top: 1px solid #090909; - - margin-bottom: .75em; - } - - color: #7a7a7a; - - /* general table class */ - .table { - width: 100em; - max-width: 100%; - - display: flex; - flex-direction: column; - justify-content: stretch; - - .head { - display: flex; - flex-direction: row; - justify-content: stretch; - - flex-grow: 0; - flex-shrink: 0; - - border: none; - border-bottom: 1px solid #161618; - } - - - .body { - flex-grow: 0; - flex-shrink: 1; - - display: flex; - flex-direction: column; - justify-content: stretch; - - overflow: auto; - - .row { - cursor: pointer; - - flex-grow: 0; - flex-shrink: 0; - - display: flex; - flex-direction: row; - justify-content: stretch; - - &:hover { - background-color: #202022; - } - - &.selected { - background-color: #131315; - } - } - - .body-empty { - height: 3em; - text-align: center; - display: flex; - flex-direction: column; - justify-content: space-around; - font-size: 1.25em; - color: rgba(121, 121, 121, 0.5); - } - } - - .column { - flex-grow: 1; - flex-shrink: 1; - - overflow: hidden; - white-space: nowrap; - - padding-right: .25em; - padding-left: .25em; - - display: flex; - flex-direction: row; - justify-content: flex-start; - - &:not(:last-of-type) { - border-right: 1px solid #161618; - } - - > a { - max-width: 100%; - text-overflow: ellipsis; - overflow: hidden; - } - } - } - - /* connect table */ - .table { - margin-left: -1.5em; /* the delete row */ - - .head { - margin-left: 1.5em; /* the delete row */ - .column.delete { - display: none; - } - } - - .column { - align-self: center; - .country, .icon-container { - align-self: center; - margin-right: 0.25em; - } - - - @mixin fixed-column($name, $width) { - &.#{$name} { - flex-grow: 0; - flex-shrink: 0; - - width: $width; - } - } - - @include fixed-column(delete, 1.5em); - @include fixed-column(password, 5em); - @include fixed-column(country-name, 7em); - @include fixed-column(clients, 4em); - @include fixed-column(connections, 6.5em); - - &.delete { - opacity: 0; - border-right: none; - border-bottom: none; - - text-align: center; - @include transition(opacity .25 ease-in-out); - - &:hover { - opacity: 1; - @include transition(opacity .25 ease-in-out); - } - } - - &.address { - flex-grow: 1; - flex-shrink: 1; - - width: 40%; - } - - &.name { - flex-grow: 1; - flex-shrink: 1; - - width: 60%; - } - } - } - } -} - -@media all and (max-width: 55rem) { - .modal .modal-connect { - min-width: calc(21.25em + 24px * 2)!important; - width: 1000em; /* allocate space */ - - .container-address-password { - .container-password { - min-width: unset!important; - margin-left: 1em!important; - } - } - - .container-buttons { - justify-content: flex-end!important; - - .button-toggle-last-servers { - display: none; - } - } - - .container-profile-name { - flex-direction: column!important; - } - - .container-connect-input { - > .row { - > div { - margin-right: 0!important; - } - } - } - - .container-last-servers { - display: none; - } - } -} \ No newline at end of file diff --git a/shared/css/static/modal-group-assignment.scss b/shared/css/static/modal-group-assignment.scss index 96c62af9..b023b84a 100644 --- a/shared/css/static/modal-group-assignment.scss +++ b/shared/css/static/modal-group-assignment.scss @@ -1,110 +1,112 @@ @import "mixin"; @import "properties"; -.modal-server-group-assignments { - @include user-select(none); +:global { + .modal-server-group-assignments { + @include user-select(none); - min-width: 25em!important; - max-height: calc(100vh - 10rem)!important; - min-height: 10em!important; + min-width: 25em!important; + max-height: calc(100vh - 10rem)!important; + min-height: 10em!important; - width: 30em!important; + width: 30em!important; - display: flex!important; - flex-direction: column!important; - justify-content: stretch!important; + display: flex!important; + flex-direction: column!important; + justify-content: stretch!important; - background-color: #2f2f35; - padding: .5em!important; + background-color: #2f2f35; + padding: .5em!important; - .group-assignment-list { - flex-grow: 1; - flex-shrink: 1; - min-height: 6em; - - display: flex; - flex-direction: column; - justify-content: stretch; - - color: #999999; - - a { - flex-shrink: 0; - flex-grow: 0; - - .htmltag-client { - display: inline; - color: #999999; - } - } - - .group-list { - flex-shrink: 1; + .group-assignment-list { flex-grow: 1; - min-height: 4em; + flex-shrink: 1; + min-height: 6em; - padding: 3px; - overflow-y: auto; + display: flex; + flex-direction: column; + justify-content: stretch; - border: 1px #161616 solid; - border-radius: $border_radius_middle; - background-color: #28292b; + color: #999999; - @include chat-scrollbar-vertical(); - - .group-entry { + a { flex-shrink: 0; flex-grow: 0; - display: flex; - flex-direction: row; - justify-content: stretch; + .htmltag-client { + display: inline; + color: #999999; + } + } - height: 1.75em; + .group-list { + flex-shrink: 1; + flex-grow: 1; + min-height: 4em; - > * { + padding: 3px; + overflow-y: auto; + + border: 1px #161616 solid; + border-radius: $border_radius_middle; + background-color: #28292b; + + @include chat-scrollbar-vertical(); + + .group-entry { flex-shrink: 0; flex-grow: 0; + + display: flex; + flex-direction: row; + justify-content: stretch; + + height: 1.75em; + + > * { + flex-shrink: 0; + flex-grow: 0; + align-self: center; + } + + a { + flex-shrink: 1; + flex-grow: 1; + + min-width: 6em; + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + label { + margin-right: .25em; + } + } + + .icon-container { align-self: center; + margin-right: 4px; + margin-left: 2px; + margin-top: -2px; } a { - flex-shrink: 1; - flex-grow: 1; - - min-width: 6em; - - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + align-self: center; } - - label { - margin-right: .25em; - } - } - - .icon-container { - align-self: center; - margin-right: 4px; - margin-left: 2px; - margin-top: -2px; - } - - a { - align-self: center; } } - } - .container-buttons { - flex-grow: 0; - flex-shrink: 0; + .container-buttons { + flex-grow: 0; + flex-shrink: 0; - padding-top: 1em; + padding-top: 1em; - display: flex; - flex-direction: row; - justify-content: space-between; + display: flex; + flex-direction: row; + justify-content: space-between; + } } } \ No newline at end of file diff --git a/shared/css/static/modal-icons.scss b/shared/css/static/modal-icons.scss index 7ca1c730..2db79fc2 100644 --- a/shared/css/static/modal-icons.scss +++ b/shared/css/static/modal-icons.scss @@ -1,508 +1,512 @@ @import "properties"; @import "mixin"; -.modal-icon-select { - @include user-select(none); +:global { + .modal-icon-select { + @include user-select(none); - display: flex!important; - flex-direction: column!important; - justify-content: stretch!important; + display: flex!important; + flex-direction: column!important; + justify-content: stretch!important; - width: 50em!important; + width: 50em!important; - /* - .right, .left { - .header { - text-transform: uppercase; - color: #557edc; + /* + .right, .left { + .header { + text-transform: uppercase; + color: #557edc; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - } - */ + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + } + */ - .container-icons { - flex-grow: 1; - flex-shrink: 1; - - display: flex; - flex-direction: row; - justify-content: stretch; - - > div { - width: 50%; - - &:not(:first-of-type) { - margin-left: 10px; - } - } - - .content, .container-icons-list { + .container-icons { flex-grow: 1; flex-shrink: 1; display: flex; - flex-direction: column; - } - - .container-icons-list { - position: relative; + flex-direction: row; + justify-content: stretch; > div { - border-radius: 3px; + width: 50%; + + &:not(:first-of-type) { + margin-left: 10px; + } } - .container-icons-remote, .container-icons-local { - width: 100%; - min-height: 300px; + .content, .container-icons-list { + flex-grow: 1; + flex-shrink: 1; - overflow-x: hidden; + display: flex; + flex-direction: column; + } + + .container-icons-list { + position: relative; + + > div { + border-radius: 3px; + } + + .container-icons-remote, .container-icons-local { + width: 100%; + min-height: 300px; + + overflow-x: hidden; + overflow-y: auto; + + background-color: $color_list_background; + border: 1px $color_list_border solid; + + border-radius: $border_radius_large; + + padding: .5em; + + flex-direction: row; + display: flex; + flex-wrap: wrap; + align-content: baseline; + + &.container-icons-local { + font-size: 16px; + } + + .icon-container, .icon { + margin-left: 1px; + margin-right: 1px; + } + + &.icon-select { + .icon-container, .icon { + cursor: pointer; + + &:hover { + border-radius: .1em; + + background-color: rgba(0, 0, 0, 0.07); + border: 1px solid black; + } + + &.selected { + border-radius: .1em; + + background-color: rgba(0, 51, 0, 0.07); + border: 1px solid red; + } + + &:hover, &.selected { + width: 18px; + height: 18px; + + margin: -1px 0px; + } + } + } + } + + .container-loading, .container-no-permissions, .container-error { + top: 0; + bottom: 0; + left: 0; + right: 0; + + font-size: 1.1em; + color: hsla(0, 0%, 40%, 1); + + position: absolute; + background-color: rgba(0, 0, 0, 0.27); + + cursor: not-allowed; + + text-align: center; + display: flex; + flex-direction: column; + justify-content: space-around; + + > a { + padding-bottom: 30px; + } + } + + .container-loading { + z-index: 40; + } + + .container-error { + z-index: 30; + } + .container-no-permissions { + z-index: 20; + } + } + } + + .container-buttons { + margin-top: 20px; + + flex-grow: 0; + flex-shrink: 0; + + display: flex; + flex-direction: row; + justify-content: space-between; + + .spacer { + min-width: 0; + + flex-grow: 1; + flex-shrink: 1; + } + + button { + flex-grow: 0; + flex-shrink: 1; + + width: 8em; + min-width: 4em; + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + margin-right: 1em; + } + + .button-select { + margin-left: 10px; + + display: flex; + align-items: center; + flex-direction: row; + justify-content: center; + + a, div { + align-self: center; + } + + > div { + font-size: 16px; + + display: flex; + flex-direction: column; + justify-content: center; + + margin-left: .5rem; + + > div { + display: flex; + } + } + } + + .button-select-no-icon { + margin-left: 10px; + } + } + } + + .modal-icon-upload { + @include user-select(none); + + width: 50em; + min-width: 300px; + + padding: 0!important; + + display: flex; + flex-direction: column; + + .container-select { + padding: 1em; + min-height: 130px; + + display: flex; + flex-direction: row; + justify-content: stretch; + + .container-icons { + flex-grow: 1; + flex-shrink: 1; + + width: min-content; + min-width: 150px; + min-height: 130px; overflow-y: auto; + margin-right: 1em; + background-color: $color_list_background; border: 1px $color_list_border solid; border-radius: $border_radius_large; padding: .5em; + display: block; - flex-direction: row; - display: flex; - flex-wrap: wrap; - align-content: baseline; + .icon-container { + cursor: pointer; - &.container-icons-local { - font-size: 16px; - } + &:hover { + border-radius: .1em; - .icon-container, .icon { - margin-left: 1px; - margin-right: 1px; - } - - &.icon-select { - .icon-container, .icon { - cursor: pointer; - - &:hover { - border-radius: .1em; - - background-color: rgba(0, 0, 0, 0.07); - border: 1px solid black; - } - - &.selected { - border-radius: .1em; - - background-color: rgba(0, 51, 0, 0.07); - border: 1px solid red; - } - - &:hover, &.selected { - width: 18px; - height: 18px; - - margin: -1px 0px; - } + background-color: rgba(0, 0, 0, 0.07); + border: 1px solid black; } - } - } - .container-loading, .container-no-permissions, .container-error { - top: 0; - bottom: 0; - left: 0; - right: 0; + &.selected { + border-radius: .1em; - font-size: 1.1em; - color: hsla(0, 0%, 40%, 1); + background-color: rgba(0, 51, 0, 0.07); + border: 1px solid red; + } - position: absolute; - background-color: rgba(0, 0, 0, 0.27); + &:hover, &.selected { + width: 18px; + height: 18px; - cursor: not-allowed; - - text-align: center; - display: flex; - flex-direction: column; - justify-content: space-around; - - > a { - padding-bottom: 30px; - } - } - - .container-loading { - z-index: 40; - } - - .container-error { - z-index: 30; - } - .container-no-permissions { - z-index: 20; - } - } - } - - .container-buttons { - margin-top: 20px; - - flex-grow: 0; - flex-shrink: 0; - - display: flex; - flex-direction: row; - justify-content: space-between; - - .spacer { - min-width: 0; - - flex-grow: 1; - flex-shrink: 1; - } - - button { - flex-grow: 0; - flex-shrink: 1; - - width: 8em; - min-width: 4em; - - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - - margin-right: 1em; - } - - .button-select { - margin-left: 10px; - - display: flex; - align-items: center; - flex-direction: row; - justify-content: center; - - a, div { - align-self: center; - } - - > div { - font-size: 16px; - - display: flex; - flex-direction: column; - justify-content: center; - - margin-left: .5rem; - - > div { - display: flex; - } - } - } - - .button-select-no-icon { - margin-left: 10px; - } - } -} - -.modal-icon-upload { - @include user-select(none); - - width: 50em; - min-width: 300px; - - padding: 0!important; - - display: flex; - flex-direction: column; - - .container-select { - padding: 1em; - min-height: 130px; - - display: flex; - flex-direction: row; - justify-content: stretch; - - .container-icons { - flex-grow: 1; - flex-shrink: 1; - - width: min-content; - min-width: 150px; - min-height: 130px; - overflow-y: auto; - - margin-right: 1em; - - background-color: $color_list_background; - border: 1px $color_list_border solid; - - border-radius: $border_radius_large; - - padding: .5em; - display: block; - - .icon-container { - cursor: pointer; - - &:hover { - border-radius: .1em; - - background-color: rgba(0, 0, 0, 0.07); - border: 1px solid black; - } - - &.selected { - border-radius: .1em; - - background-color: rgba(0, 51, 0, 0.07); - border: 1px solid red; - } - - &:hover, &.selected { - width: 18px; - height: 18px; - - margin: -1px 0px; - } - - > img { - height: 16px; - width: 16px; - } - } - } - - .container-buttons { - flex-grow: 1; - flex-shrink: 2; - - min-width: 50px; - max-width: 200px; - - display: flex; - flex-direction: column; - justify-content: space-between; - - .buttons-manage { - display: flex; - flex-direction: column; - justify-content: flex-start; - - > button:not(:first-of-type) { - margin-top: .5em; - } - } - } - } - - .container-upload { - -webkit-box-shadow: 0px -5px 5px 0px rgba(0,0,0,0.25); - -moz-box-shadow: 0px -5px 5px 0px rgba(0,0,0,0.25); - box-shadow: 0px -5px 2px 0px rgba(0, 0, 0, 0.25); - - display: flex; - flex-direction: column; - - padding: .5em 1em 1em; - - .container-error, .container-success { - width: 100%; - min-height: 60px; - - border: 2px solid; - border-radius: $border_radius_middle; - - &.container-error { - border-color: rgba(128, 0, 0, 0.5); - background-color: rgba(128, 0, 0, 0.25); - } - - &.container-success { - margin-top: .5em; - - border-color: rgba(50, 143, 51, 0.25); - background-color: rgba(50, 143, 51, 0.13); - } - - padding: .5em; - - display: flex; - flex-direction: row; - justify-content: space-between; - - > * { - align-self: center; - display: inline-block; - } - - button { - width: 6em; - } - - &.hidden { - opacity: 0; - height: 0; - min-height: 0; - padding: 0; - margin: 0; - } - - @include transition(.25s ease-in-out); - } - - .container-info { - display: flex; - flex-direction: row; - justify-content: space-between; - } - - .container-process { - margin-top: .5em; - - width: 100%; - min-height: 100px; - - overflow-y: auto; - - background-color: $color_list_background; - border: 1px $color_list_border solid; - - border-radius: $border_radius_large; - - .upload-entry { - display: flex; - flex-direction: row; - justify-content: stretch; - - .container-icon { - height: 16px; - width: 16px; - flex-grow: 0; - flex-shrink: 0; - - margin: 1px 1px 1px 4px; - - align-self: center; - - display: flex; - flex-direction: column; - justify-content: center; + margin: -1px 0px; + } > img { height: 16px; width: 16px; } } - - .progress { - position: relative; - - flex-grow: 1; - flex-shrink: 1; - - display: flex; - flex-direction: row; - justify-content: flex-start; - - min-width: 2em; - - margin: 2px 5px 2px 3px; - height: 16px; - - overflow: hidden; - font-size: .75rem; - - background-color: #222222; - border: 1px solid hsla(0, 0%, 10%, 1); - border-radius: .25rem; - - .progress-bar { - height: 100%; - - &.bg-danger { - background-color: rgba(128, 0, 0, 0.5); - } - - &.bg-success { - background-color: rgba(50, 143, 51, 0.5); - } - - @include transition(width 1s ease-in-out, background-color $button_hover_animation_time ease-in-out); - } - - .progress-message { - position: absolute; - width: 100%; - - display: flex; - flex-direction: row; - justify-content: center; - - flex-grow: 1; - flex-shrink: 1; - - min-width: 1em; - line-height: normal; - - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - } - } - } - } - - input[type="file"] { - display: none; - } -} - -@media screen and (max-width: 650px) { - .modal-icon-upload { - .container-select { - flex-direction: column; - - .container-icons { - width: 100%; - margin-right: 0; } .container-buttons { - max-width: unset; - margin-top: 5px; + flex-grow: 1; + flex-shrink: 2; - > button { - width: 100%; - } + min-width: 50px; + max-width: 200px; + + display: flex; + flex-direction: column; + justify-content: space-between; .buttons-manage { display: flex; - flex-direction: row; - justify-content: stretch; + flex-direction: column; + justify-content: flex-start; - > button { - width: 50%; - flex-grow: 1; - flex-shrink: 1; - min-width: 0; + > button:not(:first-of-type) { + margin-top: .5em; } } } } .container-upload { + -webkit-box-shadow: 0px -5px 5px 0px rgba(0,0,0,0.25); + -moz-box-shadow: 0px -5px 5px 0px rgba(0,0,0,0.25); + box-shadow: 0px -5px 2px 0px rgba(0, 0, 0, 0.25); + display: flex; flex-direction: column; - justify-content: flex-start; + + padding: .5em 1em 1em; + + .container-error, .container-success { + width: 100%; + min-height: 60px; + + border: 2px solid; + border-radius: $border_radius_middle; + + &.container-error { + border-color: rgba(128, 0, 0, 0.5); + background-color: rgba(128, 0, 0, 0.25); + } + + &.container-success { + margin-top: .5em; + + border-color: rgba(50, 143, 51, 0.25); + background-color: rgba(50, 143, 51, 0.13); + } + + padding: .5em; + + display: flex; + flex-direction: row; + justify-content: space-between; + + > * { + align-self: center; + display: inline-block; + } + + button { + width: 6em; + } + + &.hidden { + opacity: 0; + height: 0; + min-height: 0; + padding: 0; + margin: 0; + } + + @include transition(.25s ease-in-out); + } + + .container-info { + display: flex; + flex-direction: row; + justify-content: space-between; + } + + .container-process { + margin-top: .5em; + + width: 100%; + min-height: 100px; + + overflow-y: auto; + + background-color: $color_list_background; + border: 1px $color_list_border solid; + + border-radius: $border_radius_large; + + .upload-entry { + display: flex; + flex-direction: row; + justify-content: stretch; + + .container-icon { + height: 16px; + width: 16px; + flex-grow: 0; + flex-shrink: 0; + + margin: 1px 1px 1px 4px; + + align-self: center; + + display: flex; + flex-direction: column; + justify-content: center; + + > img { + height: 16px; + width: 16px; + } + } + + .progress { + position: relative; + + flex-grow: 1; + flex-shrink: 1; + + display: flex; + flex-direction: row; + justify-content: flex-start; + + min-width: 2em; + + margin: 2px 5px 2px 3px; + height: 16px; + + overflow: hidden; + font-size: .75rem; + + background-color: #222222; + border: 1px solid hsla(0, 0%, 10%, 1); + border-radius: .25rem; + + .progress-bar { + height: 100%; + + &.bg-danger { + background-color: rgba(128, 0, 0, 0.5); + } + + &.bg-success { + background-color: rgba(50, 143, 51, 0.5); + } + + @include transition(width 1s ease-in-out, background-color $button_hover_animation_time ease-in-out); + } + + .progress-message { + position: absolute; + width: 100%; + + display: flex; + flex-direction: row; + justify-content: center; + + flex-grow: 1; + flex-shrink: 1; + + min-width: 1em; + line-height: normal; + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + } + } + } + } + + input[type="file"] { + display: none; + } + } +} + +@media screen and (max-width: 650px) { + :global { + .modal-icon-upload { + .container-select { + flex-direction: column; + + .container-icons { + width: 100%; + margin-right: 0; + } + + .container-buttons { + max-width: unset; + margin-top: 5px; + + > button { + width: 100%; + } + + .buttons-manage { + display: flex; + flex-direction: row; + justify-content: stretch; + + > button { + width: 50%; + flex-grow: 1; + flex-shrink: 1; + min-width: 0; + } + } + } + } + + .container-upload { + display: flex; + flex-direction: column; + justify-content: flex-start; + } } } } \ No newline at end of file diff --git a/shared/css/static/modal-identity.scss b/shared/css/static/modal-identity.scss index dc1b729b..3863c599 100644 --- a/shared/css/static/modal-identity.scss +++ b/shared/css/static/modal-identity.scss @@ -1,60 +1,85 @@ @import "mixin"; -.modal-body.modal-identity-improve { - padding: 0!important; +:global { + .modal-body.modal-identity-improve { + padding: 0!important; - display: flex!important; - flex-direction: column!important; - justify-content: flex-start!important; + display: flex!important; + flex-direction: column!important; + justify-content: flex-start!important; - .container-tooltip { - flex-grow: 0!important; - flex-shrink: 0!important; - min-width: unset!important; + .container-tooltip { + flex-grow: 0!important; + flex-shrink: 0!important; + min-width: unset!important; - position: relative; - width: .8em; - margin-right: .5em; - font-size: .9em; + position: relative; + width: .8em; + margin-right: .5em; + font-size: .9em; - display: inline-flex; - flex-direction: column; - justify-content: center; - vertical-align: middle; - margin-bottom: .1em; + display: inline-flex; + flex-direction: column; + justify-content: center; + vertical-align: middle; + margin-bottom: .1em; - img { - height: 1em; - width: 1em; + img { + height: 1em; + width: 1em; - align-self: center; - font-size: 1.2em; + align-self: center; + font-size: 1.2em; + } + + .tooltip { + display: none; + } } - .tooltip { - display: none; - } - } + .options, .status { + flex-grow: 0; + flex-shrink: 0; - .options, .status { - flex-grow: 0; - flex-shrink: 0; + padding: 1em; - padding: 1em; + .title { + color: #387fb5; + } - .title { - color: #387fb5; + .row { + display: flex; + flex-direction: row; + justify-content: stretch; + + div { + flex-grow: 1; + flex-shrink: 1; + min-width: 4em; + + &:not(:first-of-type) { + margin-left: 1em; + } + } + } } - .row { + .status { + border-top: 3px solid #20262d; + } + + .buttons { + flex-grow: 0; + flex-shrink: 0; + + margin: 0 1em 1em; + display: flex; flex-direction: row; - justify-content: stretch; + justify-content: flex-end; - div { - flex-grow: 1; - flex-shrink: 1; - min-width: 4em; + button { + min-width: 8em; &:not(:first-of-type) { margin-left: 1em; @@ -63,126 +88,103 @@ } } - .status { - border-top: 3px solid #20262d; - } - - .buttons { - flex-grow: 0; - flex-shrink: 0; - - margin: 0 1em 1em; + .modal-body.modal-identity-import { + padding: 0!important; display: flex; - flex-direction: row; - justify-content: flex-end; + flex-direction: column; + justify-content: flex-start; - button { - min-width: 8em; + @include user-select(none); - &:not(:first-of-type) { - margin-left: 1em; + .container-status { + display: flex; + flex-direction: row; + justify-content: center; + + margin: 1em 1em -1em; + height: 1.6em; + + overflow: hidden; + + color: #389738; + &.error { + color: #973838; + } + + &.loading { + color: #96903a; + } + + &.hidden { + height: 0; + } + + a { + align-self: center; + } + + @include transition(.2s ease-in-out); + } + + .container-text, .container-file { + display: flex; + flex-direction: row; + justify-content: stretch; + + > label { + flex-shrink: 0; + flex-grow: 0; + + width: 10em; + + display: flex; + flex-direction: row; + justify-content: flex-start; + + padding-left: .25em; + align-self: center; + + margin-right: 1em; + + .radio-button { + align-self: center; + margin-right: .5em; + } + } + + > * { + align-self: center; + } + + .form-group { + margin-bottom: 1.75em; + width: 100%; + } + + button { + min-width: 8em; + margin-right: 1em; } } - } -} -.modal-body.modal-identity-import { - padding: 0!important; - - display: flex; - flex-direction: column; - justify-content: flex-start; - - @include user-select(none); - - .container-status { - display: flex; - flex-direction: row; - justify-content: center; - - margin: 1em 1em -1em; - height: 1.6em; - - overflow: hidden; - - color: #389738; - &.error { - color: #973838; - } - - &.loading { - color: #96903a; - } - - &.hidden { - height: 0; - } - - a { - align-self: center; - } - - @include transition(.2s ease-in-out); - } - - .container-text, .container-file { - display: flex; - flex-direction: row; - justify-content: stretch; - - > label { + .footer { flex-shrink: 0; flex-grow: 0; - width: 10em; + padding: 1em; display: flex; flex-direction: row; - justify-content: flex-start; + justify-content: flex-end; - padding-left: .25em; - align-self: center; - - margin-right: 1em; - - .radio-button { - align-self: center; - margin-right: .5em; + button { + min-width: 8em; } } - > * { - align-self: center; + .file-selector { + display: none; } - - .form-group { - margin-bottom: 1.75em; - width: 100%; - } - - button { - min-width: 8em; - margin-right: 1em; - } - } - - .footer { - flex-shrink: 0; - flex-grow: 0; - - padding: 1em; - - display: flex; - flex-direction: row; - justify-content: flex-end; - - button { - min-width: 8em; - } - } - - .file-selector { - display: none; } } \ No newline at end of file diff --git a/shared/css/static/modal-invite.scss b/shared/css/static/modal-invite.scss index 7142a560..d9f4f827 100644 --- a/shared/css/static/modal-invite.scss +++ b/shared/css/static/modal-invite.scss @@ -1,73 +1,75 @@ @import "mixin"; @import "properties"; -.modal-invite { - padding: .5em!important; - @include user-select(none); +:global { + .modal-invite { + padding: .5em!important; + @include user-select(none); - .general-properties { - flex: 0; - - display: flex; - flex-direction: column; - justify-content: stretch; - - .form-group { + .general-properties { flex: 0; + + display: flex; + flex-direction: column; + justify-content: stretch; + + .form-group { + flex: 0; + } + + .container-settings { + flex: 0; + + margin-bottom: .5em; + + display: flex; + flex-direction: row; + justify-content: space-between; + + label { + display: flex; + flex-direction: row; + justify-content: flex-start; + + > * { + align-self: center; + } + + a { + margin-left: .5em; + } + } + } } - .container-settings { - flex: 0; + .text-output { + background-color: $color_list_background; + border: 1px $color_list_border solid; - margin-bottom: .5em; + border-radius: $border_radius_large; + padding: .5em; + min-height: 5em; + + width: 100%; + resize: none; + + color: #999999; + + @include user-select(text); + } + + .buttons { display: flex; flex-direction: row; justify-content: space-between; - label { - display: flex; - flex-direction: row; - justify-content: flex-start; + margin-top: 5px; - > * { - align-self: center; - } - - a { - margin-left: .5em; - } + .icon { + vertical-align: middle; + margin-right: 5px; } } } - - .text-output { - background-color: $color_list_background; - border: 1px $color_list_border solid; - - border-radius: $border_radius_large; - - padding: .5em; - min-height: 5em; - - width: 100%; - resize: none; - - color: #999999; - - @include user-select(text); - } - - .buttons { - display: flex; - flex-direction: row; - justify-content: space-between; - - margin-top: 5px; - - .icon { - vertical-align: middle; - margin-right: 5px; - } - } } \ No newline at end of file diff --git a/shared/css/static/modal-keyselect.scss b/shared/css/static/modal-keyselect.scss index f37be98a..d14c20c5 100644 --- a/shared/css/static/modal-keyselect.scss +++ b/shared/css/static/modal-keyselect.scss @@ -1,50 +1,52 @@ -.modal-body.modal-keyselect { - width: max-content!important; - - .body { - display: flex; - flex-direction: column; - justify-content: flex-start; - - .container-select { - margin-top: .5em; +:global { + .modal-body.modal-keyselect { + width: max-content!important; + .body { display: flex; - flex-direction: row; + flex-direction: column; justify-content: flex-start; - a { - align-self: center; - margin-right: .5em; - } - - .container-key { - background-color: #272626; - border-radius: 0.15em; - -webkit-box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); - -moz-box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); - box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); - - min-width: 12em; - height: 2em; - padding: 0 .5em; + .container-select { + margin-top: .5em; display: flex; flex-direction: row; - justify-content: center; + justify-content: flex-start; + + a { + align-self: center; + margin-right: .5em; + } + + .container-key { + background-color: #272626; + border-radius: 0.15em; + -webkit-box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); + -moz-box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); + box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); + + min-width: 12em; + height: 2em; + padding: 0 .5em; + + display: flex; + flex-direction: row; + justify-content: center; + } + } + } + + .container-buttons { + display: flex; + flex-direction: row; + justify-content: flex-end; + + margin-top: 1em; + + button { + margin-left: 1em; } } } - - .container-buttons { - display: flex; - flex-direction: row; - justify-content: flex-end; - - margin-top: 1em; - - button { - margin-left: 1em; - } - } } \ No newline at end of file diff --git a/shared/css/static/modal-latency.scss b/shared/css/static/modal-latency.scss index 07d94c71..9c5c232b 100644 --- a/shared/css/static/modal-latency.scss +++ b/shared/css/static/modal-latency.scss @@ -1,84 +1,86 @@ @import "mixin"; @import "properties"; -.modal-body.modal-latency { - @include user-select(none); - @include transform(all $button_hover_animation_time ease-in-out); +:global { + .modal-body.modal-latency { + @include user-select(none); + @include transform(all $button_hover_animation_time ease-in-out); - .info { - display: flex; - flex-direction: row; - justify-content: stretch; - - .htmltag-client { - color: #999!important; - margin-left: .25em; - } - - div { + .info { display: flex; flex-direction: row; justify-content: stretch; - } - .value { - margin-left: .25em; - } - } + .htmltag-client { + color: #999!important; + margin-left: .25em; + } - .container-min, .container-max { - display: flex; - flex-direction: row; - justify-content: stretch; - - height: 2em; - - .container-value { - display: flex; - flex-direction: row; - justify-content: space-between; - - flex-shrink: 0; - flex-grow: 0; - - margin-right: 1em; - width: 9em; - - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - - align-self: center; + div { + display: flex; + flex-direction: row; + justify-content: stretch; + } .value { + margin-left: .25em; + } + } + + .container-min, .container-max { + display: flex; + flex-direction: row; + justify-content: stretch; + + height: 2em; + + .container-value { + display: flex; + flex-direction: row; + justify-content: space-between; + + flex-shrink: 0; + flex-grow: 0; + + margin-right: 1em; + width: 9em; + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + align-self: center; + + .value { + } + } + } + + .container-max { + padding-top: 1em; + } + + .container-slider { + align-self: center; + } + + .buttons { + display: flex; + flex-direction: row; + justify-content: stretch; + + margin-top: 2em; + + .spacer { + flex-grow: 1; + flex-shrink: 1; + + min-width: 0; + } + + button:not(:last-of-type) { + margin-right: 1em; } } } - - .container-max { - padding-top: 1em; - } - - .container-slider { - align-self: center; - } - - .buttons { - display: flex; - flex-direction: row; - justify-content: stretch; - - margin-top: 2em; - - .spacer { - flex-grow: 1; - flex-shrink: 1; - - min-width: 0; - } - - button:not(:last-of-type) { - margin-right: 1em; - } - } } \ No newline at end of file diff --git a/shared/css/static/modal-musicmanage.scss b/shared/css/static/modal-musicmanage.scss index 5fe95b9e..621a31fe 100644 --- a/shared/css/static/modal-musicmanage.scss +++ b/shared/css/static/modal-musicmanage.scss @@ -1,697 +1,699 @@ @import "mixin"; @import "properties"; -.modal-body.modal-music-manage { - padding: 0 !important; +:global { + .modal-body.modal-music-manage { + padding: 0 !important; - display: flex !important;; - flex-direction: column !important;; - justify-content: stretch !important;; + display: flex !important;; + flex-direction: column !important;; + justify-content: stretch !important;; - width: 80em; - min-height: 20em; /* Set it here, so we dont have a inner modal scroll */ + width: 80em; + min-height: 20em; /* Set it here, so we dont have a inner modal scroll */ - @include user-select(none); + @include user-select(none); - > .header { - flex-grow: 0; - flex-shrink: 0; + > .header { + flex-grow: 0; + flex-shrink: 0; - height: 4em; - - display: flex; - flex-direction: row; - justify-content: stretch; - - .category { - flex-grow: 1; - flex-shrink: 1; - - min-width: 0; - width: 50%; - - position: relative; - overflow: hidden; - - cursor: pointer; - padding-bottom: 2px; + height: 4em; display: flex; - flex-direction: column; - justify-content: center; + flex-direction: row; + justify-content: stretch; - a { - text-align: center; - color: #e1e1e1; + .category { + flex-grow: 1; + flex-shrink: 1; + min-width: 0; + width: 50%; + + position: relative; overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - &:hover { - border: none; - border-bottom: 2px solid #4e4e4e; + cursor: pointer; + padding-bottom: 2px; - padding-bottom: 0; + display: flex; + flex-direction: column; + justify-content: center; - &:before { - position: absolute; - content: ''; + a { + text-align: center; + color: #e1e1e1; - margin-right: -10em; - margin-left: -10em; - margin-bottom: -.2em; - bottom: 0; - - height: 100%; - width: calc(100% + 20em); - - box-shadow: inset 0px -1.2em 3em -20px #424242; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; } - } - &.selected { - border: none; - border-bottom: 2px solid #0073d4; + &:hover { + border: none; + border-bottom: 2px solid #4e4e4e; - padding-bottom: 0; + padding-bottom: 0; - &:before { - position: absolute; - content: ''; + &:before { + position: absolute; + content: ''; - margin-right: -10em; - margin-left: -10em; - margin-bottom: -.2em; - bottom: 0; + margin-right: -10em; + margin-left: -10em; + margin-bottom: -.2em; + bottom: 0; - height: 100%; - width: calc(100% + 20em); + height: 100%; + width: calc(100% + 20em); - box-shadow: inset 0px -1.2em 3em -20px #0073d4; + box-shadow: inset 0px -1.2em 3em -20px #424242; + } + } + + &.selected { + border: none; + border-bottom: 2px solid #0073d4; + + padding-bottom: 0; + + &:before { + position: absolute; + content: ''; + + margin-right: -10em; + margin-left: -10em; + margin-bottom: -.2em; + bottom: 0; + + height: 100%; + width: calc(100% + 20em); + + box-shadow: inset 0px -1.2em 3em -20px #0073d4; + } } } } - } - - > .body { - display: flex; - flex-direction: column; - justify-content: stretch; - - min-height: 20em; - - background-color: #303036; - - @include tooltip(1.6em, 1em); - .container { - flex-grow: 0; - flex-shrink: 1; + > .body { display: flex; flex-direction: column; justify-content: stretch; min-height: 20em; - height: 40.5em; - .input-boxed, .btn { - height: 2em; - } + background-color: #303036; - $border_color: #1e2025; - &.category-permissions { - .column { - flex-shrink: 0; - flex-grow: 0; + @include tooltip(1.6em, 1em); + .container { + flex-grow: 0; + flex-shrink: 1; - display: flex; - flex-direction: column; - justify-content: flex-start; + display: flex; + flex-direction: column; + justify-content: stretch; - &.column-permission { - flex-shrink: 1000; - flex-grow: 1; - min-width: 6em; + min-height: 20em; + height: 40.5em; - a { - @include text-dotdotdot(); - } - - .master { - font-weight: bold; - } - - .slave { - padding-left: 1em; - } - } - - &.column-required { - flex-shrink: 1; - flex-grow: 0; - - a { - @include text-dotdotdot(); - } - - min-width: 6em; - width: 10em; - } - - &.column-client-specific { - flex-shrink: 1; - flex-grow: 0; - - min-width: 20em; - width: 30em; - } + .input-boxed, .btn { + height: 2em; } - .table-head { - flex-shrink: 0; - flex-grow: 0; - - display: flex; - flex-direction: row; - justify-content: stretch; - + $border_color: #1e2025; + &.category-permissions { .column { - height: 5.5em; - padding: .5em; - - justify-content: flex-end!important; - - &.column-permission, &.column-required { - color: #e1e1e1; - font-weight: bold; - - border-right: 1px solid $border_color; - } - } - - .select-client { - padding-top: .5em; - - display: flex; - flex-direction: row; - justify-content: stretch; - - input { - flex-grow: 1; - flex-shrink: 1; - min-width: 1em; - } - - button { - flex-grow: 0; - flex-shrink: 0; - - width: 5em; - margin-left: 1em; - } - } - - .client-select, .client-info { - display: flex; - flex-direction: column; - justify-content: stretch; - - &.hidden { - display: none; - } - - button { - flex-grow: 0; - flex-shrink: 0; - margin-left: 1em; - - @include text-dotdotdot(); - - &.button-search { - width: 6em; - } - - &.button-list-clients, &.button-client-deselect { - width: 8em; - } - } - - .row { - height: 2em; - - display: flex; - flex-direction: row; - justify-content: stretch; - - &:not(:first-of-type) { - margin-top: .5em; - } - - a { - flex-grow: 1; - flex-shrink: 1; - min-width: 0; - - align-self: center; - - @include text-dotdotdot(); - } - - input { - flex-grow: 1; - flex-shrink: 1; - - min-width: 2em; - } - } - } - - .client-info { - color: #e1e1e1; - font-weight: bold; - - a { - flex-shrink: 0; - margin-right: .5em; - } - - .htmltag-client { - color: #e1e1e1; - align-self: center; - - @include text-dotdotdot(); - } - } - } - - .table-body { - flex-shrink: 1; - flex-grow: 1; - - display: flex; - flex-direction: row; - justify-content: flex-start; - - min-height: 6em; - - overflow-x: hidden; - overflow-y: auto; - - @include chat-scrollbar-vertical(); - - .entry { - height: 2.6em; /* input box + 2 * .5em */ - padding: .5em; - flex-shrink: 0; flex-grow: 0; display: flex; flex-direction: column; - justify-content: center; + justify-content: flex-start; - background-color: unset; + &.column-permission { + flex-shrink: 1000; + flex-grow: 1; + min-width: 6em; - &:nth-of-type(2n) { - background-color: #25252a; + a { + @include text-dotdotdot(); + } + + .master { + font-weight: bold; + } + + .slave { + padding-left: 1em; + } } - border-top: 1px solid $border_color; - border-right: 1px solid $border_color; + &.column-required { + flex-shrink: 1; + flex-grow: 0; - .container-input { - color: #e1e1e1; + a { + @include text-dotdotdot(); + } + + min-width: 6em; + width: 10em; + } + + &.column-client-specific { + flex-shrink: 1; + flex-grow: 0; + + min-width: 20em; + width: 30em; + } + } + + .table-head { + flex-shrink: 0; + flex-grow: 0; + + display: flex; + flex-direction: row; + justify-content: stretch; + + .column { + height: 5.5em; + padding: .5em; + + justify-content: flex-end!important; + + &.column-permission, &.column-required { + color: #e1e1e1; + font-weight: bold; + + border-right: 1px solid $border_color; + } + } + + .select-client { + padding-top: .5em; display: flex; flex-direction: row; justify-content: stretch; + input { + flex-grow: 1; + flex-shrink: 1; + min-width: 1em; + } + + button { + flex-grow: 0; + flex-shrink: 0; + + width: 5em; + margin-left: 1em; + } + } + + .client-select, .client-info { + display: flex; + flex-direction: column; + justify-content: stretch; + &.hidden { display: none; } - input { - text-align: right; - - flex-shrink: 1; - flex-grow: 1; - - min-width: 2em; - - outline: none; - background: transparent; - border: none; - - height: 1.6em; - - /* fix the column padding */ - padding-left: 1em; - margin-left: -.5em; /* have a bit of space on both sides */ - - color: #999; - } - - .container-tooltip { - flex-shrink: 0; + button { flex-grow: 0; - } + flex-shrink: 0; + margin-left: 1em; - border-bottom: 2px solid transparent; + @include text-dotdotdot(); - &:focus-within { - border-bottom-color: #3f7dbf; + &.button-search { + width: 6em; + } - input { - color: #e1e1e1; + &.button-list-clients, &.button-client-deselect { + width: 8em; } } - @include transition(border-bottom-color $button_hover_animation_time ease-in-out); + + .row { + height: 2em; + + display: flex; + flex-direction: row; + justify-content: stretch; + + &:not(:first-of-type) { + margin-top: .5em; + } + + a { + flex-grow: 1; + flex-shrink: 1; + min-width: 0; + + align-self: center; + + @include text-dotdotdot(); + } + + input { + flex-grow: 1; + flex-shrink: 1; + + min-width: 2em; + } + } + } + + .client-info { + color: #e1e1e1; + font-weight: bold; + + a { + flex-shrink: 0; + margin-right: .5em; + } + + .htmltag-client { + color: #e1e1e1; + align-self: center; + + @include text-dotdotdot(); + } } } - .column-client-specific { - position: relative; + .table-body { + flex-shrink: 1; + flex-grow: 1; + + display: flex; + flex-direction: row; + justify-content: flex-start; + + min-height: 6em; + + overflow-x: hidden; + overflow-y: auto; + + @include chat-scrollbar-vertical(); .entry { - border-right: unset; + height: 2.6em; /* input box + 2 * .5em */ + padding: .5em; + + flex-shrink: 0; + flex-grow: 0; + + display: flex; + flex-direction: column; + justify-content: center; + + background-color: unset; + + &:nth-of-type(2n) { + background-color: #25252a; + } + + border-top: 1px solid $border_color; + border-right: 1px solid $border_color; + + .container-input { + color: #e1e1e1; + + display: flex; + flex-direction: row; + justify-content: stretch; + + &.hidden { + display: none; + } + + input { + text-align: right; + + flex-shrink: 1; + flex-grow: 1; + + min-width: 2em; + + outline: none; + background: transparent; + border: none; + + height: 1.6em; + + /* fix the column padding */ + padding-left: 1em; + margin-left: -.5em; /* have a bit of space on both sides */ + + color: #999; + } + + .container-tooltip { + flex-shrink: 0; + flex-grow: 0; + } + + border-bottom: 2px solid transparent; + + &:focus-within { + border-bottom-color: #3f7dbf; + + input { + color: #e1e1e1; + } + } + @include transition(border-bottom-color $button_hover_animation_time ease-in-out); + } } - .overlay-client-list { - position: absolute; - z-index: 1; + .column-client-specific { + position: relative; - top: 0; - bottom: 0; - left: 0; - right: 0; + .entry { + border-right: unset; + } + + .overlay-client-list { + position: absolute; + z-index: 1; + + top: 0; + bottom: 0; + left: 0; + right: 0; + + display: flex; + flex-direction: column; + justify-content: stretch; + + border-top: 1px solid $border_color; + background-color: #303036; + padding: .5em; + + opacity: 1; + pointer-events: all; + + @include transition(all .25s ease-in-out); + + &.hidden { + pointer-events: none; + opacity: 0; + } + + .title { + flex-grow: 0; + flex-shrink: 0; + } + + .container-client-list { + flex-grow: 1; + flex-shrink: 1; + + position: relative; + + display: flex; + flex-direction: column; + justify-content: flex-start; + + border: 1px #161616 solid; + border-radius: 0.2em; + background-color: #28292b; + + overflow-x: hidden; + overflow-y: auto; + + padding-top: 0.25em; + padding-bottom: 0.25em; + + margin-top: .5em; + margin-bottom: .5em; + + @include chat-scrollbar-vertical(); + + .overlay { + position: absolute; + z-index: 1; + + top: 0; + bottom: 0; + left: 0; + right: 0; + + display: flex; + flex-direction: column; + justify-content: center; + + background-color: #28292b; + color: #676468; + + text-align: center; + font-size: 1.3em; + + &.hidden { + display: none; + } + } + + .client { + padding-left: .5em; + padding-right: .5em; + + .htmltag-client { + @include text-dotdotdot(); + color: #999; + font-weight: unset; + } + + &:hover { + background-color: #2c2d2f; + } + + &.hidden { + display: none; + } + } + } + + .container-buttons { + flex-grow: 0; + flex-shrink: 0; + + display: flex; + flex-direction: row; + justify-content: flex-end; + } + } + } + } + + .container-buttons { + flex-shrink: 0; + flex-grow: 0; + + display: flex; + flex-direction: row; + justify-content: flex-end; + + margin-top: .5em; + } + } + + &.category-settings { + .container-settings { + flex-grow: 1; + flex-shrink: 1; + min-height: 10em; + + display: flex; + flex-direction: row; + justify-content: stretch; + + .settings { + flex-grow: 1; + flex-shrink: 1; + + width: 50%; + min-width: 15em; display: flex; flex-direction: column; justify-content: stretch; - border-top: 1px solid $border_color; - background-color: #303036; padding: .5em; - opacity: 1; - pointer-events: all; + &.settings-bot { + border-right: 1px solid $border_color; - @include transition(all .25s ease-in-out); - - &.hidden { - pointer-events: none; - opacity: 0; + padding-left: 0; } - .title { - flex-grow: 0; - flex-shrink: 0; + &.settings-playlist { + padding-right: 0; } - .container-client-list { - flex-grow: 1; - flex-shrink: 1; - - position: relative; + > a { + color: #e1e1e1; + font-weight: bold; + } + .body { display: flex; flex-direction: column; justify-content: flex-start; - border: 1px #161616 solid; - border-radius: 0.2em; - background-color: #28292b; - - overflow-x: hidden; - overflow-y: auto; - - padding-top: 0.25em; - padding-bottom: 0.25em; - - margin-top: .5em; - margin-bottom: .5em; - - @include chat-scrollbar-vertical(); - - .overlay { - position: absolute; - z-index: 1; - - top: 0; - bottom: 0; - left: 0; - right: 0; - + > label, > div { display: flex; - flex-direction: column; - justify-content: center; + justify-content: flex-start; + flex-direction: row; - background-color: #28292b; - color: #676468; + margin-top: .5em; - text-align: center; - font-size: 1.3em; - - &.hidden { - display: none; + * { + align-self: center; } } - .client { - padding-left: .5em; - padding-right: .5em; - - .htmltag-client { - @include text-dotdotdot(); - color: #999; - font-weight: unset; - } - - &:hover { - background-color: #2c2d2f; - } - - &.hidden { - display: none; - } - } - } - - .container-buttons { - flex-grow: 0; - flex-shrink: 0; - - display: flex; - flex-direction: row; - justify-content: flex-end; - } - } - } - } - - .container-buttons { - flex-shrink: 0; - flex-grow: 0; - - display: flex; - flex-direction: row; - justify-content: flex-end; - - margin-top: .5em; - } - } - - &.category-settings { - .container-settings { - flex-grow: 1; - flex-shrink: 1; - min-height: 10em; - - display: flex; - flex-direction: row; - justify-content: stretch; - - .settings { - flex-grow: 1; - flex-shrink: 1; - - width: 50%; - min-width: 15em; - - display: flex; - flex-direction: column; - justify-content: stretch; - - padding: .5em; - - &.settings-bot { - border-right: 1px solid $border_color; - - padding-left: 0; - } - - &.settings-playlist { - padding-right: 0; - } - - > a { - color: #e1e1e1; - font-weight: bold; - } - - .body { - display: flex; - flex-direction: column; - justify-content: flex-start; - - > label, > div { - display: flex; - justify-content: flex-start; - flex-direction: row; - - margin-top: .5em; - - * { - align-self: center; - } - } - - a { - @include text-dotdotdot(); - } - - .container-name-country { - display: flex; - flex-direction: row; - justify-content: stretch; - - .option-bot-name { - flex-grow: 1; - flex-shrink: 1; - - min-width: 6em; - margin-right: 1em; + a { + @include text-dotdotdot(); } - .container-country { - flex-grow: 0; - flex-shrink: 0; - + .container-name-country { display: flex; flex-direction: row; justify-content: stretch; - width: 5em; - - input { - flex-shrink: 1; + .option-bot-name { flex-grow: 1; - min-width: 0; + flex-shrink: 1; + + min-width: 6em; + margin-right: 1em; } - .country { + .container-country { flex-grow: 0; flex-shrink: 0; - margin: .5em; + display: flex; + flex-direction: row; + justify-content: stretch; + + width: 5em; + + input { + flex-shrink: 1; + flex-grow: 1; + min-width: 0; + } + + .country { + flex-grow: 0; + flex-shrink: 0; + + margin: .5em; + } } } - } - .checkbox { - margin-right: .5em; - } - - .container-replay-mode, .container-max-playlist-size { - display: flex; - flex-direction: row; - justify-content: stretch; - - a { - flex-grow: 1; - flex-shrink: 1; - - min-width: 0; + .checkbox { + margin-right: .5em; } - select, .input-boxed { - flex-grow: 0; - flex-shrink: 0; - + .container-replay-mode, .container-max-playlist-size { display: flex; flex-direction: row; justify-content: stretch; - width: 10em; - - margin-left: .5em; - - input { - flex-shrink: 1; + a { flex-grow: 1; + flex-shrink: 1; min-width: 0; } + + select, .input-boxed { + flex-grow: 0; + flex-shrink: 0; + + display: flex; + flex-direction: row; + justify-content: stretch; + + width: 10em; + + margin-left: .5em; + + input { + flex-shrink: 1; + flex-grow: 1; + + min-width: 0; + } + } } } } } + + .container-buttons { + flex-grow: 0; + flex-shrink: 0; + + display: flex; + flex-direction: row; + justify-content: flex-end; + } } - .container-buttons { - flex-grow: 0; - flex-shrink: 0; - - display: flex; - flex-direction: row; - justify-content: flex-end; + &.hidden { + display: none; } } - - &.hidden { - display: none; - } } } -} -.tooltip-music-permission-overview { - padding-left: .25em; - padding-right: .25em; - text-align: left; - - display: flex; - flex-direction: column; - justify-content: flex-start; - - max-height: 8em; - - .container-title { - flex-grow: 0; - flex-shrink: 0; - } - - .container-groups { - flex-grow: 0; - flex-shrink: 1; - - min-height: 0; + .tooltip-music-permission-overview { + padding-left: .25em; + padding-right: .25em; + text-align: left; display: flex; flex-direction: column; justify-content: flex-start; - overflow-x: hidden; - overflow-y: auto; + max-height: 8em; - @include chat-scrollbar-horizontal(); - } + .container-title { + flex-grow: 0; + flex-shrink: 0; + } - .container-status { - &.hidden { - display: none; + .container-groups { + flex-grow: 0; + flex-shrink: 1; + + min-height: 0; + + display: flex; + flex-direction: column; + justify-content: flex-start; + + overflow-x: hidden; + overflow-y: auto; + + @include chat-scrollbar-horizontal(); + } + + .container-status { + &.hidden { + display: none; + } } } } \ No newline at end of file diff --git a/shared/css/static/modal-newcomer.scss b/shared/css/static/modal-newcomer.scss index b6da49eb..aefa46b1 100644 --- a/shared/css/static/modal-newcomer.scss +++ b/shared/css/static/modal-newcomer.scss @@ -6,154 +6,156 @@ html:root { --modal-newcomer-divider: #313135; } -.modal-body.modal-newcomer { - display: flex!important; - flex-direction: column!important; - justify-content: stretch!important; +:global { + .modal-body.modal-newcomer { + display: flex!important; + flex-direction: column!important; + justify-content: stretch!important; - padding: 0!important; + padding: 0!important; - min-width: 20em; - width: 60em; + min-width: 20em; + width: 60em; - @include user-select(none); + @include user-select(none); - .container-header { - flex-shrink: 0; - flex-grow: 0; + .container-header { + flex-shrink: 0; + flex-grow: 0; - color: var(--modal-newcommer-header-color); - padding: .5em .5em .25em; + color: var(--modal-newcommer-header-color); + padding: .5em .5em .25em; - position: relative; - font-size: 1.5em; - text-transform: uppercase; - - .step { - &.hidden { - display: none; - } - - - &::after { - content: ' '; - position: absolute; - - left: 0; - right: 0; - bottom: 0; - - height: 1.25px; - //background: linear-gradient(90deg, rgba(49,49,53,1) 80%, rgba(49,49,53,0) 100%); - background: var(--modal-newcomer-divider); - } - - &.hidden { - &::after { - content: unset; - } - } - } - } - - .container-body { - //flex-grow: 1; - //flex-shrink: 1; - flex-shrink: 1; - min-height: 18em; - - display: flex; - flex-direction: column; - justify-content: center; - - overflow: auto; - @include chat-scrollbar-horizontal(); - @include chat-scrollbar-vertical(); - - background-color: #19191b; - - .body { - display: flex; - flex-direction: column; - justify-content: stretch; - - padding: .5em .5em .5em; - - &.height-transition { - @include transition(max-height .25s ease-in-out, min-height .25s ease-in-out); - overflow: hidden; - } + position: relative; + font-size: 1.5em; + text-transform: uppercase; .step { - &.step-welcome, &.step-finish { - display: flex; - flex-direction: row; - justify-content: center; - - .text { - align-self: center; - h1 { - line-height: 1.1em; - - margin-bottom: .8em; - margin-top: 0; - } - - flex-shrink: 0; - } - - &.step-welcome h1 { - margin-bottom: 0; - } - - .logo { - max-height: 15em; - max-width: 15em; - - align-self: center; - margin-right: 1em; - - img { - max-height: 100%; - max-width: 100%; - } - } - } - - /* for step-identity or step-microphone */ - .container-settings-identity-profile { - padding: .5em; - - .left .body { - background-color: #202122; - .overlay { - background-color: #202122; - } - - .profile.selected { - background-color: #141415; - } - } - } - - &.step-identity { } - &.hidden { display: none; } + + + &::after { + content: ' '; + position: absolute; + + left: 0; + right: 0; + bottom: 0; + + height: 1.25px; + //background: linear-gradient(90deg, rgba(49,49,53,1) 80%, rgba(49,49,53,0) 100%); + background: var(--modal-newcomer-divider); + } + + &.hidden { + &::after { + content: unset; + } + } } } - } - .buttons { - flex-shrink: 0; - flex-grow: 0; + .container-body { + //flex-grow: 1; + //flex-shrink: 1; + flex-shrink: 1; + min-height: 18em; - display: flex; - flex-direction: row; - justify-content: space-between; + display: flex; + flex-direction: column; + justify-content: center; - border-top: 1.25px solid var(--modal-newcomer-divider); - padding: .5em; + overflow: auto; + @include chat-scrollbar-horizontal(); + @include chat-scrollbar-vertical(); + + background-color: #19191b; + + .body { + display: flex; + flex-direction: column; + justify-content: stretch; + + padding: .5em .5em .5em; + + &.height-transition { + @include transition(max-height .25s ease-in-out, min-height .25s ease-in-out); + overflow: hidden; + } + + .step { + &.step-welcome, &.step-finish { + display: flex; + flex-direction: row; + justify-content: center; + + .text { + align-self: center; + h1 { + line-height: 1.1em; + + margin-bottom: .8em; + margin-top: 0; + } + + flex-shrink: 0; + } + + &.step-welcome h1 { + margin-bottom: 0; + } + + .logo { + max-height: 15em; + max-width: 15em; + + align-self: center; + margin-right: 1em; + + img { + max-height: 100%; + max-width: 100%; + } + } + } + + /* for step-identity or step-microphone */ + .container-settings-identity-profile { + padding: .5em; + + .left .body { + background-color: #202122; + .overlay { + background-color: #202122; + } + + .profile.selected { + background-color: #141415; + } + } + } + + &.step-identity { } + + &.hidden { + display: none; + } + } + } + } + + .buttons { + flex-shrink: 0; + flex-grow: 0; + + display: flex; + flex-direction: row; + justify-content: space-between; + + border-top: 1.25px solid var(--modal-newcomer-divider); + padding: .5em; + } } } \ No newline at end of file diff --git a/shared/css/static/modal-poke.scss b/shared/css/static/modal-poke.scss index 89df1be4..e69dacc4 100644 --- a/shared/css/static/modal-poke.scss +++ b/shared/css/static/modal-poke.scss @@ -3,86 +3,88 @@ html:root { --modal-poke-text: #004d00; } -.container-poke { - display: flex!important;; - flex-direction: column!important;; +:global { + .container-poke { + display: flex!important;; + flex-direction: column!important;; - .container-servers { - display: flex; - flex-direction: column; - justify-content: stretch; - - .server { + .container-servers { display: flex; flex-direction: column; justify-content: stretch; - .server-name { - margin-top: 5px; - - flex-grow: 0; - flex-shrink: 0; - - font-weight: bold; - text-decoration: underline; - } - - .poke-list { + .server { display: flex; flex-direction: column; - justify-content: flex-start; + justify-content: stretch; - overflow-y: auto; - overflow-x: auto; + .server-name { + margin-top: 5px; - .entry { + flex-grow: 0; + flex-shrink: 0; + + font-weight: bold; + text-decoration: underline; + } + + .poke-list { display: flex; - flex-direction: row; + flex-direction: column; justify-content: flex-start; - flex-shrink: 0; - flex-grow: 0; + overflow-y: auto; + overflow-x: auto; - > * { - white-space: nowrap; - } + .entry { + display: flex; + flex-direction: row; + justify-content: flex-start; - .date, .user, .text { - margin-right: 5px; - } + flex-shrink: 0; + flex-grow: 0; - .date { - color: var(--modal-poke-date); - } - .text { - color: var(--modal-poke-text); + > * { + white-space: nowrap; + } + + .date, .user, .text { + margin-right: 5px; + } + + .date { + color: var(--modal-poke-date); + } + .text { + color: var(--modal-poke-text); + } } } } } - } - .buttons { - display: flex; - flex-direction: row; - justify-content: stretch; - - margin-top: 5px; - flex-shrink: 0; - flex-grow: 0; - - .spacer { - flex-grow: 1; - flex-shrink: 1; - } - - .button-close { - flex-grow: 0; - flex-shrink: 0; + .buttons { + display: flex; + flex-direction: row; + justify-content: stretch; margin-top: 5px; - width: 150px; - float: right; + flex-shrink: 0; + flex-grow: 0; + + .spacer { + flex-grow: 1; + flex-shrink: 1; + } + + .button-close { + flex-grow: 0; + flex-shrink: 0; + + margin-top: 5px; + width: 150px; + float: right; + } } } } \ No newline at end of file diff --git a/shared/css/static/modal-query.scss b/shared/css/static/modal-query.scss index 3e7759d6..91eceb51 100644 --- a/shared/css/static/modal-query.scss +++ b/shared/css/static/modal-query.scss @@ -1,375 +1,377 @@ @import "properties"; @import "mixin"; -.query-create { - display: flex!important; - flex-direction: column!important; +:global { + .query-create { + display: flex!important; + flex-direction: column!important; - .row-name { - width: 100%; - - display: flex; - flex-direction: row; - justify-content: stretch; - - input { - flex-grow: 1; - flex-shrink: 1; - margin-left: 5px; - } - } - - .buttons { - margin-top: 5px; - text-align: right; - } -} - -.query-created { - display: flex!important; - flex-direction: column!important; - - .buttons { - text-align: right; - } - - .form-row { - margin-right: 0!important; - margin-left: 0!important; - - display: flex; - flex-direction: row; - justify-content: stretch; - - .icon_x32 { - align-self: center; - margin-right: 5px; - - cursor: pointer; - } - - .form-group { - flex-grow: 1; - } - } -} - -html:root { - --modal-query-title: #e0e0e0; - - --modal-query-list: #28292b; - --modal-query-list-border: #1f2122; - - --modal-query-empty: #4d4d4d; - --modal-query-error: #732626; - - --modal-query-entry-hover: #2c2d2f; - --modal-query-entry-selected: #1a1a1b; - - --modal-query-key: #557edc; - --modal-query-copy-hover: #28292b; -} - -.modal-body.modal-query-manage { - display: flex!important; - flex-direction: row!important; - justify-content: stretch!important; - - padding: 1em!important; - - min-width: 25em!important; /* 23em to be exact */ - min-height: 20em!important; - - width: 60em; /* recommend width */ - height: 50em; - - @include user-select(none); - - .container { - flex-grow: 1; - flex-shrink: 1; - - min-width: 20em; - min-height: 10em; - - display: flex; - flex-direction: row; - justify-content: stretch; - } - - .left, .right { - flex-grow: 1; - flex-shrink: 1; - - display: flex; - flex-direction: column; - justify-content: stretch; - - > .title { - flex-grow: 0; - flex-shrink: 0; - margin-bottom: .5em; + .row-name { + width: 100%; display: flex; flex-direction: row; justify-content: stretch; - a { - font-weight: bold; - color: var(--modal-query-title); - + input { flex-grow: 1; flex-shrink: 1; + margin-left: 5px; + } + } - font-size: 1.05em; - min-width: 5em; + .buttons { + margin-top: 5px; + text-align: right; + } + } - align-self: flex-end; - line-height: normal; + .query-created { + display: flex!important; + flex-direction: column!important; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + .buttons { + text-align: right; + } + + .form-row { + margin-right: 0!important; + margin-left: 0!important; + + display: flex; + flex-direction: row; + justify-content: stretch; + + .icon_x32 { + align-self: center; + margin-right: 5px; + + cursor: pointer; } - button { - flex-grow: 0; - flex-shrink: 1; - - height: 2em; - font-size: .9em; - - width: 10em; - min-width: 5em; - - align-self: center; - overflow: hidden; - text-overflow: ellipsis; + .form-group { + flex-grow: 1; } } } - .left { - margin-right: .4em; - min-width: 10em; + html:root { + --modal-query-title: #e0e0e0; - .container-list { + --modal-query-list: #28292b; + --modal-query-list-border: #1f2122; + + --modal-query-empty: #4d4d4d; + --modal-query-error: #732626; + + --modal-query-entry-hover: #2c2d2f; + --modal-query-entry-selected: #1a1a1b; + + --modal-query-key: #557edc; + --modal-query-copy-hover: #28292b; + } + + .modal-body.modal-query-manage { + display: flex!important; + flex-direction: row!important; + justify-content: stretch!important; + + padding: 1em!important; + + min-width: 25em!important; /* 23em to be exact */ + min-height: 20em!important; + + width: 60em; /* recommend width */ + height: 50em; + + @include user-select(none); + + .container { flex-grow: 1; + flex-shrink: 1; + + min-width: 20em; + min-height: 10em; + + display: flex; + flex-direction: row; + justify-content: stretch; + } + + .left, .right { + flex-grow: 1; + flex-shrink: 1; display: flex; flex-direction: column; justify-content: stretch; - border-radius: 0.2em; - border: 1px solid var(--modal-query-list-border); - background-color: var(--modal-query-list); - - .container-entries { - flex-shrink: 1; - flex-grow: 1; - - min-height: 5em; - - position: relative; - - overflow-x: hidden; - overflow-y: auto; - @include chat-scrollbar-vertical(); - - .container-empty, .container-error { - position: absolute; - - top: 0; - bottom: 0; - left: 0; - right: 0; - - display: flex; - flex-direction: column; - justify-content: center; - - text-align: center; - font-size: 2em; - - background-color: var(--modal-query-list); - } - - .container-empty { - color: var(--modal-query-empty); - } - - .container-error { - color: var(--modal-query-error); - } - - .entry { - display: flex; - flex-direction: row; - justify-content: flex-start; - - flex-shrink: 1; - min-width: 4em; - - padding-left: .5em; - padding-right: .5em; - - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - - cursor: pointer; - - &:hover { - background-color: var(--modal-query-entry-hover); - } - - &.selected { - background-color: var(--modal-query-entry-selected); - } - } - } - - .container-search { - flex-shrink: 0; + > .title { flex-grow: 0; - - padding: 0 .5em; - - border-top: 1px solid var(--modal-query-list-border); + flex-shrink: 0; + margin-bottom: .5em; display: flex; flex-direction: row; justify-content: stretch; + a { + font-weight: bold; + color: var(--modal-query-title); + + flex-grow: 1; + flex-shrink: 1; + + font-size: 1.05em; + min-width: 5em; + + align-self: flex-end; + line-height: normal; + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + button { flex-grow: 0; flex-shrink: 1; height: 2em; - min-width: 2em; + font-size: .9em; + + width: 10em; + min-width: 5em; align-self: center; - margin-top: .8em; - - margin-right: .5em; - - white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } - - .form-group { - flex-grow: 1; - flex-shrink: 1; - - min-width: 5em; - } } } - } - .right { - min-width: 10em; - margin-left: .4em; + .left { + margin-right: .4em; + min-width: 10em; - .container-details { - flex-grow: 1; - - display: flex; - flex-direction: column; - justify-content: stretch; - - .detail { - flex-shrink: 0; + .container-list { + flex-grow: 1; display: flex; flex-direction: column; - justify-content: flex-start; + justify-content: stretch; - margin-bottom: 1em; + border-radius: 0.2em; + border: 1px solid var(--modal-query-list-border); + background-color: var(--modal-query-list); - .title, .title a { - text-transform: uppercase; - color: var(--modal-query-key); + .container-entries { + flex-shrink: 1; + flex-grow: 1; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } + min-height: 5em; - .value { - @include user-select(text); + position: relative; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } + overflow-x: hidden; + overflow-y: auto; + @include chat-scrollbar-vertical(); - &.unique-id { - .title { + .container-empty, .container-error { + position: absolute; + + top: 0; + bottom: 0; + left: 0; + right: 0; + + display: flex; + flex-direction: column; + justify-content: center; + + text-align: center; + font-size: 2em; + + background-color: var(--modal-query-list); + } + + .container-empty { + color: var(--modal-query-empty); + } + + .container-error { + color: var(--modal-query-error); + } + + .entry { display: flex; flex-direction: row; justify-content: flex-start; - .button { - display: flex; - flex-direction: column; - justify-content: center; + flex-shrink: 1; + min-width: 4em; - width: 1.2em; - height: 1.2em; + padding-left: .5em; + padding-right: .5em; - align-self: center; - margin-left: .25em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; - cursor: pointer; - border-radius: .2em; + cursor: pointer; - &:hover { - background: var(--modal-query-copy-hover); - } + &:hover { + background-color: var(--modal-query-entry-hover); + } - margin-bottom: .2em; /* "text sub" */ - - > div { - align-self: center; - } - - @include transition($button_hover_animation_time ease-in-out); + &.selected { + background-color: var(--modal-query-entry-selected); } } } - } - .spacer { flex-grow: 1; flex-shrink: 1; min-height: 0; } + .container-search { + flex-shrink: 0; + flex-grow: 0; - .buttons { - display: flex; - flex-direction: row; - justify-content: space-between; + padding: 0 .5em; - button { - flex-shrink: 1; - min-width: 5em; + border-top: 1px solid var(--modal-query-list-border); - height: 2em; - font-size: .9em; + display: flex; + flex-direction: row; + justify-content: stretch; - width: 14em; + button { + flex-grow: 0; + flex-shrink: 1; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + height: 2em; + min-width: 2em; - &:not(:first-of-type) { - margin-left: 1em; + align-self: center; + margin-top: .8em; + + margin-right: .5em; + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .form-group { + flex-grow: 1; + flex-shrink: 1; + + min-width: 5em; } } } } - } - .container-seperator { - background: transparent; + .right { + min-width: 10em; + margin-left: .4em; + + .container-details { + flex-grow: 1; + + display: flex; + flex-direction: column; + justify-content: stretch; + + .detail { + flex-shrink: 0; + + display: flex; + flex-direction: column; + justify-content: flex-start; + + margin-bottom: 1em; + + .title, .title a { + text-transform: uppercase; + color: var(--modal-query-key); + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .value { + @include user-select(text); + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + &.unique-id { + .title { + display: flex; + flex-direction: row; + justify-content: flex-start; + + .button { + display: flex; + flex-direction: column; + justify-content: center; + + width: 1.2em; + height: 1.2em; + + align-self: center; + margin-left: .25em; + + cursor: pointer; + border-radius: .2em; + + &:hover { + background: var(--modal-query-copy-hover); + } + + margin-bottom: .2em; /* "text sub" */ + + > div { + align-self: center; + } + + @include transition($button_hover_animation_time ease-in-out); + } + } + } + } + + .spacer { flex-grow: 1; flex-shrink: 1; min-height: 0; } + + .buttons { + display: flex; + flex-direction: row; + justify-content: space-between; + + button { + flex-shrink: 1; + min-width: 5em; + + height: 2em; + font-size: .9em; + + width: 14em; + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + &:not(:first-of-type) { + margin-left: 1em; + } + } + } + } + } + + .container-seperator { + background: transparent; + } } } \ No newline at end of file diff --git a/shared/css/static/modal-server.scss b/shared/css/static/modal-server.scss index 67c67b6a..3f9e07d8 100644 --- a/shared/css/static/modal-server.scss +++ b/shared/css/static/modal-server.scss @@ -1,397 +1,33 @@ @import "mixin"; @import "properties"; -.modal-body.modal-server-edit { - display: flex!important; - flex-direction: column!important; - justify-content: stretch!important; +:global { + .modal-body.modal-server-edit { + display: flex!important; + flex-direction: column!important; + justify-content: stretch!important; - max-height: calc(100vh - 10em); - padding: 1em!important; + max-height: calc(100vh - 10em); + padding: 1em!important; - min-width: 35em!important; - width: 60em; /* recommend width */ + min-width: 35em!important; + width: 60em; /* recommend width */ - @include user-select(none); + @include user-select(none); - input, textarea, select { - width: 100%; - } - - select { - margin-left: 0; - height: 2.5em; - } - - textarea { - padding: .5em; - } - - label { - display: flex; - flex-direction: row; - justify-content: stretch; - - /* total height 2.5em */ - margin-top: .5em; - margin-bottom: .5em; - height: 1.5em; - - cursor: pointer; - - * { - align-self: center; - } - - a { - margin-left: .5em; - margin-right: .5em; - } - - .form-group { - margin: -.5em 0!important; - - padding: 0!important; - - input { - height: 1.5em!important; - } - } - } - - /* radio buttons */ - $icon_width: 1.7em; /* equal to the label height */ - - @mixin tooltip-size($lines, $line_length) { - $tooltip_height: $lines * 1.6; - $tooltip_width: $line_length + 1; - .tooltip { - top: -($tooltip_height + .6em); - left: ($icon_width - $tooltip_width) / 2; - - height: $tooltip_height * 1em; - width: $tooltip_width * 1em; - - - &:before { - left: $tooltip_width / 2 - .5em; - } - } - } - - .input-boxed { - position: relative; - - flex-grow: 1; - flex-shrink: 1; - - min-width: 4em; - - display: flex; - flex-direction: row; - justify-content: stretch; - - .container-tooltip { - flex-shrink: 0; - flex-grow: 0; - - position: relative; - width: $icon_width; - - display: flex; - flex-direction: column; - justify-content: center; - - img { - height: 1em; - width: 1em; - - align-self: center; - font-size: 1.2em; - } - - .tooltip { - /* only a container for the actual JS generated tooltip */ - display: none; - } - } - } - - .container-general { - display: flex; - flex-direction: column; - justify-content: stretch; - - flex-shrink: 0; - flex-grow: 0; - - > div:not(:first-of-type) { - flex-grow: 0; - flex-shrink: 0; - - margin-top: 1em; - } - - .container-name-icon { - flex-grow: 0; - flex-shrink: 0; - - display: flex; - flex-direction: row; - justify-content: stretch; - - .container-icon-select { - position: relative; - - height: 2.5em; - border-radius: .2em; - - margin-left: 1em; - - display: flex; - flex-direction: row; - justify-content: flex-start; - - cursor: pointer; - background-color: #121213; - border: 1px solid #0d0d0d; - - .icon-preview { - height: 100%; - width: 3em; - - border: none; - border-right: 1px solid #0d0d0d; - - display: flex; - flex-direction: column; - justify-content: space-around; - - > div { - align-self: center; - } - - @include transition(border-color $button_hover_animation_time ease-in-out); - } - - .container-dropdown { - position: relative; - cursor: pointer; - - display: flex; - flex-direction: column; - justify-content: space-around; - - height: 100%; - width: 1.5em; - - .button { - text-align: center; - - .arrow { - border-color: #999999; - } - } - - .dropdown { - display: none; - position: absolute; - width: max-content; - - top: calc(2.5em - 1px); - - flex-direction: column; - justify-content: flex-start; - - background-color: #121213; - border: 1px solid #0d0d0d; - border-radius: .2em 0 .2em .2em; - - right: -1px; - - z-index: 2; - - .entry { - padding: .5em; - - &:not(:last-of-type) { - border: none; - border-bottom: 1px solid #0d0d0d; - } - - &:hover { - background-color: #17171a; - } - } - } - - &:hover { - border-bottom-right-radius: 0; - .dropdown { - display: flex; - } - } - } - - &:hover { - background-color: #17171a; - border-color: hsla(0, 0%, 20%, 1); - - .icon-preview { - border-color: hsla(0, 0%, 20%, 1); - } - } - - @include transition(border-color $button_hover_animation_time ease-in-out); - } - } - - .container-slots { - display: flex; - flex-direction: row; - justify-content: stretch; - - > div { - width: 50%; - - &:not(:first-child) { - margin-left: 1em; - } - } - } - - .container-welcome-message { - position: relative; - - flex-grow: 1!important; - flex-shrink: 1!important; - - min-height: 5em; - max-height: 22.5em; - - border-radius: .2em; - border: 1px solid #111112; - - overflow: hidden; - - display: flex; - flex-direction: column; - justify-content: stretch; - - .toolbar { - flex-shrink: 0; - flex-grow: 0; - - display: flex; - flex-direction: row; - justify-content: flex-start; - - width: 100%; - height: 2.5em; - - background-color: #17171a; - font-size: .8em; - - padding: .25em; - - .button { - cursor: pointer; - - padding: .5em; - &:not(:first-child) { - margin-left: .25em; - } - - border-radius: .2em; - border: 1px solid #111112; - - background-color: #121213; - - height: 2em; - width: 2em; - - display: flex; - flex-direction: column; - justify-content: center; - - text-align: center; - align-self: center; - - &.button-bold { - font-weight: bold; - } - - &.button-italic { - font-style: italic; - } - - &.button-underline { - text-decoration: underline; - } - - &.button-color { - input { - position: absolute; - width: 0; - height: 0; - opacity: 0; - } - } - - &:hover { - background-color: #0f0f0f; - @include transition(background-color $button_hover_animation_time); - } - } - } - - > .input-boxed { - flex-shrink: 1; - flex-grow: 1; - - min-height: 2.5em; - height: 5em; - max-height: 20em; - - border: none; - border-radius: 0; - border-top: 1px solid #111112; - - - overflow-x: hidden;; - overflow-y: auto; - - resize: vertical; - - @include chat-scrollbar-vertical(); - } - - &:focus-within { - background-color: #131b22; - //border-color: #284262; - } - } - } - - .container-categories { - margin-top: 1em; - - display: flex; - flex-direction: column; - justify-content: stretch; - - min-height: 14em; - - border-radius: .2em; - border: 1px solid #111112; - - background-color: #17171a; - - fieldset { - padding: 0; + input, textarea, select { width: 100%; } + select { + margin-left: 0; + height: 2.5em; + } + + textarea { + padding: .5em; + } + label { display: flex; flex-direction: row; @@ -424,729 +60,1095 @@ } } - .input-boxed:not(textarea), input, select { - height: 1.7em; + /* radio buttons */ + $icon_width: 1.7em; /* equal to the label height */ + + @mixin tooltip-size($lines, $line_length) { + $tooltip_height: $lines * 1.6; + $tooltip_width: $line_length + 1; + .tooltip { + top: -($tooltip_height + .6em); + left: ($icon_width - $tooltip_width) / 2; + + height: $tooltip_height * 1em; + width: $tooltip_width * 1em; + + + &:before { + left: $tooltip_width / 2 - .5em; + } + } } - textarea { - height: 3.4em; /* double the input height */ - max-height: 17em; - min-height: 1.7em; - } + .input-boxed { + position: relative; - .categories { - height: 2.5em; + flex-grow: 1; + flex-shrink: 1; - flex-grow: 0; - flex-shrink: 0; + min-width: 4em; display: flex; flex-direction: row; justify-content: stretch; - border-bottom: 1px solid #1d1d1d; + .container-tooltip { + flex-shrink: 0; + flex-grow: 0; - .entry { - padding: .5em; + position: relative; + width: $icon_width; - text-align: center; + display: flex; + flex-direction: column; + justify-content: center; - flex-grow: 1; - flex-shrink: 1; + img { + height: 1em; + width: 1em; - cursor: pointer; - - &:hover { - color: #b6c4d6; + align-self: center; + font-size: 1.2em; } - &.selected { - border-bottom: 3px solid #245184; - margin-bottom: -1px; - - color: #245184; + .tooltip { + /* only a container for the actual JS generated tooltip */ + display: none; } - - @include transition(color $button_hover_animation_time, border-bottom-color $button_hover_animation_time); } } - .bodies { - position: relative; - - flex-shrink: 1; - flex-grow: 1; + .container-general { display: flex; + flex-direction: column; justify-content: stretch; - min-height: 10em; - height: 30em; + flex-shrink: 0; + flex-grow: 0; - .body { - position: absolute; + > div:not(:first-of-type) { + flex-grow: 0; + flex-shrink: 0; - top: 0; - left: 0; - right: 0; - bottom: 0; + margin-top: 1em; + } - padding: .5em; + .container-name-icon { + flex-grow: 0; + flex-shrink: 0; display: flex; + flex-direction: row; justify-content: stretch; - overflow: auto; /* else the tooltip will trigger the scrollbar */ - @include chat-scrollbar-vertical(); + .container-icon-select { + position: relative; - &.hidden { - display: none; - } + height: 2.5em; + border-radius: .2em; - .header { - flex-shrink: 0; - flex-grow: 0; + margin-left: 1em; - text-align: center; - color: #548abc; - } + display: flex; + flex-direction: row; + justify-content: flex-start; - .content { - flex-grow: 1; - flex-shrink: 1; - } + cursor: pointer; + background-color: #121213; + border: 1px solid #0d0d0d; - &.container-host { - flex-direction: column; + .icon-preview { + height: 100%; + width: 3em; - .container-top, .container-bottom { - flex-grow: 1; - flex-shrink: 1; - min-height: min-content; - - display: flex; - flex-direction: row; - justify-content: stretch; - } - - .container-left, .container-right { - flex-grow: 1; - flex-shrink: 1; - - min-width: 8em; - width: 50%; - } - - .container-top { - flex-direction: column; - flex-grow: 0; - - padding-bottom: .5em; - - border-bottom: 2px solid #111113; - } - - .container-bottom .container-left { - padding-top: .5em; - padding-right: .5em; - - border-right: 2px solid #111113; - } - - .container-bottom .container-right { - padding-top: .5em; - padding-left: .5em; - } - - .container-host-message { - .container-message, .container-mode { - padding-top: 1em; - - display: flex; - flex-direction: row; - justify-content: stretch; - - .container-title { - width: 8em; - flex-grow: 0; - flex-shrink: 0; - - height: 1.7em; - - display: flex; - flex-direction: row; - justify-content: flex-start; - - a { - align-self: center; - overflow: hidden; - text-overflow: ellipsis; - } - } - - textarea, select { - flex-grow: 1; - flex-shrink: 1; - } - - textarea { - resize: vertical; - } - } - } - - .container-host-banner { - .container-url, .container-gfx-url, .container-refresh, .container-resize { - margin-top: 1em; - - display: flex; - flex-direction: row; - justify-content: stretch; - - height: 1.7em; - - a { - flex-grow: 0; - flex-shrink: 0; - - align-self: center; - overflow: hidden; - text-overflow: ellipsis; - - width: 6em; - } - - &.container-refresh, &.container-resize { - a { - width: 9em; - } - } - } - - .container-gfx-preview { - margin-top: 1em; - - display: flex; - flex-direction: row; - justify-content: stretch; - - .container-title { - width: 8em; - flex-grow: 0; - flex-shrink: 0; - - height: 1.7em; - - display: flex; - flex-direction: row; - justify-content: flex-start; - - a { - align-self: center; - overflow: hidden; - text-overflow: ellipsis; - } - } - - .container-image { - flex-grow: 1; - flex-shrink: 1; - - min-width: 0; - max-height: 6em; - - display: flex; - flex-direction: column; - justify-content: center; - - > img { - flex-grow: 0; - flex-shrink: 0; - - max-height: 100%; - max-width: 100%; - - object-fit: contain; - } - } - } - } - - .container-host-button { - .container-url, .container-gfx-url, .container-tooltip-button { - margin-top: 1em; - - display: flex; - flex-direction: row; - justify-content: stretch; - - height: 1.7em; - - > a { - flex-grow: 0; - flex-shrink: 0; - - align-self: center; - overflow: hidden; - text-overflow: ellipsis; - - width: 6em; - } - } - - .container-gfx-preview { - margin-top: 1em; - - display: flex; - flex-direction: row; - justify-content: space-between; - - .container-title { - width: 8em; - flex-grow: 0; - flex-shrink: 0; - - height: 1.7em; - - display: flex; - flex-direction: row; - justify-content: flex-start; - - a { - align-self: center; - overflow: hidden; - text-overflow: ellipsis; - } - } - - .container-image { - flex-grow: 0; - flex-shrink: 0; - - height: 2em; - width: 2em; - - display: flex; - flex-direction: column; - justify-content: center; - - > img { - flex-grow: 0; - flex-shrink: 0; - - height: 100%; - width: 100%; - } - } - } - } - } - - &.container-network { - flex-direction: column; - - .container-top, .container-bottom { - flex-grow: 1; - flex-shrink: 1; - min-height: min-content; - - display: flex; - flex-direction: row; - justify-content: stretch; - } - - .container-left, .container-right { - flex-grow: 1; - flex-shrink: 1; - - min-width: 8em; - width: 50%; - } - - .container-top { - flex-direction: column; - flex-grow: 0; - - padding-bottom: .5em; - - border-bottom: 2px solid #111113; - } - - .container-bottom .container-left { - padding-top: .5em; - padding-right: .5em; - - border-right: 2px solid #111113; - } - - .container-bottom .container-right { - padding-top: .5em; - padding-left: .5em; - } - - .container-binding { - .container-host, .container-port { - padding-top: 1em; - - display: flex; - flex-direction: row; - justify-content: stretch; - - a { - align-self: center; - overflow: hidden; - text-overflow: ellipsis; - - flex-grow: 0; - flex-shrink: 0; - - width: 6em; - } - } - - .container-weblist { - padding-top: 1em; - - display: flex; - flex-direction: row; - justify-content: stretch; - } - } - - .container-download, .container-upload { - .container-bandwidth, .container-quota, .container-used-quota { - margin-top: 1em; - - display: flex; - flex-direction: row; - justify-content: stretch; - - a { - flex-grow: 0; - flex-shrink: 0; - - align-self: center; - overflow: hidden; - text-overflow: ellipsis; - - width: 12em; - - &.unit { - width: 4em; - text-align: right; - } - } - - .value { - flex-grow: 1; - flex-shrink: 1; - } - } - } - } - - &.container-security { - flex-direction: column; - - .container-top, .container-bottom { - flex-grow: 0; - flex-shrink: 0; - - min-height: min-content; + border: none; + border-right: 1px solid #0d0d0d; display: flex; flex-direction: column; - justify-content: stretch; - } + justify-content: space-around; - .container-top { - border-bottom: 2px solid #111113; - - padding-bottom: .5em; - } - - .container-bottom { - padding-top: .5em; - } - - .container-antiflood { - .container-reduce, .container-block-commands, .container-block-ip { - margin-top: 1em; - - display: flex; - flex-direction: row; - justify-content: stretch; - - height: 1.7em; - - a { - flex-grow: 0; - flex-shrink: 0; - - align-self: center; - overflow: hidden; - text-overflow: ellipsis; - - width: 17em; - } + > div { + align-self: center; } + + @include transition(border-color $button_hover_animation_time ease-in-out); } - .container-security { - .container-encryption, .container-security-level, .container-security-level-description { - margin-top: 1em; + .container-dropdown { + position: relative; + cursor: pointer; - display: flex; - flex-direction: row; - justify-content: stretch; + display: flex; + flex-direction: column; + justify-content: space-around; - height: 1.7em; + height: 100%; + width: 1.5em; - a { - flex-grow: 0; - flex-shrink: 0; + .button { + text-align: center; - align-self: center; - overflow: hidden; - text-overflow: ellipsis; - - width: 17em; - } - - &.container-refresh, &.container-resize { - a { - width: 9em; - } + .arrow { + border-color: #999999; } } - .container-description { - display: flex; + .dropdown { + display: none; + position: absolute; + width: max-content; + + top: calc(2.5em - 1px); + flex-direction: column; justify-content: flex-start; - a { - flex-grow: 0; - flex-shrink: 0; + background-color: #121213; + border: 1px solid #0d0d0d; + border-radius: .2em 0 .2em .2em; - font-size: .85em; - color: #3c3c3c; + right: -1px; - width: fit-content; - align-self: end; + z-index: 2; + + .entry { + padding: .5em; + + &:not(:last-of-type) { + border: none; + border-bottom: 1px solid #0d0d0d; + } + + &:hover { + background-color: #17171a; + } } } + + &:hover { + border-bottom-right-radius: 0; + .dropdown { + display: flex; + } + } + } + + &:hover { + background-color: #17171a; + border-color: hsla(0, 0%, 20%, 1); + + .icon-preview { + border-color: hsla(0, 0%, 20%, 1); + } + } + + @include transition(border-color $button_hover_animation_time ease-in-out); + } + } + + .container-slots { + display: flex; + flex-direction: row; + justify-content: stretch; + + > div { + width: 50%; + + &:not(:first-child) { + margin-left: 1em; + } + } + } + + .container-welcome-message { + position: relative; + + flex-grow: 1!important; + flex-shrink: 1!important; + + min-height: 5em; + max-height: 22.5em; + + border-radius: .2em; + border: 1px solid #111112; + + overflow: hidden; + + display: flex; + flex-direction: column; + justify-content: stretch; + + .toolbar { + flex-shrink: 0; + flex-grow: 0; + + display: flex; + flex-direction: row; + justify-content: flex-start; + + width: 100%; + height: 2.5em; + + background-color: #17171a; + font-size: .8em; + + padding: .25em; + + .button { + cursor: pointer; + + padding: .5em; + &:not(:first-child) { + margin-left: .25em; + } + + border-radius: .2em; + border: 1px solid #111112; + + background-color: #121213; + + height: 2em; + width: 2em; + + display: flex; + flex-direction: column; + justify-content: center; + + text-align: center; + align-self: center; + + &.button-bold { + font-weight: bold; + } + + &.button-italic { + font-style: italic; + } + + &.button-underline { + text-decoration: underline; + } + + &.button-color { + input { + position: absolute; + width: 0; + height: 0; + opacity: 0; + } + } + + &:hover { + background-color: #0f0f0f; + @include transition(background-color $button_hover_animation_time); + } } } - &.container-messages { - flex-direction: column; + > .input-boxed { + flex-shrink: 1; + flex-grow: 1; - .container-top, .container-bottom { - flex-grow: 0; + min-height: 2.5em; + height: 5em; + max-height: 20em; + + border: none; + border-radius: 0; + border-top: 1px solid #111112; + + + overflow-x: hidden;; + overflow-y: auto; + + resize: vertical; + + @include chat-scrollbar-vertical(); + } + + &:focus-within { + background-color: #131b22; + //border-color: #284262; + } + } + } + + .container-categories { + margin-top: 1em; + + display: flex; + flex-direction: column; + justify-content: stretch; + + min-height: 14em; + + border-radius: .2em; + border: 1px solid #111112; + + background-color: #17171a; + + fieldset { + padding: 0; + width: 100%; + } + + label { + display: flex; + flex-direction: row; + justify-content: stretch; + + /* total height 2.5em */ + margin-top: .5em; + margin-bottom: .5em; + height: 1.5em; + + cursor: pointer; + + * { + align-self: center; + } + + a { + margin-left: .5em; + margin-right: .5em; + } + + .form-group { + margin: -.5em 0!important; + + padding: 0!important; + + input { + height: 1.5em!important; + } + } + } + + .input-boxed:not(textarea), input, select { + height: 1.7em; + } + + textarea { + height: 3.4em; /* double the input height */ + max-height: 17em; + min-height: 1.7em; + } + + .categories { + height: 2.5em; + + flex-grow: 0; + flex-shrink: 0; + + display: flex; + flex-direction: row; + justify-content: stretch; + + border-bottom: 1px solid #1d1d1d; + + .entry { + padding: .5em; + + text-align: center; + + flex-grow: 1; + flex-shrink: 1; + + cursor: pointer; + + &:hover { + color: #b6c4d6; + } + + &.selected { + border-bottom: 3px solid #245184; + margin-bottom: -1px; + + color: #245184; + } + + @include transition(color $button_hover_animation_time, border-bottom-color $button_hover_animation_time); + } + } + + .bodies { + position: relative; + + flex-shrink: 1; + flex-grow: 1; + display: flex; + justify-content: stretch; + + min-height: 10em; + height: 30em; + + .body { + position: absolute; + + top: 0; + left: 0; + right: 0; + bottom: 0; + + padding: .5em; + + display: flex; + justify-content: stretch; + + overflow: auto; /* else the tooltip will trigger the scrollbar */ + @include chat-scrollbar-vertical(); + + &.hidden { + display: none; + } + + .header { flex-shrink: 0; + flex-grow: 0; - min-height: min-content; + text-align: center; + color: #548abc; + } - display: flex; + .content { + flex-grow: 1; + flex-shrink: 1; + } + + &.container-host { flex-direction: column; - justify-content: stretch; - } - .container-top { - border-bottom: 2px solid #111113; - - padding-bottom: .5em; - } - - .container-bottom { - padding-top: .5em; - } - - .container-channel { - .container-description, .container-topic { - padding-top: 1em; + .container-top, .container-bottom { + flex-grow: 1; + flex-shrink: 1; + min-height: min-content; display: flex; flex-direction: row; justify-content: stretch; + } - .container-title { - width: 8em; - flex-grow: 0; - flex-shrink: 0; + .container-left, .container-right { + flex-grow: 1; + flex-shrink: 1; - height: 1.7em; + min-width: 8em; + width: 50%; + } + + .container-top { + flex-direction: column; + flex-grow: 0; + + padding-bottom: .5em; + + border-bottom: 2px solid #111113; + } + + .container-bottom .container-left { + padding-top: .5em; + padding-right: .5em; + + border-right: 2px solid #111113; + } + + .container-bottom .container-right { + padding-top: .5em; + padding-left: .5em; + } + + .container-host-message { + .container-message, .container-mode { + padding-top: 1em; display: flex; flex-direction: row; - justify-content: flex-start; + justify-content: stretch; + + .container-title { + width: 8em; + flex-grow: 0; + flex-shrink: 0; + + height: 1.7em; + + display: flex; + flex-direction: row; + justify-content: flex-start; + + a { + align-self: center; + overflow: hidden; + text-overflow: ellipsis; + } + } + + textarea, select { + flex-grow: 1; + flex-shrink: 1; + } + + textarea { + resize: vertical; + } + } + } + + .container-host-banner { + .container-url, .container-gfx-url, .container-refresh, .container-resize { + margin-top: 1em; + + display: flex; + flex-direction: row; + justify-content: stretch; + + height: 1.7em; + + a { + flex-grow: 0; + flex-shrink: 0; + + align-self: center; + overflow: hidden; + text-overflow: ellipsis; + + width: 6em; + } + + &.container-refresh, &.container-resize { + a { + width: 9em; + } + } + } + + .container-gfx-preview { + margin-top: 1em; + + display: flex; + flex-direction: row; + justify-content: stretch; + + .container-title { + width: 8em; + flex-grow: 0; + flex-shrink: 0; + + height: 1.7em; + + display: flex; + flex-direction: row; + justify-content: flex-start; + + a { + align-self: center; + overflow: hidden; + text-overflow: ellipsis; + } + } + + .container-image { + flex-grow: 1; + flex-shrink: 1; + + min-width: 0; + max-height: 6em; + + display: flex; + flex-direction: column; + justify-content: center; + + > img { + flex-grow: 0; + flex-shrink: 0; + + max-height: 100%; + max-width: 100%; + + object-fit: contain; + } + } + } + } + + .container-host-button { + .container-url, .container-gfx-url, .container-tooltip-button { + margin-top: 1em; + + display: flex; + flex-direction: row; + justify-content: stretch; + + height: 1.7em; + + > a { + flex-grow: 0; + flex-shrink: 0; + + align-self: center; + overflow: hidden; + text-overflow: ellipsis; + + width: 6em; + } + } + + .container-gfx-preview { + margin-top: 1em; + + display: flex; + flex-direction: row; + justify-content: space-between; + + .container-title { + width: 8em; + flex-grow: 0; + flex-shrink: 0; + + height: 1.7em; + + display: flex; + flex-direction: row; + justify-content: flex-start; + + a { + align-self: center; + overflow: hidden; + text-overflow: ellipsis; + } + } + + .container-image { + flex-grow: 0; + flex-shrink: 0; + + height: 2em; + width: 2em; + + display: flex; + flex-direction: column; + justify-content: center; + + > img { + flex-grow: 0; + flex-shrink: 0; + + height: 100%; + width: 100%; + } + } + } + } + } + + &.container-network { + flex-direction: column; + + .container-top, .container-bottom { + flex-grow: 1; + flex-shrink: 1; + min-height: min-content; + + display: flex; + flex-direction: row; + justify-content: stretch; + } + + .container-left, .container-right { + flex-grow: 1; + flex-shrink: 1; + + min-width: 8em; + width: 50%; + } + + .container-top { + flex-direction: column; + flex-grow: 0; + + padding-bottom: .5em; + + border-bottom: 2px solid #111113; + } + + .container-bottom .container-left { + padding-top: .5em; + padding-right: .5em; + + border-right: 2px solid #111113; + } + + .container-bottom .container-right { + padding-top: .5em; + padding-left: .5em; + } + + .container-binding { + .container-host, .container-port { + padding-top: 1em; + + display: flex; + flex-direction: row; + justify-content: stretch; a { align-self: center; overflow: hidden; text-overflow: ellipsis; + + flex-grow: 0; + flex-shrink: 0; + + width: 6em; } } - textarea, select { - flex-grow: 1; - flex-shrink: 1; - } + .container-weblist { + padding-top: 1em; - textarea { - resize: vertical; + display: flex; + flex-direction: row; + justify-content: stretch; + } + } + + .container-download, .container-upload { + .container-bandwidth, .container-quota, .container-used-quota { + margin-top: 1em; + + display: flex; + flex-direction: row; + justify-content: stretch; + + a { + flex-grow: 0; + flex-shrink: 0; + + align-self: center; + overflow: hidden; + text-overflow: ellipsis; + + width: 12em; + + &.unit { + width: 4em; + text-align: right; + } + } + + .value { + flex-grow: 1; + flex-shrink: 1; + } } } } - .container-client { - .container-description { - padding-top: 1em; - - display: flex; - flex-direction: row; - justify-content: stretch; - - - a { - width: 8em; - flex-grow: 0; - flex-shrink: 0; - - align-self: center; - overflow: hidden; - text-overflow: ellipsis; - } - } - } - } - - &.container-misc { - flex-direction: column; - - .container-top, .container-bottom { - flex-grow: 1; - flex-shrink: 1; - min-height: min-content; - - display: flex; - flex-direction: row; - justify-content: stretch; - } - - .container-left, .container-right { - flex-grow: 1; - flex-shrink: 1; - - min-width: 8em; - width: 50%; - } - - .container-top { + &.container-security { flex-direction: column; - flex-grow: 0; - padding-bottom: .5em; + .container-top, .container-bottom { + flex-grow: 0; + flex-shrink: 0; - border-bottom: 2px solid #111113; - } - - .container-bottom .container-left { - padding-top: .5em; - padding-right: .5em; - - border-right: 2px solid #111113; - } - - .container-bottom .container-right { - padding-top: .5em; - padding-left: .5em; - } - - .container-default-groups { - .container-default-group { - padding-top: 1em; + min-height: min-content; display: flex; - flex-direction: row; + flex-direction: column; justify-content: stretch; + } - a { - align-self: center; - overflow: hidden; - text-overflow: ellipsis; + .container-top { + border-bottom: 2px solid #111113; - flex-grow: 0; - flex-shrink: 0; + padding-bottom: .5em; + } - width: 12em; + .container-bottom { + padding-top: .5em; + } + + .container-antiflood { + .container-reduce, .container-block-commands, .container-block-ip { + margin-top: 1em; + + display: flex; + flex-direction: row; + justify-content: stretch; + + height: 1.7em; + + a { + flex-grow: 0; + flex-shrink: 0; + + align-self: center; + overflow: hidden; + text-overflow: ellipsis; + + width: 17em; + } + } + } + + .container-security { + .container-encryption, .container-security-level, .container-security-level-description { + margin-top: 1em; + + display: flex; + flex-direction: row; + justify-content: stretch; + + height: 1.7em; + + a { + flex-grow: 0; + flex-shrink: 0; + + align-self: center; + overflow: hidden; + text-overflow: ellipsis; + + width: 17em; + } + + &.container-refresh, &.container-resize { + a { + width: 9em; + } + } } - select { - flex-grow: 1; - flex-shrink: 1; + .container-description { + display: flex; + flex-direction: column; + justify-content: flex-start; + + a { + flex-grow: 0; + flex-shrink: 0; + + font-size: .85em; + color: #3c3c3c; + + width: fit-content; + align-self: end; + } } } } - .container-complains { - .container-ban-threshold, .container-ban-time, .container-cooldown { - margin-top: 1em; + &.container-messages { + flex-direction: column; + + .container-top, .container-bottom { + flex-grow: 0; + flex-shrink: 0; + + min-height: min-content; display: flex; - flex-direction: row; + flex-direction: column; justify-content: stretch; + } - a { - flex-grow: 0; - flex-shrink: 0; + .container-top { + border-bottom: 2px solid #111113; - align-self: center; - overflow: hidden; - text-overflow: ellipsis; + padding-bottom: .5em; + } - width: 12em; + .container-bottom { + padding-top: .5em; + } + + .container-channel { + .container-description, .container-topic { + padding-top: 1em; + + display: flex; + flex-direction: row; + justify-content: stretch; + + .container-title { + width: 8em; + flex-grow: 0; + flex-shrink: 0; + + height: 1.7em; + + display: flex; + flex-direction: row; + justify-content: flex-start; + + a { + align-self: center; + overflow: hidden; + text-overflow: ellipsis; + } + } + + textarea, select { + flex-grow: 1; + flex-shrink: 1; + } + + textarea { + resize: vertical; + } + } + } + + .container-client { + .container-description { + padding-top: 1em; + + display: flex; + flex-direction: row; + justify-content: stretch; + + + a { + width: 8em; + flex-grow: 0; + flex-shrink: 0; + + align-self: center; + overflow: hidden; + text-overflow: ellipsis; + } } } } - .container-others { - .container-silence, .container-dim, .container-gfx-url { - margin-top: 1em; + &.container-misc { + flex-direction: column; + + .container-top, .container-bottom { + flex-grow: 1; + flex-shrink: 1; + min-height: min-content; display: flex; flex-direction: row; justify-content: stretch; + } - > a { - flex-grow: 0; - flex-shrink: 0; + .container-left, .container-right { + flex-grow: 1; + flex-shrink: 1; - align-self: center; - overflow: hidden; - text-overflow: ellipsis; + min-width: 8em; + width: 50%; + } - width: 12em; + .container-top { + flex-direction: column; + flex-grow: 0; + + padding-bottom: .5em; + + border-bottom: 2px solid #111113; + } + + .container-bottom .container-left { + padding-top: .5em; + padding-right: .5em; + + border-right: 2px solid #111113; + } + + .container-bottom .container-right { + padding-top: .5em; + padding-left: .5em; + } + + .container-default-groups { + .container-default-group { + padding-top: 1em; + + display: flex; + flex-direction: row; + justify-content: stretch; + + a { + align-self: center; + overflow: hidden; + text-overflow: ellipsis; + + flex-grow: 0; + flex-shrink: 0; + + width: 12em; + } + + select { + flex-grow: 1; + flex-shrink: 1; + } + } + } + + .container-complains { + .container-ban-threshold, .container-ban-time, .container-cooldown { + margin-top: 1em; + + display: flex; + flex-direction: row; + justify-content: stretch; + + a { + flex-grow: 0; + flex-shrink: 0; + + align-self: center; + overflow: hidden; + text-overflow: ellipsis; + + width: 12em; + } + } + } + + .container-others { + .container-silence, .container-dim, .container-gfx-url { + margin-top: 1em; + + display: flex; + flex-direction: row; + justify-content: stretch; + + > a { + flex-grow: 0; + flex-shrink: 0; + + align-self: center; + overflow: hidden; + text-overflow: ellipsis; + + width: 12em; + } } } } } } } - } - .container-buttons { - flex-grow: 0; - flex-shrink: 0; + .container-buttons { + flex-grow: 0; + flex-shrink: 0; - display: flex; - flex-direction: row; - justify-content: flex-end; + display: flex; + flex-direction: row; + justify-content: flex-end; - margin-top: 1em; + margin-top: 1em; - button { - margin-left: 1em; + button { + margin-left: 1em; + } } } } \ No newline at end of file diff --git a/shared/css/static/modal-serverinfo.scss b/shared/css/static/modal-serverinfo.scss index 577c6a67..da83e98b 100644 --- a/shared/css/static/modal-serverinfo.scss +++ b/shared/css/static/modal-serverinfo.scss @@ -11,253 +11,257 @@ html:root { --serverinfo-value: #d6d6d7; } -.modal-body.modal-server-info { - padding: 0!important; - width: 55em; +:global { + .modal-body.modal-server-info { + padding: 0!important; + width: 55em; - display: flex!important; - flex-direction: column!important; - justify-content: flex-start!important; + display: flex!important; + flex-direction: column!important; + justify-content: flex-start!important; - background-color: var(--serverinfo-background); + background-color: var(--serverinfo-background); - .container-tooltip { - flex-shrink: 0; - flex-grow: 0; - - position: relative; - width: 1.6em; - margin-left: .5em; - margin-right: .5em; - font-size: .9em; - - display: flex; - flex-direction: column; - justify-content: center; - - img { - height: 1em; - width: 1em; - - align-self: center; - font-size: 1.2em; - } - - .tooltip { - display: none; - } - } - - .container-top { - flex-grow: 0; - flex-shrink: 0; - - max-height: 9em; - //width: 30em; /* set a default width where we have to grow/shrink */ - - display: flex; - flex-direction: column; - justify-content: stretch; - - .container-hostbanner { - border: none; - border-radius: 0; - background-color: var(--serverinfo-hostbanner-background); - } - - &.hidden { - display: none; - } - } - - .container-body { - flex-shrink: 1; - min-height: 12em; /* 10em + 2 * 1em margin */ - - overflow-y: auto; - - @include chat-scrollbar-vertical(); - } - - .group { - flex-grow: 0; - flex-shrink: 0; - - margin: 1em; - padding: .5em; - - border-radius: .2em; - border: 1px solid var(--serverinfo-group-border); - - background-color: var(--serverinfo-group-background); - - display: flex; - flex-direction: row; - justify-content: stretch; - - height: 10em; - max-height: 10em; - - .container-image { - flex-grow: 0; + .container-tooltip { flex-shrink: 0; + flex-grow: 0; - max-width: 15em; - max-height: 9em; /* minus one padding */ + position: relative; + width: 1.6em; + margin-left: .5em; + margin-right: .5em; + font-size: .9em; display: flex; flex-direction: column; justify-content: center; img { - object-fit: contain; - max-height: 100%; - max-width: 100%; + height: 1em; + width: 1em; + + align-self: center; + font-size: 1.2em; } - margin-right: 2em; - @include transition(.25s ease-in-out); + .tooltip { + display: none; + } } - .container-properties { - flex-shrink: 1; - flex-grow: 1; + .container-top { + flex-grow: 0; + flex-shrink: 0; - min-width: 20em; + max-height: 9em; + //width: 30em; /* set a default width where we have to grow/shrink */ display: flex; flex-direction: column; - justify-content: flex-start; + justify-content: stretch; - height: inherit; + .container-hostbanner { + border: none; + border-radius: 0; + background-color: var(--serverinfo-hostbanner-background); + } - .row { + &.hidden { + display: none; + } + } + + .container-body { + flex-shrink: 1; + min-height: 12em; /* 10em + 2 * 1em margin */ + + overflow-y: auto; + + @include chat-scrollbar-vertical(); + } + + .group { + flex-grow: 0; + flex-shrink: 0; + + margin: 1em; + padding: .5em; + + border-radius: .2em; + border: 1px solid var(--serverinfo-group-border); + + background-color: var(--serverinfo-group-background); + + display: flex; + flex-direction: row; + justify-content: stretch; + + height: 10em; + max-height: 10em; + + .container-image { flex-grow: 0; flex-shrink: 0; - height: 1.8em; + max-width: 15em; + max-height: 9em; /* minus one padding */ display: flex; - flex-direction: row; - justify-content: flex-start; + flex-direction: column; + justify-content: center; - .key { - flex-shrink: 0; - flex-grow: 0; - - color: var(--serverinfo-key); - text-transform: uppercase; - align-self: center; - - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - - width: 15em; + img { + object-fit: contain; + max-height: 100%; + max-width: 100%; } - .value { - color: var(--serverinfo-value); - align-self: center; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + margin-right: 2em; + @include transition(.25s ease-in-out); + } - .country { - display: inline-block; - margin-right: .25em; + .container-properties { + flex-shrink: 1; + flex-grow: 1; + + min-width: 20em; + + display: flex; + flex-direction: column; + justify-content: flex-start; + + height: inherit; + + .row { + flex-grow: 0; + flex-shrink: 0; + + height: 1.8em; + + display: flex; + flex-direction: row; + justify-content: flex-start; + + .key { + flex-shrink: 0; + flex-grow: 0; + + color: var(--serverinfo-key); + text-transform: uppercase; + align-self: center; + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + width: 15em; } - &.server-version { - display: flex; - flex-direction: row; - justify-content: flex-start; + .value { + color: var(--serverinfo-value); + align-self: center; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; - a { - flex-shrink: 1; - min-width: 0; + .country { + display: inline-block; + margin-right: .25em; + } + + &.server-version { + display: flex; + flex-direction: row; + justify-content: flex-start; + + a { + flex-shrink: 1; + min-width: 0; + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + } + } + } + + .container-network { + display: flex; + flex-direction: row; + justify-content: center; + + .container-button { + margin-right: 1em; + + flex-shrink: 1e8; + min-width: 5em; + + display: flex; + flex-direction: column; + justify-content: flex-end; + + button { + height: 2.5em; + width: 12em; + + max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } } - } - } - .container-network { - display: flex; - flex-direction: row; - justify-content: center; - - .container-button { - margin-right: 1em; - - flex-shrink: 1e8; - min-width: 5em; - - display: flex; - flex-direction: column; - justify-content: flex-end; - - button { - height: 2.5em; - width: 12em; - - max-width: 100%; - - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + .right { + flex-grow: 1; + flex-shrink: 1; + min-width: 10em; } } + } - .right { - flex-grow: 1; - flex-shrink: 1; - min-width: 10em; + &.reverse { + flex-direction: row-reverse; + text-align: right; + + .container-image { + margin-right: 0; + margin-left: 2em; + } + + .container-properties { + .row { + flex-direction: row-reverse; + } } } } - &.reverse { - flex-direction: row-reverse; - text-align: right; + .container-buttons { + margin: 1em; - .container-image { - margin-right: 0; - margin-left: 2em; + flex-grow: 0; + flex-shrink: 0; + + display: flex; + flex-direction: row; + justify-content: space-between; + + button { + min-width: 8em; } - - .container-properties { - .row { - flex-direction: row-reverse; - } - } - } - } - - .container-buttons { - margin: 1em; - - flex-grow: 0; - flex-shrink: 0; - - display: flex; - flex-direction: row; - justify-content: space-between; - - button { - min-width: 8em; } } } @media all and (max-width: 50em) { - .modal-body.modal-server-info { - .container-image { - margin: 0!important; - max-width: 0!important; + :global { + .modal-body.modal-server-info { + .container-image { + margin: 0!important; + max-width: 0!important; + } } } } \ No newline at end of file diff --git a/shared/css/static/modal-serverinfobandwidth.scss b/shared/css/static/modal-serverinfobandwidth.scss index a8b8505e..e594a194 100644 --- a/shared/css/static/modal-serverinfobandwidth.scss +++ b/shared/css/static/modal-serverinfobandwidth.scss @@ -8,211 +8,215 @@ html:root { --serverinfo-statistics-title: #244c78; } -.modal-body.modal-server-info-bandwidth { - padding: 0!important; - width: 55em; +:global { + .modal-body.modal-server-info-bandwidth { + padding: 0!important; + width: 55em; - display: flex!important; - flex-direction: column!important; - justify-content: flex-start!important; + display: flex!important; + flex-direction: column!important; + justify-content: flex-start!important; - background-color: #2f2f35; + background-color: #2f2f35; - .container-tooltip { - flex-shrink: 0; - flex-grow: 0; - - position: relative; - width: 1.6em; - margin-left: .5em; - font-size: .9em; - - display: flex; - flex-direction: column; - justify-content: center; - - img { - height: 1em; - width: 1em; - - align-self: center; - font-size: 1.2em; - } - - .tooltip { - display: none; - } - } - - .top { - flex-grow: 0; - flex-shrink: 0; - - margin: 1em; - padding: .5em; - - display: flex; - flex-direction: row; - justify-content: stretch; - - height: 12em; - max-height: 12em; - - .container-image { - flex-grow: 0; + .container-tooltip { flex-shrink: 0; + flex-grow: 0; - max-width: 18em; - max-height: 11em; /* minus one padding */ + position: relative; + width: 1.6em; + margin-left: .5em; + font-size: .9em; display: flex; flex-direction: column; justify-content: center; img { - object-fit: contain; - max-height: 100%; - max-width: 100%; + height: 1em; + width: 1em; + + align-self: center; + font-size: 1.2em; } - margin-right: 2em; - @include transition(.25s ease-in-out); + .tooltip { + display: none; + } } - .container-stats { - flex-shrink: 1; - flex-grow: 1; + .top { + flex-grow: 0; + flex-shrink: 0; - min-width: 25em; + margin: 1em; + padding: .5em; display: flex; - flex-direction: column; - justify-content: space-evenly; + flex-direction: row; + justify-content: stretch; + + height: 12em; + max-height: 12em; + + .container-image { + flex-grow: 0; + flex-shrink: 0; + + max-width: 18em; + max-height: 11em; /* minus one padding */ - .statistic { display: flex; flex-direction: column; - justify-content: flex-start; + justify-content: center; - > a { - font-size: 1.25em; - color: var(--serverinfo-title); - line-height: normal; - - text-transform: uppercase; + img { + object-fit: contain; + max-height: 100%; + max-width: 100%; } - .values { + margin-right: 2em; + @include transition(.25s ease-in-out); + } + + .container-stats { + flex-shrink: 1; + flex-grow: 1; + + min-width: 25em; + + display: flex; + flex-direction: column; + justify-content: space-evenly; + + .statistic { display: flex; - flex-direction: row; - justify-content: space-between; + flex-direction: column; + justify-content: flex-start; > a { - font-size: 1.2em; + font-size: 1.25em; + color: var(--serverinfo-title); line-height: normal; + + text-transform: uppercase; } - .upload { - color: var(--serverinfo-bandwidth-upload); + .values { + display: flex; + flex-direction: row; + justify-content: space-between; + + > a { + font-size: 1.2em; + line-height: normal; + } + + .upload { + color: var(--serverinfo-bandwidth-upload); + } + + .download { + color: var(--serverinfo-bandwidth-download); + } } - .download { - color: var(--serverinfo-bandwidth-download); + &:not(:first-of-type) { + margin-top: 1em; } } - - &:not(:first-of-type) { - margin-top: 1em; - } } } - } - .bottom { - flex-grow: 0; - flex-shrink: 0; + .bottom { + flex-grow: 0; + flex-shrink: 0; - margin: 1em; - padding: .5em; + margin: 1em; + padding: .5em; - border-radius: .2em; - border: 1px solid #1f2122; + border-radius: .2em; + border: 1px solid #1f2122; - background-color: #28292b; + background-color: #28292b; - display: flex; - flex-direction: column; - justify-content: stretch; - - //height: 15em; - //max-height: 10em; - - .statistic { display: flex; flex-direction: column; justify-content: stretch; - .title { - flex-grow: 0; - flex-shrink: 0; - - color: var(--serverinfo-statistics-title); - font-size: 1.25em; - - text-transform: uppercase; - } - - .body { - flex-grow: 0; - flex-shrink: 0; + //height: 15em; + //max-height: 10em; + .statistic { display: flex; - flex-direction: row; + flex-direction: column; justify-content: stretch; - height: 7em; + .title { + flex-grow: 0; + flex-shrink: 0; - .container-canvas { - flex-grow: 1; - flex-shrink: 1; + color: var(--serverinfo-statistics-title); + font-size: 1.25em; - min-width: 6em; - margin-right: 1em; + text-transform: uppercase; } - .values { + .body { flex-grow: 0; flex-shrink: 0; display: flex; - flex-direction: column; - justify-content: center; + flex-direction: row; + justify-content: stretch; - width: 8em; - text-align: right; + height: 7em; - .upload { - color: var(--serverinfo-bandwidth-upload); + .container-canvas { + flex-grow: 1; + flex-shrink: 1; + + min-width: 6em; + margin-right: 1em; } - .download { - color: var(--serverinfo-bandwidth-download); + .values { + flex-grow: 0; + flex-shrink: 0; + + display: flex; + flex-direction: column; + justify-content: center; + + width: 8em; + text-align: right; + + .upload { + color: var(--serverinfo-bandwidth-upload); + } + + .download { + color: var(--serverinfo-bandwidth-download); + } } } - } - &:not(:first-of-type) { - margin-top: 1.5em; + &:not(:first-of-type) { + margin-top: 1.5em; + } } } } } @media all and (max-width: 50em) { - .modal-body.modal-server-info { - .container-image { - margin: 0!important; - max-width: 0!important; + :global { + .modal-body.modal-server-info { + .container-image { + margin: 0!important; + max-width: 0!important; + } } } } \ No newline at end of file diff --git a/shared/css/static/modal-settings.scss b/shared/css/static/modal-settings.scss index 1910db06..8d96b0c8 100644 --- a/shared/css/static/modal-settings.scss +++ b/shared/css/static/modal-settings.scss @@ -1,420 +1,215 @@ @import "properties"; @import "mixin"; -.modal-body.modal-settings { - padding: 0!important; +:global { + .modal-body.modal-settings { + padding: 0!important; - display: flex!important; - flex-direction: column!important; - justify-content: stretch!important; + display: flex!important; + flex-direction: column!important; + justify-content: stretch!important; - @include user-select(none); - width: 10000em; /* allocate some space */ + @include user-select(none); + width: 10000em; /* allocate some space */ - .inner-container { - flex-grow: 1; - flex-shrink: 1; + .inner-container { + flex-grow: 1; + flex-shrink: 1; - height: 50em; - max-height: calc(100vh - 10em); + height: 50em; + max-height: calc(100vh - 10em); - display: flex; - flex-direction: row !important; - justify-content: stretch; - - > .left, > .right { display: flex; - flex-direction: column; + flex-direction: row !important; justify-content: stretch; - padding: .5em; - - overflow: auto; - - @include chat-scrollbar-horizontal(); - @include chat-scrollbar-vertical(); - } - - .container-seperator { - height: unset !important; - background-color: #222224!important; - } - - > .left { - width: 25%; - min-width: 10em; - - height: 100%; - - justify-content: flex-start; - - background-color: #212125; - - .entry { - flex-grow: 0; - flex-shrink: 0; - - display: flex; - flex-direction: row; - justify-content: stretch; - - padding: .5em; - - border-radius: $border_radius_middle; - - color: #e0e0e0; - - &.group { - font-size: 1.3em; - text-transform: uppercase; - - color: #565656; - } - - &:not(.group) { - cursor: pointer; - - &:hover { - background-color: #2c2d2f; - } - - &.selected { - background-color: #1a1a1b; - } - } - } - } - - > .right { - width: 75%; - min-width: 12em; - - position: relative; - - background-color: #2f2f35; - - > .container { - position: absolute; - top: 0; - bottom: 0; - right: 0; - left: 0; - + > .left, > .right { display: flex; flex-direction: column; justify-content: stretch; - min-height: min-content; - min-width: 30em; + padding: .5em; - max-height: 100%; - height: 100%; + overflow: auto; @include chat-scrollbar-horizontal(); + @include chat-scrollbar-vertical(); + } - &.general-chat, &.general-application, &.audio-sounds { - label { - display: flex; - flex-direction: row; - justify-content: flex-start; + .container-seperator { + height: unset !important; + background-color: #222224!important; + } - > * { - align-self: center; + > .left { + width: 25%; + min-width: 10em; + + height: 100%; + + justify-content: flex-start; + + background-color: #212125; + + .entry { + flex-grow: 0; + flex-shrink: 0; + + display: flex; + flex-direction: row; + justify-content: stretch; + + padding: .5em; + + border-radius: $border_radius_middle; + + color: #e0e0e0; + + &.group { + font-size: 1.3em; + text-transform: uppercase; + + color: #565656; + } + + &:not(.group) { + cursor: pointer; + + &:hover { + background-color: #2c2d2f; } - a { - margin-left: .5em; + &.selected { + background-color: #1a1a1b; } } } + } - &.general-application { - > div { - margin-top: .25em; - } + > .right { + width: 75%; + min-width: 12em; - > label:not(:first-child) { - margin-top: 0.25em; - } + position: relative; - .container-font-size { - display: flex; - flex-direction: row; - justify-content: stretch; + background-color: #2f2f35; - a { - align-self: center; - margin-right: 1em; - } + > .container { + position: absolute; + top: 0; + bottom: 0; + right: 0; + left: 0; - select { - height: 1.7em; - width: 12em; - } - } - } - - &.general-language { display: flex; flex-direction: column; justify-content: stretch; - .container-selected { - flex-grow: 0; - flex-shrink: 0; + min-height: min-content; + min-width: 30em; - display: flex; - flex-direction: row; - justify-content: flex-start; + max-height: 100%; + height: 100%; - a, div { - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - } + @include chat-scrollbar-horizontal(); - a { - align-self: center; - padding-right: .75em; - } - - div { + &.general-chat, &.general-application, &.audio-sounds { + label { display: flex; flex-direction: row; justify-content: flex-start; - > .country { + > * { align-self: center; - margin-right: .3em; } - } - } - - .container-list { - flex-grow: 1; - flex-shrink: 1; - - display: flex; - flex-direction: column; - justify-content: stretch; - - min-height: 6em; - - background-color: $color_list_background; - border: 1px $color_list_border solid; - - border-radius: $border_radius_large; - - .entries { - flex-grow: 1; - flex-shrink: 1; - - display: flex; - flex-direction: column; - justify-content: flex-start; - - overflow-x: hidden; - overflow-y: auto; - - padding-top: .5em; - padding-bottom: .5em; - - @include chat-scrollbar-vertical(); - - .entry { - flex-grow: 0; - flex-shrink: 0; - - display: flex; - flex-direction: row; - justify-content: stretch; - - height: 1.5em; - - padding-left: .5em; - padding-right: .5em; - - cursor: pointer; - - &.translation { - padding-left: 1.5em; - } - - .country { - flex-grow: 0; - flex-shrink: 0; - - align-self: center; - margin-right: .25em; - margin-bottom: .1em; - } - - .name { - flex-grow: 1; - flex-shrink: 1; - - - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - } - - .button { - display: flex; - flex-direction: column; - justify-content: space-around; - - width: 1.2em; - height: 1.2em; - - cursor: pointer; - - align-self: center; - - border-radius: $border_radius_middle; - - > div { - align-self: center; - } - - &:hover { - background-color: #3c3d40; - } - - > *:not(.spacer) { - flex-grow: 0; - flex-shrink: 1; - } - - .spacer { - flex-grow: 1; - flex-shrink: 1; - - width: 0; - } - - @include transition(background-color $button_hover_animation_time); - } - - &:hover { - background-color: $color_list_hover; - } - - &.selected { - background-color: $color_list_selected; - } - } - } - - .buttons { - flex-grow: 0; - flex-shrink: 0; - - display: flex; - flex-direction: row; - justify-content: space-between; - - background-color: #242527; - - padding: .5em; - - border: none; - border-top: 1px solid #161616; - } - } - } - - &.general-chat { - .container-icon-size { - .value { - margin-left: .5em; - } - } - } - - &.audio-speaker, &.audio-sounds, &.identity-forum { - flex-direction: row; - justify-content: stretch; - - .left, .right, .fill { - flex-grow: 1; - flex-shrink: 1; - - width: calc(50% - .5em); /* the .5em for the padding/margin */ - &.fill { - width: calc(100% - 1em); - } - - display: flex; - flex-direction: column; - justify-content: stretch; - - .header { - height: 3em; - - flex-grow: 0; - flex-shrink: 0; - - display: flex; - flex-direction: row; - justify-content: stretch; - - padding-bottom: .5em; a { - flex-grow: 1; - flex-shrink: 1; - - align-self: flex-end; - - font-weight: bold; - color: #e0e0e0; - - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - .btn { - flex-shrink: 0; - flex-grow: 0; - - height: 2em; - align-self: flex-end; - - margin-left: 1em; - min-width: 8em; + margin-left: .5em; } } } - .left { - margin-right: 1em; + &.general-application { + > div { + margin-top: .25em; + } - min-height: 0; - max-height: 100%; + > label:not(:first-child) { + margin-top: 0.25em; + } - .body { + .container-font-size { + display: flex; + flex-direction: row; + justify-content: stretch; + + a { + align-self: center; + margin-right: 1em; + } + + select { + height: 1.7em; + width: 12em; + } + } + } + + &.general-language { + display: flex; + flex-direction: column; + justify-content: stretch; + + .container-selected { + flex-grow: 0; + flex-shrink: 0; + + display: flex; + flex-direction: row; + justify-content: flex-start; + + a, div { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + } + + a { + align-self: center; + padding-right: .75em; + } + + div { + display: flex; + flex-direction: row; + justify-content: flex-start; + + > .country { + align-self: center; + margin-right: .3em; + } + } + } + + .container-list { flex-grow: 1; flex-shrink: 1; - min-height: 6.5em; - display: flex; flex-direction: column; justify-content: stretch; - border: 1px $color_list_border solid; - border-radius: $border_radius_large; + min-height: 6em; background-color: $color_list_background; + border: 1px $color_list_border solid; - &.container-devices, .container-devices { + border-radius: $border_radius_large; + + .entries { flex-grow: 1; flex-shrink: 1; - min-height: 3em; - display: flex; flex-direction: column; justify-content: flex-start; @@ -422,105 +217,84 @@ overflow-x: hidden; overflow-y: auto; + padding-top: .5em; + padding-bottom: .5em; + @include chat-scrollbar-vertical(); - .device { - flex-shrink: 0; + .entry { flex-grow: 0; + flex-shrink: 0; display: flex; flex-direction: row; justify-content: stretch; + height: 1.5em; + + padding-left: .5em; + padding-right: .5em; + cursor: pointer; - height: 3em; - width: 100%; - - .container-selected { - /* the selected border */ - margin-top: 1px; - margin-bottom: 1px; - - flex-shrink: 0; - flex-grow: 0; - - padding: .5em; - - border: none; - border-right: 1px solid #242527; - - > .icon_em { - font-size: 2em; - opacity: 0; - } + &.translation { + padding-left: 1.5em; } - .container-name { - /* the selected border */ - margin-top: 1px; - margin-bottom: 1px; + .country { + flex-grow: 0; + flex-shrink: 0; - flex-shrink: 1; + align-self: center; + margin-right: .25em; + margin-bottom: .1em; + } + + .name { flex-grow: 1; + flex-shrink: 1; - min-width: 4em; - padding: .5em; - - display: flex; - flex-direction: column; - justify-content: space-around; - - border: none; - - .device-driver { - font-size: .8em; - line-height: 1em; - - color: #6a6a6a; - - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - .device-name { - line-height: 1em; - - color: #999999; - - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; } - .container-activity { - /* the selected border */ - margin-top: 1px; - margin-bottom: 1px; - - flex-shrink: 0; - flex-grow: 0; - + .button { display: flex; flex-direction: column; justify-content: space-around; - padding: .5em; + width: 1.2em; + height: 1.2em; - width: 10em; + cursor: pointer; - border: none; - border-left: 1px solid #242527; + align-self: center; - .container-activity-bar { - flex-grow: 0; - flex-shrink: 0; + border-radius: $border_radius_middle; - width: 8em; + > div { + align-self: center; } + + &:hover { + background-color: #3c3d40; + } + + > *:not(.spacer) { + flex-grow: 0; + flex-shrink: 1; + } + + .spacer { + flex-grow: 1; + flex-shrink: 1; + + width: 0; + } + + @include transition(background-color $button_hover_animation_time); } &:hover { @@ -528,24 +302,7 @@ } &.selected { - .container-selected { - > .icon_em { - opacity: 1; - } - - margin-top: 0; - margin-bottom: 0; - - border-bottom: 1px solid #242527; - border-top: 1px solid #242527; - } - .container-name, .container-activity { - margin-top: 0; - margin-bottom: 0; - - border-bottom: 1px solid #242527; - border-top: 1px solid #242527; - } + background-color: $color_list_selected; } } } @@ -554,513 +311,1879 @@ flex-grow: 0; flex-shrink: 0; - height: 3.5em; + display: flex; + flex-direction: row; + justify-content: space-between; + + background-color: #242527; + padding: .5em; + border: none; + border-top: 1px solid #161616; + } + } + } + + &.general-chat { + .container-icon-size { + .value { + margin-left: .5em; + } + } + } + + &.audio-speaker, &.audio-sounds, &.identity-forum { + flex-direction: row; + justify-content: stretch; + + .left, .right, .fill { + flex-grow: 1; + flex-shrink: 1; + + width: calc(50% - .5em); /* the .5em for the padding/margin */ + &.fill { + width: calc(100% - 1em); + } + + display: flex; + flex-direction: column; + justify-content: stretch; + + .header { + height: 3em; + + flex-grow: 0; + flex-shrink: 0; + display: flex; flex-direction: row; justify-content: stretch; - border: none; - border-top: 1px $color_list_border solid; + padding-bottom: .5em; - .spacer { + a { flex-grow: 1; flex-shrink: 1; + + align-self: flex-end; + + font-weight: bold; + color: #e0e0e0; + + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } - :not(.spacer) { - flex-grow: 0; + .btn { flex-shrink: 0; - } + flex-grow: 0; - .container-error { - color: #a10000; - align-self: center; - } + height: 2em; + align-self: flex-end; - button { + margin-left: 1em; min-width: 8em; - height: 2.5em; } } } - } - .right, .fill { - padding-right: .5em; /* for the sliders etc*/ - justify-content: flex-start; + .left { + margin-right: 1em; - .body { - flex-grow: 0; - flex-shrink: 1; + min-height: 0; + max-height: 100%; - display: flex; - flex-direction: column; + .body { + flex-grow: 1; + flex-shrink: 1; + + min-height: 6.5em; + + display: flex; + flex-direction: column; + justify-content: stretch; + + border: 1px $color_list_border solid; + border-radius: $border_radius_large; + + background-color: $color_list_background; + + &.container-devices, .container-devices { + flex-grow: 1; + flex-shrink: 1; + + min-height: 3em; + + display: flex; + flex-direction: column; + justify-content: flex-start; + + overflow-x: hidden; + overflow-y: auto; + + @include chat-scrollbar-vertical(); + + .device { + flex-shrink: 0; + flex-grow: 0; + + display: flex; + flex-direction: row; + justify-content: stretch; + + cursor: pointer; + + height: 3em; + width: 100%; + + .container-selected { + /* the selected border */ + margin-top: 1px; + margin-bottom: 1px; + + flex-shrink: 0; + flex-grow: 0; + + padding: .5em; + + border: none; + border-right: 1px solid #242527; + + > .icon_em { + font-size: 2em; + opacity: 0; + } + } + + .container-name { + /* the selected border */ + margin-top: 1px; + margin-bottom: 1px; + + flex-shrink: 1; + flex-grow: 1; + + min-width: 4em; + + padding: .5em; + + display: flex; + flex-direction: column; + justify-content: space-around; + + border: none; + + .device-driver { + font-size: .8em; + line-height: 1em; + + color: #6a6a6a; + + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .device-name { + line-height: 1em; + + color: #999999; + + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + + .container-activity { + /* the selected border */ + margin-top: 1px; + margin-bottom: 1px; + + flex-shrink: 0; + flex-grow: 0; + + display: flex; + flex-direction: column; + justify-content: space-around; + + padding: .5em; + + width: 10em; + + border: none; + border-left: 1px solid #242527; + + .container-activity-bar { + flex-grow: 0; + flex-shrink: 0; + + width: 8em; + } + } + + &:hover { + background-color: $color_list_hover; + } + + &.selected { + .container-selected { + > .icon_em { + opacity: 1; + } + + margin-top: 0; + margin-bottom: 0; + + border-bottom: 1px solid #242527; + border-top: 1px solid #242527; + } + .container-name, .container-activity { + margin-top: 0; + margin-bottom: 0; + + border-bottom: 1px solid #242527; + border-top: 1px solid #242527; + } + } + } + } + + .buttons { + flex-grow: 0; + flex-shrink: 0; + + height: 3.5em; + padding: .5em; + + display: flex; + flex-direction: row; + justify-content: stretch; + + border: none; + border-top: 1px $color_list_border solid; + + .spacer { + flex-grow: 1; + flex-shrink: 1; + } + + :not(.spacer) { + flex-grow: 0; + flex-shrink: 0; + } + + .container-error { + color: #a10000; + align-self: center; + } + + button { + min-width: 8em; + height: 2.5em; + } + } + } + } + + .right, .fill { + padding-right: .5em; /* for the sliders etc*/ justify-content: flex-start; - /* microphone */ - .container-volume { + .body { flex-grow: 0; - flex-shrink: 0; + flex-shrink: 1; display: flex; flex-direction: column; justify-content: flex-start; - height: 3em; - width: 100%; - } - - /* microphone */ - .container-select-vad { - width: 100%; - - .fieldset { - padding: 0; - margin: 0; - - flex-shrink: 1; - flex-grow: 1; + /* microphone */ + .container-volume { + flex-grow: 0; + flex-shrink: 0; display: flex; flex-direction: column; + justify-content: flex-start; + + height: 3em; + width: 100%; + } + + /* microphone */ + .container-select-vad { + width: 100%; + + .fieldset { + padding: 0; + margin: 0; + + flex-shrink: 1; + flex-grow: 1; + + display: flex; + flex-direction: column; + justify-content: stretch; + + > .container { + padding: 0; + + display: flex; + flex-direction: row; + justify-content: space-between; + + > label { + flex-shrink: 0; + min-width: 5em; + + cursor: pointer; + + display: flex; + flex-direction: row; + justify-content: flex-start; + + height: 1.7em; + + .ratio-button { + align-self: center; + margin-right: .5em; + } + + a { + align-self: center; + line-height: 1.2em; + } + } + + button { + width: 100%; + + height: 2em; + font-size: .75em; + + align-self: center; + + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + .container-button { + flex-shrink: 1; + margin-left: .5em; + + min-width: 3em; + width: 15em; + } + } + } + } + + /* microphone */ + .container-sensitivity { + width: 100%; + + display: flex; + flex-direction: row; justify-content: stretch; - > .container { - padding: 0; + .container-activity-bar { + flex-grow: 1; + flex-shrink: 1; + } + + + .container-activity-bar .thumb { + @include transition(background-color $button_hover_animation_time ease-in-out); + } + + &.disabled { + pointer-events: none; + + .container-activity-bar { + .bar-hider { + width: 100%!important; + } + + .thumb { + background-color: #4d4d4d!important; + .tooltip { + opacity: 0!important; + } + } + } + } + } + + /* microphone */ + .container-advanced { + display: flex; + flex-direction: column; + justify-content: flex-start; + + .container-ppt-delay { display: flex; flex-direction: row; justify-content: space-between; - > label { - flex-shrink: 0; - min-width: 5em; - + label { cursor: pointer; display: flex; flex-direction: row; justify-content: flex-start; - height: 1.7em; + margin-right: .5em; - .ratio-button { - align-self: center; + .checkbox { margin-right: .5em; } a { - align-self: center; line-height: 1.2em; } } - button { - width: 100%; + .container-input { + display: flex; + flex-direction: row; + justify-content: stretch; + + cursor: text; + + border-radius: $border_radius_middle; + overflow: hidden; + + width: 5em; + + height: 1.8em; + font-size: 0.75em; - height: 2em; - font-size: .75em; align-self: center; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } + color: #464646; + background-color: #17171a; - .container-button { - flex-shrink: 1; - margin-left: .5em; + input { + flex-shrink: 1; + flex-grow: 1; - min-width: 3em; - width: 15em; + min-width: 2em; + text-align: right; + + position: relative; + outline: none; + border: none; + + color: #464646; + padding: 0 .3em 0 .5em; + + background-color: transparent; + + -webkit-box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.25); + -moz-box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.25); + box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.25); + + &::-webkit-inner-spin-button, + &::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; + } + } + + label { + flex-shrink: 0; + flex-grow: 0; + + align-self: center; + } + + &.disabled { + cursor: unset; + pointer-events: none; + + background-color: #222227; + } } } } + + /* speaker */ + .container-volume-master { + .filler { + background-color: #2b8541; + } + } + + .container-volume-soundpack { + padding-top: .75em; + } + } + } + + } + + &.identity-profiles { + flex-direction: row; + justify-content: stretch; + } + + &.identity-forum { + .container-login { + flex-grow: 0; + flex-shrink: 0; + + max-width: 25em; + + .container-button { + display: flex; + flex-direction: row; + justify-content: flex-end; + + button { + min-width: 8em; + } } - /* microphone */ - .container-sensitivity { - width: 100%; + .container-error { + display: block; + margin-bottom: -1em; + color: red; + opacity: 0; + + &.shown { + opacity: 1; + } + + @include transform(opacity $button_hover_animation_time ease-in-out); + } + } + } + + &.audio-sounds { + flex-direction: row; + + min-height: 6em; + width: 100%; + + .left { + flex-shrink: 1; + flex-grow: 1; + + width: 75%; + margin-right: 1em; + + .header { + flex-shrink: 0; + flex-grow: 0; + + height: 3em; display: flex; flex-direction: row; justify-content: stretch; - .container-activity-bar { + padding-bottom: .5em; + + a { flex-grow: 1; flex-shrink: 1; + + align-self: flex-end; + + font-weight: bold; + color: #e0e0e0; + + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } + .btn { + flex-shrink: 0; + flex-grow: 0; - - .container-activity-bar .thumb { - @include transition(background-color $button_hover_animation_time ease-in-out); - } - - &.disabled { - pointer-events: none; - - .container-activity-bar { - .bar-hider { - width: 100%!important; - } - - .thumb { - background-color: #4d4d4d!important; - .tooltip { - opacity: 0!important; - } - } - } + margin-left: 1em; + min-width: 8em; } } - /* microphone */ - .container-advanced { + + .body { + flex-grow: 1; + flex-shrink: 1; + + min-height: 6em; + display: flex; flex-direction: column; - justify-content: flex-start; + justify-content: stretch; + + border: 1px $color_list_border solid; + border-radius: $border_radius_large; + + background-color: $color_list_background; + + .container-sounds { + flex-grow: 1; + flex-shrink: 1; + + min-height: 3em; - .container-ppt-delay { display: flex; - flex-direction: row; - justify-content: space-between; + flex-direction: column; + justify-content: flex-start; - label { - cursor: pointer; + overflow-x: hidden; + overflow-y: auto; - display: flex; - flex-direction: row; - justify-content: flex-start; + @include chat-scrollbar-vertical(); - margin-right: .5em; + .sound { + flex-shrink: 0; + flex-grow: 0; - .checkbox { - margin-right: .5em; - } - - a { - line-height: 1.2em; - } - } - - .container-input { display: flex; flex-direction: row; justify-content: stretch; - cursor: text; + cursor: pointer; - border-radius: $border_radius_middle; - overflow: hidden; + width: 100%; - width: 5em; + padding-left: .5em; + padding-right: 1em; - height: 1.8em; - font-size: 0.75em; + font-size: .9em; + .container-button-play_pause { + /* the selected border */ + margin-top: 1px; + margin-bottom: 1px; - align-self: center; - - color: #464646; - background-color: #17171a; - - input { - flex-shrink: 1; - flex-grow: 1; - - min-width: 2em; - text-align: right; - - position: relative; - outline: none; - border: none; - - color: #464646; - padding: 0 .3em 0 .5em; - - background-color: transparent; - - -webkit-box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.25); - -moz-box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.25); - box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.25); - - &::-webkit-inner-spin-button, - &::-webkit-outer-spin-button { - -webkit-appearance: none; - margin: 0; - } - } - - label { flex-shrink: 0; flex-grow: 0; + display: flex; + flex-direction: column; + justify-content: space-around; + align-self: center; + margin-right: .25em; + + padding: .25em; + + border: none; + + /* copy checkmark */ + position: relative; + + width: 1.3em; + height: 1.3em; + + cursor: pointer; + pointer-events: all; + + overflow: hidden; + + background-color: #272626; + border-radius: $border_radius_middle; + + -webkit-box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); + -moz-box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); + box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); + + img { + height: 100%; + width: 100%; + + align-self: center; + } } - &.disabled { - cursor: unset; - pointer-events: none; + .container-name { + /* the selected border */ + margin-top: 1px; + margin-bottom: 1px; - background-color: #222227; + flex-shrink: 1; + flex-grow: 1; + + min-width: 4em; + + padding: .25em; + line-height: 1.2em; + + display: flex; + flex-direction: row; + justify-content: flex-start; + + border: none; + text-align: right; + } + + .container-button-toggle { + font-size: .8em; + } + + &:hover { + background-color: $color_list_hover; + } + + label { + display: flex; + flex-direction: column; + justify-content: space-around; } } } - } - /* speaker */ - .container-volume-master { - .filler { - background-color: #2b8541; + .container-filter { + border: none; + border-top: 1px $color_list_border solid; + + padding-right: 1em; + padding-left: 1em; } } + } - .container-volume-soundpack { - padding-top: .75em; - } + .right { + flex-grow: 0; + flex-shrink: 1; + + width: 25%; } } + &.hidden { + display: none; + } + } + } + } + } + + /* the microphone stuff */ + .container-settings-audio-microphone { + display: flex; + flex-direction: row; + justify-content: stretch; + flex-shrink: 1; + flex-grow: 1; + + min-width: 43em; + min-height: 41em; + + position: relative; + + .left, .right { + flex-grow: 1; + flex-shrink: 1; + + width: calc(50% - .5em); /* the .5em for the padding/margin */ + + display: flex; + flex-direction: column; + justify-content: stretch; + + .header { + height: 3em; + + flex-grow: 0; + flex-shrink: 0; + + display: flex; + flex-direction: row; + justify-content: stretch; + + padding-bottom: .5em; + + a { + flex-grow: 1; + flex-shrink: 1; + + align-self: flex-end; + + font-weight: bold; + color: #e0e0e0; + + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } - &.identity-profiles { - flex-direction: row; - justify-content: stretch; - } + .btn { + flex-shrink: 0; + flex-grow: 0; - &.identity-forum { - .container-login { - flex-grow: 0; + height: 2em; + align-self: flex-end; + + margin-left: 1em; + min-width: 8em; + } + } + } + + .container-activity-bar { + $bar_height: 1em; + + $thumb_width: .6em; + $thumb_height: 2em; + + position: relative; + align-self: center; + + display: flex; + flex-direction: column; + justify-content: space-around; + + height: $bar_height; + border-radius: $border_radius_large; + + cursor: pointer; + + .bar-hider { + position: absolute; + + top: 0; + right: 0; + bottom: 0; + + background-color: #242527; + + -webkit-box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.75); + -moz-box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.75); + box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.75); + + border-bottom-right-radius: $border_radius_large; + border-top-right-radius: $border_radius_large; + } + + &[value] { + overflow: visible; /* for the thumb */ + + border-bottom-left-radius: $border_radius_large; + border-top-left-radius: $border_radius_large; + } + + .bar-error { + z-index: 2; + width: 100%; + text-align: center; + + line-height: 1em; + font-size: .8em; + color: #a10000; + + padding-left: .2em; + padding-right: .2em; + + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .thumb { + position: absolute; + + top: 0; + right: 0; + + height: $thumb_height; + width: $thumb_width; + + margin-left: -($thumb_width / 2); + margin-right: -($thumb_width / 2); + + margin-top: -($thumb_height - $bar_height) / 2; + margin-bottom: -($thumb_height - $bar_height) / 2; + + background-color: #808080; + + .tooltip { + display: none; + } + } + + -webkit-box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.25); + -moz-box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.25); + box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.25); + + /* Permalink - use to edit and share this gradient: https://colorzilla.com/gradient-editor/#70407e+0,45407e+100 */ + background: rgb(112,64,126); /* Old browsers */ + background: -moz-linear-gradient(left, rgba(112,64,126,1) 0%, rgba(69,64,126,1) 100%); /* FF3.6-15 */ + background: -webkit-linear-gradient(left, rgba(112,64,126,1) 0%,rgba(69,64,126,1) 100%); /* Chrome10-25,Safari5.1-6 */ + background: linear-gradient(to right, rgba(112,64,126,1) 0%,rgba(69,64,126,1) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#70407e', endColorstr='#45407e',GradientType=1 ); /* IE6-9 */ + } + + .left { + margin-right: 1em; + + min-height: 0; + max-height: 100%; + + .body { + flex-grow: 1; + flex-shrink: 1; + + min-height: 6.5em; + + display: flex; + flex-direction: column; + justify-content: stretch; + + border: 1px $color_list_border solid; + border-radius: $border_radius_large; + + background-color: $color_list_background; + + &.container-devices, .container-devices { + flex-grow: 1; + flex-shrink: 1; + + min-height: 3em; + position: relative; + + display: flex; + flex-direction: column; + justify-content: flex-start; + + overflow-x: hidden; + overflow-y: auto; + + @include chat-scrollbar-vertical(); + + .device { flex-shrink: 0; + flex-grow: 0; - max-width: 25em; + display: flex; + flex-direction: row; + justify-content: stretch; - .container-button { - display: flex; - flex-direction: row; - justify-content: flex-end; + cursor: pointer; - button { - min-width: 8em; - } - } + height: 3em; + width: 100%; - .container-error { - display: block; - margin-bottom: -1em; - color: red; - opacity: 0; + .container-selected { + /* the selected border */ + margin-top: 1px; + margin-bottom: 1px; - &.shown { - opacity: 1; - } - - @include transform(opacity $button_hover_animation_time ease-in-out); - } - } - } - - &.audio-sounds { - flex-direction: row; - - min-height: 6em; - width: 100%; - - .left { - flex-shrink: 1; - flex-grow: 1; - - width: 75%; - margin-right: 1em; - - .header { flex-shrink: 0; flex-grow: 0; - height: 3em; + width: 3em; + position: relative; + + border: none; + border-right: 1px solid #242527; + + > * { + padding: .5em; + position: absolute; + + top: 0; + left: 0; + right: 0; + bottom: 0; + + margin: auto; + } + + > .icon_em { + font-size: 2em; + opacity: 0; + } + + > .icon-loading { + opacity: 0; + + img { + max-height: 100%; + max-width: 100%; + + -webkit-animation:spin 4s linear infinite; + -moz-animation:spin 4s linear infinite; + animation:spin 4s linear infinite; + } + } + } + + .container-name { + /* the selected border */ + margin-top: 1px; + margin-bottom: 1px; + + flex-shrink: 1; + flex-grow: 1; + + min-width: 4em; + + padding: .5em; display: flex; - flex-direction: row; - justify-content: stretch; + flex-direction: column; + justify-content: space-around; - padding-bottom: .5em; + border: none; - a { - flex-grow: 1; - flex-shrink: 1; + .device-driver { + font-size: .8em; + line-height: 1em; - align-self: flex-end; - - font-weight: bold; - color: #e0e0e0; + color: #6a6a6a; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } - .btn { - flex-shrink: 0; - flex-grow: 0; + .device-name { + line-height: 1em; - margin-left: 1em; - min-width: 8em; + color: #999999; + + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } } + .container-activity { + /* the selected border */ + margin-top: 1px; + margin-bottom: 1px; - .body { - flex-grow: 1; - flex-shrink: 1; - - min-height: 6em; + flex-shrink: 0; + flex-grow: 0; display: flex; flex-direction: column; - justify-content: stretch; + justify-content: space-around; - border: 1px $color_list_border solid; - border-radius: $border_radius_large; + padding: .5em; - background-color: $color_list_background; + width: 10em; - .container-sounds { - flex-grow: 1; - flex-shrink: 1; + border: none; + border-left: 1px solid #242527; - min-height: 3em; + .container-activity-bar { + flex-grow: 0; + flex-shrink: 0; - display: flex; - flex-direction: column; - justify-content: flex-start; - - overflow-x: hidden; - overflow-y: auto; - - @include chat-scrollbar-vertical(); - - .sound { - flex-shrink: 0; - flex-grow: 0; - - display: flex; - flex-direction: row; - justify-content: stretch; - - cursor: pointer; - - width: 100%; - - padding-left: .5em; - padding-right: 1em; - - font-size: .9em; - - .container-button-play_pause { - /* the selected border */ - margin-top: 1px; - margin-bottom: 1px; - - flex-shrink: 0; - flex-grow: 0; - - display: flex; - flex-direction: column; - justify-content: space-around; - - align-self: center; - margin-right: .25em; - - padding: .25em; - - border: none; - - /* copy checkmark */ - position: relative; - - width: 1.3em; - height: 1.3em; - - cursor: pointer; - pointer-events: all; - - overflow: hidden; - - background-color: #272626; - border-radius: $border_radius_middle; - - -webkit-box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); - -moz-box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); - box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); - - img { - height: 100%; - width: 100%; - - align-self: center; - } - } - - .container-name { - /* the selected border */ - margin-top: 1px; - margin-bottom: 1px; - - flex-shrink: 1; - flex-grow: 1; - - min-width: 4em; - - padding: .25em; - line-height: 1.2em; - - display: flex; - flex-direction: row; - justify-content: flex-start; - - border: none; - text-align: right; - } - - .container-button-toggle { - font-size: .8em; - } - - &:hover { - background-color: $color_list_hover; - } - - label { - display: flex; - flex-direction: column; - justify-content: space-around; - } - } + width: 8em; } + } - .container-filter { - border: none; - border-top: 1px $color_list_border solid; + &:hover { + background-color: $color_list_hover; + } - padding-right: 1em; - padding-left: 1em; + &.selected { + .container-selected { + > .icon_em { + opacity: 1; + } + + margin-top: 0; + margin-bottom: 0; + + border-bottom: 1px solid #242527; + border-top: 1px solid #242527; + } + .container-name, .container-activity { + margin-top: 0; + margin-bottom: 0; + + border-bottom: 1px solid #242527; + border-top: 1px solid #242527; + } + } + + &.loading { + .container-selected { + .icon-loading { + opacity: 1; + } } } } - .right { - flex-grow: 0; - flex-shrink: 1; + .overlay { + position: absolute; - width: 25%; + top: 0; + left: 0; + right: 0; + bottom: 0; + + display: flex; + flex-direction: column; + justify-content: center; + + background-color: #28292b; + + a { + font-size: 1.75em; + align-self: center; + color: #9e9494; + } } } - &.hidden { + .buttons { + flex-grow: 0; + flex-shrink: 0; + + height: 3.5em; + padding: .5em; + + display: flex; + flex-direction: row; + justify-content: stretch; + + border: none; + border-top: 1px $color_list_border solid; + + .spacer { + flex-grow: 1; + flex-shrink: 1; + } + + :not(.spacer) { + flex-grow: 0; + flex-shrink: 0; + } + + .container-error { + color: #a10000; + align-self: center; + } + + button { + min-width: 8em; + height: 2.5em; + } + } + } + } + + .right { + padding-right: .5em; /* for the sliders etc*/ + justify-content: flex-start; + + .body { + flex-grow: 0; + flex-shrink: 1; + + display: flex; + flex-direction: column; + justify-content: flex-start; + + /* microphone */ + .container-volume { + flex-grow: 0; + flex-shrink: 0; + + display: flex; + flex-direction: column; + justify-content: flex-start; + + height: 3em; + width: 100%; + } + + /* microphone */ + .container-select-vad { + width: 100%; + + .fieldset { + padding: 0; + margin: 0; + + flex-shrink: 1; + flex-grow: 1; + + display: flex; + flex-direction: column; + justify-content: stretch; + + > .container { + padding: 0; + + display: flex; + flex-direction: row; + justify-content: space-between; + + > label { + flex-shrink: 0; + min-width: 5em; + + cursor: pointer; + + display: flex; + flex-direction: row; + justify-content: flex-start; + + height: 1.7em; + + .ratio-button { + align-self: center; + margin-right: .5em; + } + + a { + align-self: center; + line-height: 1.2em; + } + } + + button { + width: 100%; + + height: 2em; + font-size: .75em; + + align-self: center; + + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + .container-button { + flex-shrink: 1; + margin-left: .5em; + + min-width: 3em; + width: 15em; + } + } + } + } + + /* microphone */ + .container-sensitivity { + width: 100%; + + display: flex; + flex-direction: row; + justify-content: stretch; + + .container-activity-bar { + flex-grow: 1; + flex-shrink: 1; + } + + + + .container-activity-bar .thumb { + @include transition(background-color $button_hover_animation_time ease-in-out); + } + + &.disabled { + pointer-events: none; + + .container-activity-bar { + .bar-hider { + width: 100%!important; + } + + .thumb { + background-color: #4d4d4d!important; + .tooltip { + opacity: 0!important; + } + } + } + } + } + + /* microphone */ + .container-advanced { + display: flex; + flex-direction: column; + justify-content: flex-start; + + .container-ppt-delay { + display: flex; + flex-direction: row; + justify-content: space-between; + + label { + cursor: pointer; + + display: flex; + flex-direction: row; + justify-content: flex-start; + + margin-right: .5em; + + .checkbox { + margin-right: .5em; + } + + a { + line-height: 1.2em; + } + } + + .container-input { + display: flex; + flex-direction: row; + justify-content: stretch; + + cursor: text; + + border-radius: $border_radius_middle; + overflow: hidden; + + width: 5em; + + height: 1.8em; + font-size: 0.75em; + + + align-self: center; + + color: #464646; + background-color: #17171a; + + input { + flex-shrink: 1; + flex-grow: 1; + + min-width: 2em; + text-align: right; + + position: relative; + outline: none; + border: none; + + color: #464646; + padding: 0 .3em 0 .5em; + + background-color: transparent; + + -webkit-box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.25); + -moz-box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.25); + box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.25); + + &::-webkit-inner-spin-button, + &::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; + } + } + + label { + flex-shrink: 0; + flex-grow: 0; + + align-self: center; + } + + &.disabled { + cursor: unset; + pointer-events: none; + + background-color: #222227; + } + } + } + } + + /* speaker */ + .container-volume-master { + .filler { + background-color: #2b8541; + } + } + + .container-volume-soundpack { + padding-top: .75em; + } + } + } + } + + /* the profile stuff */ + .container-settings-identity-profile { + display: flex; + flex-direction: row; + justify-content: stretch; + flex-shrink: 1; + flex-grow: 1; + + min-width: 43em; + min-height: 41em; + + position: relative; + + .left, .right { + flex-grow: 1; + flex-shrink: 1; + + width: 50%; + min-width: 25em; + min-height: min-content; + + display: flex; + flex-direction: column; + justify-content: stretch; + + position: relative; + + .header { + height: 3em; + + display: flex; + flex-direction: row; + justify-content: stretch; + + padding-bottom: .5em; + + a { + flex-grow: 1; + flex-shrink: 1; + + align-self: flex-end; + + font-weight: bold; + color: #e0e0e0; + + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .btn { + flex-shrink: 0; + flex-grow: 0; + + margin-left: 1em; + min-width: 8em; + } + } + + button { + height: 2.2em; + align-self: flex-end; + } + } + + .left { + margin-right: 1em; + min-width: 15em; + + .body { + flex-grow: 1; + flex-shrink: 1; + + display: flex; + flex-direction: column; + justify-content: stretch; + + border: 1px $color_list_border solid; + border-radius: $border_radius_large; + + background-color: $color_list_background; + + .container-profiles { + flex-grow: 1; + flex-shrink: 1; + + min-height: 3em; + + display: flex; + flex-direction: column; + justify-content: flex-start; + + position: relative; + + overflow-x: hidden; + overflow-y: auto; + + @include chat-scrollbar-vertical(); + + .overlay { + position: absolute; + background-color: #28292b; + + top: 0; + right: 0; + left: 0; + bottom: 0; + + z-index: 1; + display: flex; + flex-direction: column; + justify-content: center; + + a { + align-self: center; + font-size: 1.25em; + } + + a.error { + align-self: center; + font-size: 1.75em; + + color: hsla(0, 5%, 60%, 1); + } + + button { + flex-grow: 0; + width: 8em; + align-self: center; + } + } + + .profile { + flex-shrink: 0; + flex-grow: 0; + + display: flex; + flex-direction: row; + justify-content: stretch; + + cursor: pointer; + + height: 3em; + width: 100%; + + .container-avatar { + flex-shrink: 0; + flex-grow: 0; + + height: 3em; + width: 3em; + } + + .container-info { + flex-shrink: 1; + flex-grow: 1; + + margin-left: .5em; + min-width: 4em; + + display: flex; + flex-direction: column; + justify-content: center; + + .container-type { + width: 100%; + + display: flex; + flex-direction: row; + justify-content: flex-start; + + text-transform: uppercase; + font-weight: bold; + + font-size: 0.8em; + + line-height: 1em; + + color: #6a6a6a; + + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + > *:not(:first-of-type) { + margin-left: .25em; + } + .icon-status { + margin-bottom: .2em; /* push it a bit higher than the center */ + } + + div { + align-self: center; + } + } + + .profile-name { + line-height: 1.2em; + + color: #999999; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + + &:hover { + background-color: $color_list_hover; + } + + &.selected { + background-color: $color_list_selected; + } + } + } + + .buttons, .buttons-small { + flex-grow: 0; + flex-shrink: 0; + + height: 3.5em; + padding: .5em; + + display: flex; + flex-direction: row; + justify-content: stretch; + + border: none; + border-top: 1px $color_list_border solid; + + .spacer { + flex-grow: 1; + flex-shrink: 1000000000; + } + + .container-error { + color: #a10000; + align-self: center; + } + + button { + flex-shrink: 1; + min-width: 2em; + + @include text-dotdotdot(); + + &:not(:last-of-type) { + margin-right: .5em; + } + } + } + + .buttons { + display: none; + } + } + } + + .right { + padding-right: .5em; /* for the sliders etc*/ + justify-content: flex-start; + + .body { + flex-grow: 1; + flex-shrink: 1; + + display: flex; + flex-direction: column; + justify-content: stretch; + + > div { + flex-shrink: 0; + } + + .container-teamspeak { + .container-invalid { + padding: 1em; + text-align: center; + } + .container-valid { + .container-level { + display: flex; + flex-direction: row; + justify-content: stretch; + + .form-group { + flex-grow: 1; + flex-shrink: 1; + min-width: 4em; + } + + button { + height: 2em; + + align-self: center; + margin-left: 1em; + } + } + } + + .buttons { + display: flex; + flex-direction: row; + justify-content: space-between; + + > div { + text-align: right; + + width: max-content; + margin-left: 1em; + } + + button { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + text-align: end; + + margin-top: 1em; + } + } + } + + .container-teaforo { + .container-valid, .container-invalid { + padding: 1em; + text-align: center; + + button { + margin-top: .5em; + } + } + } + + .container-highlight-dummy { + margin-top: 1em; + margin-bottom: .5em; + + display: none; + flex-grow: 1; + } + } + } + } + + /* the highlight stuff for the newcommer modal */ + .container-settings-identity-profile, .container-settings-audio-microphone { + $highlight-time: .5s; + $backdrop-color: rgba(0, 0, 0, .9); + .help-background { + position: absolute; + + top: 0; + left: 0; + right: 0; + bottom: 0; + + display: none; + background-color: $backdrop-color; + border-radius: .15em; + + padding: .5em; + } + + .container-help-text { + position: absolute; + + top: 1em; + left: 1em; + right: 1em; + bottom: 1em; + + display: none; + z-index: 20; + + a { + display: block; + } + } + + &.help-shown { + .help-background { + display: flex; + z-index: 1; + + opacity: 1; + } + + .highlightable { + border-radius: .1em; + position: relative; + z-index: 10; + + background: #19191b; + + @include transition($highlight-time ease-in-out); + + &::after { + content: ' '; + + z-index: 5; + position: absolute; + + top: 0; + left: 0; + right: 0; + bottom: 0; + + background-color: $backdrop-color; + + @include transition($highlight-time ease-in-out); + } + + &.highlighted { + padding: .5em; + + &::after { + background-color: #00000000; + } + } + } + + .container-help-text { + display: block; + + overflow: auto; + @include chat-scrollbar(); + @include transition($highlight-time ease-in-out); + + .help-microphone-settings { + ol { + margin-top: .5em; + margin-bottom: 0; + } + + li { + margin-bottom: .5em; + + .title { + font-weight: bold; + } + } + } + } + + .container-teamspeak, .container-teaforo, .container-nickname { + display: none; + } + + .container-highlight-dummy { + display: flex!important; + } + + &.hide-help { + .help-background { + @include transition($highlight-time ease-in-out); + + opacity: 0; + } + + .highlightable::after { + background-color: #00000000; + } + + .container-help-text { display: none; } } @@ -1068,1135 +2191,16 @@ } } -/* the microphone stuff */ -.container-settings-audio-microphone { - display: flex; - flex-direction: row; - justify-content: stretch; - flex-shrink: 1; - flex-grow: 1; - - min-width: 43em; - min-height: 41em; - - position: relative; - - .left, .right { - flex-grow: 1; - flex-shrink: 1; - - width: calc(50% - .5em); /* the .5em for the padding/margin */ - - display: flex; - flex-direction: column; - justify-content: stretch; - - .header { - height: 3em; - - flex-grow: 0; - flex-shrink: 0; - - display: flex; - flex-direction: row; - justify-content: stretch; - - padding-bottom: .5em; - - a { - flex-grow: 1; - flex-shrink: 1; - - align-self: flex-end; - - font-weight: bold; - color: #e0e0e0; - - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - .btn { - flex-shrink: 0; - flex-grow: 0; - - height: 2em; - align-self: flex-end; - - margin-left: 1em; - min-width: 8em; - } - } - } - - .container-activity-bar { - $bar_height: 1em; - - $thumb_width: .6em; - $thumb_height: 2em; - - position: relative; - align-self: center; - - display: flex; - flex-direction: column; - justify-content: space-around; - - height: $bar_height; - border-radius: $border_radius_large; - - cursor: pointer; - - .bar-hider { - position: absolute; - - top: 0; - right: 0; - bottom: 0; - - background-color: #242527; - - -webkit-box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.75); - -moz-box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.75); - box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.75); - - border-bottom-right-radius: $border_radius_large; - border-top-right-radius: $border_radius_large; - } - - &[value] { - overflow: visible; /* for the thumb */ - - border-bottom-left-radius: $border_radius_large; - border-top-left-radius: $border_radius_large; - } - - .bar-error { - z-index: 2; - width: 100%; - text-align: center; - - line-height: 1em; - font-size: .8em; - color: #a10000; - - padding-left: .2em; - padding-right: .2em; - - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - .thumb { - position: absolute; - - top: 0; - right: 0; - - height: $thumb_height; - width: $thumb_width; - - margin-left: -($thumb_width / 2); - margin-right: -($thumb_width / 2); - - margin-top: -($thumb_height - $bar_height) / 2; - margin-bottom: -($thumb_height - $bar_height) / 2; - - background-color: #808080; - - .tooltip { - display: none; - } - } - - -webkit-box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.25); - -moz-box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.25); - box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.25); - - /* Permalink - use to edit and share this gradient: https://colorzilla.com/gradient-editor/#70407e+0,45407e+100 */ - background: rgb(112,64,126); /* Old browsers */ - background: -moz-linear-gradient(left, rgba(112,64,126,1) 0%, rgba(69,64,126,1) 100%); /* FF3.6-15 */ - background: -webkit-linear-gradient(left, rgba(112,64,126,1) 0%,rgba(69,64,126,1) 100%); /* Chrome10-25,Safari5.1-6 */ - background: linear-gradient(to right, rgba(112,64,126,1) 0%,rgba(69,64,126,1) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#70407e', endColorstr='#45407e',GradientType=1 ); /* IE6-9 */ - } - - .left { - margin-right: 1em; - - min-height: 0; - max-height: 100%; - - .body { - flex-grow: 1; - flex-shrink: 1; - - min-height: 6.5em; - - display: flex; - flex-direction: column; - justify-content: stretch; - - border: 1px $color_list_border solid; - border-radius: $border_radius_large; - - background-color: $color_list_background; - - &.container-devices, .container-devices { - flex-grow: 1; - flex-shrink: 1; - - min-height: 3em; - position: relative; - - display: flex; - flex-direction: column; - justify-content: flex-start; - - overflow-x: hidden; - overflow-y: auto; - - @include chat-scrollbar-vertical(); - - .device { - flex-shrink: 0; - flex-grow: 0; - - display: flex; - flex-direction: row; - justify-content: stretch; - - cursor: pointer; - - height: 3em; - width: 100%; - - .container-selected { - /* the selected border */ - margin-top: 1px; - margin-bottom: 1px; - - flex-shrink: 0; - flex-grow: 0; - - width: 3em; - position: relative; - - border: none; - border-right: 1px solid #242527; - - > * { - padding: .5em; - position: absolute; - - top: 0; - left: 0; - right: 0; - bottom: 0; - - margin: auto; - } - - > .icon_em { - font-size: 2em; - opacity: 0; - } - - > .icon-loading { - opacity: 0; - - img { - max-height: 100%; - max-width: 100%; - - -webkit-animation:spin 4s linear infinite; - -moz-animation:spin 4s linear infinite; - animation:spin 4s linear infinite; - } - } - } - - .container-name { - /* the selected border */ - margin-top: 1px; - margin-bottom: 1px; - - flex-shrink: 1; - flex-grow: 1; - - min-width: 4em; - - padding: .5em; - - display: flex; - flex-direction: column; - justify-content: space-around; - - border: none; - - .device-driver { - font-size: .8em; - line-height: 1em; - - color: #6a6a6a; - - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - .device-name { - line-height: 1em; - - color: #999999; - - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - } - - .container-activity { - /* the selected border */ - margin-top: 1px; - margin-bottom: 1px; - - flex-shrink: 0; - flex-grow: 0; - - display: flex; - flex-direction: column; - justify-content: space-around; - - padding: .5em; - - width: 10em; - - border: none; - border-left: 1px solid #242527; - - .container-activity-bar { - flex-grow: 0; - flex-shrink: 0; - - width: 8em; - } - } - - &:hover { - background-color: $color_list_hover; - } - - &.selected { - .container-selected { - > .icon_em { - opacity: 1; - } - - margin-top: 0; - margin-bottom: 0; - - border-bottom: 1px solid #242527; - border-top: 1px solid #242527; - } - .container-name, .container-activity { - margin-top: 0; - margin-bottom: 0; - - border-bottom: 1px solid #242527; - border-top: 1px solid #242527; - } - } - - &.loading { - .container-selected { - .icon-loading { - opacity: 1; - } - } - } - } - - .overlay { - position: absolute; - - top: 0; - left: 0; - right: 0; - bottom: 0; - - display: flex; - flex-direction: column; - justify-content: center; - - background-color: #28292b; - - a { - font-size: 1.75em; - align-self: center; - color: #9e9494; - } - } - } - - .buttons { - flex-grow: 0; - flex-shrink: 0; - - height: 3.5em; - padding: .5em; - - display: flex; - flex-direction: row; - justify-content: stretch; - - border: none; - border-top: 1px $color_list_border solid; - - .spacer { - flex-grow: 1; - flex-shrink: 1; - } - - :not(.spacer) { - flex-grow: 0; - flex-shrink: 0; - } - - .container-error { - color: #a10000; - align-self: center; - } - - button { - min-width: 8em; - height: 2.5em; - } - } - } - } - - .right { - padding-right: .5em; /* for the sliders etc*/ - justify-content: flex-start; - - .body { - flex-grow: 0; - flex-shrink: 1; - - display: flex; - flex-direction: column; - justify-content: flex-start; - - /* microphone */ - .container-volume { - flex-grow: 0; - flex-shrink: 0; - - display: flex; - flex-direction: column; - justify-content: flex-start; - - height: 3em; - width: 100%; - } - - /* microphone */ - .container-select-vad { - width: 100%; - - .fieldset { - padding: 0; - margin: 0; - - flex-shrink: 1; - flex-grow: 1; - - display: flex; - flex-direction: column; - justify-content: stretch; - - > .container { - padding: 0; - - display: flex; - flex-direction: row; - justify-content: space-between; - - > label { - flex-shrink: 0; - min-width: 5em; - - cursor: pointer; - - display: flex; - flex-direction: row; - justify-content: flex-start; - - height: 1.7em; - - .ratio-button { - align-self: center; - margin-right: .5em; - } - - a { - align-self: center; - line-height: 1.2em; - } - } - - button { - width: 100%; - - height: 2em; - font-size: .75em; - - align-self: center; - - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - - .container-button { - flex-shrink: 1; - margin-left: .5em; - - min-width: 3em; - width: 15em; - } - } - } - } - - /* microphone */ - .container-sensitivity { - width: 100%; - - display: flex; - flex-direction: row; - justify-content: stretch; - - .container-activity-bar { - flex-grow: 1; - flex-shrink: 1; - } - - - - .container-activity-bar .thumb { - @include transition(background-color $button_hover_animation_time ease-in-out); - } - - &.disabled { - pointer-events: none; - - .container-activity-bar { - .bar-hider { - width: 100%!important; - } - - .thumb { - background-color: #4d4d4d!important; - .tooltip { - opacity: 0!important; - } - } - } - } - } - - /* microphone */ - .container-advanced { - display: flex; - flex-direction: column; - justify-content: flex-start; - - .container-ppt-delay { - display: flex; - flex-direction: row; - justify-content: space-between; - - label { - cursor: pointer; - - display: flex; - flex-direction: row; - justify-content: flex-start; - - margin-right: .5em; - - .checkbox { - margin-right: .5em; - } - - a { - line-height: 1.2em; - } - } - - .container-input { - display: flex; - flex-direction: row; - justify-content: stretch; - - cursor: text; - - border-radius: $border_radius_middle; - overflow: hidden; - - width: 5em; - - height: 1.8em; - font-size: 0.75em; - - - align-self: center; - - color: #464646; - background-color: #17171a; - - input { - flex-shrink: 1; - flex-grow: 1; - - min-width: 2em; - text-align: right; - - position: relative; - outline: none; - border: none; - - color: #464646; - padding: 0 .3em 0 .5em; - - background-color: transparent; - - -webkit-box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.25); - -moz-box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.25); - box-shadow: inset 0 0 2px 0 rgba(0,0,0,0.25); - - &::-webkit-inner-spin-button, - &::-webkit-outer-spin-button { - -webkit-appearance: none; - margin: 0; - } - } - - label { - flex-shrink: 0; - flex-grow: 0; - - align-self: center; - } - - &.disabled { - cursor: unset; - pointer-events: none; - - background-color: #222227; - } - } - } - } - - /* speaker */ - .container-volume-master { - .filler { - background-color: #2b8541; - } - } - - .container-volume-soundpack { - padding-top: .75em; - } - } - } -} - -/* the profile stuff */ -.container-settings-identity-profile { - display: flex; - flex-direction: row; - justify-content: stretch; - flex-shrink: 1; - flex-grow: 1; - - min-width: 43em; - min-height: 41em; - - position: relative; - - .left, .right { - flex-grow: 1; - flex-shrink: 1; - - width: 50%; - min-width: 25em; - min-height: min-content; - - display: flex; - flex-direction: column; - justify-content: stretch; - - position: relative; - - .header { - height: 3em; - - display: flex; - flex-direction: row; - justify-content: stretch; - - padding-bottom: .5em; - - a { - flex-grow: 1; - flex-shrink: 1; - - align-self: flex-end; - - font-weight: bold; - color: #e0e0e0; - - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - .btn { - flex-shrink: 0; - flex-grow: 0; - - margin-left: 1em; - min-width: 8em; - } - } - - button { - height: 2.2em; - align-self: flex-end; - } - } - - .left { - margin-right: 1em; - min-width: 15em; - - .body { - flex-grow: 1; - flex-shrink: 1; - - display: flex; - flex-direction: column; - justify-content: stretch; - - border: 1px $color_list_border solid; - border-radius: $border_radius_large; - - background-color: $color_list_background; - - .container-profiles { - flex-grow: 1; - flex-shrink: 1; - - min-height: 3em; - - display: flex; - flex-direction: column; - justify-content: flex-start; - - position: relative; - - overflow-x: hidden; - overflow-y: auto; - - @include chat-scrollbar-vertical(); - - .overlay { - position: absolute; - background-color: #28292b; - - top: 0; - right: 0; - left: 0; - bottom: 0; - - z-index: 1; - display: flex; - flex-direction: column; - justify-content: center; - - a { - align-self: center; - font-size: 1.25em; - } - - a.error { - align-self: center; - font-size: 1.75em; - - color: hsla(0, 5%, 60%, 1); - } - - button { - flex-grow: 0; - width: 8em; - align-self: center; - } - } - - .profile { - flex-shrink: 0; - flex-grow: 0; - - display: flex; - flex-direction: row; - justify-content: stretch; - - cursor: pointer; - - height: 3em; - width: 100%; - - .container-avatar { - flex-shrink: 0; - flex-grow: 0; - - height: 3em; - width: 3em; - } - - .container-info { - flex-shrink: 1; - flex-grow: 1; - - margin-left: .5em; - min-width: 4em; - - display: flex; - flex-direction: column; - justify-content: center; - - .container-type { - width: 100%; - - display: flex; - flex-direction: row; - justify-content: flex-start; - - text-transform: uppercase; - font-weight: bold; - - font-size: 0.8em; - - line-height: 1em; - - color: #6a6a6a; - - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - - > *:not(:first-of-type) { - margin-left: .25em; - } - .icon-status { - margin-bottom: .2em; /* push it a bit higher than the center */ - } - - div { - align-self: center; - } - } - - .profile-name { - line-height: 1.2em; - - color: #999999; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - } - - &:hover { - background-color: $color_list_hover; - } - - &.selected { - background-color: $color_list_selected; - } - } - } - - .buttons, .buttons-small { - flex-grow: 0; - flex-shrink: 0; - - height: 3.5em; - padding: .5em; - - display: flex; - flex-direction: row; - justify-content: stretch; - - border: none; - border-top: 1px $color_list_border solid; - - .spacer { - flex-grow: 1; - flex-shrink: 1000000000; - } - - .container-error { - color: #a10000; - align-self: center; - } - - button { - flex-shrink: 1; - min-width: 2em; - - @include text-dotdotdot(); - - &:not(:last-of-type) { - margin-right: .5em; - } - } - } - - .buttons { - display: none; - } - } - } - - .right { - padding-right: .5em; /* for the sliders etc*/ - justify-content: flex-start; - - .body { - flex-grow: 1; - flex-shrink: 1; - - display: flex; - flex-direction: column; - justify-content: stretch; - - > div { - flex-shrink: 0; - } - - .container-teamspeak { - .container-invalid { - padding: 1em; - text-align: center; - } - .container-valid { - .container-level { - display: flex; - flex-direction: row; - justify-content: stretch; - - .form-group { - flex-grow: 1; - flex-shrink: 1; - min-width: 4em; - } - - button { - height: 2em; - - align-self: center; - margin-left: 1em; - } - } - } - - .buttons { - display: flex; - flex-direction: row; - justify-content: space-between; - - > div { - text-align: right; - - width: max-content; - margin-left: 1em; - } - - button { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - - text-align: end; - - margin-top: 1em; - } - } - } - - .container-teaforo { - .container-valid, .container-invalid { - padding: 1em; - text-align: center; - - button { - margin-top: .5em; - } - } - } - - .container-highlight-dummy { - margin-top: 1em; - margin-bottom: .5em; - - display: none; - flex-grow: 1; - } - } - } -} - -/* the highlight stuff for the newcommer modal */ -.container-settings-identity-profile, .container-settings-audio-microphone { - $highlight-time: .5s; - $backdrop-color: rgba(0, 0, 0, .9); - .help-background { - position: absolute; - - top: 0; - left: 0; - right: 0; - bottom: 0; - - display: none; - background-color: $backdrop-color; - border-radius: .15em; - - padding: .5em; - } - - .container-help-text { - position: absolute; - - top: 1em; - left: 1em; - right: 1em; - bottom: 1em; - - display: none; - z-index: 20; - - a { - display: block; - } - } - - &.help-shown { - .help-background { - display: flex; - z-index: 1; - - opacity: 1; - } - - .highlightable { - border-radius: .1em; - position: relative; - z-index: 10; - - background: #19191b; - - @include transition($highlight-time ease-in-out); - - &::after { - content: ' '; - - z-index: 5; - position: absolute; - - top: 0; - left: 0; - right: 0; - bottom: 0; - - background-color: $backdrop-color; - - @include transition($highlight-time ease-in-out); - } - - &.highlighted { - padding: .5em; - - &::after { - background-color: #00000000; - } - } - } - - .container-help-text { - display: block; - - overflow: auto; - @include chat-scrollbar(); - @include transition($highlight-time ease-in-out); - - .help-microphone-settings { - ol { - margin-top: .5em; - margin-bottom: 0; - } - - li { - margin-bottom: .5em; - - .title { - font-weight: bold; - } - } - } - } - - .container-teamspeak, .container-teaforo, .container-nickname { - display: none; - } - - .container-highlight-dummy { - display: flex!important; - } - - &.hide-help { - .help-background { - @include transition($highlight-time ease-in-out); - - opacity: 0; - } - - .highlightable::after { - background-color: #00000000; - } - - .container-help-text { - display: none; - } - } - } -} - @media all and (min-width: 50em) { - .container-settings-identity-profile { - .buttons { - display: flex!important; - } + :global { + .container-settings-identity-profile { + .buttons { + display: flex!important; + } - .buttons-small { - display: none!important; + .buttons-small { + display: none!important; + } } } } diff --git a/shared/css/static/modal.scss b/shared/css/static/modal.scss index 9cb6de84..abc5abb0 100644 --- a/shared/css/static/modal.scss +++ b/shared/css/static/modal.scss @@ -1,968 +1,971 @@ @import "properties"; @import "mixin"; -.modal { - color: #999999; /* base color */ +:global { - overflow: auto; /* allow scrolling if a modal is too big */ + .modal { + color: #999999; /* base color */ - background-color: rgba(0, 0, 0, 0.8); + overflow: auto; /* allow scrolling if a modal is too big */ - padding-right: 5%; - padding-left: 5%; + background-color: rgba(0, 0, 0, 0.8); - z-index: 100000; - position: fixed; + padding-right: 5%; + padding-left: 5%; - top: 0; - left: 0; - right: 0; - bottom: 0; + z-index: 100000; + position: fixed; - display: none; + top: 0; + left: 0; + right: 0; + bottom: 0; - margin-top: -7em; - opacity: 0; + display: none; - $animation_length: .3s; - @include transition(opacity $animation_length ease-in, margin-top $animation_length ease-in); - &.shown { - display: flex; - flex-direction: column; - justify-content: center; - - margin-top: 0; - opacity: 1; - - @include transition(opacity $animation_length ease-out, margin-top $animation_length ease-out); - } - - .modal-dialog { - display: block; - - margin: 1.75rem 0; - - /* width calculations */ - align-items: center; - - /* height stuff */ - max-height: calc(100% - 3.5em); - - .modal-content { - background: #19191b; - - border: 1px solid black; - border-radius: $border_radius_middle; - - width: max-content; - max-width: 100%; - min-width: 20em; - - min-height: min-content; - - /* align us in the center */ - margin-right: auto; - margin-left: auto; - - flex-shrink: 1; - flex-grow: 0; /* we dont want a grow over the limit set within the content, but we want to shrink the content if necessary */ - align-self: center; + margin-top: -7em; + opacity: 0; + $animation_length: .3s; + @include transition(opacity $animation_length ease-in, margin-top $animation_length ease-in); + &.shown { display: flex; flex-direction: column; - justify-content: stretch; + justify-content: center; - .modal-header, .modal-footer { - flex-grow: 0; - flex-shrink: 0; - } + margin-top: 0; + opacity: 1; - .modal-header { - background-color: #222224; + @include transition(opacity $animation_length ease-out, margin-top $animation_length ease-out); + } + + .modal-dialog { + display: block; + + margin: 1.75rem 0; + + /* width calculations */ + align-items: center; + + /* height stuff */ + max-height: calc(100% - 3.5em); + + .modal-content { + background: #19191b; + + border: 1px solid black; + border-radius: $border_radius_middle; + + width: max-content; + max-width: 100%; + min-width: 20em; + + min-height: min-content; + + /* align us in the center */ + margin-right: auto; + margin-left: auto; + + flex-shrink: 1; + flex-grow: 0; /* we dont want a grow over the limit set within the content, but we want to shrink the content if necessary */ + align-self: center; display: flex; - flex-direction: row; + flex-direction: column; justify-content: stretch; - padding: .25em; - - .container-icon, .container-close { + .modal-header, .modal-footer { flex-grow: 0; flex-shrink: 0; } - .container-close { - height: 1.4em; - width: 1.4em; + .modal-header { + background-color: #222224; - padding: .2em; - border-radius: .2em; + display: flex; + flex-direction: row; + justify-content: stretch; - cursor: pointer; + padding: .25em; - &:hover { - background-color: #1b1b1c; + .container-icon, .container-close { + flex-grow: 0; + flex-shrink: 0; + } + + .container-close { + height: 1.4em; + width: 1.4em; + + padding: .2em; + border-radius: .2em; + + cursor: pointer; + + &:hover { + background-color: #1b1b1c; + } + } + + .container-icon { + margin-right: .25em; + + img { + height: 1em; + width: 1em; + } + } + + .modal-title, modal-header { + flex-grow: 1; + flex-shrink: 1; + + color: #9d9d9e; + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + h5 { + margin: 0; + padding: 0; } } - .container-icon { - margin-right: .25em; + .modal-body { + max-width: 100%; + min-width: 20em; /* may adjust if needed */ - img { - height: 1em; - width: 1em; - } + max-height: calc(100vh - 8em); + min-height: 5em; + + overflow-y: auto; + overflow-x: auto; + + display: block; + } + } + } + } + + .modal { + //General style + .properties { + display: grid; + grid-template-columns: minmax(min-content, max-content) auto; + grid-column-gap: 10px; + grid-row-gap: 3px; + box-sizing: border-box; + } + + hr { + border-top: 3px double #8c8b8b; + width: 100%; + } + + + .input_error { + border-radius: 1px; + border: solid red; + } + + .properties_misc { + .complains { + display: grid; + grid-template-columns: auto auto auto; + grid-template-rows: auto auto; + grid-column-gap: 5px; + margin-bottom: 10px; + } + } + + .container { + padding: 6px; + } + + .modal-dialog { + display: flex; + flex-direction: column; + justify-content: stretch; + + &.modal-dialog-centered { + justify-content: stretch; + } + } + + .modal-content { + /* max-height: 500px; */ + min-height: 0; /* required for moz */ + flex-direction: column; + justify-content: stretch; + + .modal-header { + flex-shrink: 0; + flex-grow: 0; + + &.modal-header-error { + //background-color: #ce0000; + background-color: hsla(0, 100%, 25%, 1); } - .modal-title, modal-header { - flex-grow: 1; - flex-shrink: 1; - - color: #9d9d9e; - - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + &.modal-header-info { + background-color: hsla(199, 98%, 20%, 1); } - h5 { - margin: 0; - padding: 0; + &.modal-header-warning, &.modal-header-info, &.modal-header-error { + border-top-left-radius: .125rem; + border-top-right-radius: .125rem; } } .modal-body { - max-width: 100%; - min-width: 20em; /* may adjust if needed */ + padding: 20px 24px 24px; - max-height: calc(100vh - 8em); - min-height: 5em; + flex-grow: 1; + flex-shrink: 1; + display: flex; + flex-direction: column; + min-height: 0; - overflow-y: auto; - overflow-x: auto; + input.is-invalid { + background-image: linear-gradient(0deg, #d50000 2px, rgba(213, 0, 0, 0) 0), linear-gradient(0deg, rgba(241, 1, 1, 0.61) 1px, transparent 0); + } + } + .modal-footer { + flex-shrink: 0; + flex-grow: 0; + + &.modal-footer-button-group { + button { + min-width: 100px; + } + + button:not(:first-of-type) { + margin-left: 15px; + }; + } + } + } + } + + /* special general modals */ + .modal { + .modal-body.modal-blue { + border-left: 2px solid #0a73d2; + } + .modal-body.modal-green { + border-left: 2px solid #00d400; + } + .modal-body.modal-red { + border: none; + border-left: 2px solid #d50000; + } + + .modal-body.modal-body-input { + color: #999999; + + width: 100%; + + .form-group:not(.with-title) { + padding-top: .75rem; + } + + input.is-invalid ~ .container-help-feedback > .invalid-feedback { display: block; } - } - } -} -.modal { - //General style - .properties { - display: grid; - grid-template-columns: minmax(min-content, max-content) auto; - grid-column-gap: 10px; - grid-row-gap: 3px; - box-sizing: border-box; - } - - hr { - border-top: 3px double #8c8b8b; - width: 100%; - } - - - .input_error { - border-radius: 1px; - border: solid red; - } - - .properties_misc { - .complains { - display: grid; - grid-template-columns: auto auto auto; - grid-template-rows: auto auto; - grid-column-gap: 5px; - margin-bottom: 10px; - } - } - - .container { - padding: 6px; - } - - .modal-dialog { - display: flex; - flex-direction: column; - justify-content: stretch; - - &.modal-dialog-centered { - justify-content: stretch; - } - } - - .modal-content { - /* max-height: 500px; */ - min-height: 0; /* required for moz */ - flex-direction: column; - justify-content: stretch; - - .modal-header { - flex-shrink: 0; - flex-grow: 0; - - &.modal-header-error { - //background-color: #ce0000; - background-color: hsla(0, 100%, 25%, 1); + .container-help-feedback { + position: absolute; } - &.modal-header-info { - background-color: hsla(199, 98%, 20%, 1); - } + .buttons { + display: flex; + flex-direction: row; + justify-content: flex-end; - &.modal-header-warning, &.modal-header-info, &.modal-header-error { - border-top-left-radius: .125rem; - border-top-right-radius: .125rem; - } - } - - .modal-body { - padding: 20px 24px 24px; - - flex-grow: 1; - flex-shrink: 1; - display: flex; - flex-direction: column; - min-height: 0; - - input.is-invalid { - background-image: linear-gradient(0deg, #d50000 2px, rgba(213, 0, 0, 0) 0), linear-gradient(0deg, rgba(241, 1, 1, 0.61) 1px, transparent 0); - } - } - - .modal-footer { - flex-shrink: 0; - flex-grow: 0; - - &.modal-footer-button-group { button { - min-width: 100px; - } + width: 6em; - button:not(:first-of-type) { - margin-left: 15px; - }; - } - } - } -} - -/* special general modals */ -.modal { - .modal-body.modal-blue { - border-left: 2px solid #0a73d2; - } - .modal-body.modal-green { - border-left: 2px solid #00d400; - } - .modal-body.modal-red { - border: none; - border-left: 2px solid #d50000; - } - - .modal-body.modal-body-input { - color: #999999; - - width: 100%; - - .form-group:not(.with-title) { - padding-top: .75rem; - } - - input.is-invalid ~ .container-help-feedback > .invalid-feedback { - display: block; - } - - .container-help-feedback { - position: absolute; - } - - .buttons { - display: flex; - flex-direction: row; - justify-content: flex-end; - - button { - width: 6em; - - &:not(:last-of-type) { - margin-right: 1em; + &:not(:last-of-type) { + margin-right: 1em; + } } } } - } - .modal-body.modal-body-yesno { - color: #999999; - - border: none; - border-left: 2px solid #d50000; - - width: 100%; - - .buttons { - padding-top: 2em; - - display: flex; - flex-direction: row; - justify-content: flex-end; - - button { - width: 6em; - - &:not(:last-of-type) { - margin-right: 1em; - } - } - } - } - - .modal-body.modal-info, .modal-body.modal-error { - justify-content: center; - } -} - - -/* Input group */ -.form-group { - position: relative; - - padding-top: 1.75rem; /* the label above (might be floating) */ - margin-bottom: 1rem; /* for invalid label/help label */ - - .form-control { - display: block; - width: 100%; - padding: .4375rem 0; - font-size: 1rem; - line-height: 1.5; - color: #cdd1d0; - background-color: transparent; - background-clip: padding-box; - border: 1px solid rgba(0, 0, 0, .26); - border-radius: 0; - box-shadow: none; - - @include transition(border-color .15s ease-in-out, box-shadow .15s ease-in-out); - } - - label { - color: #999999; - - top: 1rem; - left: 0; - font-size: .75rem; - - position: absolute; - pointer-events: none; - transition: all .3s ease; - - line-height: 1; - - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - - max-width: 100%; - - &.bmd-label-floating { - will-change: left, top, contents; + .modal-body.modal-body-yesno { color: #999999; - top: 2.42rem; - font-size: 1rem; + + border: none; + border-left: 2px solid #d50000; + + width: 100%; + + .buttons { + padding-top: 2em; + + display: flex; + flex-direction: row; + justify-content: flex-end; + + button { + width: 6em; + + &:not(:last-of-type) { + margin-right: 1em; + } + } + } } - @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); + .modal-body.modal-info, .modal-body.modal-error { + justify-content: center; + } } - &:focus-within { + /* Input group */ + .form-group { + position: relative; + + padding-top: 1.75rem; /* the label above (might be floating) */ + margin-bottom: 1rem; /* for invalid label/help label */ + + .form-control { + display: block; + width: 100%; + padding: .4375rem 0; + font-size: 1rem; + line-height: 1.5; + color: #cdd1d0; + background-color: transparent; + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, .26); + border-radius: 0; + box-shadow: none; + + @include transition(border-color .15s ease-in-out, box-shadow .15s ease-in-out); + } + label { - color: #3c74a2; + color: #999999; + + top: 1rem; + left: 0; + font-size: .75rem; + + position: absolute; + pointer-events: none; + transition: all .3s ease; + + line-height: 1; + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + max-width: 100%; &.bmd-label-floating { - //color: #343434; + will-change: left, top, contents; + color: #999999; + top: 2.42rem; + font-size: 1rem; + } + + @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); + } + + + &:focus-within { + label { + color: #3c74a2; + + &.bmd-label-floating { + //color: #343434; + } } } - } - &:focus-within, &.is-filled { - label.bmd-label-floating { - top: 1rem; - font-size: .75rem; - color: #3c74a2; + &:focus-within, &.is-filled { + label.bmd-label-floating { + top: 1rem; + font-size: .75rem; + color: #3c74a2; + } } - } - .form-control { - height: 2.25em; - - background: no-repeat bottom, 50% calc(100% - 1px); - background-size: 0 100%, 100% 100%; - border: 0; - transition: background 0s ease-out; - padding-left: 0; - padding-right: 0; - - - background-image: linear-gradient(0deg, #008aff 2px, rgba(0, 150, 136, 0) 0), linear-gradient(0deg, #393939 1px, transparent 0); - - &:focus { + .form-control { height: 2.25em; - background-size: 100% 100%, 100% 100%; - transition-duration: .3s; - - color: #ced3d3; - background-color: transparent; - outline: 0; - } - - &.is-invalid { - background-image: linear-gradient(0deg, #d50000 2px,rgba(213,0,0,0) 0),linear-gradient(0deg,rgba(241,1,1,.61) 1px,transparent 0); - } - } - - .invalid-feedback { - position: absolute; - opacity: 0; - width: 100%; - margin-top: .25rem; - font-size: 80%; - color: #f44336; - - @include transition(opacity .25s ease-in-out); - } - - .form-control.is-invalid ~ .invalid-feedback { - opacity: 1; - } + background: no-repeat bottom, 50% calc(100% - 1px); + background-size: 0 100%, 100% 100%; + border: 0; + transition: background 0s ease-out; + padding-left: 0; + padding-right: 0; - &.is-invalid { - .form-control { - background-image: linear-gradient(0deg, #d50000 2px,rgba(213,0,0,0) 0),linear-gradient(0deg,rgba(241,1,1,.61) 1px,transparent 0); + background-image: linear-gradient(0deg, #008aff 2px, rgba(0, 150, 136, 0) 0), linear-gradient(0deg, #393939 1px, transparent 0); + + &:focus { + height: 2.25em; + + background-size: 100% 100%, 100% 100%; + transition-duration: .3s; + + color: #ced3d3; + background-color: transparent; + outline: 0; + } + + &.is-invalid { + background-image: linear-gradient(0deg, #d50000 2px,rgba(213,0,0,0) 0),linear-gradient(0deg,rgba(241,1,1,.61) 1px,transparent 0); + } } .invalid-feedback { + position: absolute; + opacity: 0; + width: 100%; + margin-top: .25rem; + font-size: 80%; + color: #f44336; + + @include transition(opacity .25s ease-in-out); + } + + .form-control.is-invalid ~ .invalid-feedback { opacity: 1; } - label { - color: #f44336!important; + + &.is-invalid { + .form-control { + background-image: linear-gradient(0deg, #d50000 2px,rgba(213,0,0,0) 0),linear-gradient(0deg,rgba(241,1,1,.61) 1px,transparent 0); + } + + .invalid-feedback { + opacity: 1; + } + + label { + color: #f44336!important; + } + } + + .bmd-help { + position: absolute; + opacity: 0; + width: 100%; + margin-top: .25rem; + + font-size: .75em; + + @include transition(opacity .25s ease-in-out); + } + + .form-control:focus-within ~ .bmd-help { + opacity: 1; } } - .bmd-help { - position: absolute; - opacity: 0; - width: 100%; - margin-top: .25rem; + .modal-body.modal-disconnect-kick { + display: block; - font-size: .75em; + a { + display: inline-block; + } - @include transition(opacity .25s ease-in-out); + .htmltag-client { + display: inline-block; + color: unset!important; + } } - .form-control:focus-within ~ .bmd-help { - opacity: 1; - } -} + /* button look */ + .btn { + cursor: pointer; -.modal-body.modal-disconnect-kick { - display: block; + background-color: rgba(0, 0, 0, 0.5); - a { - display: inline-block; - } + border-width: 0; + border-radius: $border_radius_middle; + border-style: solid; - .htmltag-client { - display: inline-block; - color: unset!important; - } -} + color: #7c7c7c; -/* button look */ -.btn { - cursor: pointer; + padding: .25em 1em; - background-color: rgba(0, 0, 0, 0.5); + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 3px 1px -2px rgba(0, 0, 0, .2), 0 1px 5px 0 rgba(0, 0, 0, .12); - border-width: 0; - border-radius: $border_radius_middle; - border-style: solid; - - color: #7c7c7c; - - padding: .25em 1em; - - box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 3px 1px -2px rgba(0, 0, 0, .2), 0 1px 5px 0 rgba(0, 0, 0, .12); - - @include text-dotdotdot(); - - &:hover { - background-color: #0a0a0a; - } - - &:disabled { - box-shadow: none; - background-color: rgba(0, 0, 0, 0.27); + @include text-dotdotdot(); &:hover { + background-color: #0a0a0a; + } + + &:disabled { + box-shadow: none; background-color: rgba(0, 0, 0, 0.27); + + &:hover { + background-color: rgba(0, 0, 0, 0.27); + } } + + &.btn-success, &.btn-green { + border-bottom-width: 2px; + border-bottom-color: #389738; + } + + &.btn-info, &.btn-blue { + border-bottom-width: 2px; + border-bottom-color: #386896; + } + + &.btn-warning, &.btn-danger, &.btn-red { + border-bottom-width: 2px; + border-bottom-color: #973838; + } + + &.btn-purple { + border-bottom-width: 2px; + border-bottom-color: #5f3586; + } + + &.btn-brown { + border-bottom-width: 2px; + border-bottom-color: #965238; + } + + &.btn-yellow { + border-bottom-width: 2px; + border-bottom-color: #96903a; + } + + @include transition(background-color $button_hover_animation_time ease-in-out); } - &.btn-success, &.btn-green { - border-bottom-width: 2px; - border-bottom-color: #389738; - } + /* general switch look */ + .switch { + $ball_outer_width: 1.5em; /* 1.5? */ + $ball_inner_width: .4em; - &.btn-info, &.btn-blue { - border-bottom-width: 2px; - border-bottom-color: #386896; - } + $slider_height: .8em; + $slider_width: 2em; - &.btn-warning, &.btn-danger, &.btn-red { - border-bottom-width: 2px; - border-bottom-color: #973838; - } + $slider_border_size: .1em; - &.btn-purple { - border-bottom-width: 2px; - border-bottom-color: #5f3586; - } - - &.btn-brown { - border-bottom-width: 2px; - border-bottom-color: #965238; - } - - &.btn-yellow { - border-bottom-width: 2px; - border-bottom-color: #96903a; - } - - @include transition(background-color $button_hover_animation_time ease-in-out); -} - -/* general switch look */ -.switch { - $ball_outer_width: 1.5em; /* 1.5? */ - $ball_inner_width: .4em; - - $slider_height: .8em; - $slider_width: 2em; - - $slider_border_size: .1em; - - position: relative; - display: inline-block; - outline: none; - - width: $slider_width; - height: $slider_height; - - /* "allocate" space for the slider */ - margin-top: ($ball_outer_width - $slider_height) / 2; - margin-bottom: ($ball_outer_width - $slider_height) / 2; - margin-left: $ball_outer_width / 2; - margin-right: $ball_outer_width / 2; - - /* fix size */ - flex-shrink: 0; - flex-grow: 0; - - input { - /* "hide" the actual input node */ - opacity: 0; - width: 0; - height: 0; - outline: none; - } - - .slider { - pointer-events: all!important; - position: absolute; - cursor: pointer; + position: relative; + display: inline-block; outline: none; - top: -$slider_border_size; - left: -$slider_border_size; - right: -$slider_border_size; - bottom: -$slider_border_size; + width: $slider_width; + height: $slider_height; - background-color: #252424; + /* "allocate" space for the slider */ + margin-top: ($ball_outer_width - $slider_height) / 2; + margin-bottom: ($ball_outer_width - $slider_height) / 2; + margin-left: $ball_outer_width / 2; + margin-right: $ball_outer_width / 2; - border: $slider_border_size solid #262628; - border-radius: 5px; - - &:before { - position: absolute; - content: ""; - - height: $ball_outer_width; - width: $ball_outer_width; - - left: - $ball_outer_width / 2; - bottom: -($ball_outer_width - $slider_height) / 2; - - background-color: #3d3a3a; - - @include transition(.4s); - border-radius: 50%; - - box-shadow: 0 0 .2em 1px rgba(0, 0, 0, 0.27); - } - - .dot { - position: absolute; - - height: $ball_inner_width; - width: $ball_inner_width; - - left: -($ball_inner_width / 2); - bottom: $slider_height / 2 - $ball_inner_width / 2; - - background-color: #a5a5a5; - box-shadow: 0 0 1em 1px rgba(165, 165, 165, 0.4); - border-radius: 50%; - - @include transition(.4s); - } - } - - - - input:focus + .slider { - } - - input:checked + .slider { - &:before { - @include transform(translateX($slider_width)); - } - - .dot { - @include transform(translateX($slider_width)); - background-color: #46c0ec; - box-shadow: 0 0 1em 1px #46c0ec; - } - } -} - -/* general radio button look */ -.ratio-button, .radio-button { - $button_size: 1.2em; - $mark_size: .6em; - - position: relative; - - width: $button_size; - height: $button_size; - - cursor: pointer; - - overflow: hidden; - - background-color: #272626; - border-radius: 50%; - - input { - position: absolute; - width: 0; - height: 0; - opacity: 0; - } - - //#07d1fe - .mark { - position: absolute; - opacity: 0; - - top: ($button_size - $mark_size) / 2; - bottom: ($button_size - $mark_size) / 2; - right: ($button_size - $mark_size) / 2; - left: ($button_size - $mark_size) / 2; - - background-color: #46c0ec; - box-shadow: 0 0 .5em 1px rgba(70, 192, 236, 0.4); - border-radius: 50%; - - @include transition(.4s); - } - - input:checked + .mark { - opacity: 1; - } - - @include transition(background-color $button_hover_animation_time); - - -webkit-box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); - -moz-box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); - box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); -} - -label:hover > .ratio-button, .ratio-button:hover, -label:hover > .radio-button, .radio-button:hover{ - &.ratio-button, > .ratio-button, - &.radio-button, > .radio-button{ - background-color: #2c2b2b; - } -} - -label.disabled > .ratio-button, .ratio-button.disabled, .ratio-button:disabled, -label.disabled > .radio-button, .radio-button.disabled, .radio-button:disabled { - &.ratio-button, > .ratio-button, - &.radio-button, > .radio-button { - pointer-events: none!important; - background-color: #1a1919!important; - } -} - - -/* - - */ -.checkbox { - flex-shrink: 0; - flex-grow: 0; - - position: relative; - - width: 1.3em; - height: 1.3em; - - cursor: pointer; - pointer-events: all; - - overflow: hidden; - - background-color: #272626; - border-radius: $border_radius_middle; - - input { - position: absolute; - width: 0; - height: 0; - opacity: 0; - } - - //#07d1fe - .mark { - position: absolute; - opacity: 0; - - height: .5em; - width: .8em; - - margin-left: 0.25em; - margin-top: .3em; - - border: none; - border-bottom: .2em solid #46c0ec; - border-left: .2em solid #46c0ec; - - transform: rotateY(0deg) rotate(-45deg); /* needs Y at 0 deg to behave properly*/ - @include transition(.4s); - } - - input:checked + .mark { - opacity: 1; - } - - -webkit-box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); - -moz-box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); - box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); -} - -label.disabled > .checkbox, .checkbox:disabled, .checkbox.disabled { - &.checkbox, > .checkbox { - pointer-events: none!important; - background-color: #1a1a1e; - } -} - -/* slider */ -$track_height: .6em; - -$thumb_width: .6em; -$thumb_height: 2em; - -$tooltip_width: 4em; -$tooltip_height: 1.8em; - -.container-slider { - font-size: .8em; - - position: relative; - - margin-top: .5em; /* for the track */ - - width: 100%; - height: $track_height; - - cursor: pointer; - - background-color: #242527; - border-radius: $border_radius_large; - - overflow: visible; - - .filler { - position: absolute; - - left: 0; - top: 0; - bottom: 0; - - background-color: #4370a2; - border-radius: $border_radius_large; - } - - .thumb { - position: absolute; - - top: 0; - right: 0; - - height: $thumb_height; - width: $thumb_width; - - margin-left: -($thumb_width / 2); - margin-right: -($thumb_width / 2); - - margin-top: -($thumb_height - $track_height) / 2; - margin-bottom: -($thumb_height - $track_height) / 2; - - background-color: #808080; - - .tooltip { - display: none; - } - } - - &:hover, &.active { - .tooltip { - opacity: 1; - } - } -} - -input::-webkit-outer-spin-button, -input::-webkit-inner-spin-button { - /* display: none; <- Crashes Chrome on hover */ - -webkit-appearance: none; - margin: 0; /* <-- Apparently some margin are still there even though it's hidden */ -} - -input[type=number] { - -moz-appearance:textfield; /* Firefox */ -} - -/* "Boxed input" Used in channeledit & serveredit */ -.input-boxed { - height: 2.5em; - - border-radius: .2em; - border: 1px solid #111112; - - background-color: #121213; - - display: flex; - flex-direction: row; - justify-content: stretch; - - color: #b3b3b3; - - @include placeholder(&) { - color: #606060; - }; - - .prefix { - flex-grow: 0; + /* fix size */ flex-shrink: 0; + flex-grow: 0; - margin: 0; + input { + /* "hide" the actual input node */ + opacity: 0; + width: 0; + height: 0; + outline: none; + } - line-height: initial; - align-self: center; - padding: 0 .5em; + .slider { + pointer-events: all!important; + position: absolute; + cursor: pointer; + outline: none; + + top: -$slider_border_size; + left: -$slider_border_size; + right: -$slider_border_size; + bottom: -$slider_border_size; + + background-color: #252424; + + border: $slider_border_size solid #262628; + border-radius: 5px; + + &:before { + position: absolute; + content: ""; + + height: $ball_outer_width; + width: $ball_outer_width; + + left: - $ball_outer_width / 2; + bottom: -($ball_outer_width - $slider_height) / 2; + + background-color: #3d3a3a; + + @include transition(.4s); + border-radius: 50%; + + box-shadow: 0 0 .2em 1px rgba(0, 0, 0, 0.27); + } + + .dot { + position: absolute; + + height: $ball_inner_width; + width: $ball_inner_width; + + left: -($ball_inner_width / 2); + bottom: $slider_height / 2 - $ball_inner_width / 2; + + background-color: #a5a5a5; + box-shadow: 0 0 1em 1px rgba(165, 165, 165, 0.4); + border-radius: 50%; + + @include transition(.4s); + } + } + + + + input:focus + .slider { + } + + input:checked + .slider { + &:before { + @include transform(translateX($slider_width)); + } + + .dot { + @include transform(translateX($slider_width)); + background-color: #46c0ec; + box-shadow: 0 0 1em 1px #46c0ec; + } + } + } + + /* general radio button look */ + .ratio-button, .radio-button { + $button_size: 1.2em; + $mark_size: .6em; + + position: relative; + + width: $button_size; + height: $button_size; + + cursor: pointer; overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - opacity: 1; + background-color: #272626; + border-radius: 50%; + + input { + position: absolute; + width: 0; + height: 0; + opacity: 0; + } + + //#07d1fe + .mark { + position: absolute; + opacity: 0; + + top: ($button_size - $mark_size) / 2; + bottom: ($button_size - $mark_size) / 2; + right: ($button_size - $mark_size) / 2; + left: ($button_size - $mark_size) / 2; + + background-color: #46c0ec; + box-shadow: 0 0 .5em 1px rgba(70, 192, 236, 0.4); + border-radius: 50%; + + @include transition(.4s); + } + + input:checked + .mark { + opacity: 1; + } + + @include transition(background-color $button_hover_animation_time); + + -webkit-box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); + -moz-box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); + box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); + } + + label:hover > .ratio-button, .ratio-button:hover, + label:hover > .radio-button, .radio-button:hover{ + &.ratio-button, > .ratio-button, + &.radio-button, > .radio-button{ + background-color: #2c2b2b; + } + } + + label.disabled > .ratio-button, .ratio-button.disabled, .ratio-button:disabled, + label.disabled > .radio-button, .radio-button.disabled, .radio-button:disabled { + &.ratio-button, > .ratio-button, + &.radio-button, > .radio-button { + pointer-events: none!important; + background-color: #1a1919!important; + } + } + + + /* + + */ + .checkbox { + flex-shrink: 0; + flex-grow: 0; + + position: relative; + + width: 1.3em; + height: 1.3em; + + cursor: pointer; + pointer-events: all; + + overflow: hidden; + + background-color: #272626; + border-radius: $border_radius_middle; + + input { + position: absolute; + width: 0; + height: 0; + opacity: 0; + } + + //#07d1fe + .mark { + position: absolute; + opacity: 0; + + height: .5em; + width: .8em; + + margin-left: 0.25em; + margin-top: .3em; + + border: none; + border-bottom: .2em solid #46c0ec; + border-left: .2em solid #46c0ec; + + transform: rotateY(0deg) rotate(-45deg); /* needs Y at 0 deg to behave properly*/ + @include transition(.4s); + } + + input:checked + .mark { + opacity: 1; + } + + -webkit-box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); + -moz-box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); + box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.5); + } + + label.disabled > .checkbox, .checkbox:disabled, .checkbox.disabled { + &.checkbox, > .checkbox { + pointer-events: none!important; + background-color: #1a1a1e; + } + } + + /* slider */ + $track_height: .6em; + + $thumb_width: .6em; + $thumb_height: 2em; + + $tooltip_width: 4em; + $tooltip_height: 1.8em; + + .container-slider { + font-size: .8em; + + position: relative; + + margin-top: .5em; /* for the track */ + + width: 100%; + height: $track_height; + + cursor: pointer; + + background-color: #242527; + border-radius: $border_radius_large; + + overflow: visible; + + .filler { + position: absolute; + + left: 0; + top: 0; + bottom: 0; + + background-color: #4370a2; + border-radius: $border_radius_large; + } + + .thumb { + position: absolute; + + top: 0; + right: 0; + + height: $thumb_height; + width: $thumb_width; + + margin-left: -($thumb_width / 2); + margin-right: -($thumb_width / 2); + + margin-top: -($thumb_height - $track_height) / 2; + margin-bottom: -($thumb_height - $track_height) / 2; + + background-color: #808080; + + .tooltip { + display: none; + } + } + + &:hover, &.active { + .tooltip { + opacity: 1; + } + } + } + + input::-webkit-outer-spin-button, + input::-webkit-inner-spin-button { + /* display: none; <- Crashes Chrome on hover */ + -webkit-appearance: none; + margin: 0; /* <-- Apparently some margin are still there even though it's hidden */ + } + + input[type=number] { + -moz-appearance:textfield; /* Firefox */ + } + + /* "Boxed input" Used in channeledit & serveredit */ + .input-boxed { + height: 2.5em; + + border-radius: .2em; + border: 1px solid #111112; + + background-color: #121213; + + display: flex; + flex-direction: row; + justify-content: stretch; + + color: #b3b3b3; + + @include placeholder(&) { + color: #606060; + }; + + .prefix { + flex-grow: 0; + flex-shrink: 0; + + margin: 0; + + line-height: initial; + align-self: center; + padding: 0 .5em; + + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + opacity: 1; + + @include transition($button_hover_animation_time ease-in-out); + } + + &.is-invalid { + background-color: #180d0d; + border-color: #721c1c; + + background-image: unset!important; + } + + &:focus, &:focus-within { + background-color: #131b22; + border-color: #284262; + + color: #e1e2e3; + + .prefix { + width: 0; + padding-left: 0; + padding-right: 0; + opacity: 0; + } + } + + input, select { + flex-grow: 1; + flex-shrink: 1; + + padding: 0 0.5em; + + background: transparent; + border: none; + outline: none; + margin: 0; + + color: #b3b3b3; + } + + .prefix + input { + padding-left: 0; + } + + + &:focus, &:focus-within { + .prefix + input { + padding-left: .5em; + } + } + + &.disabled, &:disabled { + background-color: #1a1819; + } @include transition($button_hover_animation_time ease-in-out); } - &.is-invalid { - background-color: #180d0d; - border-color: #721c1c; - - background-image: unset!important; + input.input-boxed { + padding: 0.5em; } + textarea.input-boxed { + resize: vertical; + width: 100%; - &:focus, &:focus-within { - background-color: #131b22; - border-color: #284262; + min-height: 2em; + padding: .2em .5em; - color: #e1e2e3; - - .prefix { - width: 0; - padding-left: 0; - padding-right: 0; - opacity: 0; - } + @include chat-scrollbar-vertical(); } - - input, select { - flex-grow: 1; - flex-shrink: 1; - - padding: 0 0.5em; - - background: transparent; - border: none; - outline: none; - margin: 0; - - color: #b3b3b3; - } - - .prefix + input { - padding-left: 0; - } - - - &:focus, &:focus-within { - .prefix + input { - padding-left: .5em; - } - } - - &.disabled, &:disabled { - background-color: #1a1819; - } - - @include transition($button_hover_animation_time ease-in-out); -} - -input.input-boxed { - padding: 0.5em; -} -textarea.input-boxed { - resize: vertical; - width: 100%; - - min-height: 2em; - padding: .2em .5em; - - @include chat-scrollbar-vertical(); } \ No newline at end of file diff --git a/shared/css/static/modals.scss b/shared/css/static/modals.scss index 7b580e43..c35ad314 100644 --- a/shared/css/static/modals.scss +++ b/shared/css/static/modals.scss @@ -1,32 +1,34 @@ -.arrow { - display: inline-block; - border: solid black; - //border-width: 0 3px 3px 0; - //padding: 3px; - //height: 10px; +:global { + .arrow { + display: inline-block; + border: solid black; + //border-width: 0 3px 3px 0; + //padding: 3px; + //height: 10px; - border-width: 0 .2em .2em 0; - padding: .21em; - height: .5em; - width: .5em; + border-width: 0 .2em .2em 0; + padding: .21em; + height: .5em; + width: .5em; - &.right { - transform: rotate(-45deg); - -webkit-transform: rotate(-45deg); - } + &.right { + transform: rotate(-45deg); + -webkit-transform: rotate(-45deg); + } - &.left { - transform: rotate(135deg); - -webkit-transform: rotate(135deg); - } + &.left { + transform: rotate(135deg); + -webkit-transform: rotate(135deg); + } - &.up { - transform: rotate(-135deg); - -webkit-transform: rotate(-135deg); - } + &.up { + transform: rotate(-135deg); + -webkit-transform: rotate(-135deg); + } - &.down { - transform: rotate(45deg); - -webkit-transform: rotate(45deg); + &.down { + transform: rotate(45deg); + -webkit-transform: rotate(45deg); + } } } \ No newline at end of file diff --git a/shared/css/static/overlay-image-preview.scss b/shared/css/static/overlay-image-preview.scss index 22328c84..55a042b4 100644 --- a/shared/css/static/overlay-image-preview.scss +++ b/shared/css/static/overlay-image-preview.scss @@ -1,88 +1,90 @@ @import "mixin"; -.overlay-image-preview { - position: absolute; - z-index: 1000; - - pointer-events: all; - - top: 0; - bottom: 0; - left: 0; - right: 0; - - opacity: 1; - background-color: #000000EF; - - display: flex; - flex-direction: column; - justify-content: center; - - .container-menu-bar { +:global { + .overlay-image-preview { position: absolute; + z-index: 1000; - top: .25em; + pointer-events: all; + + top: 0; + bottom: 0; left: 0; - right: .25em; + right: 0; - display: flex; - flex-direction: row; - justify-content: flex-end; - - .entry { - display: flex; - flex-direction: column; - justify-content: center; - font-size: 2em; - - margin: .25em; - padding: .15em; - - border-radius: .125em; - - cursor: pointer; - - .container-icon { - width: 1em; - height: 1em; - display: flex; - - img { - height: 100%; - width: 100%; - } - } - - &:hover { - background-color: #FFFFFF1F; - } - } - } - - .container-image { - max-width: 90%; - max-height: 90%; - align-self: center; + opacity: 1; + background-color: #000000EF; display: flex; flex-direction: column; - justify-content: stretch; + justify-content: center; - img { - flex-shrink: 1; + .container-menu-bar { + position: absolute; - min-height: 1em; - min-width: 1em; + top: .25em; + left: 0; + right: .25em; - max-height: 100%; - max-width: 100%; + display: flex; + flex-direction: row; + justify-content: flex-end; + + .entry { + display: flex; + flex-direction: column; + justify-content: center; + font-size: 2em; + + margin: .25em; + padding: .15em; + + border-radius: .125em; + + cursor: pointer; + + .container-icon { + width: 1em; + height: 1em; + display: flex; + + img { + height: 100%; + width: 100%; + } + } + + &:hover { + background-color: #FFFFFF1F; + } + } } - } - &.hidden { - pointer-events: none; - opacity: 0; - } + .container-image { + max-width: 90%; + max-height: 90%; + align-self: center; - @include transition(ease-in-out .25s); + display: flex; + flex-direction: column; + justify-content: stretch; + + img { + flex-shrink: 1; + + min-height: 1em; + min-width: 1em; + + max-height: 100%; + max-width: 100%; + } + } + + &.hidden { + pointer-events: none; + opacity: 0; + } + + @include transition(ease-in-out .25s); + } } \ No newline at end of file diff --git a/shared/css/static/scroll.scss b/shared/css/static/scroll.scss deleted file mode 100644 index 2548b437..00000000 --- a/shared/css/static/scroll.scss +++ /dev/null @@ -1,41 +0,0 @@ -.scroll-left { - height: 100%; - overflow: hidden; - position: relative; -} -.scroll-left p { - position: absolute; - width: max-content; - height: 100%; - margin: 0; - text-align: center; - /* Starting position */ - -moz-transform:translateX(100%); - -webkit-transform:translateX(100%); - transform:translateX(100%); - /* Apply animation to this element */ - -moz-animation: scroll-left 10s linear infinite; - -webkit-animation: scroll-left 10s linear infinite; - animation: scroll-left 10s linear infinite; -} -/* Move it (define the animation) */ -@-moz-keyframes scroll-left { - 0% { -moz-transform: translateX(100%); } - 100% { -moz-transform: translateX(-100%); } -} -@-webkit-keyframes scroll-left { - 0% { -webkit-transform: translateX(100%); } - 100% { -webkit-transform: translateX(-100%); } -} -@keyframes scroll-left { - 0% { - -moz-transform: translateX(100%); /* Browser bug fix */ - -webkit-transform: translateX(100%); /* Browser bug fix */ - transform: translateX(100%); - } - 100% { - -moz-transform: translateX(-100%); /* Browser bug fix */ - -webkit-transform: translateX(-100%); /* Browser bug fix */ - transform: translateX(-100%); - } -} \ No newline at end of file diff --git a/shared/css/static/server-log.scss b/shared/css/static/server-log.scss deleted file mode 100644 index 173d179c..00000000 --- a/shared/css/static/server-log.scss +++ /dev/null @@ -1,63 +0,0 @@ -@import "mixin"; - -html:root { - --server-log-text: #6e6e6e; - --server-log-error: #e62222; - --server-log-tree-entry: #d8d8d8; -} - -.container-log { - display: block; - overflow-y: auto; - - height: 100%; - width: 100%; - - @include chat-scrollbar-vertical(); - @include chat-scrollbar-horizontal(); - - .container-messages { - width: 100%; - line-height: 16px; - } - - .log-message { - flex-shrink: 0; - flex-grow: 0; - - color: var(--server-log-text); - - overflow-x: hidden; - overflow-y: hidden; - - display: block; - - &, > * { - overflow-wrap: break-word; - word-wrap: break-word; - - max-width: 100%; - } - - > * { - display: inline-block; - - font-family: sans-serif; - font-size: 13px; - line-height: initial; - } - - > .timestamp { - padding-right: 5px; - } - - - .log-error { - color: var(--server-log-error); - } - - .htmltag-client, .htmltag-channel { - color: var(--server-log-tree-entry); - } - } -} \ No newline at end of file diff --git a/shared/css/static/ts/country.scss b/shared/css/static/ts/country.scss index 06b751ae..2516e61f 100644 --- a/shared/css/static/ts/country.scss +++ b/shared/css/static/ts/country.scss @@ -1,1010 +1,1012 @@ -.country { - width: 16px; - height: 11px; - background: url('../../../img/ts/country_icons.png'), url('./img/ts/country_icons.png') no-repeat; +:global { + .country { + width: 16px; + height: 11px; + background: url('../../../img/ts/country_icons.png') no-repeat; - flex-shrink: 0; - flex-grow: 0; + flex-shrink: 0; + flex-grow: 0; - background-position: 0 -2717px; /* by default use global flag */ -} + background-position: 0 -2717px; /* by default use global flag */ + } -.country.flag-ad { - background-position: 0 -11px -} + .country.flag-ad { + background-position: 0 -11px + } -.country.flag-ae { - background-position: 0 -22px -} + .country.flag-ae { + background-position: 0 -22px + } -.country.flag-af { - background-position: 0 -33px -} + .country.flag-af { + background-position: 0 -33px + } -.country.flag-ag { - background-position: 0 -44px -} + .country.flag-ag { + background-position: 0 -44px + } -.country.flag-ai { - background-position: 0 -55px -} + .country.flag-ai { + background-position: 0 -55px + } -.country.flag-al { - background-position: 0 -66px -} + .country.flag-al { + background-position: 0 -66px + } -.country.flag-am { - background-position: 0 -77px -} + .country.flag-am { + background-position: 0 -77px + } -.country.flag-an { - background-position: 0 -88px -} + .country.flag-an { + background-position: 0 -88px + } -.country.flag-ao { - background-position: 0 -99px -} + .country.flag-ao { + background-position: 0 -99px + } -.country.flag-ar { - background-position: 0 -110px -} + .country.flag-ar { + background-position: 0 -110px + } -.country.flag-as { - background-position: 0 -121px -} + .country.flag-as { + background-position: 0 -121px + } -.country.flag-at { - background-position: 0 -132px -} + .country.flag-at { + background-position: 0 -132px + } -.country.flag-au { - background-position: 0 -143px -} + .country.flag-au { + background-position: 0 -143px + } -.country.flag-aw { - background-position: 0 -154px -} + .country.flag-aw { + background-position: 0 -154px + } -.country.flag-ax { - background-position: 0 -165px -} + .country.flag-ax { + background-position: 0 -165px + } -.country.flag-az { - background-position: 0 -176px -} + .country.flag-az { + background-position: 0 -176px + } -.country.flag-ba { - background-position: 0 -187px -} + .country.flag-ba { + background-position: 0 -187px + } -.country.flag-bb { - background-position: 0 -198px -} + .country.flag-bb { + background-position: 0 -198px + } -.country.flag-bd { - background-position: 0 -209px -} + .country.flag-bd { + background-position: 0 -209px + } -.country.flag-be { - background-position: 0 -220px -} + .country.flag-be { + background-position: 0 -220px + } -.country.flag-bf { - background-position: 0 -231px -} + .country.flag-bf { + background-position: 0 -231px + } -.country.flag-bg { - background-position: 0 -242px -} + .country.flag-bg { + background-position: 0 -242px + } -.country.flag-bh { - background-position: 0 -253px -} + .country.flag-bh { + background-position: 0 -253px + } -.country.flag-bi { - background-position: 0 -264px -} + .country.flag-bi { + background-position: 0 -264px + } -.country.flag-bj { - background-position: 0 -275px -} + .country.flag-bj { + background-position: 0 -275px + } -.country.flag-bl { - background-position: 0 -286px -} + .country.flag-bl { + background-position: 0 -286px + } -.country.flag-bm { - background-position: 0 -297px -} + .country.flag-bm { + background-position: 0 -297px + } -.country.flag-bn { - background-position: 0 -308px -} + .country.flag-bn { + background-position: 0 -308px + } -.country.flag-bo { - background-position: 0 -319px -} + .country.flag-bo { + background-position: 0 -319px + } -.country.flag-br { - background-position: 0 -330px -} + .country.flag-br { + background-position: 0 -330px + } -.country.flag-bs { - background-position: 0 -341px -} + .country.flag-bs { + background-position: 0 -341px + } -.country.flag-bt { - background-position: 0 -352px -} + .country.flag-bt { + background-position: 0 -352px + } -.country.flag-bv { - background-position: 0 -363px -} + .country.flag-bv { + background-position: 0 -363px + } -.country.flag-bw { - background-position: 0 -374px -} + .country.flag-bw { + background-position: 0 -374px + } -.country.flag-by { - background-position: 0 -385px -} + .country.flag-by { + background-position: 0 -385px + } -.country.flag-bz { - background-position: 0 -396px -} + .country.flag-bz { + background-position: 0 -396px + } -.country.flag-ca { - background-position: 0 -407px -} + .country.flag-ca { + background-position: 0 -407px + } -.country.flag-cc { - background-position: 0 -418px -} + .country.flag-cc { + background-position: 0 -418px + } -.country.flag-cd { - background-position: 0 -429px -} + .country.flag-cd { + background-position: 0 -429px + } -.country.flag-cf { - background-position: 0 -440px -} + .country.flag-cf { + background-position: 0 -440px + } -.country.flag-cg { - background-position: 0 -451px -} + .country.flag-cg { + background-position: 0 -451px + } -.country.flag-ch { - background-position: 0 -462px -} + .country.flag-ch { + background-position: 0 -462px + } -.country.flag-ci { - background-position: 0 -473px -} + .country.flag-ci { + background-position: 0 -473px + } -.country.flag-ck { - background-position: 0 -484px -} + .country.flag-ck { + background-position: 0 -484px + } -.country.flag-cl { - background-position: 0 -495px -} + .country.flag-cl { + background-position: 0 -495px + } -.country.flag-cm { - background-position: 0 -506px -} + .country.flag-cm { + background-position: 0 -506px + } -.country.flag-cn { - background-position: 0 -517px -} + .country.flag-cn { + background-position: 0 -517px + } -.country.flag-co { - background-position: 0 -528px -} + .country.flag-co { + background-position: 0 -528px + } -.country.flag-cr { - background-position: 0 -539px -} + .country.flag-cr { + background-position: 0 -539px + } -.country.flag-cs { - background-position: 0 -550px -} + .country.flag-cs { + background-position: 0 -550px + } -.country.flag-cu { - background-position: 0 -561px -} + .country.flag-cu { + background-position: 0 -561px + } -.country.flag-cv { - background-position: 0 -572px -} + .country.flag-cv { + background-position: 0 -572px + } -.country.flag-cx { - background-position: 0 -583px -} + .country.flag-cx { + background-position: 0 -583px + } -.country.flag-cy { - background-position: 0 -594px -} + .country.flag-cy { + background-position: 0 -594px + } -.country.flag-cz { - background-position: 0 -605px -} + .country.flag-cz { + background-position: 0 -605px + } -.country.flag-de { - background-position: 0 -616px -} + .country.flag-de { + background-position: 0 -616px + } -.country.flag-dj { - background-position: 0 -627px -} + .country.flag-dj { + background-position: 0 -627px + } -.country.flag-dk { - background-position: 0 -638px -} + .country.flag-dk { + background-position: 0 -638px + } -.country.flag-dm { - background-position: 0 -649px -} + .country.flag-dm { + background-position: 0 -649px + } -.country.flag-do { - background-position: 0 -660px -} + .country.flag-do { + background-position: 0 -660px + } -.country.flag-dz { - background-position: 0 -671px -} + .country.flag-dz { + background-position: 0 -671px + } -.country.flag-ec { - background-position: 0 -682px -} + .country.flag-ec { + background-position: 0 -682px + } -.country.flag-ee { - background-position: 0 -693px -} + .country.flag-ee { + background-position: 0 -693px + } -.country.flag-eg { - background-position: 0 -704px -} + .country.flag-eg { + background-position: 0 -704px + } -.country.flag-eh { - background-position: 0 -715px -} + .country.flag-eh { + background-position: 0 -715px + } -.country.flag-er { - background-position: 0 -726px -} + .country.flag-er { + background-position: 0 -726px + } -.country.flag-es { - background-position: 0 -737px -} + .country.flag-es { + background-position: 0 -737px + } -.country.flag-et { - background-position: 0 -748px -} + .country.flag-et { + background-position: 0 -748px + } -.country.flag-fi { - background-position: 0 -759px -} + .country.flag-fi { + background-position: 0 -759px + } -.country.flag-fj { - background-position: 0 -770px -} + .country.flag-fj { + background-position: 0 -770px + } -.country.flag-fk { - background-position: 0 -781px -} + .country.flag-fk { + background-position: 0 -781px + } -.country.flag-fm { - background-position: 0 -792px -} + .country.flag-fm { + background-position: 0 -792px + } -.country.flag-fo { - background-position: 0 -803px -} + .country.flag-fo { + background-position: 0 -803px + } -.country.flag-fr { - background-position: 0 -814px -} + .country.flag-fr { + background-position: 0 -814px + } -.country.flag-ga { - background-position: 0 -825px -} + .country.flag-ga { + background-position: 0 -825px + } -.country.flag-gb { - background-position: 0 -836px -} + .country.flag-gb { + background-position: 0 -836px + } -.country.flag-gd { - background-position: 0 -847px -} + .country.flag-gd { + background-position: 0 -847px + } -.country.flag-ge { - background-position: 0 -858px -} + .country.flag-ge { + background-position: 0 -858px + } -.country.flag-gf { - background-position: 0 -869px -} + .country.flag-gf { + background-position: 0 -869px + } -.country.flag-gg { - background-position: 0 -880px -} + .country.flag-gg { + background-position: 0 -880px + } -.country.flag-gh { - background-position: 0 -891px -} + .country.flag-gh { + background-position: 0 -891px + } -.country.flag-gi { - background-position: 0 -902px -} + .country.flag-gi { + background-position: 0 -902px + } -.country.flag-gl { - background-position: 0 -913px -} + .country.flag-gl { + background-position: 0 -913px + } -.country.flag-gm { - background-position: 0 -924px -} + .country.flag-gm { + background-position: 0 -924px + } -.country.flag-gn { - background-position: 0 -935px -} + .country.flag-gn { + background-position: 0 -935px + } -.country.flag-gp { - background-position: 0 -946px -} + .country.flag-gp { + background-position: 0 -946px + } -.country.flag-gq { - background-position: 0 -957px -} + .country.flag-gq { + background-position: 0 -957px + } -.country.flag-gr { - background-position: 0 -968px -} + .country.flag-gr { + background-position: 0 -968px + } -.country.flag-gs { - background-position: 0 -979px -} + .country.flag-gs { + background-position: 0 -979px + } -.country.flag-gt { - background-position: 0 -990px -} + .country.flag-gt { + background-position: 0 -990px + } -.country.flag-gu { - background-position: 0 -1001px -} + .country.flag-gu { + background-position: 0 -1001px + } -.country.flag-gw { - background-position: 0 -1012px -} + .country.flag-gw { + background-position: 0 -1012px + } -.country.flag-gy { - background-position: 0 -1023px -} + .country.flag-gy { + background-position: 0 -1023px + } -.country.flag-hk { - background-position: 0 -1034px -} + .country.flag-hk { + background-position: 0 -1034px + } -.country.flag-hm { - background-position: 0 -1045px -} + .country.flag-hm { + background-position: 0 -1045px + } -.country.flag-hn { - background-position: 0 -1056px -} + .country.flag-hn { + background-position: 0 -1056px + } -.country.flag-hr { - background-position: 0 -1067px -} + .country.flag-hr { + background-position: 0 -1067px + } -.country.flag-ht { - background-position: 0 -1078px -} + .country.flag-ht { + background-position: 0 -1078px + } -.country.flag-hu { - background-position: 0 -1089px -} + .country.flag-hu { + background-position: 0 -1089px + } -.country.flag-id { - background-position: 0 -1100px -} + .country.flag-id { + background-position: 0 -1100px + } -.country.flag-ie { - background-position: 0 -1111px -} + .country.flag-ie { + background-position: 0 -1111px + } -.country.flag-il { - background-position: 0 -1122px -} + .country.flag-il { + background-position: 0 -1122px + } -.country.flag-im { - background-position: 0 -1133px -} + .country.flag-im { + background-position: 0 -1133px + } -.country.flag-in { - background-position: 0 -1144px -} + .country.flag-in { + background-position: 0 -1144px + } -.country.flag-io { - background-position: 0 -1155px -} + .country.flag-io { + background-position: 0 -1155px + } -.country.flag-iq { - background-position: 0 -1166px -} + .country.flag-iq { + background-position: 0 -1166px + } -.country.flag-ir { - background-position: 0 -1177px -} + .country.flag-ir { + background-position: 0 -1177px + } -.country.flag-is { - background-position: 0 -1188px -} + .country.flag-is { + background-position: 0 -1188px + } -.country.flag-it { - background-position: 0 -1199px -} + .country.flag-it { + background-position: 0 -1199px + } -.country.flag-je { - background-position: 0 -1210px -} + .country.flag-je { + background-position: 0 -1210px + } -.country.flag-jm { - background-position: 0 -1221px -} + .country.flag-jm { + background-position: 0 -1221px + } -.country.flag-jo { - background-position: 0 -1232px -} + .country.flag-jo { + background-position: 0 -1232px + } -.country.flag-jp { - background-position: 0 -1243px -} + .country.flag-jp { + background-position: 0 -1243px + } -.country.flag-ke { - background-position: 0 -1254px -} + .country.flag-ke { + background-position: 0 -1254px + } -.country.flag-kg { - background-position: 0 -1265px -} + .country.flag-kg { + background-position: 0 -1265px + } -.country.flag-kh { - background-position: 0 -1276px -} + .country.flag-kh { + background-position: 0 -1276px + } -.country.flag-ki { - background-position: 0 -1287px -} + .country.flag-ki { + background-position: 0 -1287px + } -.country.flag-km { - background-position: 0 -1298px -} + .country.flag-km { + background-position: 0 -1298px + } -.country.flag-kn { - background-position: 0 -1309px -} + .country.flag-kn { + background-position: 0 -1309px + } -.country.flag-kp { - background-position: 0 -1320px -} + .country.flag-kp { + background-position: 0 -1320px + } -.country.flag-kr { - background-position: 0 -1331px -} + .country.flag-kr { + background-position: 0 -1331px + } -.country.flag-kw { - background-position: 0 -1342px -} + .country.flag-kw { + background-position: 0 -1342px + } -.country.flag-ky { - background-position: 0 -1353px -} + .country.flag-ky { + background-position: 0 -1353px + } -.country.flag-kz { - background-position: 0 -1364px -} + .country.flag-kz { + background-position: 0 -1364px + } -.country.flag-la { - background-position: 0 -1375px -} + .country.flag-la { + background-position: 0 -1375px + } -.country.flag-lb { - background-position: 0 -1386px -} + .country.flag-lb { + background-position: 0 -1386px + } -.country.flag-lc { - background-position: 0 -1397px -} + .country.flag-lc { + background-position: 0 -1397px + } -.country.flag-li { - background-position: 0 -1408px -} + .country.flag-li { + background-position: 0 -1408px + } -.country.flag-lk { - background-position: 0 -1419px -} + .country.flag-lk { + background-position: 0 -1419px + } -.country.flag-lr { - background-position: 0 -1430px -} + .country.flag-lr { + background-position: 0 -1430px + } -.country.flag-ls { - background-position: 0 -1441px -} + .country.flag-ls { + background-position: 0 -1441px + } -.country.flag-lt { - background-position: 0 -1452px -} + .country.flag-lt { + background-position: 0 -1452px + } -.country.flag-lu { - background-position: 0 -1463px -} + .country.flag-lu { + background-position: 0 -1463px + } -.country.flag-lv { - background-position: 0 -1474px -} + .country.flag-lv { + background-position: 0 -1474px + } -.country.flag-ly { - background-position: 0 -1485px -} + .country.flag-ly { + background-position: 0 -1485px + } -.country.flag-ma { - background-position: 0 -1496px -} + .country.flag-ma { + background-position: 0 -1496px + } -.country.flag-mc { - background-position: 0 -1507px -} + .country.flag-mc { + background-position: 0 -1507px + } -.country.flag-md { - background-position: 0 -1518px -} + .country.flag-md { + background-position: 0 -1518px + } -.country.flag-me { - background-position: 0 -1529px -} + .country.flag-me { + background-position: 0 -1529px + } -.country.flag-mg { - background-position: 0 -1540px -} + .country.flag-mg { + background-position: 0 -1540px + } -.country.flag-mh { - background-position: 0 -1551px -} + .country.flag-mh { + background-position: 0 -1551px + } -.country.flag-mk { - background-position: 0 -1562px -} + .country.flag-mk { + background-position: 0 -1562px + } -.country.flag-ml { - background-position: 0 -1573px -} + .country.flag-ml { + background-position: 0 -1573px + } -.country.flag-mm { - background-position: 0 -1584px -} + .country.flag-mm { + background-position: 0 -1584px + } -.country.flag-mn { - background-position: 0 -1595px -} + .country.flag-mn { + background-position: 0 -1595px + } -.country.flag-mo { - background-position: 0 -1606px -} + .country.flag-mo { + background-position: 0 -1606px + } -.country.flag-mp { - background-position: 0 -1617px -} + .country.flag-mp { + background-position: 0 -1617px + } -.country.flag-mq { - background-position: 0 -1628px -} + .country.flag-mq { + background-position: 0 -1628px + } -.country.flag-mr { - background-position: 0 -1639px -} + .country.flag-mr { + background-position: 0 -1639px + } -.country.flag-ms { - background-position: 0 -1650px -} + .country.flag-ms { + background-position: 0 -1650px + } -.country.flag-mt { - background-position: 0 -1661px -} + .country.flag-mt { + background-position: 0 -1661px + } -.country.flag-mu { - background-position: 0 -1672px -} + .country.flag-mu { + background-position: 0 -1672px + } -.country.flag-mv { - background-position: 0 -1683px -} + .country.flag-mv { + background-position: 0 -1683px + } -.country.flag-mw { - background-position: 0 -1694px -} + .country.flag-mw { + background-position: 0 -1694px + } -.country.flag-mx { - background-position: 0 -1705px -} + .country.flag-mx { + background-position: 0 -1705px + } -.country.flag-my { - background-position: 0 -1716px -} + .country.flag-my { + background-position: 0 -1716px + } -.country.flag-mz { - background-position: 0 -1727px -} + .country.flag-mz { + background-position: 0 -1727px + } -.country.flag-na { - background-position: 0 -1738px -} + .country.flag-na { + background-position: 0 -1738px + } -.country.flag-nc { - background-position: 0 -1749px -} + .country.flag-nc { + background-position: 0 -1749px + } -.country.flag-ne { - background-position: 0 -1760px -} + .country.flag-ne { + background-position: 0 -1760px + } -.country.flag-nf { - background-position: 0 -1771px -} + .country.flag-nf { + background-position: 0 -1771px + } -.country.flag-ng { - background-position: 0 -1782px -} + .country.flag-ng { + background-position: 0 -1782px + } -.country.flag-ni { - background-position: 0 -1793px -} + .country.flag-ni { + background-position: 0 -1793px + } -.country.flag-nl { - background-position: 0 -1804px -} + .country.flag-nl { + background-position: 0 -1804px + } -.country.flag-no { - background-position: 0 -1815px -} + .country.flag-no { + background-position: 0 -1815px + } -.country.flag-np { - background-position: 0 -1826px -} + .country.flag-np { + background-position: 0 -1826px + } -.country.flag-nr { - background-position: 0 -1837px -} + .country.flag-nr { + background-position: 0 -1837px + } -.country.flag-nu { - background-position: 0 -1848px -} + .country.flag-nu { + background-position: 0 -1848px + } -.country.flag-nz { - background-position: 0 -1859px -} + .country.flag-nz { + background-position: 0 -1859px + } -.country.flag-om { - background-position: 0 -1870px -} + .country.flag-om { + background-position: 0 -1870px + } -.country.flag-pa { - background-position: 0 -1881px -} + .country.flag-pa { + background-position: 0 -1881px + } -.country.flag-pe { - background-position: 0 -1892px -} + .country.flag-pe { + background-position: 0 -1892px + } -.country.flag-pf { - background-position: 0 -1903px -} + .country.flag-pf { + background-position: 0 -1903px + } -.country.flag-pg { - background-position: 0 -1914px -} + .country.flag-pg { + background-position: 0 -1914px + } -.country.flag-ph { - background-position: 0 -1925px -} + .country.flag-ph { + background-position: 0 -1925px + } -.country.flag-pk { - background-position: 0 -1936px -} + .country.flag-pk { + background-position: 0 -1936px + } -.country.flag-pl { - background-position: 0 -1947px -} + .country.flag-pl { + background-position: 0 -1947px + } -.country.flag-pm { - background-position: 0 -1958px -} + .country.flag-pm { + background-position: 0 -1958px + } -.country.flag-pn { - background-position: 0 -1969px -} + .country.flag-pn { + background-position: 0 -1969px + } -.country.flag-pr { - background-position: 0 -1980px -} + .country.flag-pr { + background-position: 0 -1980px + } -.country.flag-ps { - background-position: 0 -1991px -} + .country.flag-ps { + background-position: 0 -1991px + } -.country.flag-pt { - background-position: 0 -2002px -} + .country.flag-pt { + background-position: 0 -2002px + } -.country.flag-pw { - background-position: 0 -2013px -} + .country.flag-pw { + background-position: 0 -2013px + } -.country.flag-py { - background-position: 0 -2024px -} + .country.flag-py { + background-position: 0 -2024px + } -.country.flag-qa { - background-position: 0 -2035px -} + .country.flag-qa { + background-position: 0 -2035px + } -.country.flag-re { - background-position: 0 -2046px -} + .country.flag-re { + background-position: 0 -2046px + } -.country.flag-ro { - background-position: 0 -2057px -} + .country.flag-ro { + background-position: 0 -2057px + } -.country.flag-rs { - background-position: 0 -2068px -} + .country.flag-rs { + background-position: 0 -2068px + } -.country.flag-ru { - background-position: 0 -2079px -} + .country.flag-ru { + background-position: 0 -2079px + } -.country.flag-rw { - background-position: 0 -2090px -} + .country.flag-rw { + background-position: 0 -2090px + } -.country.flag-sa { - background-position: 0 -2101px -} + .country.flag-sa { + background-position: 0 -2101px + } -.country.flag-sb { - background-position: 0 -2112px -} + .country.flag-sb { + background-position: 0 -2112px + } -.country.flag-sc { - background-position: 0 -2123px -} + .country.flag-sc { + background-position: 0 -2123px + } -.country.flag-sd { - background-position: 0 -2134px -} + .country.flag-sd { + background-position: 0 -2134px + } -.country.flag-se { - background-position: 0 -2145px -} + .country.flag-se { + background-position: 0 -2145px + } -.country.flag-sg { - background-position: 0 -2156px -} + .country.flag-sg { + background-position: 0 -2156px + } -.country.flag-sh { - background-position: 0 -2167px -} + .country.flag-sh { + background-position: 0 -2167px + } -.country.flag-si { - background-position: 0 -2178px -} + .country.flag-si { + background-position: 0 -2178px + } -.country.flag-sj { - background-position: 0 -2189px -} + .country.flag-sj { + background-position: 0 -2189px + } -.country.flag-sk { - background-position: 0 -2200px -} + .country.flag-sk { + background-position: 0 -2200px + } -.country.flag-sl { - background-position: 0 -2211px -} + .country.flag-sl { + background-position: 0 -2211px + } -.country.flag-sm { - background-position: 0 -2222px -} + .country.flag-sm { + background-position: 0 -2222px + } -.country.flag-sn { - background-position: 0 -2233px -} + .country.flag-sn { + background-position: 0 -2233px + } -.country.flag-so { - background-position: 0 -2244px -} + .country.flag-so { + background-position: 0 -2244px + } -.country.flag-sr { - background-position: 0 -2255px -} + .country.flag-sr { + background-position: 0 -2255px + } -.country.flag-st { - background-position: 0 -2266px -} + .country.flag-st { + background-position: 0 -2266px + } -.country.flag-sv { - background-position: 0 -2277px -} + .country.flag-sv { + background-position: 0 -2277px + } -.country.flag-sy { - background-position: 0 -2288px -} + .country.flag-sy { + background-position: 0 -2288px + } -.country.flag-sz { - background-position: 0 -2299px -} + .country.flag-sz { + background-position: 0 -2299px + } -.country.flag-tc { - background-position: 0 -2310px -} + .country.flag-tc { + background-position: 0 -2310px + } -.country.flag-td { - background-position: 0 -2321px -} + .country.flag-td { + background-position: 0 -2321px + } -.country.flag-tf { - background-position: 0 -2332px -} + .country.flag-tf { + background-position: 0 -2332px + } -.country.flag-tg { - background-position: 0 -2343px -} + .country.flag-tg { + background-position: 0 -2343px + } -.country.flag-th { - background-position: 0 -2354px -} + .country.flag-th { + background-position: 0 -2354px + } -.country.flag-tj { - background-position: 0 -2365px -} + .country.flag-tj { + background-position: 0 -2365px + } -.country.flag-tk { - background-position: 0 -2376px -} + .country.flag-tk { + background-position: 0 -2376px + } -.country.flag-tl { - background-position: 0 -2387px -} + .country.flag-tl { + background-position: 0 -2387px + } -.country.flag-tm { - background-position: 0 -2398px -} + .country.flag-tm { + background-position: 0 -2398px + } -.country.flag-tn { - background-position: 0 -2409px -} + .country.flag-tn { + background-position: 0 -2409px + } -.country.flag-to { - background-position: 0 -2420px -} + .country.flag-to { + background-position: 0 -2420px + } -.country.flag-tr { - background-position: 0 -2431px -} + .country.flag-tr { + background-position: 0 -2431px + } -.country.flag-tt { - background-position: 0 -2442px -} + .country.flag-tt { + background-position: 0 -2442px + } -.country.flag-tv { - background-position: 0 -2453px -} + .country.flag-tv { + background-position: 0 -2453px + } -.country.flag-tw { - background-position: 0 -2464px -} + .country.flag-tw { + background-position: 0 -2464px + } -.country.flag-tz { - background-position: 0 -2475px -} + .country.flag-tz { + background-position: 0 -2475px + } -.country.flag-ua { - background-position: 0 -2486px -} + .country.flag-ua { + background-position: 0 -2486px + } -.country.flag-ug { - background-position: 0 -2497px -} + .country.flag-ug { + background-position: 0 -2497px + } -.country.flag-uk { - background-position: 0 -2508px -} + .country.flag-uk { + background-position: 0 -2508px + } -.country.flag-um { - background-position: 0 -2519px -} + .country.flag-um { + background-position: 0 -2519px + } -.country.flag-us { - background-position: 0 -2530px -} + .country.flag-us { + background-position: 0 -2530px + } -.country.flag-uy { - background-position: 0 -2541px -} + .country.flag-uy { + background-position: 0 -2541px + } -.country.flag-uz { - background-position: 0 -2552px -} + .country.flag-uz { + background-position: 0 -2552px + } -.country.flag-va { - background-position: 0 -2563px -} + .country.flag-va { + background-position: 0 -2563px + } -.country.flag-vc { - background-position: 0 -2574px -} + .country.flag-vc { + background-position: 0 -2574px + } -.country.flag-ve { - background-position: 0 -2585px -} + .country.flag-ve { + background-position: 0 -2585px + } -.country.flag-vg { - background-position: 0 -2596px -} + .country.flag-vg { + background-position: 0 -2596px + } -.country.flag-vi { - background-position: 0 -2607px -} + .country.flag-vi { + background-position: 0 -2607px + } -.country.flag-vn { - background-position: 0 -2618px -} + .country.flag-vn { + background-position: 0 -2618px + } -.country.flag-vu { - background-position: 0 -2629px -} + .country.flag-vu { + background-position: 0 -2629px + } -.country.flag-wf { - background-position: 0 -2640px -} + .country.flag-wf { + background-position: 0 -2640px + } -.country.flag-ws { - background-position: 0 -2651px -} + .country.flag-ws { + background-position: 0 -2651px + } -.country.flag-ye { - background-position: 0 -2662px -} + .country.flag-ye { + background-position: 0 -2662px + } -.country.flag-yt { - background-position: 0 -2673px -} + .country.flag-yt { + background-position: 0 -2673px + } -.country.flag-za { - background-position: 0 -2684px -} + .country.flag-za { + background-position: 0 -2684px + } -.country.flag-zm { - background-position: 0 -2695px -} + .country.flag-zm { + background-position: 0 -2695px + } -.country.flag-zw { - background-position: 0 -2706px -} + .country.flag-zw { + background-position: 0 -2706px + } -.country.flag-en { - background-position: 0 -2717px -} + .country.flag-en { + background-position: 0 -2717px + } -.country.flag-eu { - background-position: 0 -2728px -} + .country.flag-eu { + background-position: 0 -2728px + } -.country.flag-uk { - background-position: 0 -2739px -} + .country.flag-uk { + background-position: 0 -2739px + } -.country.flag-unknown { - background-position: 0 -2750px -} + .country.flag-unknown { + background-position: 0 -2750px + } +} \ No newline at end of file diff --git a/shared/css/static/ts/tab.scss b/shared/css/static/ts/tab.scss index ed9616e2..6f63c5df 100644 --- a/shared/css/static/ts/tab.scss +++ b/shared/css/static/ts/tab.scss @@ -1,92 +1,94 @@ -x-tab { display:none } +:global { + x-tab { display:none } -.tab { - padding: 2px; - height: 100%; - flex-direction: column; - display: flex; - flex-grow: 1; + .tab { + padding: 2px; + height: 100%; + flex-direction: column; + display: flex; + flex-grow: 1; - min-height: 220px; /* min the header */ -} - -.tab div * { - vertical-align: middle; -} - -.tab .tab-content { - min-height: 200px; - - border-radius: 0 2px 2px 2px; - border: solid #6f6f6f; - overflow-y: hidden; - height: 100%; - padding: 2px; - - display: flex; - flex-grow: 1; - - x-content { - min-height: 0; - overflow-y: auto; - - width: 100%; + min-height: 220px; /* min the header */ } - @-moz-document url-prefix() { + .tab div * { + vertical-align: middle; + } + + .tab .tab-content { + min-height: 200px; + + border-radius: 0 2px 2px 2px; + border: solid #6f6f6f; + overflow-y: hidden; + height: 100%; + padding: 2px; + + display: flex; + flex-grow: 1; + x-content { - height: 100%; + min-height: 0; + overflow-y: auto; + + width: 100%; + } + + @-moz-document url-prefix() { + x-content { + height: 100%; + } } } -} -/* -#chat .tab-content { - flex-wrap: wrap; - display: flex; - align-items: flex-start; - height: auto; -} -*/ + /* + #chat .tab-content { + flex-wrap: wrap; + display: flex; + align-items: flex-start; + height: auto; + } + */ -.tab .tab-header { - font-family: Arial, serif; - font-size: 12px; - /*white-space: pre;*/ - line-height: 1; + .tab .tab-header { + font-family: Arial, serif; + font-size: 12px; + /*white-space: pre;*/ + line-height: 1; - max-width: 100%; - overflow: auto; - /*height: 24px;*/ - overflow-y: hidden; - white-space: nowrap; - margin-bottom: -1px; - display: flex; - user-select: none; + max-width: 100%; + overflow: auto; + /*height: 24px;*/ + overflow-y: hidden; + white-space: nowrap; + margin-bottom: -1px; + display: flex; + user-select: none; - flex-direction: row; - justify-content: stretch; - width: 100%; + flex-direction: row; + justify-content: stretch; + width: 100%; - flex-grow: 0; - flex-shrink: 0; -} + flex-grow: 0; + flex-shrink: 0; + } -.tab .tab-header .entry { - background: #5f5f5f5f; - display: inline-block; - border: 1px solid #6f6f6f; - border-radius: 2px 2px 0px 0px; - vertical-align: middle; - padding: 2px 5px; - cursor: pointer; - flex-grow: 1; -} + .tab .tab-header .entry { + background: #5f5f5f5f; + display: inline-block; + border: 1px solid #6f6f6f; + border-radius: 2px 2px 0px 0px; + vertical-align: middle; + padding: 2px 5px; + cursor: pointer; + flex-grow: 1; + } -.tab .tab-content-invisible { - display: none; -} + .tab .tab-content-invisible { + display: none; + } -.tab .tab-header .entry.selected { - background: #11111111; + .tab .tab-header .entry.selected { + background: #11111111; + } } \ No newline at end of file diff --git a/shared/generate_i18n_gtranslate.ts b/shared/generate_i18n_gtranslate.ts index 32fef229..e34f43c6 100644 --- a/shared/generate_i18n_gtranslate.ts +++ b/shared/generate_i18n_gtranslate.ts @@ -194,7 +194,7 @@ if(process_args.length < 1) { process.exit(1); } -const input_files = ["../dist/translations.json", "generated/translations_html.json"].map(e => path.join(__dirname, e)); +const input_files = ["../dist/translations.json"].map(e => path.join(__dirname, e)); const output_file = process_args[1] || path.join(__dirname, "i18n", process_args[0] + "_google_translate.translation"); (async () => { diff --git a/shared/generate_translations.sh b/shared/generate_translations.sh deleted file mode 100644 index 3e671cff..00000000 --- a/shared/generate_translations.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -cd "$(dirname "$0")" || { echo "Failed to enter base directory"; exit 1; } - -npm run trgen -- -f "$(pwd)/html/templates.html" -f "$(pwd)/html/templates/modal/newcomer.html" -f "$(pwd)/html/templates/modal/musicmanage.html" -d "$(pwd)/generated/translations_html.json"; _exit_code=$? -if [[ $_exit_code -ne 0 ]]; then - echo "Failed to generate translations file for the template files" - exit 1 -fi \ No newline at end of file diff --git a/shared/js/ui/react-elements/external-modal/ModalRenderer.scss b/shared/js/ui/react-elements/external-modal/ModalRenderer.scss index f1201346..24545dd4 100644 --- a/shared/js/ui/react-elements/external-modal/ModalRenderer.scss +++ b/shared/js/ui/react-elements/external-modal/ModalRenderer.scss @@ -1,10 +1,8 @@ @import "../../../../css/static/mixin"; /* FIXME: Remove this wired import */ -:global { - @import "../../../../css/static/general"; - @import "../../../../css/static/modal"; -} +@import "../../../../css/static/general"; +@import "../../../../css/static/modal"; html, body { margin: 0; From cce73043a6c9d38ee49c363468a27495408327e3 Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Wed, 17 Mar 2021 16:06:16 +0100 Subject: [PATCH 022/128] Cleaned up required runtime dependencies --- package.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/package.json b/package.json index d0282a73..3248692b 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,6 @@ "@types/react-color": "^3.0.4", "@types/react-dom": "^16.9.5", "@types/react-grid-layout": "^1.1.1", - "@types/react-transition-group": "^4.4.0", "@types/remarkable": "^1.7.4", "@types/sdp-transform": "^2.4.4", "@types/sha256": "^0.2.0", @@ -101,22 +100,18 @@ "highlight.js": "^10.1.1", "ip-regex": "^4.2.0", "jquery": "^3.5.1", - "jsonschema": "^1.4.0", "jsrender": "^1.0.7", "moment": "^2.24.0", "react": "^16.13.1", "react-dom": "^16.13.1", "react-grid-layout": "^1.2.2", "react-player": "^2.5.0", - "react-transition-group": "^4.4.1", "remarkable": "^2.0.1", "resize-observer-polyfill": "^1.5.1", "sdp-transform": "^2.14.0", "simple-jsonp-promise": "^1.1.0", - "simplebar-react": "^2.2.0", "twemoji": "^13.0.0", "url-knife": "^3.1.3", - "webcrypto-liner": "^1.2.3", "webpack-manifest-plugin": "^3.1.0", "webrtc-adapter": "^7.5.1" } From b7dc3f4fdc81caaec6c5469691c48007770af5ff Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Wed, 17 Mar 2021 18:05:39 +0100 Subject: [PATCH 023/128] fixed a compile error when using webpack serve --- webpack/ManifestPlugin.ts | 161 ++++++++++++++++++++------------------ 1 file changed, 86 insertions(+), 75 deletions(-) diff --git a/webpack/ManifestPlugin.ts b/webpack/ManifestPlugin.ts index fc6c59c8..84b57b47 100644 --- a/webpack/ManifestPlugin.ts +++ b/webpack/ManifestPlugin.ts @@ -1,5 +1,6 @@ import * as webpack from "webpack"; import * as path from "path"; +import {Compilation, NormalModule} from "webpack"; interface Options { outputFileName?: string; @@ -14,96 +15,106 @@ class ManifestGenerator { } apply(compiler: webpack.Compiler) { - compiler.hooks.emit.tap("ManifestGenerator", compilation => { - const chunkData = {}; - for(const chunkGroup of compilation.chunkGroups) { - const fileJs = []; - const filesCss = []; - const modules = []; + compiler.hooks.thisCompilation.tap({ + name: "ManifestGenerator", + stage: Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL + }, compilation => { + compilation.hooks.processAssets.tap("ManifestGenerator", () => this.emitAssets(compilation)); + }); + } - for(const chunk of chunkGroup.chunks) { - if(!chunk.files.size) { - continue; - } + emitAssets(compilation: webpack.Compilation) { + const chunkData = {}; - for(const file of chunk.files) { - const extension = path.extname(file); - switch (extension) { - case ".js": - fileJs.push({ - hash: chunk.hash, - file: file - }); - break; + for(const chunkGroup of compilation.chunkGroups) { + const fileJs = []; + const filesCss = []; + const modules = []; - case ".css": - filesCss.push({ - hash: chunk.hash, - file: file - }); - break; + for(const chunk of chunkGroup.chunks) { + if(!chunk.files.size) { + continue; + } - case ".wasm": - break; - - default: - throw "Unknown chunk file with extension " + extension; - } - } - - for(const module of chunk.getModules() as any[]) { - if(!module.type.startsWith("javascript/")) { - continue; - } - - if(!module.context) { - continue; - } - - if(module.context.startsWith("svg-sprites/")) { - /* custom svg sprite handler */ - modules.push({ - id: module.id, - context: "svg-sprites", - resource: module.context.substring("svg-sprites/".length) + for(const file of chunk.files) { + const extension = path.extname(file); + switch (extension) { + case ".js": + fileJs.push({ + hash: chunk.hash, + file: file }); - continue; - } + break; - if(!module.resource) { - continue; - } + case ".css": + filesCss.push({ + hash: chunk.hash, + file: file + }); + break; - if(module.context !== path.dirname(module.resource)) { - throw "invalid context/resource relation"; - } + case ".wasm": + break; - modules.push({ - id: module.id, - context: path.relative(this.options.context, module.context).replace(/\\/g, "/"), - resource: path.basename(module.resource) - }); + default: + throw "Unknown chunk file with extension " + extension; } } - chunkData[chunkGroup.options.name] = { - files: fileJs, - css_files: filesCss, - modules: modules - }; + for(const module of compilation.chunkGraph.getChunkModules(chunk)) { + if(!module.type.startsWith("javascript/")) { + continue; + } + + if(!module.context) { + continue; + } + + if(module.context.startsWith("svg-sprites/")) { + /* custom svg sprite handler */ + modules.push({ + id: module.id, + context: "svg-sprites", + resource: module.context.substring("svg-sprites/".length) + }); + continue; + } + + if(!(module instanceof NormalModule)) { + continue; + } + + if(module.resource.indexOf("webpack-dev-server") !== -1) { + /* Don't include dev server files */ + continue; + } + + if(module.context !== path.dirname(module.resource)) { + throw "invalid context/resource relation (" + module.context + " <-> " + path.dirname(module.resource) + ")"; + } + + modules.push({ + id: compilation.chunkGraph.getModuleId(module), + context: path.relative(this.options.context, module.context).replace(/\\/g, "/"), + resource: path.basename(module.resource) + }); + } } - const payload = JSON.stringify({ - version: 2, - chunks: chunkData - }); + chunkData[chunkGroup.options.name] = { + files: fileJs, + css_files: filesCss, + modules: modules + }; + } - const fileName = this.options.outputFileName || "manifest.json"; - compilation.assets[fileName] = { - size() { return payload.length; }, - source() { return payload; } - } as any; + const payload = JSON.stringify({ + version: 2, + chunks: chunkData }); + + const fileName = this.options.outputFileName || "manifest.json"; + compilation.emitAsset(fileName, new webpack.sources.RawSource(payload)); } } From 1193f4e0b194b5498c3d416f2c7de38192314b9e Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Wed, 17 Mar 2021 18:25:04 +0100 Subject: [PATCH 024/128] Updated the loader which now uses webpack assets --- file.ts | 2 +- loader/app/css/loader.scss | 16 +- loader/app/css/overlay.scss | 16 +- {shared/img/loader => loader/images}/bowl.png | Bin .../images}/halloween-initial-sequence.gif | Bin .../images}/halloween-loop.gif | Bin .../images}/initial-sequence-uncompressed.gif | Bin .../images}/initial-sequence.gif | Bin .../images}/initial-sequence.png | Bin .../img => loader/images}/loading_error.svg | 0 .../images}/loading_error_right.svg | 0 loader/images/script.svg | 66 ++ loader/{app => }/images/steam.png | Bin {shared/img/loader => loader/images}/text.png | Bin loader/index.ejs | 24 +- package-lock.json | 812 +++++------------- package.json | 4 +- webpack.config.ts | 28 +- 18 files changed, 345 insertions(+), 623 deletions(-) rename {shared/img/loader => loader/images}/bowl.png (100%) rename {shared/img/loader => loader/images}/halloween-initial-sequence.gif (100%) rename {shared/img/loader => loader/images}/halloween-loop.gif (100%) rename {shared/img/loader => loader/images}/initial-sequence-uncompressed.gif (100%) rename {shared/img/loader => loader/images}/initial-sequence.gif (100%) rename {shared/img/loader => loader/images}/initial-sequence.png (100%) rename {shared/img => loader/images}/loading_error.svg (100%) rename {shared/img => loader/images}/loading_error_right.svg (100%) create mode 100644 loader/images/script.svg rename loader/{app => }/images/steam.png (100%) rename {shared/img/loader => loader/images}/text.png (100%) diff --git a/file.ts b/file.ts index f8eb49d8..ff084d0e 100644 --- a/file.ts +++ b/file.ts @@ -32,7 +32,7 @@ type ProjectResource = { const APP_FILE_LIST_SHARED_SOURCE: ProjectResource[] = [ { /* javascript files as manifest.json */ "type": "js", - "search-pattern": /.*\.(js|json|svg|png|css|html)$/, + "search-pattern": /.*\.(js|json|svg|png|css)$/, "build-target": "dev|rel", "path": "js/", diff --git a/loader/app/css/loader.scss b/loader/app/css/loader.scss index af9eabd8..82a8c2d1 100644 --- a/loader/app/css/loader.scss +++ b/loader/app/css/loader.scss @@ -81,7 +81,7 @@ width: 249px; height: 125px; - background: url("../images/steam.png") 0 0; + background: url("../../images/steam.png") 0 0; animation: sprite-steam 2.5s steps(50) forwards infinite; } @@ -160,19 +160,19 @@ } } -@keyframes loader-initial-sequence { +@keyframes :global(loader-initial-sequence) { to { display: none; } } -@keyframes sprite-steam { +@keyframes :global(sprite-steam) { to { background-position: 0 -6250px; } } -@keyframes swipe-out-bowl { +@keyframes :global(swipe-out-bowl) { from { transform: translate3d(0, 0, 0); } @@ -188,7 +188,7 @@ } } -@keyframes swipe-out-text { +@keyframes :global(swipe-out-text) { from { transform: translate3d(0, 0, 0); } @@ -204,19 +204,19 @@ } } -@keyframes animation-nothing { +@keyframes :global(animation-nothing) { to { background-position: 0 -6250px; } } -@keyframes overlay-fade { +@keyframes :global(overlay-fade) { to { opacity: 0; } } -@keyframes loader-setup-timeout { +@keyframes :global(loader-setup-timeout) { to { opacity: 1; } diff --git a/loader/app/css/overlay.scss b/loader/app/css/overlay.scss index be486a87..bcc8c3dc 100644 --- a/loader/app/css/overlay.scss +++ b/loader/app/css/overlay.scss @@ -30,8 +30,17 @@ } } + #overlay-no-js { + display: block; + color: #999; + + svg { + fill: #999; + } + } + #critical-load { - img { + .img { height: 12em } @@ -45,6 +54,11 @@ margin-top: .5em } } + + svg { + max-height: 100%; + max-width: 100%; + } } diff --git a/shared/img/loader/bowl.png b/loader/images/bowl.png similarity index 100% rename from shared/img/loader/bowl.png rename to loader/images/bowl.png diff --git a/shared/img/loader/halloween-initial-sequence.gif b/loader/images/halloween-initial-sequence.gif similarity index 100% rename from shared/img/loader/halloween-initial-sequence.gif rename to loader/images/halloween-initial-sequence.gif diff --git a/shared/img/loader/halloween-loop.gif b/loader/images/halloween-loop.gif similarity index 100% rename from shared/img/loader/halloween-loop.gif rename to loader/images/halloween-loop.gif diff --git a/shared/img/loader/initial-sequence-uncompressed.gif b/loader/images/initial-sequence-uncompressed.gif similarity index 100% rename from shared/img/loader/initial-sequence-uncompressed.gif rename to loader/images/initial-sequence-uncompressed.gif diff --git a/shared/img/loader/initial-sequence.gif b/loader/images/initial-sequence.gif similarity index 100% rename from shared/img/loader/initial-sequence.gif rename to loader/images/initial-sequence.gif diff --git a/shared/img/loader/initial-sequence.png b/loader/images/initial-sequence.png similarity index 100% rename from shared/img/loader/initial-sequence.png rename to loader/images/initial-sequence.png diff --git a/shared/img/loading_error.svg b/loader/images/loading_error.svg similarity index 100% rename from shared/img/loading_error.svg rename to loader/images/loading_error.svg diff --git a/shared/img/loading_error_right.svg b/loader/images/loading_error_right.svg similarity index 100% rename from shared/img/loading_error_right.svg rename to loader/images/loading_error_right.svg diff --git a/loader/images/script.svg b/loader/images/script.svg new file mode 100644 index 00000000..ea32f4c0 --- /dev/null +++ b/loader/images/script.svg @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/loader/app/images/steam.png b/loader/images/steam.png similarity index 100% rename from loader/app/images/steam.png rename to loader/images/steam.png diff --git a/shared/img/loader/text.png b/loader/images/text.png similarity index 100% rename from shared/img/loader/text.png rename to loader/images/text.png diff --git a/loader/index.ejs b/loader/index.ejs index aa2289e0..5ed5eca3 100644 --- a/loader/index.ejs +++ b/loader/index.ejs @@ -40,10 +40,10 @@ gtag('config', 'UA-113151733-4'); - - + "> + "> <% /* We don't preload the bowl since it's only a div background */ %> - + "> <%= htmlWebpackPlugin.tags.headTags %> @@ -52,7 +52,9 @@