mirror of
https://github.com/roleypoly/roleypoly-v1.git
synced 2025-04-25 04:09:12 +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
|
@ -8,7 +8,13 @@ class ServerService extends Service {
|
|||
}
|
||||
|
||||
async ensure (server) {
|
||||
const srv = await this.get(server.id)
|
||||
let srv
|
||||
try {
|
||||
srv = await this.get(server.id)
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
|
||||
if (srv == null) {
|
||||
return this.create({
|
||||
id: server.id,
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
"immutable": "^3.8.2",
|
||||
"prop-types": "^15.6.0",
|
||||
"react": "^16.2.0",
|
||||
"react-custom-scrollbars": "^4.2.1",
|
||||
"react-dom": "^16.2.0",
|
||||
"react-immutable-proptypes": "^2.1.0",
|
||||
"react-redux": "^5.0.6",
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/png" sizes="any" href="%PUBLIC_URL%/favicon.png"/>
|
||||
<title>Roleypoly</title>
|
||||
<script src="https://use.typekit.net/bck0pci.js"></script>
|
||||
<script>try{Typekit.load({ async: true });}catch(e){}</script>
|
||||
<!-- <script src="https://use.typekit.net/bck0pci.js"></script>
|
||||
<script>try{Typekit.load({ async: true });}catch(e){}</script> -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.35/css/uikit.min.css" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.35/js/uikit.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.35/js/uikit-icons.min.js"></script>
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
flex-wrap: wrap
|
||||
flex-direction: row
|
||||
|
||||
|
||||
&__category
|
||||
// flex: 1 3 33%
|
||||
box-sizing: border-box
|
||||
|
@ -19,3 +18,56 @@
|
|||
padding: 15px
|
||||
margin: 10px
|
||||
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>
|
||||
<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}>
|
||||
<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'
|
||||
|
||||
|
@ -22,8 +23,10 @@ class Servers extends Component {
|
|||
return <div className="servers">
|
||||
<Navigation className="servers__nav" servers={this.props.servers} user={this.props.user} />
|
||||
<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
|
46
UI/yarn.lock
46
UI/yarn.lock
|
@ -64,6 +64,10 @@ acorn@^5.0.0, acorn@^5.2.1:
|
|||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.2.1.tgz#317ac7821826c22c702d66189ab8359675f135d7"
|
||||
|
||||
add-px-to-style@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/add-px-to-style/-/add-px-to-style-1.0.0.tgz#d0c135441fa8014a8137904531096f67f28f263a"
|
||||
|
||||
address@1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/address/-/address-1.0.2.tgz#480081e82b587ba319459fef512f516fe03d58af"
|
||||
|
@ -2304,6 +2308,14 @@ dom-converter@~0.1:
|
|||
dependencies:
|
||||
utila "~0.3"
|
||||
|
||||
dom-css@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/dom-css/-/dom-css-2.1.0.tgz#fdbc2d5a015d0a3e1872e11472bbd0e7b9e6a202"
|
||||
dependencies:
|
||||
add-px-to-style "1.0.0"
|
||||
prefix-style "2.0.1"
|
||||
to-camel-case "1.0.0"
|
||||
|
||||
dom-serializer@0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
|
||||
|
@ -5812,6 +5824,10 @@ postcss@^6.0.1, postcss@^6.0.2, postcss@^6.0.6:
|
|||
source-map "^0.6.1"
|
||||
supports-color "^4.4.0"
|
||||
|
||||
prefix-style@2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/prefix-style/-/prefix-style-2.0.1.tgz#66bba9a870cfda308a5dc20e85e9120932c95a06"
|
||||
|
||||
prelude-ls@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
|
||||
|
@ -5954,6 +5970,12 @@ querystringify@~1.0.0:
|
|||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-1.0.0.tgz#6286242112c5b712fa654e526652bf6a13ff05cb"
|
||||
|
||||
raf@^3.1.0:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.0.tgz#a28876881b4bc2ca9117d4138163ddb80f781575"
|
||||
dependencies:
|
||||
performance-now "^2.1.0"
|
||||
|
||||
randomatic@^1.1.3:
|
||||
version "1.1.7"
|
||||
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c"
|
||||
|
@ -6005,6 +6027,14 @@ react-base16-styling@^0.5.1:
|
|||
lodash.flow "^3.3.0"
|
||||
pure-color "^1.2.0"
|
||||
|
||||
react-custom-scrollbars@^4.2.1:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/react-custom-scrollbars/-/react-custom-scrollbars-4.2.1.tgz#830fd9502927e97e8a78c2086813899b2a8b66db"
|
||||
dependencies:
|
||||
dom-css "^2.0.0"
|
||||
prop-types "^15.5.10"
|
||||
raf "^3.1.0"
|
||||
|
||||
react-dev-utils@^3.1.0:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-3.1.1.tgz#09ae7209a81384248db56547e718e65bd3b20eb5"
|
||||
|
@ -7233,6 +7263,12 @@ to-arraybuffer@^1.0.0:
|
|||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
|
||||
|
||||
to-camel-case@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/to-camel-case/-/to-camel-case-1.0.0.tgz#1a56054b2f9d696298ce66a60897322b6f423e46"
|
||||
dependencies:
|
||||
to-space-case "^1.0.0"
|
||||
|
||||
to-descriptor@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/to-descriptor/-/to-descriptor-1.0.1.tgz#a0e678c34ebc7d2dae464d8372bc21479d9c2bcd"
|
||||
|
@ -7241,6 +7277,16 @@ to-fast-properties@^1.0.3:
|
|||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
|
||||
|
||||
to-no-case@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/to-no-case/-/to-no-case-1.0.2.tgz#c722907164ef6b178132c8e69930212d1b4aa16a"
|
||||
|
||||
to-space-case@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/to-space-case/-/to-space-case-1.0.0.tgz#b052daafb1b2b29dc770cea0163e5ec0ebc9fc17"
|
||||
dependencies:
|
||||
to-no-case "^1.0.0"
|
||||
|
||||
toposort@^1.0.0:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.6.tgz#c31748e55d210effc00fdcdc7d6e68d7d7bb9cec"
|
||||
|
|
Loading…
Add table
Reference in a new issue