add role diff calculations, add action buttons, fix a few regressions

This commit is contained in:
Katalina / stardust 2017-12-23 02:21:31 -06:00
parent 3d541ac480
commit 3c545bdeaa
13 changed files with 203 additions and 89 deletions

View file

@ -11,11 +11,63 @@
flex-wrap: wrap
flex-direction: row
&__category
// flex: 1 3 33%
box-sizing: border-box
background-color: var(--c-1)
padding: 15px
margin: 10px
width: 220px - 30px
width: 220px - 30px
&__roles-header
display: flex
&__spacer
flex: 1
&__actions
opacity: 1
transition: opacity 0.3s ease-in-out
button
margin-left: 5px
&.hidden
opacity: 0
// display: none
.action__button
border: 0
border-radius: 5px
transition: transform 0.2s ease-out, box-shadow 0.2s ease-out
position: relative
&::after
content: ""
position: absolute
top: 0
bottom: 0
right: 0
left: 0
background-color: rgba(0,0,0,0.1)
border-radius: 5px
opacity: 0
transition: opacity 0.15s ease-in-out
&:hover
transform: translateY(-1px)
box-shadow: 0 1px 2px rgba(0,0,0,0.3)
&::after
opacity: 0.7
&:active
transform: translateY(0px)
box-shadow: none
&::after
opacity: 1
&.primary
background-color: var(--c-5)
&.secondary
background-color: var(--c-3)

View file

@ -42,7 +42,11 @@ export const constructView = id => (dispatch, getState) => {
hidden: false,
type: 'multi'
})).map(c => {
const roles = c.get('roles').map(r => server.get('roles').find(sr => sr.get('id') === r))
const roles = c.get('roles')
.map(r =>
server.get('roles').find(sr => sr.get('id') === r)
)
.sort((a, b) => a.position > b.position)
return c.set('roles_map', roles)
})
@ -59,3 +63,30 @@ export const constructView = id => (dispatch, getState) => {
}
})
}
export const resetSelected = (dispatch) => {
dispatch({
type: Symbol.for('reset selected')
})
}
export const submitSelected = serverId => async (dispatch, getState) => {
const { rolePicker } = getState()
const original = rolePicker.get('originalRolesSelected')
const current = rolePicker.get('rolesSelected')
const diff = original.reduce((acc, v, k) => {
if (current.get(k) !== v) {
// if original value is false, then we know we're adding, otherwise removing.
if (v !== true) {
return acc.set('added', acc.get('added').add(k))
} else {
return acc.set('removed', acc.get('removed').add(k))
}
}
return acc
}, Map({ added: Set(), removed: Set() }))
await superagent.patch(`/api/servers/${serverId}/roles`).send(diff.toJS())
}

View file

@ -1,10 +1,11 @@
import React, { Component } from 'react'
import React, { Component, Fragment } from 'react'
import { connect } from 'react-redux'
import superagent from 'superagent'
import * as Actions from './actions'
import './RolePicker.sass'
import Role from '../role'
import { Scrollbars } from 'react-custom-scrollbars';
const mapState = ({ rolePicker, servers }, ownProps) => {
return {
@ -31,15 +32,21 @@ class RolePicker extends Component {
return this.props.data.getIn([ 'rolesSelected', id ])
}
get rolesHaveChanged () {
const { data } = this.props
return !data.get('rolesSelected').equals(data.get('originalRolesSelected'))
}
render () {
const { data, server } = this.props
const { data, server, dispatch } = this.props
const vm = data.get('viewMap')
if (server === undefined) {
return null
}
return <div className={`role-picker ${(data.get('hidden')) ? 'hidden' : ''}`}>
return <div className={`inner role-picker ${(data.get('hidden')) ? 'hidden' : ''}`}>
{/* <Scrollbars> */}
{ (server.get('message') !== '')
? <section>
<h3>Server Message</h3>
@ -48,7 +55,18 @@ class RolePicker extends Component {
: null
}
<section>
<h3>Roles</h3>
<div className="role-picker__roles-header">
<h3>Roles</h3>
<div className="role-picker__spacer"></div>
<div className={`role-picker__actions ${(!this.rolesHaveChanged) ? 'hidden' : ''}`}>
<button disabled={!this.rolesHaveChanged} onClick={() => dispatch(Actions.resetSelected)} className="uk-button action__button secondary">
Reset
</button>
<button disabled={!this.rolesHaveChanged} onClick={() => dispatch(Actions.submitSelected(server.id))} className="uk-button action__button primary">
Save Changes
</button>
</div>
</div>
<div className="role-picker__categories">
{
vm.map((c, name) => {
@ -68,6 +86,8 @@ class RolePicker extends Component {
}
</div>
</section>
{/* </Scrollbars> */}
</div>
}
}

View file

@ -15,7 +15,7 @@
&:hover
.role__option
transform: translateY(-1px)
transform: translateY(-1px) translateZ(0px)
box-shadow: 0 1px 1px var(--c-dark)
border-color: var(--role-color-hover)
background-color: transparent
@ -35,11 +35,12 @@
/* display: inline-block */
background-color: transparent
overflow: hidden
transform: translateZ(0px)
border: 1px solid var(--role-color-hex)
transition: background-color 0.1s ease-in-out, border-left-width 0.3s ease-in-out, border-right-width 0.5s ease-in-out, border-color 0.1s ease-in-out, transform 0.1s ease-in-out, box-shadow 0.1s ease-out
transition: background-color 0.1s ease-in-out, border-left-width 0.3s ease-in-out, border-color 0.1s ease-in-out, transform 0.1s ease-in-out, box-shadow 0.1s ease-out
&.selected
background-color: var(--role-color-hex)
// background-color: var(--role-color-hex)
// This **must** be width-1, otherwise blink adds width to the boundaries.
border-left-width: 21px
@ -57,4 +58,4 @@
user-select: none
.role__option:active, .role:active .role__option:not(:active)
transform: translateY(0) !important
transform: translateY(0) translateZ(0px) !important

View file

@ -3,6 +3,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'
import PropTypes from 'prop-types'
import ServerCard from './ServerCard'
import UserCard from './UserCard'
import { Scrollbars } from 'react-custom-scrollbars';
class ServersNavigation extends Component {
static propTypes = {
@ -16,12 +17,14 @@ class ServersNavigation extends Component {
return <Fragment>
<UserCard user={this.props.user} />
<div className={this.props.className}>
{
this.props.servers.reduce((acc, s, i) => {
acc.push(<ServerCard server={s} user={this.props.user} key={i} />)
return acc
}, [])
}
<Scrollbars autoHeight autoHeightMax='calc(100vh - 180px)'>
{
this.props.servers.reduce((acc, s, i) => {
acc.push(<ServerCard server={s} user={this.props.user} key={i} />)
return acc
}, [])
}
</Scrollbars>
</div>
</Fragment>
}

View file

@ -1,5 +1,6 @@
import React, { Component } from 'react'
import { Route } from 'react-router-dom'
import { Scrollbars } from 'react-custom-scrollbars'
import { connect } from 'react-redux'
import './index.sass'
@ -21,10 +22,12 @@ class Servers extends Component {
render () {
return <div className="servers">
<Navigation className="servers__nav" servers={this.props.servers} user={this.props.user} />
<div className="servers__content">
<Route path='/s/:server' component={RolePicker} />
<Route path='/s/:server/edit' component={RolePicker} />
</div>
<div className="servers__content">
<Scrollbars autoHeight autoHeightMax='calc(100vh - 80px)'>
<Route path='/s/:server' component={RolePicker} />
<Route path='/s/:server/edit' component={RolePicker} />
</Scrollbars>
</div>
</div>
}
}

View file

@ -10,13 +10,17 @@
&__nav
grid-area: listing
overflow-y: scroll
height: $fullH
overflow: hidden
// height: $fullH
&__content
grid-area: content
background-color: var(--c-3)
padding: 15px
overflow-y: scroll
// padding: 15px
grid-area: content
position: relative
// height: $fullH
overflow: hidden
box-sizing: border-box
.inner
padding: 15px

View file

@ -14,20 +14,17 @@ export default (state = initialState, { type, data }) => {
return Map(data)
case Symbol.for('hide role picker ui'):
return {
...state,
hidden: data
}
return state.set('hidden', data)
case Symbol.for('reset role picker ui'):
return {
...state,
emptyRoles: data
}
return state.set('emptyRoles', data)
case Symbol.for('update selected roles'):
return state.setIn(['rolesSelected', data.id], data.state)
case Symbol.for('reset selected'):
return state.set('rolesSelected', state.get('originalRolesSelected'))
// case Symbol.for('zero role picker'):
// return initialState

View file

@ -1,50 +0,0 @@
import { observable, computed } from 'mobx'
class Store {
@observable servers = [
{
"id": "203493697696956418",
"gm": {
"nickname": "sexkittenhime",
"color": "#ff5c00"
},
"server": {
"id": "203493697696956418",
"name": "Genudine Medkit Manufacturing",
"ownerID": "62601275618889728",
"icon": "ff08d36f5aee1ff48f8377b65d031ab0"
},
"perms": {
"isAdmin": true,
"canManageRoles": true
}
},
{
"id": "386659935687147521",
"gm": {
"nickname": null,
"color": "#cca1a1"
},
"server": {
"id": "386659935687147521",
"name": "Roleypoly",
"ownerID": "62601275618889728",
"icon": "4fa0c1063649a739f3fe1a0589aa2c03"
},
"perms": {
"isAdmin": true,
"canManageRoles": true
}
}
]
@observable user = {
username: 'あたし',
discriminator: '0001',
id: '',
avatar: null
}
}
export default Store