Improve design of management UI

This commit is contained in:
Tulir Asokan 2018-11-10 19:22:04 +02:00
parent 15db7b95c3
commit 5220d2e5c9
17 changed files with 113 additions and 89 deletions

View File

@ -17,8 +17,6 @@ rules:
- mq - mq
no-warn: 1 no-warn: 1
no-debug: 1 no-debug: 1
no-ids: 2
no-important: 2
hex-notation: hex-notation:
- 2 - 2
- style: uppercase - style: uppercase
@ -26,8 +24,4 @@ rules:
- 2 - 2
- size: 4 - size: 4
property-sort-order: property-sort-order:
- 1 - 0
- order:
- display
- margin
ignore-custom-properties: true

View File

@ -17,18 +17,22 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
--> -->
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.png"> <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.png">
<link rel="stylesheet" type="text/css"
href="https://fonts.googleapis.com/css?family=Raleway:300,400,700">
<link rel="stylesheet" type="text/css"
href="https://cdn.jsdelivr.net/gh/tonsky/FiraCode@1.206/distr/fira_code.css">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#50D367"> <meta name="theme-color" content="#50D367">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"> <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<title>Maubot Manager</title> <title>Maubot Manager</title>
</head> </head>
<body> <body>
<noscript> <noscript>
You need to enable JavaScript to run this app. You need to enable JavaScript to run this app.
</noscript> </noscript>
<div id="root"></div> <div id="root"></div>
</body> </body>
</html> </html>

View File

@ -34,28 +34,28 @@ export const PrefTable = ({ children, wrapperClass }) => {
) )
} }
export const PrefRow = ({ name, children }) => ( export const PrefRow = ({ name, fullWidth = false, labelFor = undefined, children }) => (
<div className="row"> <div className={`entry ${fullWidth ? "full-width" : ""}`}>
<div className="key">{name}</div> <label htmlFor={labelFor}>{name}</label>
<div className="value">{children}</div> <div className="value">{children}</div>
</div> </div>
) )
export const PrefInput = ({ rowName, ...args }) => ( export const PrefInput = ({ rowName, fullWidth = false, ...args }) => (
<PrefRow name={rowName}> <PrefRow name={rowName} fullWidth={fullWidth} labelFor={rowName}>
<input {...args}/> <input {...args} id={rowName}/>
</PrefRow> </PrefRow>
) )
export const PrefSwitch = ({ rowName, ...args }) => ( export const PrefSwitch = ({ rowName, fullWidth = false, ...args }) => (
<PrefRow name={rowName}> <PrefRow name={rowName} fullWidth={fullWidth} labelFor={rowName}>
<Switch {...args}/> <Switch {...args} id={rowName}/>
</PrefRow> </PrefRow>
) )
export const PrefSelect = ({ rowName, ...args }) => ( export const PrefSelect = ({ rowName, fullWidth = false, ...args }) => (
<PrefRow name={rowName}> <PrefRow name={rowName} fullWidth={fullWidth} labelFor={rowName}>
<Select className="select" {...args}/> <Select className="select" {...args} id={rowName}/>
</PrefRow> </PrefRow>
) )

View File

@ -42,7 +42,7 @@ class Switch extends Component {
render() { render() {
return ( return (
<div className="switch" data-active={this.state.active} onClick={this.toggle} <div className="switch" data-active={this.state.active} onClick={this.toggle}
tabIndex="0" onKeyPress={this.toggleKeyboard}> tabIndex="0" onKeyPress={this.toggleKeyboard} id={this.props.id}>
<div className="box"> <div className="box">
<span className="text"> <span className="text">
<span className="on">{this.props.onText || "On"}</span> <span className="on">{this.props.onText || "On"}</span>

View File

@ -193,18 +193,18 @@ class Client extends Component {
renderPreferences = () => ( renderPreferences = () => (
<PrefTable> <PrefTable>
<PrefInput rowName="User ID" type="text" disabled={!this.isNew} <PrefInput rowName="User ID" type="text" disabled={!this.isNew} fullWidth={true}
name={!this.isNew ? "id" : ""} value={this.state.id} name={!this.isNew ? "id" : ""} value={this.state.id}
placeholder="@fancybot:example.com" onChange={this.inputChange}/> placeholder="@fancybot:example.com" onChange={this.inputChange}/>
<PrefInput rowName="Display name" type="text" name="displayname"
value={this.state.displayname} placeholder="My fancy bot"
onChange={this.inputChange}/>
<PrefInput rowName="Homeserver" type="text" name="homeserver" <PrefInput rowName="Homeserver" type="text" name="homeserver"
value={this.state.homeserver} placeholder="https://example.com" value={this.state.homeserver} placeholder="https://example.com"
onChange={this.inputChange}/> onChange={this.inputChange}/>
<PrefInput rowName="Access token" type="text" name="access_token" <PrefInput rowName="Access token" type="text" name="access_token"
value={this.state.access_token} onChange={this.inputChange} value={this.state.access_token} onChange={this.inputChange}
placeholder="MDAxYWxvY2F0aW9uIG1hdHJpeC5sb2NhbAowMDEzaWRlbnRpZmllc"/> placeholder="MDAxYWxvY2F0aW9uIG1hdHJpeC5sb2NhbAowMDEzaWRlbnRpZmllc"/>
<PrefInput rowName="Display name" type="text" name="displayname"
value={this.state.displayname} placeholder="My fancy bot"
onChange={this.inputChange}/>
<PrefInput rowName="Avatar URL" type="text" name="avatar_url" <PrefInput rowName="Avatar URL" type="text" name="avatar_url"
value={this.state.avatar_url} onChange={this.inputChange} value={this.state.avatar_url} onChange={this.inputChange}
placeholder="mxc://example.com/mbmwyoTvPhEQPiCskcUsppko"/> placeholder="mxc://example.com/mbmwyoTvPhEQPiCskcUsppko"/>

View File

@ -63,8 +63,8 @@ class Instance extends Component {
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
this.setState(Object.assign(this.initialState, nextProps.instance), () => this.setState(Object.assign(this.initialState, nextProps.instance))
this.updateClientOptions()) this.updateClientOptions()
} }
clientSelectEntry = client => client && { clientSelectEntry = client => client && {
@ -127,7 +127,9 @@ class Instance extends Component {
} }
get selectedClientEntry() { get selectedClientEntry() {
return this.clientSelectEntry(this.props.ctx.clients[this.state.primary_user]) return this.state.primary_user
? this.clientSelectEntry(this.props.ctx.clients[this.state.primary_user])
: {}
} }
get selectedPluginEntry() { get selectedPluginEntry() {
@ -159,7 +161,7 @@ class Instance extends Component {
<PrefTable> <PrefTable>
<PrefInput rowName="ID" type="text" name={"id"} value={this.state.id} <PrefInput rowName="ID" type="text" name={"id"} value={this.state.id}
placeholder="fancybotinstance" onChange={this.inputChange} placeholder="fancybotinstance" onChange={this.inputChange}
disabled={!this.isNew}/> disabled={!this.isNew} fullWidth={true}/>
<PrefSwitch rowName="Enabled" active={this.state.enabled} <PrefSwitch rowName="Enabled" active={this.state.enabled}
onToggle={enabled => this.setState({ enabled })}/> onToggle={enabled => this.setState({ enabled })}/>
<PrefSwitch rowName="Running" active={this.state.started} <PrefSwitch rowName="Running" active={this.state.started}

View File

@ -90,10 +90,9 @@ class Dashboard extends Component {
<img src="/favicon.png" alt=""/> <img src="/favicon.png" alt=""/>
Maubot Manager Maubot Manager
</Link> </Link>
<div className="topbar">
<div className="user"> <div className="user">
{localStorage.username} <span>{localStorage.username}</span>
</div>
</div> </div>
<nav className="sidebar"> <nav className="sidebar">
<div className="instances list"> <div className="instances list">

View File

@ -42,6 +42,7 @@
=main-color-button() =main-color-button()
background-color: $primary background-color: $primary
color: $inverted-text-color
&:hover:not(:disabled) &:hover:not(:disabled)
background-color: $primary-dark background-color: $primary-dark
@ -56,16 +57,15 @@
display: flex display: flex
> button, > .button > button, > .button
flex: 1 flex: 1
border-radius: 0
&:first-of-type &:first-of-type
border-radius: .25rem 0 0 .25rem margin-right: .5rem
&:last-of-type &:last-of-type
border-radius: 0 .25rem .25rem 0 margin-left: .5rem
&:first-of-type:last-of-type &:first-of-type:last-of-type
border-radius: .25rem margin: 0
=vertical-button-group() =vertical-button-group()
display: flex display: flex
@ -106,6 +106,9 @@
.input, .textarea .input, .textarea
+input +input
input
font-family: $font-stack
=notification($border: $error-dark, $background: transparentize($error-light, 0.5)) =notification($border: $error-dark, $background: transparentize($error-light, 0.5))
padding: 1rem padding: 1rem
border-radius: .25rem border-radius: .25rem

View File

@ -29,4 +29,4 @@ $text-color: #212121
$background: #FAFAFA $background: #FAFAFA
$background-dark: #E7E7E7 $background-dark: #E7E7E7
$inverted-text-color: $background $inverted-text-color: $background
$font-stack: sans-serif $font-stack: Raleway, sans-serif

View File

@ -15,23 +15,30 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
.preference-table .preference-table
display: table display: flex
width: 100% width: 100%
> .row flex-wrap: wrap
display: table-row
> .key, > .value > .entry
display: table-cell display: block
padding-bottom: .5rem width: calc(50% - 1rem)
margin: .5rem
> .key &.full-width
width: 7rem width: 100%
> label, > .value
display: block
width: 100%
> label
font-size: 0.875rem
padding-bottom: .25rem
font-weight: lighter
> .value > .value
margin: .5rem
> .switch > .switch
width: auto width: auto
height: 2rem height: 2rem

View File

@ -22,7 +22,7 @@
cursor: pointer cursor: pointer
border: 1px solid $primary border: 1px solid $error-light
border-radius: .25rem border-radius: .25rem
background-color: $background background-color: $background
@ -37,9 +37,9 @@
transition: .5s transition: .5s
text-align: center text-align: center
color: $text-color
border-radius: .15rem 0 0 .15rem border-radius: .15rem 0 0 .15rem
background-color: $primary background-color: $error-light
color: $inverted-text-color
align-items: center align-items: center
@ -50,7 +50,7 @@
text-align: center text-align: center
vertical-align: middle vertical-align: middle
color: $text-color color: $inverted-text-color
font-size: 1rem font-size: 1rem
user-select: none user-select: none
@ -63,7 +63,9 @@
&[data-active=true] &[data-active=true]
border: 1px solid $primary
> .box > .box
background-color: $primary
transform: translateX(100%) transform: translateX(100%)
border-radius: 0 .15rem .15rem 0 border-radius: 0 .15rem .15rem 0

View File

@ -16,13 +16,13 @@
> div.client > div.client
display: flex display: flex
margin: 2rem margin: 2rem 4rem
> div.sidebar > div.sidebar
vertical-align: top vertical-align: top
text-align: center text-align: center
width: 8rem width: 8rem
margin-right: 1rem
> div > div
margin-bottom: 1rem margin-bottom: 1rem
@ -32,7 +32,6 @@
> div.info > div.info
vertical-align: top vertical-align: top
margin-left: 1rem
flex: 1 flex: 1
@import instances @import instances

View File

@ -15,15 +15,20 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
> div.instances > div.instances
margin-top: 1rem margin: 1rem 0
display: flex
flex-wrap: wrap
> h3 > h3
margin-bottom: .5rem margin: .5rem
width: 100%
> a.instance > a.instance
display: block display: block
width: 100% width: calc(50% - 1rem)
padding: .375rem .5rem padding: .375rem .5rem
margin: .5rem
background-color: white background-color: white
border-radius: .25rem border-radius: .25rem
color: $text-color color: $text-color

View File

@ -1,6 +1,7 @@
.dashboard { .dashboard {
grid-template: grid-template:
[row1-start] "title topbar" 3.5rem [row1-end] [row1-start] "title main" 3.5rem [row1-end]
[row2-start] "sidebar main" auto [row2-end] [row2-start] "user main" 2.5rem [row2-end]
[row3-start] "sidebar main" auto [row3-end]
/ 15rem auto; / 15rem auto;
} }

View File

@ -25,6 +25,7 @@
> a.title > a.title
grid-area: title grid-area: title
background-color: white
display: flex display: flex
align-items: center align-items: center
justify-content: center justify-content: center
@ -35,37 +36,34 @@
color: $text-color color: $text-color
text-decoration: none text-decoration: none
background-color: white
border-right: 1px solid $primary
border-bottom: 1px solid $border-color
> img > img
max-width: 2rem max-width: 2rem
margin-right: .5rem margin-right: .5rem
> div.topbar > div.user
grid-area: topbar grid-area: user
background-color: white
border-bottom: 1px solid $border-color
display: flex display: flex
align-items: center align-items: center
justify-content: right justify-content: center
background-color: $primary span
box-shadow: 0 .25rem .25rem rgba(0, 0, 0, .2) display: flex
padding: .5rem 1rem
> div.user
display: inline-flex
align-items: center align-items: center
height: 100% justify-content: center
padding: 0 1rem background-color: $primary
color: $inverted-text-color
margin: .375rem .5rem
width: 100%
height: calc(100% - .375rem)
box-sizing: border-box box-sizing: border-box
background-color: $primary-dark
border-radius: .25rem border-radius: .25rem
@import sidebar @import sidebar
> main.view > main.view
grid-area: main grid-area: main
border-left: 1px solid $border-color
@import client/index @import client/index
@import instance @import instance
@ -74,6 +72,8 @@
div.buttons div.buttons
+button-group +button-group
display: flex display: flex
margin: 1rem .5rem
width: calc(100% - 1rem)
div.error div.error
+notification($error) +notification($error)
@ -82,6 +82,12 @@
&:empty &:empty
display: none display: none
button.delete
background-color: $error-light !important
&:hover
background-color: $error !important
button.save, button.delete button.save, button.delete
+button +button
+main-color-button +main-color-button

View File

@ -15,7 +15,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
> div.instance > div.instance
margin: 2rem margin: 2rem 4rem
> div.preference-table > div.preference-table
.select-client .select-client
@ -28,8 +28,10 @@
margin-right: .5rem margin-right: .5rem
> div.ace_editor > div.ace_editor
z-index: 0
height: 15rem !important height: 15rem !important
width: 100% !important width: calc(100% - 1rem) !important
font-size: 14px font-size: 12px
font-family: "Fira Code", monospace
margin-bottom: 1rem margin: .75rem .5rem 1.5rem

View File

@ -18,7 +18,6 @@
grid-area: sidebar grid-area: sidebar
background-color: white background-color: white
border-right: 1px solid $border-color
padding: .5rem padding: .5rem
overflow-y: auto overflow-y: auto
@ -57,6 +56,7 @@
&.active &.active
background-color: $primary background-color: $primary
color: white
&.client &.client
img.avatar img.avatar