add why no roles and landing pages

This commit is contained in:
Katalina / stardust 2017-12-31 13:01:21 -06:00
parent 309aee427e
commit 3d07efb5fa
24 changed files with 329 additions and 15 deletions

View file

@ -6,3 +6,5 @@ DISCORD_CLIENT_SECRET=PZd3u4RkokhnB8MVdALPz5
DISCORD_BOT_TOKEN=qgTk4wm9Q7ECmMCovpmJVNCBltzJhL
APP_URL=http://localhost:6769
APP_KEY=PJoayPGqi8vfYVFYBDgSeJSDYUpzBX
IS_BOT=true
ROOT_USERS=62601275618889721

View file

@ -7,6 +7,7 @@
"custom-react-scripts": "0.2.1",
"history": "^4.7.2",
"immutable": "^3.8.2",
"moment": "^2.20.1",
"prop-types": "^15.6.0",
"react": "^16.2.0",
"react-custom-scrollbars": "^4.2.1",
@ -18,6 +19,8 @@
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2",
"react-router-redux": "^5.0.0-alpha.8",
"react-typist": "^2.0.4",
"react-typist-cycle": "^0.1.2",
"redux": "^3.7.2",
"redux-logger": "^3.0.6",
"redux-thunk": "^2.2.0",
@ -33,7 +36,6 @@
"proxy": "http://localhost:6769",
"devDependencies": {
"eslint": "^4.14.0",
"eslint-config-standard": "^11.0.0-beta.0",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-node": "^5.2.1",

View file

@ -25,7 +25,7 @@ export const userInit = async dispatch => {
dispatch(fetchServers)
} catch (e) {
window.location.href = '/oauth/flow'
// window.location.href = '/oauth/flow'
}
} else {
dispatch({

View file

@ -22,6 +22,22 @@
&__uncat-zone
padding: 10px
&__alert
background-color: var(--c-5)
padding: 15px
a
color: var(--c-9)
text-decoration: none
font-style: italic
transition: color 0.15s ease-in-out
&:hover
color: var(--c-white)
.role-editor__category
box-sizing: border-box
background-color: var(--c-1)

View file

@ -7,13 +7,14 @@ import superagent from 'superagent'
export const constructView = id => (dispatch, getState) => {
const server = getState().servers.get(id)
let { viewMap } = getViewMap(server)
let { viewMap, hasSafeRoles } = getViewMap(server)
viewMap = viewMap.map(c => c.set('mode', Symbol.for('drop')))
dispatch({
type: Symbol.for('re: setup'),
data: {
viewMap: viewMap,
hasSafeRoles,
viewMap,
originalSnapshot: viewMap
}
})

View file

@ -2,6 +2,8 @@ import React, { Component } from 'react'
import { Set } from 'immutable'
import { connect } from 'react-redux'
import { DropTarget } from 'react-dnd'
import { Link, Prompt } from 'react-router-dom'
import { Scrollbars } from 'react-custom-scrollbars'
import * as Actions from './actions'
import * as PickerActions from '../role-picker/actions'
import * as UIActions from '../../actions/ui'
@ -10,7 +12,6 @@ import './RoleEditor.sass'
import Category from './Category'
import CategoryEditor from './CategoryEditor'
import Role from '../role/draggable'
import { Scrollbars } from 'react-custom-scrollbars';
const mapState = ({ rolePicker, roleEditor, servers }, ownProps) => ({
rp: rolePicker,
@ -113,6 +114,7 @@ class RoleEditor extends Component {
render () {
const vm = this.props.editor.get('viewMap')
return <div className="inner role-editor">
<Prompt when={this.hasChanged} message="Are you sure you want to leave? You have unsaved changes that will be lost." />
<div className="role-picker__header" style={{ marginBottom: 10 }}>
<h3>{this.props.server.getIn(['server','name'])}</h3>
<div className="role-picker__spacer"></div>
@ -161,6 +163,13 @@ class RoleEditor extends Component {
.map((r, k) => <Role key={k} categoryId='Uncategorized' role={r} />)
.toArray()
}
{
(!this.props.editor.hasSafeRoles)
? <div className="role-editor__alert">
<Link to="/help/why-no-roles">Why are there no roles here? <i uk-icon="icon: info" /></Link>
</div>
: null
}
</div>
</Scrollbars>
</div>)

View file

@ -48,9 +48,12 @@ export const getViewMap = server => {
const selected = roles.reduce((acc, r) => acc.set(r.get('id'), r.get('selected')), Map())
const hasSafeRoles = allRoles.size > 0
return {
viewMap,
selected
selected,
hasSafeRoles
}
}

View file

@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'
import { connect } from 'react-redux'
import { Prompt } from 'react-router-dom'
import superagent from 'superagent'
import * as Actions from './actions'
import * as UIActions from '../../actions/ui'
@ -100,6 +101,7 @@ class RolePicker extends Component {
}
return <div className={`inner role-picker ${(data.get('hidden')) ? 'hidden' : ''}`}>
<Prompt when={this.rolesHaveChanged} message="Are you sure you want to leave? You have unsaved changes that will be lost." />
{ this.renderServerMessage(server) }
<section>
<div className="role-picker__header">

View file

@ -22,6 +22,7 @@
cursor: inherit
&:hover:not(.disabled)
cursor: pointer
.role__option
transform: translateY(-1px) translateZ(0px)
box-shadow: 0 1px 1px var(--c-dark)

View file

@ -0,0 +1,19 @@
import React, { Component } from 'react'
import { Map } from 'immutable'
import Role from './index'
export default class DemoRole extends Component {
state = {
isSelected: false
}
handleToggle = () => {
this.setState({ isSelected: !this.state.isSelected })
}
render () {
return <Role selected={this.state.isSelected} role={Map({ name: this.props.name, color: this.props.color })} onToggle={this.handleToggle} type='button' />
}
}

View file

@ -11,7 +11,9 @@ class Wrapper extends Component {
<div style={styles.container}>
<nav uk-navbar='' style={styles.nav} className='uk-navbar-transparent'>
<div className='uk-navbar-left'>
<Logotype style={{ height: '2rem' }} className='wrapper__logotype' />
<Link to="/">
<Logotype style={{ height: '2rem' }} className='wrapper__logotype' />
</Link>
</div>
<div className='uk-navbar-right'>
<ul className='uk-navbar-nav'>

View file

@ -34,4 +34,11 @@
&.secondary
background-color: var(--c-3)
color: var(--c-7)
color: var(--c-7)
&.discord
background-color: var(--c-discord)
color: var(--c-white)
&-logo
height: 1.6rem

View file

@ -20,6 +20,8 @@ body {
--c-1: #453e3d;
--c-dark: #332d2d;
--c-green: #46b646;
--c-red: #e95353;
--c-discord: #7289da;
}
::selection {

61
UI/src/pages/Landing.js Normal file
View file

@ -0,0 +1,61 @@
import React, { Component, Fragment } from 'react'
import { Link } from 'react-router-dom'
import Scrollbars from 'react-custom-scrollbars'
import Typist from 'react-typist'
import moment from 'moment'
import './landing.sass'
import discordLogo from './images/discord-logo.svg'
import RoleDemo from '../components/role/demo'
const Landing = ({ root = false }) => <div className="landing uk-width-1-1 uk-text-center">
<div className="uk-container">
<section>
<h1>Self-assignable Discord roles for humans.</h1>
<h4>Ditch bot commands once and for all.</h4>
</section>
<section>
<Link to="/oauth/flow" className="uk-button rp-button discord"><img src={discordLogo} className="rp-button-logo"/> Sign in with Discord</Link>
</section>
<section uk-grid="">
{/* Typist */}
<div className="uk-width-1-2">
<div className="landing__discord">
<div className="discord__chat">
<span className="timestamp">{moment().format('LT')}</span>
<span className="username">Kata カタ</span>
<span className="text">Hey, I want some roles!</span>
</div>
<div className="discord__textarea">
<Typist cursor={{ blink: true }}>
<span>.iam a cute role </span>
<Typist.Backspace count={30} delay={1500} />
<span>.iam a vanity role </span>
<Typist.Backspace count={30} delay={1500} />
<span>.iam a brave role </span>
<Typist.Backspace count={30} delay={1500} />
<span>.iam a proud role </span>
<Typist.Backspace count={30} delay={1500} />
<span>.iam a wonderful role </span>
<Typist.Backspace count={30} delay={1500} />
<span>i have too many roles.</span>
</Typist>
</div>
</div>
<p className="subtext">Why are we stuck in the stupid ages?</p>
</div>
{/* role side */}
<div className="uk-width-1-2">
<div className="landing__roleypoly">
<RoleDemo name="a cute role ♡" color="#3EC1BF" />
<RoleDemo name="a vanity role ♡" color="#F7335B" />
<RoleDemo name="a brave role ♡" color="#A8D0B8" />
<RoleDemo name="a proud role ♡" color="#5C8B88" />
<RoleDemo name="a wonderful role ♡" color="#D6B3C7" />
</div>
<p className="subtext">It's 2018. We can do better.</p>
</div>
</section>
</div>
</div>
export default Landing

View file

@ -0,0 +1,19 @@
import React, { Fragment } from 'react'
import goodImg from './images/whynoroles-good.png'
import badImg from './images/whynoroles-bad.png'
const WhyNoRoles = (props) => {
return <Fragment>
<h2>Why don't I see any roles in my editor?</h2>
<p>Roleypoly needs to be a higher role position than other roles in order to assign them to anyone.</p>
<h3 className="pages__bad">Bad <i uk-icon="icon: ban"></i></h3>
<img src={badImg} alt="Bad example"/>
<p>In this example, Roleypoly is at the bottom of the list. It can't assign anyone any roles above it.</p>
<h3 className="pages__good">Good <i uk-icon="icon: check"></i></h3>
<img src={goodImg} alt="Good example"/>
<p>In this example, Roleypoly is above other roles, and will be able to assign them.</p>
</Fragment>
}
export default WhyNoRoles

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 245 240" style="enable-background:new 0 0 245 240;" xml:space="preserve">
<style type="text/css">
.st0{fill:#efefef;}
</style>
<g>
<path class="st0" d="M104.4,103.9c-5.7,0-10.2,5-10.2,11.1c0,6.1,4.6,11.1,10.2,11.1c5.7,0,10.2-5,10.2-11.1
C114.7,108.9,110.1,103.9,104.4,103.9z"/>
<path class="st0" d="M140.9,103.9c-5.7,0-10.2,5-10.2,11.1c0,6.1,4.6,11.1,10.2,11.1c5.7,0,10.2-5,10.2-11.1
C151.1,108.9,146.6,103.9,140.9,103.9z"/>
<path class="st0" d="M189.5,20H55.5C44.2,20,35,29.2,35,40.6v135.2c0,11.4,9.2,20.6,20.5,20.6h113.4l-5.3-18.5l12.8,11.9l12.1,11.2
L210,220v-44.2v-10V40.6C210,29.2,200.8,20,189.5,20z M150.9,150.6c0,0-3.6-4.3-6.6-8.1c13.1-3.7,18.1-11.9,18.1-11.9
c-4.1,2.7-8,4.6-11.5,5.9c-5,2.1-9.8,3.5-14.5,4.3c-9.6,1.8-18.4,1.3-25.9-0.1c-5.7-1.1-10.6-2.7-14.7-4.3c-2.3-0.9-4.8-2-7.3-3.4
c-0.3-0.2-0.6-0.3-0.9-0.5c-0.2-0.1-0.3-0.2-0.4-0.3c-1.8-1-2.8-1.7-2.8-1.7s4.8,8,17.5,11.8c-3,3.8-6.7,8.3-6.7,8.3
c-22.1-0.7-30.5-15.2-30.5-15.2c0-32.2,14.4-58.3,14.4-58.3c14.4-10.8,28.1-10.5,28.1-10.5l1,1.2c-18,5.2-26.3,13.1-26.3,13.1
s2.2-1.2,5.9-2.9c10.7-4.7,19.2-6,22.7-6.3c0.6-0.1,1.1-0.2,1.7-0.2c6.1-0.8,13-1,20.2-0.2c9.5,1.1,19.7,3.9,30.1,9.6
c0,0-7.9-7.5-24.9-12.7l1.4-1.6c0,0,13.7-0.3,28.1,10.5c0,0,14.4,26.1,14.4,58.3C181.5,135.4,173,149.9,150.9,150.6z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

25
UI/src/pages/index.js Normal file
View file

@ -0,0 +1,25 @@
import React from 'react'
import { Route, Switch } from 'react-router-dom'
import Scrollbars from 'react-custom-scrollbars'
import './pages.sass'
import WhyNoRoles from './WhyNoRoles'
import LandingPage from './Landing'
export const Landing = LandingPage // re-export
const isDev = process.env.NODE_ENV === 'development'
const Pages = (props) => {
return <div className="pages">
<Scrollbars autoHeight autoHeightMax='calc(100vh - 80px)'>
<div className="pages-inner">
<Switch>
<Route path="/help/why-no-roles" component={WhyNoRoles} />
{/* { isDev ? <Route path="/p/landing" component={Landing} /> : null } */}
</Switch>
</div>
</Scrollbars>
</div>
}
export default Pages

72
UI/src/pages/landing.sass Normal file
View file

@ -0,0 +1,72 @@
.landing
.Typist .Cursor
display: inline-block
color: transparent
border-left: 1px solid var(--c-white)
&--blinking
opacity: 1
animation: blink 2s ease-in-out infinite
@keyframes blink
0%
opacity: 1
50%
opacity: 0
100%
opacity: 1
&__roleypoly
&__discord
--not-quite-black: #23272A
--dark-but-not-black: #2C2F33
--greyple: #99AAB5
--blurple: var(--c-discord)
background-color: var(--dark-but-not-black)
border: 1px solid var(--not-quite-black)
box-shadow: 0 0 1px rgba(0,0,0,0.3)
padding: 10px
text-align: left
color: var(--c-white)
.discord
&__chat
padding: 10px 0
span
display: inline-block
margin-left: 5px
.timestamp
font-size: 0.7em
color: hsla(0,0%,100%,.2)
.username
font-weight: bold
&__textarea
background-color: hsla(218,5%,47%,.3)
border-radius: 5px
padding: 10px
section
margin-top: 50px
h1
color: var(--c-7)
h4
color: var(--c-9)
h1,h2,h3,h4,h5,h6
margin: 0.3em
.subtext
color: hsla(0,0%,100%,0.8)
font-size: 0.9em
line-height: 1.6

16
UI/src/pages/pages.sass Normal file
View file

@ -0,0 +1,16 @@
.pages
background-color: var(--c-3)
&-inner
padding: 45px 35px
&__bad
color: var(--c-red)
&__good
color: var(--c-green)
img
max-width: 75%
box-shadow: 0 0 1px var(--c-dark)
border: 1px solid var(--c-1)

View file

@ -2,14 +2,15 @@ import { Map, OrderedMap, fromJS } from 'immutable'
const initialState = Map({
viewMap: OrderedMap({}),
originalSnapshot: OrderedMap({})
originalSnapshot: OrderedMap({}),
hasAvailableRoles: true
})
const reducer = (state = initialState, { type, data }) => {
switch (type) {
case Symbol.for('re: setup'):
const { viewMap, originalSnapshot, ...rest } = data
return Map({ viewMap: OrderedMap(viewMap), originalSnapshot: OrderedMap(originalSnapshot), ...rest })
return state.merge({ viewMap: OrderedMap(viewMap), originalSnapshot: OrderedMap(originalSnapshot), ...rest })
case Symbol.for('re: set category'):
return state.setIn(['viewMap', data.id], Map(data))

View file

@ -1,28 +1,39 @@
import React, { Component, Fragment } from 'react'
import { Route } from 'react-router-dom'
import { Route, Switch, Redirect } from 'react-router-dom'
import { connect } from 'react-redux'
import { withRouter } from 'react-router'
import Servers from '../components/servers'
import OauthCallback from '../components/oauth-callback'
import OauthFlow from '../components/oauth-flow'
import Pages, { Landing } from '../pages'
const aaa = (props) => (<div>{ JSON.stringify(props) }</div>)
@withRouter
@connect(({ appState }) => ({ ready: appState.ready }))
@connect(({ appState, user }) => ({ ready: appState.ready, user }))
export default class AppRouter extends Component {
render () {
if (!this.props.ready) {
return null
}
return <Fragment>
<Route exact path='/' component={aaa} />
return <Switch>
<Route path='/s' component={Servers} />
<Route path='/root' component={aaa} />
<Route path='/oauth/callback' component={OauthCallback} />
<Route path='/oauth/flow' component={OauthFlow} />
</Fragment>
<Route path="/p/landing" exact component={Landing} />
<Route path='/p' component={Pages} />
<Route path='/help' component={Pages} />
<Route exact path='/' render={() =>
this.props.user.get('isLoggedIn')
? <Redirect to="/s" />
: <Landing root={true} />
} />
</Switch>
}
}

View file

@ -4965,6 +4965,10 @@ mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdi
dependencies:
minimist "0.0.8"
moment@^2.20.1:
version "2.20.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.20.1.tgz#d6eb1a46cbcc14a2b2f9434112c1ff8907f313fd"
most@^1.6.1:
version "1.7.2"
resolved "https://registry.yarnpkg.com/most/-/most-1.7.2.tgz#3f8b8bf0e4410ad8490b3599ea3777fca964a1c4"
@ -6178,6 +6182,24 @@ react-router@^4.2.0:
prop-types "^15.5.4"
warning "^3.0.0"
react-typist-cycle@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/react-typist-cycle/-/react-typist-cycle-0.1.2.tgz#d5fac8ded22ce29dec6df145a238a03d4c098a86"
dependencies:
react-typist "^1.1.0"
react-typist@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/react-typist/-/react-typist-1.1.1.tgz#3b651f8c89ce240f80afbd63038c1bcb113accf4"
dependencies:
prop-types "^15.5.10"
react-typist@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/react-typist/-/react-typist-2.0.4.tgz#e7ee4de53ead913d363d38f07b700c00ce271be0"
dependencies:
prop-types "^15.5.10"
react@^16.2.0:
version "16.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba"