Implement theming support and add MetroMumbleDark theme

This commit is contained in:
Jonas Herzig 2018-09-23 23:35:42 +02:00
parent 0a68f28c38
commit ca83780109
9 changed files with 177 additions and 46 deletions

View file

@ -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 ### License
ISC ISC
[Mumble]: https://wiki.mumble.info/wiki/Main_Page [Mumble]: https://wiki.mumble.info/wiki/Main_Page
[websockify GitHub page]: https://github.com/novnc/websockify [websockify GitHub page]: https://github.com/novnc/websockify
[MetroMumble]: https://github.com/xPoke/MetroMumble

View file

@ -13,7 +13,7 @@
<meta name="msapplication-config" content="${require('./favicon/browserconfig.xml')}"> <meta name="msapplication-config" content="${require('./favicon/browserconfig.xml')}">
<meta name="theme-color" content="#ffffff"> <meta name="theme-color" content="#ffffff">
<link rel="stylesheet" type="text/css" href="/loading.css"> <script src="theme.js"></script>
<script src="matrix.js"></script> <script src="matrix.js"></script>
</head> </head>
@ -340,6 +340,5 @@
</div> </div>
</div> </div>
</body> </body>
<link rel="stylesheet" type="text/css" href="/main.css">
<script src="index.js"></script> <script src="index.js"></script>
</html> </html>

33
app/theme.js Normal file
View file

@ -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)

View file

@ -36,8 +36,10 @@
"knockout": "^3.4.0", "knockout": "^3.4.0",
"lodash.assign": "^4.2.0", "lodash.assign": "^4.2.0",
"microphone-stream": "^3.0.5", "microphone-stream": "^3.0.5",
"node-sass": "^4.9.3",
"raw-loader": "^0.5.1", "raw-loader": "^0.5.1",
"regexp-replace-loader": "0.0.1", "regexp-replace-loader": "0.0.1",
"sass-loader": "^4.1.1",
"stream-chunker": "^1.2.8", "stream-chunker": "^1.2.8",
"transform-loader": "^0.2.3", "transform-loader": "^0.2.3",
"voice-activity-detection": "johni0702/voice-activity-detection#9f8bd90", "voice-activity-detection": "johni0702/voice-activity-detection#9f8bd90",

View file

@ -0,0 +1,5 @@
$bg-color: #2c2c2c !default
$spinner-color: #888 !default
$spinner-bg-color: #222 !default
@import '../MetroMumbleLight/loading';

View file

@ -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;
}

View file

@ -1,9 +1,13 @@
$bg-color: #eee !default
$spinner-color: #999 !default
$spinner-bg-color: #ddd !default
.loading-container { .loading-container {
position: absolute; position: absolute;
top: 0; top: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: #eee; background-color: $bg-color;
z-index: 1000; z-index: 1000;
} }
@ -15,8 +19,8 @@
top: calc(50% - 40px); top: calc(50% - 40px);
left: calc(50% - 40px); left: calc(50% - 40px);
border-radius: 100%; border-radius: 100%;
border: 10px solid #ddd; border: 10px solid $spinner-bg-color;
border-top-color: #999; border-top-color: $spinner-color;
animation: spin 1s infinite linear; animation: spin 1s infinite linear;
} }

View file

@ -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 { html, body {
background-color: #eee; background-color: $bg-color;
color: $font-color;
margin: 0; margin: 0;
overflow: hidden; overflow: hidden;
height: 100% height: 100%
@ -10,8 +55,8 @@ html, body {
.channel-root-container { .channel-root-container {
text-size: 16px; text-size: 16px;
margin-left: 2px; margin-left: 2px;
background-color: white; background-color: $channels-bg-color;
border: 1px solid lightgray; border: 1px solid $channels-border-color;
float: left; float: left;
border-radius: 3px; border-radius: 3px;
overflow-x: hidden; overflow-x: hidden;
@ -44,10 +89,10 @@ html, body {
height: calc(98% - 4px); height: calc(98% - 4px);
} }
.log { .log {
background-color: white; background-color: $chat-bg-color;
height: calc(100% - 42px); height: calc(100% - 42px);
padding: 5px; padding: 5px;
border: 1px lightgray solid; border: 1px $chat-border-color solid;
border-radius: 3px; border-radius: 3px;
overflow-x: hidden; overflow-x: hidden;
overflow-y: scroll; overflow-y: scroll;
@ -59,8 +104,7 @@ html, body {
float: left; float: left;
padding-top: 3px; padding-top: 3px;
padding-bottom: 3px; padding-bottom: 3px;
background-color: white; background-color: $channels-bg-color;
margin-right:
} }
.channel-sub { .channel-sub {
margin-left: 9px; margin-left: 9px;
@ -68,7 +112,7 @@ html, body {
padding-left: 9px; padding-left: 9px;
} }
.channel-wrapper:nth-last-child(n + 2) > .branch:not(:empty) + .channel-sub { .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, .channel-tree,
.user-wrapper { .user-wrapper {
@ -84,8 +128,8 @@ html, body {
display: block; display: block;
position: relative; position: relative;
width: 9px; width: 9px;
border-left: 1px lightgray solid; border-left: 1px $channel-tree-color solid;
border-bottom: 1px lightgray solid; border-bottom: 1px $channel-tree-color solid;
height: 14px; height: 14px;
} }
.channel-wrapper:nth-last-child(n + 2) > .channel-tree:after, .channel-wrapper:nth-last-child(n + 2) > .channel-tree:after,
@ -94,7 +138,7 @@ html, body {
display: block; display: block;
position: relative; position: relative;
width: 0px; width: 0px;
border-left: 1px lightgray solid; border-left: 1px $channel-tree-color solid;
height: 14px; height: 14px;
} }
.user { .user {
@ -109,12 +153,12 @@ html, body {
border: 1px solid transparent; border: 1px solid transparent;
} }
.selected { .selected {
background-color: lightblue !important; background-color: $channel-selected-bg-color !important;
border: 1px solid gray; border: 1px solid $channel-selected-border-color;
border-radius: 3px; border-radius: 3px;
} }
.user:hover,.channel:hover { .user:hover,.channel:hover {
background-color: lightgray; background-color: $channel-hover-bg-color;
} }
.thisClient { .thisClient {
font-weight: bold font-weight: bold
@ -142,8 +186,8 @@ html, body {
.tooltip { .tooltip {
visibility: hidden; visibility: hidden;
height: 0px; height: 0px;
background: white; background: $tooltip-bg-color;
border: 1px solid gray; border: 1px solid $tooltip-border-color;
margin-top: 16px; margin-top: 16px;
margin-left: 30px; margin-left: 30px;
padding: 10px; padding: 10px;
@ -162,12 +206,12 @@ html, body {
border-radius: 3px; border-radius: 3px;
} }
.toolbar img:hover { .toolbar img:hover {
border: 1px solid #bbb; border: 1px solid $toolbar-hover-bg-color;
background-color: #ddd; background-color: $toolbar-hover-border-color;
} }
.toolbar .tb-active { .toolbar .tb-active {
border: 1px solid #bbb; border: 1px solid $toolbar-active-bg-color;
background-color: white; background-color: $toolbar-active-border-color;
} }
.toolbar-horizontal { .toolbar-horizontal {
flex-direction: row; flex-direction: row;
@ -195,16 +239,16 @@ html, body {
} }
.toolbar-horizontal .divider { .toolbar-horizontal .divider {
height: 32px; height: 32px;
border-left: 1px lightgray solid; border-left: 1px $toolbar-divider-color solid;
} }
.toolbar-vertical .divider { .toolbar-vertical .divider {
width: 32px; width: 32px;
border-top: 1px lightgray solid; border-top: 1px $toolbar-divider-color solid;
} }
.toolbar-horizontal .handle-horizontal { .toolbar-horizontal .handle-horizontal {
width: auto !important; width: auto !important;
border: none !important; border: none !important;
background-color: #eee !important; background-color: $bg-color !important;
} }
.toolbar-horizontal .handle-vertical { .toolbar-horizontal .handle-vertical {
display: none; display: none;
@ -212,7 +256,7 @@ html, body {
.toolbar-vertical .handle-vertical { .toolbar-vertical .handle-vertical {
height: auto !important; height: auto !important;
border: none !important; border: none !important;
background-color: #eee !important; background-color: $bg-color !important;
} }
.toolbar-vertical .handle-horizontal { .toolbar-vertical .handle-horizontal {
display: none; display: none;
@ -222,16 +266,17 @@ html, body {
} }
.channel-tag { .channel-tag {
font-weight: bold; font-weight: bold;
color: orange; color: $chat-channel-color;
} }
.user-tag { .user-tag {
font-weight: bold; font-weight: bold;
color: green; color: $chat-user-color;
} }
#message-box { #message-box {
width: 100%; width: 100%;
border: none; border: none;
background: none; background: none;
color: $chat-input-color;
margin: 5px 0 5px 0; margin: 5px 0 5px 0;
padding: 0; padding: 0;
height: 20px; height: 20px;
@ -251,9 +296,9 @@ form {
width: calc(100% - 10px); width: calc(100% - 10px);
padding: 5px; padding: 5px;
text-align: center; text-align: center;
color: white; color: $dialog-header-color;
background-color: gray; background-color: $dialog-header-bg-color;
border-bottom: 1px solid darkgray; border-bottom: 1px solid $dialog-header-border-bottom-color;
} }
.dialog-footer { .dialog-footer {
position: absolute; position: absolute;
@ -270,10 +315,10 @@ form {
.dialog-close, .dialog-submit { .dialog-close, .dialog-submit {
width: 45%; width: 45%;
font-size: 15px; font-size: 15px;
border: 1px gray solid; border: 1px $dialog-button-border-color solid;
border-radius: 3px; border-radius: 3px;
background-color: white; background-color: $dialog-button-bg-color;
color: black; color: $dialog-button-color;
padding: 1px; padding: 1px;
} }
.connect-dialog table { .connect-dialog table {
@ -282,8 +327,9 @@ form {
} }
.dialog { .dialog {
position: absolute; position: absolute;
background-color: #eee; background-color: $dialog-bg-color;
border: 1px gray solid; color: $dialog-color;
border: 1px $dialog-border-color solid;
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.25); box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.25);
z-index: 20; z-index: 20;
} }
@ -309,7 +355,7 @@ form {
} }
.settings-dialog .mic-volume-container { .settings-dialog .mic-volume-container {
height: 10px; height: 10px;
border: 3px solid black; border: 3px solid $mic-volume-border-color;
} }
.settings-dialog .mic-volume { .settings-dialog .mic-volume {
height: 100%; height: 100%;
@ -335,19 +381,19 @@ form {
} }
.connect-dialog input[type=text] { .connect-dialog input[type=text] {
font-size: 15px; font-size: 15px;
border: 1px gray solid; border: 1px $dialog-input-border-color solid;
border-radius: 3px; border-radius: 3px;
background-color: white; background-color: $dialog-input-bg-color;
color: black; color: $dialog-input-color;
padding: 2px; padding: 2px;
width: calc(100% - 8px); width: calc(100% - 8px);
} }
.connect-dialog input[type=password] { .connect-dialog input[type=password] {
font-size: 15px; font-size: 15px;
border: 1px gray solid; border: 1px $dialog-input-border-color solid;
border-radius: 3px; border-radius: 3px;
background-color: white; background-color: $dialog-input-bg-color;
color: black; color: $dialog-input-color;
padding: 2px; padding: 2px;
width: calc(100% - 8px); width: calc(100% - 8px);
} }

View file

@ -8,6 +8,7 @@ module.exports = {
'./app/index.js', './app/index.js',
'./app/index.html' './app/index.html'
], ],
theme: './app/theme.js',
matrix: './app/matrix.js' matrix: './app/matrix.js'
}, },
output: { output: {
@ -51,6 +52,15 @@ module.exports = {
'css-loader' 'css-loader'
] ]
}, },
{
test: /\.scss$/,
loaders: [
'file-loader?name=[hash].css',
'extract-loader',
'css-loader',
'sass-loader'
]
},
{ {
test: /manifest\.json$|\.xml$/, test: /manifest\.json$|\.xml$/,
loaders: [ loaders: [