mirror of
https://github.com/roleypoly/roleypoly-v1.git
synced 2025-06-16 02:19:08 +00:00
add role diff calculations, add action buttons, fix a few regressions
This commit is contained in:
parent
3d541ac480
commit
3c545bdeaa
13 changed files with 203 additions and 89 deletions
|
@ -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)
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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>
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue