From ca83780109037ec0318c54dd434ed05dc3692373 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 23 Sep 2018 23:35:42 +0200 Subject: [PATCH] Implement theming support and add MetroMumbleDark theme --- README.md | 10 ++ app/index.html | 3 +- app/theme.js | 33 +++++ package.json | 2 + themes/MetroMumbleDark/loading.scss | 5 + themes/MetroMumbleDark/main.scss | 22 +++ .../{loading.css => loading.scss} | 10 +- .../MetroMumbleLight/{main.css => main.scss} | 128 ++++++++++++------ webpack.config.js | 10 ++ 9 files changed, 177 insertions(+), 46 deletions(-) create mode 100644 app/theme.js create mode 100644 themes/MetroMumbleDark/loading.scss create mode 100644 themes/MetroMumbleDark/main.scss rename themes/MetroMumbleLight/{loading.css => loading.scss} (69%) rename themes/MetroMumbleLight/{main.css => main.scss} (65%) diff --git a/README.md b/README.md index 870382f..8c688d1 100644 --- a/README.md +++ b/README.md @@ -86,8 +86,18 @@ map $http_upgrade $connection_upgrade { } ``` +### Themes +The default theme of mumble-web tries to mimic the excellent [MetroMumble]Light theme. +mumble-web also includes a dark version, named MetroMumbleDark, which is heavily inspired by [MetroMumble]'s dark version. + +To select a theme other than the default one, append a `theme=dark` query parameter (where `dark` is the name of the theme) when accessing the mumble-web page. +E.g. [this](https://voice.johni0702.de/?address=voice.johni0702.de&port=443/demo&theme=dark)is the live demo linked above but using the dark theme (`dark` is an alias for `MetroMumbleDark`). + +Custom themes can be created by deriving them from the MetroMumbleLight/Dark themes just like the MetroMumbleDark theme is derived from the MetroMumbleLight theme. + ### License ISC [Mumble]: https://wiki.mumble.info/wiki/Main_Page [websockify GitHub page]: https://github.com/novnc/websockify +[MetroMumble]: https://github.com/xPoke/MetroMumble diff --git a/app/index.html b/app/index.html index 8ca7ccc..f4b1d2f 100644 --- a/app/index.html +++ b/app/index.html @@ -13,7 +13,7 @@ - + @@ -340,6 +340,5 @@ - diff --git a/app/theme.js b/app/theme.js new file mode 100644 index 0000000..bc28652 --- /dev/null +++ b/app/theme.js @@ -0,0 +1,33 @@ +import url from 'url' + +var queryParams = url.parse(document.location.href, true).query +var theme = queryParams.theme || window.localStorage.getItem('mumble.theme') +var themes = { + 'MetroMumbleLight': 'MetroMumbleLight', + 'MetroMumbleDark': 'MetroMumbleDark', + 'light': 'MetroMumbleLight', + 'dark': 'MetroMumbleDark' +} +theme = themes[theme] || 'MetroMumbleLight' +window.theme = theme + +var [loadingTheme, mainTheme] = { + 'MetroMumbleLight': [ + require('../themes/MetroMumbleLight/loading.scss'), + require('../themes/MetroMumbleLight/main.scss') + ], + 'MetroMumbleDark': [ + require('../themes/MetroMumbleDark/loading.scss'), + require('../themes/MetroMumbleDark/main.scss') + ] +}[theme] + +function useStyle (url) { + var style = document.createElement('link') + style.rel = 'stylesheet' + style.type = 'text/css' + style.href = url + document.getElementsByTagName('head')[0].appendChild(style) +} +useStyle(loadingTheme) +useStyle(mainTheme) diff --git a/package.json b/package.json index 7253591..59fec02 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,10 @@ "knockout": "^3.4.0", "lodash.assign": "^4.2.0", "microphone-stream": "^3.0.5", + "node-sass": "^4.9.3", "raw-loader": "^0.5.1", "regexp-replace-loader": "0.0.1", + "sass-loader": "^4.1.1", "stream-chunker": "^1.2.8", "transform-loader": "^0.2.3", "voice-activity-detection": "johni0702/voice-activity-detection#9f8bd90", diff --git a/themes/MetroMumbleDark/loading.scss b/themes/MetroMumbleDark/loading.scss new file mode 100644 index 0000000..cca22d5 --- /dev/null +++ b/themes/MetroMumbleDark/loading.scss @@ -0,0 +1,5 @@ +$bg-color: #2c2c2c !default +$spinner-color: #888 !default +$spinner-bg-color: #222 !default + +@import '../MetroMumbleLight/loading'; diff --git a/themes/MetroMumbleDark/main.scss b/themes/MetroMumbleDark/main.scss new file mode 100644 index 0000000..815507e --- /dev/null +++ b/themes/MetroMumbleDark/main.scss @@ -0,0 +1,22 @@ +$black: #bbb !default +$darkgray: #777 !default +$gray: #555 !default +$lightgray: #555 !default +$bg-color: #2c2c2c !default +$white: #1c1c1c !default + +$lightblue: #557 !default + +$toolbar-hover-bg-color: $lightblue !default +$toolbar-hover-border-color: $lightblue !default +$toolbar-active-bg-color: $gray !default +$toolbar-active-border-color: $gray !default +$dialog-color: $black !default +$channel-selected-bg-color: $lightblue !default + +@import '../MetroMumbleLight/main'; + +.dialog-header { + color: #000; + font-weight: bold; +} diff --git a/themes/MetroMumbleLight/loading.css b/themes/MetroMumbleLight/loading.scss similarity index 69% rename from themes/MetroMumbleLight/loading.css rename to themes/MetroMumbleLight/loading.scss index b5d9a41..0448a3d 100644 --- a/themes/MetroMumbleLight/loading.css +++ b/themes/MetroMumbleLight/loading.scss @@ -1,9 +1,13 @@ +$bg-color: #eee !default +$spinner-color: #999 !default +$spinner-bg-color: #ddd !default + .loading-container { position: absolute; top: 0; width: 100%; height: 100%; - background-color: #eee; + background-color: $bg-color; z-index: 1000; } @@ -15,8 +19,8 @@ top: calc(50% - 40px); left: calc(50% - 40px); border-radius: 100%; - border: 10px solid #ddd; - border-top-color: #999; + border: 10px solid $spinner-bg-color; + border-top-color: $spinner-color; animation: spin 1s infinite linear; } diff --git a/themes/MetroMumbleLight/main.css b/themes/MetroMumbleLight/main.scss similarity index 65% rename from themes/MetroMumbleLight/main.css rename to themes/MetroMumbleLight/main.scss index 78e5e9e..4c162b6 100644 --- a/themes/MetroMumbleLight/main.css +++ b/themes/MetroMumbleLight/main.scss @@ -1,5 +1,50 @@ +$black: #000 !default +$darkgray: #888 !default +$gray: #a9a9a9 !default +$lightgray: #d3d3d3 !default +$bg-color: #eee !default +$white: #fff !default + +$font-color: $black !default +$panel-bg-color: $white !default +$panel-border-color: $lightgray !default +$channel-tree-color: $lightgray !default +$channel-hover-bg-color: $lightgray !default +$channel-selected-bg-color: lightblue !default +$channel-selected-border-color: $darkgray !default +$tooltip-border-color: $darkgray !default +$chat-channel-color: orange !default +$chat-user-color: green !default +$chat-input-color: $font-color !default +$mic-volume-border-color: $black !default + +$toolbar-hover-bg-color: $lightgray !default +$toolbar-hover-border-color: $gray !default +$toolbar-active-bg-color: $white !default +$toolbar-active-border-color: $toolbar-hover-bg-color !default +$toolbar-divider-color: $lightgray !default +$dialog-header-color: $white !default +$dialog-header-bg-color: $darkgray !default +$dialog-header-border-bottom-color: $gray !default +$dialog-bg-color: $bg-color !default +$dialog-border-color: $darkgray !default +$dialog-color: $font-color !default +$dialog-button-border-color: $darkgray !default +$dialog-button-bg-color: $white !default +$dialog-button-color: $dialog-color !default +$dialog-input-border-color: $darkgray !default +$dialog-input-bg-color: $white !default +$dialog-input-color: $dialog-color !default + +$tooltip-bg-color: $panel-bg-color !default +$channels-bg-color: $panel-bg-color !default +$channels-border-color: $panel-border-color !default +$chat-bg-color: $panel-bg-color !default +$chat-border-color: $panel-border-color !default + html, body { - background-color: #eee; + background-color: $bg-color; + color: $font-color; margin: 0; overflow: hidden; height: 100% @@ -10,8 +55,8 @@ html, body { .channel-root-container { text-size: 16px; margin-left: 2px; - background-color: white; - border: 1px solid lightgray; + background-color: $channels-bg-color; + border: 1px solid $channels-border-color; float: left; border-radius: 3px; overflow-x: hidden; @@ -44,10 +89,10 @@ html, body { height: calc(98% - 4px); } .log { - background-color: white; + background-color: $chat-bg-color; height: calc(100% - 42px); padding: 5px; - border: 1px lightgray solid; + border: 1px $chat-border-color solid; border-radius: 3px; overflow-x: hidden; overflow-y: scroll; @@ -59,8 +104,7 @@ html, body { float: left; padding-top: 3px; padding-bottom: 3px; - background-color: white; - margin-right: + background-color: $channels-bg-color; } .channel-sub { margin-left: 9px; @@ -68,7 +112,7 @@ html, body { padding-left: 9px; } .channel-wrapper:nth-last-child(n + 2) > .branch:not(:empty) + .channel-sub { - border-left: 1px lightgray solid; + border-left: 1px $channel-tree-color solid; } .channel-tree, .user-wrapper { @@ -84,8 +128,8 @@ html, body { display: block; position: relative; width: 9px; - border-left: 1px lightgray solid; - border-bottom: 1px lightgray solid; + border-left: 1px $channel-tree-color solid; + border-bottom: 1px $channel-tree-color solid; height: 14px; } .channel-wrapper:nth-last-child(n + 2) > .channel-tree:after, @@ -94,7 +138,7 @@ html, body { display: block; position: relative; width: 0px; - border-left: 1px lightgray solid; + border-left: 1px $channel-tree-color solid; height: 14px; } .user { @@ -109,12 +153,12 @@ html, body { border: 1px solid transparent; } .selected { - background-color: lightblue !important; - border: 1px solid gray; + background-color: $channel-selected-bg-color !important; + border: 1px solid $channel-selected-border-color; border-radius: 3px; } .user:hover,.channel:hover { - background-color: lightgray; + background-color: $channel-hover-bg-color; } .thisClient { font-weight: bold @@ -142,8 +186,8 @@ html, body { .tooltip { visibility: hidden; height: 0px; - background: white; - border: 1px solid gray; + background: $tooltip-bg-color; + border: 1px solid $tooltip-border-color; margin-top: 16px; margin-left: 30px; padding: 10px; @@ -162,12 +206,12 @@ html, body { border-radius: 3px; } .toolbar img:hover { - border: 1px solid #bbb; - background-color: #ddd; + border: 1px solid $toolbar-hover-bg-color; + background-color: $toolbar-hover-border-color; } .toolbar .tb-active { - border: 1px solid #bbb; - background-color: white; + border: 1px solid $toolbar-active-bg-color; + background-color: $toolbar-active-border-color; } .toolbar-horizontal { flex-direction: row; @@ -195,16 +239,16 @@ html, body { } .toolbar-horizontal .divider { height: 32px; - border-left: 1px lightgray solid; + border-left: 1px $toolbar-divider-color solid; } .toolbar-vertical .divider { width: 32px; - border-top: 1px lightgray solid; + border-top: 1px $toolbar-divider-color solid; } .toolbar-horizontal .handle-horizontal { width: auto !important; border: none !important; - background-color: #eee !important; + background-color: $bg-color !important; } .toolbar-horizontal .handle-vertical { display: none; @@ -212,7 +256,7 @@ html, body { .toolbar-vertical .handle-vertical { height: auto !important; border: none !important; - background-color: #eee !important; + background-color: $bg-color !important; } .toolbar-vertical .handle-horizontal { display: none; @@ -222,16 +266,17 @@ html, body { } .channel-tag { font-weight: bold; - color: orange; + color: $chat-channel-color; } .user-tag { font-weight: bold; - color: green; + color: $chat-user-color; } #message-box { width: 100%; border: none; background: none; + color: $chat-input-color; margin: 5px 0 5px 0; padding: 0; height: 20px; @@ -251,9 +296,9 @@ form { width: calc(100% - 10px); padding: 5px; text-align: center; - color: white; - background-color: gray; - border-bottom: 1px solid darkgray; + color: $dialog-header-color; + background-color: $dialog-header-bg-color; + border-bottom: 1px solid $dialog-header-border-bottom-color; } .dialog-footer { position: absolute; @@ -270,10 +315,10 @@ form { .dialog-close, .dialog-submit { width: 45%; font-size: 15px; - border: 1px gray solid; + border: 1px $dialog-button-border-color solid; border-radius: 3px; - background-color: white; - color: black; + background-color: $dialog-button-bg-color; + color: $dialog-button-color; padding: 1px; } .connect-dialog table { @@ -282,8 +327,9 @@ form { } .dialog { position: absolute; - background-color: #eee; - border: 1px gray solid; + background-color: $dialog-bg-color; + color: $dialog-color; + border: 1px $dialog-border-color solid; box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.25); z-index: 20; } @@ -309,7 +355,7 @@ form { } .settings-dialog .mic-volume-container { height: 10px; - border: 3px solid black; + border: 3px solid $mic-volume-border-color; } .settings-dialog .mic-volume { height: 100%; @@ -335,19 +381,19 @@ form { } .connect-dialog input[type=text] { font-size: 15px; - border: 1px gray solid; + border: 1px $dialog-input-border-color solid; border-radius: 3px; - background-color: white; - color: black; + background-color: $dialog-input-bg-color; + color: $dialog-input-color; padding: 2px; width: calc(100% - 8px); } .connect-dialog input[type=password] { font-size: 15px; - border: 1px gray solid; + border: 1px $dialog-input-border-color solid; border-radius: 3px; - background-color: white; - color: black; + background-color: $dialog-input-bg-color; + color: $dialog-input-color; padding: 2px; width: calc(100% - 8px); } diff --git a/webpack.config.js b/webpack.config.js index e388c77..74d1154 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -8,6 +8,7 @@ module.exports = { './app/index.js', './app/index.html' ], + theme: './app/theme.js', matrix: './app/matrix.js' }, output: { @@ -51,6 +52,15 @@ module.exports = { 'css-loader' ] }, + { + test: /\.scss$/, + loaders: [ + 'file-loader?name=[hash].css', + 'extract-loader', + 'css-loader', + 'sass-loader' + ] + }, { test: /manifest\.json$|\.xml$/, loaders: [