Merge pull request #47 from EbookFoundation/feature/mobile
breakpoints for mobile displayspull/48/head
commit
9c6c841957
|
@ -18,11 +18,16 @@ const ACTIONS = {
|
|||
add_publisher: 'add_publisher',
|
||||
delete_publisher: 'delete_publisher',
|
||||
set_publishers: 'set_publishers',
|
||||
update_publisher: 'update_publisher'
|
||||
update_publisher: 'update_publisher',
|
||||
toggle_menu: 'toggle_menu'
|
||||
}
|
||||
|
||||
export default ACTIONS
|
||||
|
||||
export const toggleMenu = () => ({
|
||||
type: ACTIONS.toggle_menu
|
||||
})
|
||||
|
||||
export const setWorking = working => ({
|
||||
type: ACTIONS.set_working,
|
||||
data: working
|
||||
|
|
|
@ -7,8 +7,10 @@ import Progress from './components/Progress'
|
|||
import appReducer from './reducers'
|
||||
import adminReducer from './reducers/admin'
|
||||
import { fetchAdminData, patchUser, patchPublisher } from './actions/admin'
|
||||
import { toggleMenu } from './actions'
|
||||
import Util from './lib/Util'
|
||||
import Icon from './components/Icon'
|
||||
import IconButton from './components/IconButton'
|
||||
|
||||
import '../styles/admin.scss'
|
||||
import './containers/listitem.scss'
|
||||
|
@ -28,7 +30,8 @@ class App extends React.Component {
|
|||
},
|
||||
users: [],
|
||||
publishers: [],
|
||||
working: false
|
||||
working: false,
|
||||
navMenu: false
|
||||
}
|
||||
|
||||
this.dispatch = this.dispatch.bind(this)
|
||||
|
@ -64,10 +67,10 @@ class App extends React.Component {
|
|||
getRegisteredUsers () {
|
||||
return this.state.users.map(user => {
|
||||
return (
|
||||
<li className='uri-list-item flex-container' key={`is-admin-${user.id}`}>
|
||||
<li className='uri-list-item cols flex-container' key={`is-admin-${user.id}`}>
|
||||
<span className='flex'>{user.email}</span>
|
||||
<span className='flex'>
|
||||
<label for={`is-admin-${user.id}`} className='cb-label'>Admin?</label>
|
||||
<label htmlFor={`is-admin-${user.id}`} className='cb-label'>Admin?</label>
|
||||
<input className='checkbox' type='checkbox' checked={user.admin} onChange={() => this.dispatch(patchUser({ id: user.id, admin: !user.admin }))} id={`is-admin-${user.id}`} />
|
||||
<label htmlFor={`is-admin-${user.id}`} />
|
||||
</span>
|
||||
|
@ -84,7 +87,7 @@ class App extends React.Component {
|
|||
return (
|
||||
<li className='uri-list-item flex-container flex-vertical' key={`is-whitelisted-${pub.id}`}>
|
||||
<header><h3>{pub.name}</h3></header>
|
||||
<div className='flex flex-container'>
|
||||
<div className='cols flex flex-container'>
|
||||
<div className='flex flex-container flex-vertical key-value'>
|
||||
<span className='flex'><span className='key'>Owner:</span><span className='value'>{pub.user.email}</span></span>
|
||||
<span className='flex'><span className='key'>App ID:</span><span className='value'>{pub.appid}</span></span>
|
||||
|
@ -111,19 +114,19 @@ class App extends React.Component {
|
|||
render () {
|
||||
return (
|
||||
<Router basename='/admin'>
|
||||
<div className='root-container flex-container admin-container'>
|
||||
<div className={'root-container flex-container admin-container two-panels' + (this.state.navMenu ? ' nav-active' : '')}>
|
||||
<aside className='nav nav-left'>
|
||||
<header>
|
||||
<h1>RoE Admin</h1>
|
||||
<h1 className='flex-container'><IconButton icon='menu' className='menu-small' onClick={() => this.dispatch(toggleMenu())} /><span className='flex'>RoE Admin</span></h1>
|
||||
<h2 className='flex-container'>
|
||||
<span className='flex'>{this.state.user.email}</span>
|
||||
<a href='/logout'>Log out</a>
|
||||
</h2>
|
||||
</header>
|
||||
<ul>
|
||||
<li><NavLink to='/users'>Users</NavLink></li>
|
||||
<li><NavLink to='/publishers'>Publishers</NavLink></li>
|
||||
<li><a href='/keys'>Exit admin</a></li>
|
||||
<li className='flex-container'><NavLink to='/users'><Icon icon='account' /><span className='flex'>Users</span></NavLink></li>
|
||||
<li className='flex-container'><NavLink to='/publishers'><Icon icon='transfer-right' /><span className='flex'>Publishers</span></NavLink></li>
|
||||
<li className='flex-container'><a href='/keys'><Icon icon='exit' /><span className='flex'>Exit admin</span></a></li>
|
||||
</ul>
|
||||
</aside>
|
||||
<section className={'content flex' + (this.state.working ? ' working' : '')}>
|
||||
|
|
|
@ -18,6 +18,12 @@ function getSVG (icon) {
|
|||
case 'shield-check': return '<path d="M10,17L6,13L7.41,11.59L10,14.17L16.59,7.58L18,9M12,1L3,5V11C3,16.55 6.84,21.74 12,23C17.16,21.74 21,16.55 21,11V5L12,1Z" />'
|
||||
case 'alert-circle': return '<path d="M13,13H11V7H13M13,17H11V15H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" />'
|
||||
case 'refresh': return '<path d="M17.65,6.35C16.2,4.9 14.21,4 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20C15.73,20 18.84,17.45 19.73,14H17.65C16.83,16.33 14.61,18 12,18A6,6 0 0,1 6,12A6,6 0 0,1 12,6C13.66,6 15.14,6.69 16.22,7.78L13,11H20V4L17.65,6.35Z" />'
|
||||
case 'key': return '<path d="M22,18V22H18V19H15V16H12L9.74,13.74C9.19,13.91 8.61,14 8,14A6,6 0 0,1 2,8A6,6 0 0,1 8,2A6,6 0 0,1 14,8C14,8.61 13.91,9.19 13.74,9.74L22,18M7,5A2,2 0 0,0 5,7A2,2 0 0,0 7,9A2,2 0 0,0 9,7A2,2 0 0,0 7,5Z" />'
|
||||
case 'transfer-right': return '<path d="M3,8H5V16H3V8M7,8H9V16H7V8M11,8H13V16H11V8M15,19.25V4.75L22.25,12L15,19.25Z" />'
|
||||
case 'account': return '<path d="M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z" />'
|
||||
case 'flash': return '<path d="M7,2V13H10V22L17,10H13L17,2H7Z" />'
|
||||
case 'menu': return '<path d="M3,6H21V8H3V6M3,11H21V13H3V11M3,16H21V18H3V16Z" />'
|
||||
case 'exit': return ' <path d="M19,3H5C3.89,3 3,3.89 3,5V9H5V5H19V19H5V15H3V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3M10.08,15.58L11.5,17L16.5,12L11.5,7L10.08,8.41L12.67,11H3V13H12.67L10.08,15.58Z" />'
|
||||
default: return icon || 'missing icon prop'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
width: 100%;
|
||||
height: 46px;
|
||||
pointer-events: none;
|
||||
overflow: hidden;
|
||||
|
||||
label {
|
||||
position: absolute;
|
||||
|
@ -100,5 +101,9 @@
|
|||
& + .underlined-input-readonly.stack-h {
|
||||
margin-left: 14px;
|
||||
margin-top: 0;
|
||||
|
||||
@include break('small') {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ class PublisherListItem extends React.Component {
|
|||
<h3 className='flex'>{`${this.props.item.name}${this.props.item.whitelisted ? '' : ' (awaiting approval)'}`}</h3>
|
||||
<ConfirmIconButton icon='delete' onClick={() => this.props.dispatch(removePublisher(this.props.item.id))} />
|
||||
</header>
|
||||
<div className='flex flex-container'>
|
||||
<div className='cols flex flex-container'>
|
||||
<div className='col flex flex-container flex-vertical'>
|
||||
<div className='stack flex-container flex-vertical'>
|
||||
<span className='label'>AppID</span>
|
||||
|
@ -73,7 +73,7 @@ class PublisherListItem extends React.Component {
|
|||
<h3 className='flex'>{this.props.item.name}</h3>
|
||||
<ConfirmIconButton icon='delete' onClick={() => this.props.dispatch(removePublisher(this.props.item.id))} />
|
||||
</header>
|
||||
<div className='flex flex-container'>
|
||||
<div className='cols flex flex-container'>
|
||||
<div className='col flex flex-container flex-vertical'>
|
||||
<p>
|
||||
Download <span className='name'>{this.props.item.verification_key}.html</span> and upload it to the root directory of your webserver. Then, click <strong>VERIFY</strong> to verify that you own and control <span className='name'>{this.props.item.url}</span>.
|
||||
|
|
|
@ -23,12 +23,12 @@ class UriListItem extends React.Component {
|
|||
}
|
||||
getView () {
|
||||
return (
|
||||
<li className='uri-list-item flex-container' onClick={(e) => this.cancelEvent(e, this.props.item.id)}>
|
||||
<div className='stack flex flex-container flex-vertical'>
|
||||
<li className='cols uri-list-item flex-container' onClick={(e) => this.cancelEvent(e, this.props.item.id)}>
|
||||
<div className='col stack flex flex-container flex-vertical'>
|
||||
<span className='label'>Destination URL</span>
|
||||
<span className='value'>{this.props.item.url}</span>
|
||||
</div>
|
||||
<div className='stack flex flex-container flex-vertical'>
|
||||
<div className='col stack flex flex-container flex-vertical'>
|
||||
<span className='label'>Filters</span>
|
||||
<span className='value'>{['publisher', 'title', 'author', 'isbn'].reduce((a, x) => a + (this.props.item[x] ? 1 : 0), 0) || 'None'}</span>
|
||||
</div>
|
||||
|
|
|
@ -5,10 +5,11 @@ import Progress from './components/Progress'
|
|||
import UnderlineInput from './components/UnderlineInput'
|
||||
import UriListItem from './containers/UriListItem'
|
||||
import PublisherListItem from './containers/PublisherListItem'
|
||||
import Icon from './components/Icon'
|
||||
import IconButton from './components/IconButton'
|
||||
import ConfirmIconButton from './containers/ConfirmIconButton'
|
||||
import reducer from './reducers'
|
||||
import { fetchData, createNewUrl, setEditing, editUser, createNewPublisher, regenerateSigningSecret } from './actions'
|
||||
import { fetchData, createNewUrl, setEditing, editUser, createNewPublisher, regenerateSigningSecret, toggleMenu } from './actions'
|
||||
|
||||
import '../styles/index.scss'
|
||||
|
||||
|
@ -32,7 +33,8 @@ class App extends React.Component {
|
|||
newPublisher: { name: '', url: '' },
|
||||
editingUrl: null,
|
||||
editingPublisher: null,
|
||||
working: false
|
||||
working: false,
|
||||
navMenu: false
|
||||
}
|
||||
|
||||
this.dispatch = this.dispatch.bind(this)
|
||||
|
@ -111,21 +113,21 @@ class App extends React.Component {
|
|||
render () {
|
||||
return (
|
||||
<Router>
|
||||
<div className='root-container flex-container' onClick={() => this.dispatch(setEditing(null))}>
|
||||
<div className={'root-container flex-container two-panels' + (this.state.navMenu ? ' nav-active' : '')} onClick={() => this.dispatch(setEditing(null))}>
|
||||
<aside className='nav nav-left'>
|
||||
<header>
|
||||
<h1>River of Ebooks</h1>
|
||||
<h1 className='flex-container'><IconButton icon='menu' className='menu-small' onClick={() => this.dispatch(toggleMenu())} /><span className='flex'>River of Ebooks</span></h1>
|
||||
<h2 className='flex-container'>
|
||||
<span className='flex'>{this.state.user.email}</span>
|
||||
<a href='/logout'>Log out</a>
|
||||
</h2>
|
||||
</header>
|
||||
<ul>
|
||||
<li><NavLink to='/keys'>Publishing keys</NavLink></li>
|
||||
<li><NavLink to='/targets'>Push URIs</NavLink></li>
|
||||
<li><NavLink to='/account'>My account</NavLink></li>
|
||||
<li><NavLink to='/keys' className='flex-container'><Icon icon='key' /><span className='flex'>Publishing keys</span></NavLink></li>
|
||||
<li><NavLink to='/targets' className='flex-container'><Icon icon='transfer-right' /><span className='flex'>Push URIs</span></NavLink></li>
|
||||
<li><NavLink to='/account' className='flex-container'><Icon icon='account' /><span className='flex'>My account</span></NavLink></li>
|
||||
{(this.state.user.id === 1 || this.state.user.admin) &&
|
||||
<li><a href='/admin'>Admin</a></li>
|
||||
<li><a href='/admin' className='flex-container'><Icon icon='flash' /><span className='flex'>Admin</span></a></li>
|
||||
}
|
||||
</ul>
|
||||
</aside>
|
||||
|
@ -155,7 +157,7 @@ class App extends React.Component {
|
|||
<h2>If you own a publishing site, generate a publishing key for it here.</h2>
|
||||
</div>
|
||||
</header>
|
||||
<div className='creator flex-container'>
|
||||
<div className='creator flex-container cols'>
|
||||
<UnderlineInput
|
||||
className='flex stack-h'
|
||||
placeholder='Website name'
|
||||
|
|
|
@ -10,6 +10,10 @@ const reducer = (state = {}, action) => {
|
|||
return {
|
||||
working: data
|
||||
}
|
||||
case Actions.toggle_menu:
|
||||
return {
|
||||
navMenu: !state.navMenu
|
||||
}
|
||||
case Actions.set_user:
|
||||
return {
|
||||
user: {
|
||||
|
|
|
@ -33,10 +33,13 @@
|
|||
.creator {
|
||||
padding: 0 14px;
|
||||
line-height: 60px;
|
||||
// max-width: 500px;
|
||||
|
||||
.btn {
|
||||
margin: 12px 0 12px 12px;
|
||||
|
||||
@include break('small') {
|
||||
margin: 0 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +47,6 @@
|
|||
margin: 20px 14px;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
// overflow: hidden;
|
||||
}
|
||||
.inputs,
|
||||
.details {
|
||||
|
@ -105,6 +107,9 @@
|
|||
padding: 0 20px;
|
||||
color: $accent-2;
|
||||
|
||||
@include break('small') {
|
||||
padding: 0 5px;
|
||||
}
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
@ -115,6 +120,10 @@
|
|||
background: $accent-2;
|
||||
color: $text-light-1;
|
||||
border-radius: 3px;
|
||||
|
||||
@include break('small') {
|
||||
margin: 5px 5px 5px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +173,7 @@
|
|||
background: $black-5;
|
||||
padding: 10px;
|
||||
border-radius: 3px;
|
||||
overflow-x: scroll;
|
||||
overflow-x: auto;
|
||||
|
||||
&:before {
|
||||
display: block;
|
||||
|
|
|
@ -1,57 +1,157 @@
|
|||
.nav-left {
|
||||
min-width: 300px;
|
||||
height: 100%;
|
||||
background: $accent-1;
|
||||
color: $text-light-1;
|
||||
box-shadow: $shadow-1;
|
||||
.two-panels {
|
||||
.nav-left {
|
||||
width: 300px;
|
||||
height: 100%;
|
||||
background: $accent-1;
|
||||
color: $text-light-1;
|
||||
box-shadow: $shadow-1;
|
||||
overflow-y: auto;
|
||||
z-index: 100;
|
||||
|
||||
header {
|
||||
line-height: 50px;
|
||||
padding: 0 14px;
|
||||
|
||||
h2 {
|
||||
margin: -10px 0 0 0;
|
||||
padding: 0;
|
||||
font-weight: normal;
|
||||
font-size: 12pt;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
color: $white-2;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: $accent-3;
|
||||
}
|
||||
}
|
||||
ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
height: 50px;
|
||||
header {
|
||||
line-height: 50px;
|
||||
border-bottom: 1px solid $white-4;
|
||||
padding: 0 14px;
|
||||
|
||||
&:hover a {
|
||||
background: $white-5;
|
||||
}
|
||||
&:last-of-type {
|
||||
border-bottom: none
|
||||
}
|
||||
h1 {
|
||||
height: 50px;
|
||||
|
||||
a {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 0 12px;
|
||||
text-decoration: none !important;
|
||||
.menu-small {
|
||||
display: none;
|
||||
margin: 5px 5px 5px 0;
|
||||
|
||||
path {
|
||||
fill: $text-light-1;
|
||||
}
|
||||
|
||||
@include break('medium') {
|
||||
display: inline-block;
|
||||
margin: 5px;
|
||||
}
|
||||
}
|
||||
span:not(.icon) {
|
||||
@include break('medium') {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
h2 {
|
||||
margin: -10px 0 0 0;
|
||||
padding: 0;
|
||||
font-weight: normal;
|
||||
font-size: 12pt;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
color: $white-2;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: $accent-3;
|
||||
}
|
||||
}
|
||||
ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
&.active {
|
||||
background: $white-4;
|
||||
li {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
overflow: hidden;
|
||||
border-bottom: 1px solid $white-4;
|
||||
|
||||
&:hover a {
|
||||
background: $white-5;
|
||||
}
|
||||
&:last-of-type {
|
||||
border-bottom: none
|
||||
}
|
||||
|
||||
a {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 0 12px;
|
||||
text-decoration: none !important;
|
||||
color: $white-2;
|
||||
|
||||
&.active {
|
||||
background: $white-4;
|
||||
}
|
||||
.icon {
|
||||
margin: 5px 5px 5px 0;
|
||||
vertical-align: middle;
|
||||
|
||||
@include break('medium') {
|
||||
margin: 5px;
|
||||
}
|
||||
}
|
||||
span:not(.icon) {
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
line-height: 50px;
|
||||
|
||||
@include break('medium') {
|
||||
display: none;
|
||||
}
|
||||
@include ellip();
|
||||
}
|
||||
@include break('medium') {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.content {
|
||||
z-index: 1;
|
||||
|
||||
.cols {
|
||||
@include break('small') {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
}
|
||||
@include break('medium') {
|
||||
.nav-left {
|
||||
position: absolute;
|
||||
transition: width .3s $transition;
|
||||
|
||||
header {
|
||||
min-height: 76px;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.nav-active) {
|
||||
.nav-left {
|
||||
width: 50px;
|
||||
|
||||
header {
|
||||
padding: 0;
|
||||
|
||||
h2 {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&.nav-active {
|
||||
span:not(.icon) {
|
||||
overflow: hidden;
|
||||
display: inline-block !important;
|
||||
}
|
||||
.nav-left {
|
||||
header {
|
||||
padding: 0 14px 0 0;
|
||||
|
||||
h2 {
|
||||
display: flex;
|
||||
margin-left: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
> .content {
|
||||
margin-left: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
9825
shrinkwrap.yaml
9825
shrinkwrap.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue