diff --git a/maubot/management/frontend/src/components/Switch.js b/maubot/management/frontend/src/components/Switch.js
new file mode 100644
index 0000000..975b47c
--- /dev/null
+++ b/maubot/management/frontend/src/components/Switch.js
@@ -0,0 +1,54 @@
+// maubot - A plugin-based Matrix bot system.
+// Copyright (C) 2018 Tulir Asokan
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+import React, { Component } from "react"
+
+class Switch extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ active: props.active,
+ }
+ }
+
+ componentWillReceiveProps(nextProps) {
+ this.setState({
+ active: nextProps.active,
+ })
+ }
+
+ toggle = () => {
+ if (this.props.onToggle) {
+ this.props.onToggle(!this.state.active)
+ } else {
+ this.setState({ active: !this.state.active })
+ }
+ }
+
+ render() {
+ return (
+
+ )
+ }
+}
+
+export default Switch
diff --git a/maubot/management/frontend/src/dashboard/client/ListEntry.js b/maubot/management/frontend/src/dashboard/client/ListEntry.js
deleted file mode 100644
index e19055f..0000000
--- a/maubot/management/frontend/src/dashboard/client/ListEntry.js
+++ /dev/null
@@ -1,30 +0,0 @@
-// maubot - A plugin-based Matrix bot system.
-// Copyright (C) 2018 Tulir Asokan
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see .
-import React from "react"
-import { Link } from "react-router-dom"
-import { ReactComponent as ChevronRight } from "../../res/chevron-right.svg"
-
-const ClientListEntry = ({ client }) => (
-
-
- {client.displayname || client.id}
-
-
-)
-
-export default ClientListEntry
diff --git a/maubot/management/frontend/src/index.js b/maubot/management/frontend/src/index.js
index cbe10ed..12dd05c 100644
--- a/maubot/management/frontend/src/index.js
+++ b/maubot/management/frontend/src/index.js
@@ -16,6 +16,6 @@
import React from "react"
import ReactDOM from "react-dom"
import "./style/index.sass"
-import App from "./MaubotRouter"
+import App from "./pages/Main"
ReactDOM.render(, document.getElementById("root"))
diff --git a/maubot/management/frontend/src/Login.js b/maubot/management/frontend/src/pages/Login.js
similarity index 97%
rename from maubot/management/frontend/src/Login.js
rename to maubot/management/frontend/src/pages/Login.js
index e342abe..5b97f14 100644
--- a/maubot/management/frontend/src/Login.js
+++ b/maubot/management/frontend/src/pages/Login.js
@@ -14,8 +14,8 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
import React, { Component } from "react"
-import Spinner from "./components/Spinner"
-import api from "./api"
+import Spinner from "../components/Spinner"
+import api from "../api"
class Login extends Component {
constructor(props, context) {
diff --git a/maubot/management/frontend/src/MaubotRouter.js b/maubot/management/frontend/src/pages/Main.js
similarity index 92%
rename from maubot/management/frontend/src/MaubotRouter.js
rename to maubot/management/frontend/src/pages/Main.js
index b3c7561..efb9ac3 100644
--- a/maubot/management/frontend/src/MaubotRouter.js
+++ b/maubot/management/frontend/src/pages/Main.js
@@ -15,13 +15,13 @@
// along with this program. If not, see .
import React, { Component } from "react"
import { BrowserRouter as Router, Switch } from "react-router-dom"
-import PrivateRoute from "./components/PrivateRoute"
+import PrivateRoute from "../components/PrivateRoute"
+import Spinner from "../components/Spinner"
+import api from "../api"
import Dashboard from "./dashboard"
import Login from "./Login"
-import Spinner from "./components/Spinner"
-import api from "./api"
-class MaubotRouter extends Component {
+class Main extends Component {
constructor(props) {
super(props)
this.state = {
@@ -72,4 +72,4 @@ class MaubotRouter extends Component {
}
}
-export default MaubotRouter
+export default Main
diff --git a/maubot/management/frontend/src/pages/dashboard/Client.js b/maubot/management/frontend/src/pages/dashboard/Client.js
new file mode 100644
index 0000000..d352b31
--- /dev/null
+++ b/maubot/management/frontend/src/pages/dashboard/Client.js
@@ -0,0 +1,114 @@
+// maubot - A plugin-based Matrix bot system.
+// Copyright (C) 2018 Tulir Asokan
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+import React, { Component } from "react"
+import { Link } from "react-router-dom"
+import Switch from "../../components/Switch"
+import { ReactComponent as ChevronRight } from "../../res/chevron-right.svg"
+import { ReactComponent as UploadButton } from "../../res/upload.svg"
+
+function getAvatarURL(client) {
+ const id = client.avatar_url.substr("mxc://".length)
+ return `${client.homeserver}/_matrix/media/r0/download/${id}`
+}
+
+const ClientListEntry = ({ client }) => {
+ const classes = ["client", "entry"]
+ if (!client.enabled) {
+ classes.push("disabled")
+ } else if (!client.started) {
+ classes.push("stopped")
+ }
+ return (
+
+
+ {client.displayname || client.id}
+
+
+ )
+}
+
+class Client extends Component {
+ static ListEntry = ClientListEntry
+
+ constructor(props) {
+ super(props)
+ this.state = props
+ }
+
+ componentWillReceiveProps(nextProps) {
+ this.setState(nextProps)
+ }
+
+ inputChange = event => {
+ this.setState({ [event.target.name]: event.target.value })
+ }
+
+ render() {
+ return
+
+
+
+
+
+
+
User ID
+
+
+
+
+
+
Display name
+
+
+
+
+
+
Homeserver
+
+
+
+
+
+
Access token
+
+
+
+
+
+
Sync
+
+ this.setState({ sync })}/>
+
+
+
+
Enabled
+
+ this.setState({ enabled })}/>
+
+
+
+
+
+ }
+}
+
+export default Client
diff --git a/maubot/management/frontend/src/dashboard/index.js b/maubot/management/frontend/src/pages/dashboard/index.js
similarity index 92%
rename from maubot/management/frontend/src/dashboard/index.js
rename to maubot/management/frontend/src/pages/dashboard/index.js
index 77ea69b..34dbb0c 100644
--- a/maubot/management/frontend/src/dashboard/index.js
+++ b/maubot/management/frontend/src/pages/dashboard/index.js
@@ -15,12 +15,11 @@
// along with this program. If not, see .
import React, { Component } from "react"
import { Route, Switch, Link } from "react-router-dom"
-import api from "../api"
-import { ReactComponent as Plus } from "../res/plus.svg"
+import api from "../../api"
+import { ReactComponent as Plus } from "../../res/plus.svg"
import InstanceListEntry from "./instance/ListEntry"
import InstanceView from "./instance/View"
-import ClientListEntry from "./client/ListEntry"
-import ClientView from "./client/View"
+import Client from "./Client"
import PluginListEntry from "./plugin/ListEntry"
import PluginView from "./plugin/View"
@@ -88,7 +87,7 @@ class Dashboard extends Component {
-
+ "Hello, World!"}/>
}/>
- }/>
+ }/>
}/>
this.renderView("instance", InstanceView, match.params.id)}/>
- this.renderView("client", ClientView, match.params.id)}/>
+ this.renderView("client", Client, match.params.id)}/>
this.renderView("plugin", PluginView, match.params.id)}/>
"Not found :("}/>
diff --git a/maubot/management/frontend/src/dashboard/instance/ListEntry.js b/maubot/management/frontend/src/pages/dashboard/instance/ListEntry.js
similarity index 92%
rename from maubot/management/frontend/src/dashboard/instance/ListEntry.js
rename to maubot/management/frontend/src/pages/dashboard/instance/ListEntry.js
index 0603e4d..9b36817 100644
--- a/maubot/management/frontend/src/dashboard/instance/ListEntry.js
+++ b/maubot/management/frontend/src/pages/dashboard/instance/ListEntry.js
@@ -15,7 +15,7 @@
// along with this program. If not, see .
import React from "react"
import { Link } from "react-router-dom"
-import { ReactComponent as ChevronRight } from "../../res/chevron-right.svg"
+import { ReactComponent as ChevronRight } from "../../../res/chevron-right.svg"
const InstanceListEntry = ({ instance }) => (
diff --git a/maubot/management/frontend/src/dashboard/instance/View.js b/maubot/management/frontend/src/pages/dashboard/instance/View.js
similarity index 100%
rename from maubot/management/frontend/src/dashboard/instance/View.js
rename to maubot/management/frontend/src/pages/dashboard/instance/View.js
diff --git a/maubot/management/frontend/src/dashboard/plugin/ListEntry.js b/maubot/management/frontend/src/pages/dashboard/plugin/ListEntry.js
similarity index 92%
rename from maubot/management/frontend/src/dashboard/plugin/ListEntry.js
rename to maubot/management/frontend/src/pages/dashboard/plugin/ListEntry.js
index 6facdbf..d7563df 100644
--- a/maubot/management/frontend/src/dashboard/plugin/ListEntry.js
+++ b/maubot/management/frontend/src/pages/dashboard/plugin/ListEntry.js
@@ -15,7 +15,7 @@
// along with this program. If not, see .
import React from "react"
import { Link } from "react-router-dom"
-import { ReactComponent as ChevronRight } from "../../res/chevron-right.svg"
+import { ReactComponent as ChevronRight } from "../../../res/chevron-right.svg"
const PluginListEntry = ({ plugin }) => (
diff --git a/maubot/management/frontend/src/dashboard/plugin/View.js b/maubot/management/frontend/src/pages/dashboard/plugin/View.js
similarity index 100%
rename from maubot/management/frontend/src/dashboard/plugin/View.js
rename to maubot/management/frontend/src/pages/dashboard/plugin/View.js
diff --git a/maubot/management/frontend/src/res/upload.svg b/maubot/management/frontend/src/res/upload.svg
new file mode 100644
index 0000000..f1deea6
--- /dev/null
+++ b/maubot/management/frontend/src/res/upload.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/maubot/management/frontend/src/style/base/body.sass b/maubot/management/frontend/src/style/base/body.sass
index 462fe8c..ba0406b 100644
--- a/maubot/management/frontend/src/style/base/body.sass
+++ b/maubot/management/frontend/src/style/base/body.sass
@@ -18,7 +18,6 @@ body
margin: 0
padding: 0
font-size: 16px
- background-color: $background-color
#root
position: fixed
@@ -33,6 +32,10 @@ body
bottom: 0
left: 0
right: 0
+ background-color: $background-dark
+
+ > *
+ background-color: $background
.maubot-loading
margin-top: 10rem
diff --git a/maubot/management/frontend/src/style/base/elements.sass b/maubot/management/frontend/src/style/base/elements.sass
index 93d10f0..76f3a4e 100644
--- a/maubot/management/frontend/src/style/base/elements.sass
+++ b/maubot/management/frontend/src/style/base/elements.sass
@@ -19,7 +19,7 @@
padding: $padding
width: $width
height: $height
- background-color: $background-color
+ background-color: $background
border: none
border-radius: .25rem
color: $inverted-text-color
@@ -28,7 +28,7 @@
cursor: pointer
&:hover
- background-color: darken($background-color, 10%)
+ background-color: darken($background, 10%)
=link-button()
display: inline-block
@@ -81,7 +81,7 @@
=input($width: null, $height: null, $vertical-padding: .375rem, $horizontal-padding: 1rem, $font-size: 1rem)
font-family: $font-stack
border: 1px solid $border-color
- background-color: $background-color
+ background-color: $background
color: $text-color
width: $width
height: $height
diff --git a/maubot/management/frontend/src/style/base/vars.sass b/maubot/management/frontend/src/style/base/vars.sass
index 6e9a6c3..e179396 100644
--- a/maubot/management/frontend/src/style/base/vars.sass
+++ b/maubot/management/frontend/src/style/base/vars.sass
@@ -13,6 +13,7 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
+
$primary: #00C853
$primary-dark: #009624
$primary-light: #5EFC82
@@ -25,6 +26,7 @@ $error-light: #F05545
$border-color: #DDD
$text-color: #212121
-$background-color: #FAFAFA
-$inverted-text-color: $background-color
+$background: #FAFAFA
+$background-dark: #E7E7E7
+$inverted-text-color: $background
$font-stack: sans-serif
diff --git a/maubot/management/frontend/src/style/index.sass b/maubot/management/frontend/src/style/index.sass
index c2e9a16..f6b6033 100644
--- a/maubot/management/frontend/src/style/index.sass
+++ b/maubot/management/frontend/src/style/index.sass
@@ -14,10 +14,10 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
@import lib/spinner
-
@import base/vars
@import base/body
@import base/elements
+@import lib/switch
@import pages/login
@import pages/dashboard
diff --git a/maubot/management/frontend/src/style/lib/switch.sass b/maubot/management/frontend/src/style/lib/switch.sass
new file mode 100644
index 0000000..c087da4
--- /dev/null
+++ b/maubot/management/frontend/src/style/lib/switch.sass
@@ -0,0 +1,79 @@
+// maubot - A plugin-based Matrix bot system.
+// Copyright (C) 2018 Tulir Asokan
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+.switch
+ display: flex
+
+ width: 100%
+ height: 2rem
+
+ cursor: pointer
+
+ border: 1px solid $primary
+ border-radius: .25rem
+ background-color: $background
+
+ box-sizing: border-box
+
+ > .box
+ box-sizing: border-box
+ width: 50%
+ height: 100%
+
+ transition: .5s
+ text-align: center
+
+ color: $inverted-text-color
+ border-radius: .15rem 0 0 .15rem
+ background-color: $primary
+
+ align-items: center
+
+ > .text
+ box-sizing: border-box
+ width: 100%
+
+ text-align: center
+ vertical-align: middle
+
+ color: $inverted-text-color
+ font-size: 1rem
+
+ user-select: none
+
+ .on
+ display: none
+
+ .off
+ display: inline
+
+
+ &[data-active=true]
+ > .box
+ transform: translateX(100%)
+
+ border-radius: 0 .15rem .15rem 0
+ background-color: $primary
+
+ .on
+ display: inline
+
+ .off
+ display: none
+
+
+
+
diff --git a/maubot/management/frontend/src/style/pages/client.sass b/maubot/management/frontend/src/style/pages/client.sass
new file mode 100644
index 0000000..a6a6f6a
--- /dev/null
+++ b/maubot/management/frontend/src/style/pages/client.sass
@@ -0,0 +1,109 @@
+// maubot - A plugin-based Matrix bot system.
+// Copyright (C) 2018 Tulir Asokan
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+> .client
+ margin: 1rem
+
+ div.avatar-container
+ position: relative
+ display: inline-block
+ width: 8rem
+ height: 8rem
+ border-radius: 100%
+ cursor: pointer
+ vertical-align: top
+
+ > img.avatar
+ display: block
+ max-width: 8rem
+ max-height: 8rem
+ border-radius: 100%
+ position: absolute
+ left: 50%
+ top: 50%
+ -webkit-transform: translateY(-50%) translateX(-50%)
+
+ > svg.upload
+ position: absolute
+ display: block
+ visibility: hidden
+
+ width: 6rem
+ height: 6rem
+
+ padding: 1rem
+
+ &:hover
+ > img.avatar
+ opacity: .25
+
+ > svg.upload
+ visibility: visible
+
+ div.info-container
+ display: inline-table
+ vertical-align: top
+
+ margin: 1rem 2rem
+
+ > .row
+ display: table-row
+
+ > .key, > .value
+ display: table-cell
+ padding-bottom: .5rem
+
+ > .key
+ width: 6.5rem
+
+ > .value
+ margin: .5rem
+
+ > .value > .switch
+ width: auto
+ height: 2rem
+
+ > .value > input
+ border: none
+ height: 2rem
+ width: 100%
+
+ box-sizing: border-box
+
+ padding: .375rem 0
+ background-color: $background
+
+ font-size: 1rem
+
+ border-bottom: 1px solid transparent
+
+ &:hover:not(:disabled)
+ border-bottom: 1px solid $primary
+
+ &:focus:not(:disabled)
+ border-bottom: 2px solid $primary
+
+//> .client
+ display: table
+
+ > .field
+ display: table-row
+ width: 100%
+
+ > .name, > .value
+ display: table-cell
+ width: 50%
+ text-align: center
diff --git a/maubot/management/frontend/src/style/pages/dashboard.sass b/maubot/management/frontend/src/style/pages/dashboard.sass
index dd001a0..801fc86 100644
--- a/maubot/management/frontend/src/style/pages/dashboard.sass
+++ b/maubot/management/frontend/src/style/pages/dashboard.sass
@@ -18,6 +18,9 @@
.dashboard
display: grid
height: 100%
+ max-width: 60rem
+ margin: auto
+ box-shadow: 0 .5rem .5rem rgba(0, 0, 0, 0.5)
> a.title
grid-area: title
@@ -31,9 +34,7 @@
color: $text-color
text-decoration: none
- z-index: 1
-
- background-color: $background-color
+ background-color: white
border-right: 1px solid $primary
border-bottom: 1px solid $border-color
@@ -47,12 +48,14 @@
align-items: center
justify-content: center
background-color: $primary
- width: 110%
- margin: 0 -5%
- box-shadow: 0 .25rem .25rem rgba(0, 0, 0, .25)
+ box-shadow: 0 .25rem .25rem rgba(0, 0, 0, .2)
@import "sidebar"
- > main.dashboard
+ > main.view
grid-area: main
+
+ @import "client"
+ @import "instance"
+ @import "plugin"
diff --git a/maubot/management/frontend/src/dashboard/client/View.js b/maubot/management/frontend/src/style/pages/instance.sass
similarity index 80%
rename from maubot/management/frontend/src/dashboard/client/View.js
rename to maubot/management/frontend/src/style/pages/instance.sass
index b63d58f..7847402 100644
--- a/maubot/management/frontend/src/dashboard/client/View.js
+++ b/maubot/management/frontend/src/style/pages/instance.sass
@@ -13,12 +13,6 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
-import React, { Component } from "react"
-class ClientView extends Component {
- render() {
- return
{this.props.displayname}
- }
-}
-
-export default ClientView
+> .instance
+ margin: 1rem
diff --git a/maubot/management/frontend/src/style/pages/plugin.sass b/maubot/management/frontend/src/style/pages/plugin.sass
new file mode 100644
index 0000000..e1376b5
--- /dev/null
+++ b/maubot/management/frontend/src/style/pages/plugin.sass
@@ -0,0 +1,18 @@
+// maubot - A plugin-based Matrix bot system.
+// Copyright (C) 2018 Tulir Asokan
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+> .plugin
+ margin: 1rem
diff --git a/maubot/management/frontend/src/style/pages/sidebar.sass b/maubot/management/frontend/src/style/pages/sidebar.sass
index 47bbfd7..cb48b12 100644
--- a/maubot/management/frontend/src/style/pages/sidebar.sass
+++ b/maubot/management/frontend/src/style/pages/sidebar.sass
@@ -16,13 +16,16 @@
> .sidebar
grid-area: sidebar
- background-color: $background-color
+ background-color: white
border-right: 1px solid $border-color
padding: .5rem
+ overflow-y: auto
+
div.list
- margin-bottom: 1.5rem
+ &:not(:last-of-type)
+ margin-bottom: 1.5rem
div.title
h2