Improving UX
parent
f70fed4346
commit
19a04a6297
48
package.json
48
package.json
|
@ -1,32 +1,32 @@
|
|||
{
|
||||
"name" : "material-console",
|
||||
"version" : "0.5.29",
|
||||
"description" : "",
|
||||
"homepage" : "http://zetapath.com",
|
||||
"author" : "Zetapath LTD.",
|
||||
"name": "material-console",
|
||||
"version": "0.5.29",
|
||||
"description": "",
|
||||
"homepage": "http://zetapath.com",
|
||||
"author": "Zetapath LTD.",
|
||||
"dependencies": {
|
||||
"coffee-script" : "*"
|
||||
"coffee-script": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"browserify" : "^10.0.0",
|
||||
"coffee-reactify" : "^3.0.0",
|
||||
"moment" : "^2.10.2",
|
||||
"react" : "^0.13.2",
|
||||
"spa-router" : "^0.5.20",
|
||||
"vinyl-source-stream" : "^1.1.0",
|
||||
"gulp" : "*",
|
||||
"gulp-cjsx" : "*",
|
||||
"gulp-concat" : "*",
|
||||
"gulp-connect" : "*",
|
||||
"gulp-flatten" : "*",
|
||||
"gulp-header" : "*",
|
||||
"gulp-stylus" : "*",
|
||||
"gulp-uglify" : "*",
|
||||
"gulp-util" : "*",
|
||||
"gulp-yml" : "*"
|
||||
"browserify": "^10.0.0",
|
||||
"coffee-reactify": "^3.0.0",
|
||||
"gulp": "*",
|
||||
"gulp-cjsx": "*",
|
||||
"gulp-concat": "*",
|
||||
"gulp-connect": "*",
|
||||
"gulp-flatten": "*",
|
||||
"gulp-header": "*",
|
||||
"gulp-stylus": "*",
|
||||
"gulp-uglify": "*",
|
||||
"gulp-util": "*",
|
||||
"gulp-yml": "*",
|
||||
"moment": "^2.10.2",
|
||||
"react": "^0.13.2",
|
||||
"spa-router": "^0.5.20",
|
||||
"vinyl-source-stream": "^1.1.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start" : "gulp",
|
||||
"postinstall" : "bower install"
|
||||
"start": "gulp",
|
||||
"postinstall": "bower install"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,11 @@ App = React.createClass
|
|||
SPArouter.listen
|
||||
"/session/:id" : (id) =>
|
||||
@setState session: false, context: id
|
||||
"/console/:context" : (context) =>
|
||||
"/:context/:area/:element" : (context, area, element) =>
|
||||
@setState session: true, context: context
|
||||
"/:context/:area" : (context, area) =>
|
||||
@setState session: true, context: context
|
||||
"/:context" : (context) =>
|
||||
@setState session: true, context: context
|
||||
|
||||
# -- Events
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
###
|
||||
@todo
|
||||
###
|
||||
|
||||
module.exports = React.createClass
|
||||
|
||||
# -- States & Properties
|
||||
propTypes:
|
||||
caption : React.PropTypes.string
|
||||
icon : React.PropTypes.string
|
||||
|
||||
getDefaultProps: ->
|
||||
icon : undefined
|
||||
|
||||
# -- Events
|
||||
onClick: (event) ->
|
||||
event.preventDefault()
|
||||
console.log ">"
|
||||
|
||||
# -- Render
|
||||
render: ->
|
||||
<button onClick={@onClick} className={@props.style}>
|
||||
<abbr>{@props.caption}</abbr>
|
||||
</button>
|
|
@ -2,8 +2,10 @@
|
|||
@todo
|
||||
###
|
||||
|
||||
Button = require './button'
|
||||
Navigation = require './navigation'
|
||||
|
||||
|
||||
module.exports = React.createClass
|
||||
|
||||
# -- States & Properties
|
||||
|
@ -32,13 +34,16 @@ module.exports = React.createClass
|
|||
# -- Render
|
||||
render: ->
|
||||
<header ref="header" data-component="header" data-flex="horizontal center grow">
|
||||
<div>
|
||||
<img src="http://soyjavi.com/assets/img/soyjavi.hat.jpg" data-flex-grow="min"/>
|
||||
<div data-flex-grow="max">
|
||||
<Navigation routes={@props.routes} role="text"/>
|
||||
<h1>{@props.title}</h1>
|
||||
<div>
|
||||
<h1>{@props.title}</h1>
|
||||
</div>
|
||||
{ <Navigation routes={@props.subroutes} role="text"/> if @props.subroutes }
|
||||
</div>
|
||||
<nav data-role="circle">
|
||||
<button className="main">+</button>
|
||||
<button>?</button>
|
||||
<Button caption="+" style="circle primary"/>
|
||||
<Button caption="?" style="circle secondary"/>
|
||||
</nav>
|
||||
</header>
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
###
|
||||
@todo
|
||||
###
|
||||
|
||||
module.exports = React.createClass
|
||||
|
||||
# -- States & Properties
|
||||
propTypes:
|
||||
itemFactory : React.PropTypes.func.isRequired
|
||||
dataSource : React.PropTypes.array.isRequired
|
||||
|
||||
getDefaultProps: ->
|
||||
itemFactory : (index) -> <div key={index}></div>
|
||||
dataSource : []
|
||||
|
||||
getInitialState: ->
|
||||
scrolling : false
|
||||
scroll : 0
|
||||
|
||||
# -- Lifecycle
|
||||
componentDidMount: ->
|
||||
@setState clientHeight: @getDOMNode().clientHeight
|
||||
|
||||
# -- Events
|
||||
onScroll: (event) ->
|
||||
scroll = @refs.section.getDOMNode().scrollTop
|
||||
@props.onScroll? scroll > @state.scroll
|
||||
@setState scroll: scroll
|
||||
|
||||
# -- Render
|
||||
render: ->
|
||||
<section ref="section" onScroll={@onScroll} className="scroll">
|
||||
<ul>
|
||||
{
|
||||
for item, index in @props.dataSource
|
||||
<li key={index}>{@props.itemFactory item}</li>
|
||||
}
|
||||
</ul>
|
||||
</section>
|
|
@ -0,0 +1,13 @@
|
|||
###
|
||||
@todo
|
||||
###
|
||||
|
||||
module.exports = (data) ->
|
||||
<div data-flex="horizontal center" className="activity">
|
||||
<figure style={backgroundImage: "url()"} />
|
||||
<div data-flex="vertical" data-flex-grow="max">
|
||||
<strong data-flex-grow="max">text</strong>
|
||||
<small>lorem ipsum...</small>
|
||||
</div>
|
||||
<small>moment</small>
|
||||
</div>
|
|
@ -23,7 +23,11 @@ module.exports = React.createClass
|
|||
{
|
||||
for route, index in @props.routes
|
||||
method = if route.back is true then @onBack
|
||||
<a href={"#" + route.route} key={index} onClick={method}>
|
||||
console.log route.className
|
||||
<a href={"#" + route.route}
|
||||
key={index}
|
||||
className={route.className}
|
||||
onClick={method}>
|
||||
{route.label}
|
||||
</a>
|
||||
}
|
||||
|
|
|
@ -8,11 +8,14 @@ module.exports =
|
|||
|
||||
SUBROUTES:
|
||||
CAMPAIGNS: [
|
||||
label: "list", route: "/console/campaigns"
|
||||
label: "list", route: "/campaigns/list"
|
||||
,
|
||||
label: "reports", route: "/console/campaigns/reports"
|
||||
label: "reports", route: "/campaigns/reports"
|
||||
]
|
||||
|
||||
CREATIVES: [
|
||||
label: "list", route: "/console/creatives/list"
|
||||
label: "list", route: "/creatives/list"
|
||||
]
|
||||
|
||||
HEIGHT:
|
||||
LI : 80
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
SPArouter = require "spa-router"
|
||||
Header = require "../components/header"
|
||||
List = require "../components/list"
|
||||
ListItem = require "../components/list_item"
|
||||
C = require "../modules/constants"
|
||||
|
||||
module.exports = React.createClass
|
||||
|
@ -14,35 +16,34 @@ module.exports = React.createClass
|
|||
|
||||
getDefaultProps: ->
|
||||
routes : [
|
||||
label: "Campaigns", route: "/console/campaigns"
|
||||
label: "Campaigns", route: "/campaigns"
|
||||
,
|
||||
label: "Creatives", route: "/console/creatives"
|
||||
label: "Creatives", route: "/creatives"
|
||||
,
|
||||
label: "Users", route: "/console/users"
|
||||
label: "Users", route: "/users"
|
||||
,
|
||||
label: "Deals", route: "/console/deals"
|
||||
label: "Deals", route: "/deals"
|
||||
,
|
||||
label: "Analytics", route: "/console/analytics"
|
||||
label: "Analytics", route: "/analytics"
|
||||
]
|
||||
subroutes : []
|
||||
|
||||
getInitialState: ->
|
||||
scrolling : false
|
||||
|
||||
onScroll: (value) ->
|
||||
@setState scrolling: value
|
||||
|
||||
render: ->
|
||||
context = @props.context.toUpperCase()
|
||||
<article data-screen="console">
|
||||
<Header title="Console" routes={@props.routes} subroutes={C.SUBROUTES[context]} />
|
||||
<section className="scroll">
|
||||
<ul>
|
||||
{
|
||||
for i in [1..128]
|
||||
<li data-flex="horizontal grow">
|
||||
<img src="http://" data-flex-grow="min" />
|
||||
<div data-flex="vertical" data-flex-grow="max">
|
||||
<strong>Title {{i}}</strong>
|
||||
<small>lorem ipsum....</small>
|
||||
</div>
|
||||
<span data-flex-grow="min">time ago...</span>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</section>
|
||||
mock = (id: i, title: "Title #{i}" for i in [1..128])
|
||||
|
||||
for route in @props.routes
|
||||
route.className = if route.label.toLowerCase() is @props.context then "active" else ""
|
||||
|
||||
<article data-screen="console" className={"scrolling" if @state.scrolling}>
|
||||
<Header title="Console"
|
||||
routes={@props.routes}
|
||||
subroutes={C.SUBROUTES[context]} />
|
||||
<List dataSource={mock} itemFactory={ListItem} onScroll={@onScroll} />
|
||||
</article>
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
@import url("http://fonts.googleapis.com/css?family=Roboto:300,400,700")
|
||||
@import url("http://fonts.googleapis.com/css?family=Roboto:200,300,700")
|
||||
|
||||
// -- Colors
|
||||
COLOR = #222222
|
||||
BACKGROUND = #ffffff
|
||||
BACKGROUND = #F5F5F5
|
||||
THEME = #00bcd4
|
||||
|
||||
WHITE = #ffffff
|
||||
PRIMARY = rgb(255, 64, 129)
|
||||
|
||||
// -- Fonts
|
||||
|
@ -14,14 +15,15 @@ FONT_SIZE_TINY = 80%
|
|||
FONT_SIZE_SMALL = 90%
|
||||
FONT_SIZE_NORMAL = 100%
|
||||
FONT_SIZE_BIG = 120%
|
||||
FONT_WEIGHT_THIN = 100
|
||||
FONT_WEIGHT_NORMAL = 400
|
||||
FONT_WEIGHT_THIN = 200
|
||||
FONT_WEIGHT_NORMAL = 300
|
||||
FONT_WEIGHT_BOLD = 700
|
||||
|
||||
// -- Sizes
|
||||
UNIT = 4rem
|
||||
SPACE = (UNIT * 0.29)
|
||||
HEADER_HEIGHT = 25vh
|
||||
OFFSET = (UNIT * 1.35)
|
||||
HEADER_HEIGHT = 33vh
|
||||
|
||||
BUTTON_HEIGHT = (2.5 * SPACE)
|
||||
BUTTON_HEIGHT = 14vw
|
||||
|
@ -29,6 +31,11 @@ BUTTON_CIRCLE_HEIGHT = (2.75 * SPACE)
|
|||
BORDER_RADIUS = (SPACE / 2)
|
||||
H1_SHADOW = (SPACE / 6) (SPACE / 6) rgba(0,0,0,0.2)
|
||||
|
||||
// -- Shadows
|
||||
HEADER_SHADOW = 0 2px 5px rgba(0,0,0,0.26)
|
||||
BUTTON_SHADOW = 0 1px 6px rgba(0, 0, 0, 0.12), 0 1px 4px rgba(0, 0, 0, 0.24)
|
||||
|
||||
|
||||
// -- Animations
|
||||
ANIMATION_DURATION = 450ms
|
||||
ANIMATION_EASE = cubic-bezier(.55,0,.1,1)
|
||||
|
|
|
@ -4,15 +4,17 @@ body
|
|||
font-weight : FONT_WEIGHT_NORMAL
|
||||
color : COLOR
|
||||
background-color : BACKGROUND
|
||||
|
||||
a
|
||||
color : WHITE
|
||||
h1, h2, h3, h4, h5, h6
|
||||
font-weight : FONT_WEIGHT_NORMAL
|
||||
h1
|
||||
font-size : SIZE = (1.75 * FONT_SIZE_NORMAL)
|
||||
line-height : SIZE
|
||||
h2
|
||||
font-size : (1.5 * FONT_SIZE_NORMAL)
|
||||
|
||||
// -- Classes
|
||||
.scroll
|
||||
overflow-x : hidden
|
||||
overflow-y : scroll
|
||||
|
|
|
@ -7,4 +7,22 @@ button, .button
|
|||
text-align : center
|
||||
border : none
|
||||
overflow : hidden
|
||||
transition all ANIMATION_DURATION ANIMATION_EASE
|
||||
transition-property opacity, box-shadow
|
||||
transition-duration ANIMATION_DURATION
|
||||
transition-timing-function ANIMATION_EASE
|
||||
|
||||
&.circle
|
||||
width : SIZE = BUTTON_CIRCLE_HEIGHT
|
||||
height : SIZE
|
||||
font-size : FONT_SIZE_BIG
|
||||
line-height : SIZE
|
||||
border-radius : SIZE
|
||||
box-shadow BUTTON_SHADOW
|
||||
&:hover, &:active
|
||||
box-shadow BUTTON_SHADOW, inset 0 0 0 UNIT alpha(WHITE, 15%)
|
||||
|
||||
// -- Colors
|
||||
&.primary
|
||||
background-color : PRIMARY
|
||||
&.secondary
|
||||
background-color : PRIMARY
|
||||
|
|
|
@ -1,33 +1,45 @@
|
|||
header
|
||||
position : fixed
|
||||
// padding : UNIT 0
|
||||
height : HEADER_HEIGHT
|
||||
width : 100vw
|
||||
background-color : THEME
|
||||
color : WHITE
|
||||
transition all ANIMATION_DURATION ANIMATION_EASE
|
||||
> *
|
||||
padding : 0 UNIT
|
||||
background-color : THEME
|
||||
transition-property height, transform, box-shadow
|
||||
transition-duration ANIMATION_DURATION
|
||||
transition-timing-function ANIMATION_EASE
|
||||
> img
|
||||
width : SIZE = (UNIT / 1.5)
|
||||
height : SIZE
|
||||
margin : 0 ((OFFSET - SIZE) / 2)
|
||||
border-radius : SIZE
|
||||
background-color : alpha(WHITE, 25%)
|
||||
box-shadow 0 0 0 (SIZE / 10) alpha(WHITE, 15%)
|
||||
h1
|
||||
font-weight : FONT_WEIGHT_NORMAL
|
||||
padding : (UNIT / 2) 0
|
||||
transition all ANIMATION_DURATION ANIMATION_EASE
|
||||
nav
|
||||
&[data-role="text"]
|
||||
&:first-child
|
||||
display : block
|
||||
font-size : FONT_SIZE_TINY
|
||||
transition all ANIMATION_DURATION ANIMATION_EASE
|
||||
|
||||
&[data-role="circle"]
|
||||
position : absolute
|
||||
right : 0
|
||||
right : OFFSET
|
||||
bottom : -(BUTTON_CIRCLE_HEIGHT / 2)
|
||||
> *
|
||||
margin-left : SPACE
|
||||
|
||||
// -- Effects
|
||||
&.scrolling
|
||||
// padding : SPACE 0
|
||||
transform translateY(-(1.5 * SPACE))
|
||||
.scrolling &
|
||||
height : (HEADER_HEIGHT / 2)
|
||||
box-shadow : HEADER_SHADOW
|
||||
transform translateY(-(SPACE))
|
||||
h1
|
||||
padding : 0
|
||||
nav
|
||||
&[data-role="text"]
|
||||
&:first-child
|
||||
transform translateY(-10vh)
|
||||
opacity : 0
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
ul
|
||||
list-style: none
|
|
@ -1,5 +1,6 @@
|
|||
li
|
||||
padding : (SPACE / 2) 0
|
||||
height : 80px
|
||||
img
|
||||
width : SIZE = (2.5 * SPACE)
|
||||
height : SIZE
|
||||
|
|
|
@ -1,21 +1,14 @@
|
|||
nav
|
||||
&[data-role="text"]
|
||||
font-size : FONT_SIZE_NORMAL
|
||||
> *:not(:last-child)
|
||||
margin-right : SPACE
|
||||
> *
|
||||
transition opacity ANIMATION_DURATION ANIMATION_EASE
|
||||
&:not(.active)
|
||||
font-weight : FONT_WEIGHT_THIN
|
||||
opacity : 0.75
|
||||
opacity : 0.5
|
||||
&:hover, &:active, &.active
|
||||
opacity : 1
|
||||
|
||||
&[data-role="circle"]
|
||||
> *
|
||||
width : SIZE = BUTTON_CIRCLE_HEIGHT
|
||||
height : SIZE
|
||||
font-size : FONT_SIZE_BIG
|
||||
line-height : SIZE
|
||||
border-radius : SIZE
|
||||
background-color : PRIMARY
|
||||
box-shadow : 0 1px 6px rgba(0, 0, 0, 0.12), 0 1px 4px rgba(0, 0, 0, 0.24)
|
||||
&.active
|
||||
font-weight : FONT_WEIGHT_NORMAL
|
||||
&:not(:last-child)
|
||||
margin-right : SPACE
|
||||
|
|
|
@ -62,14 +62,14 @@ sub
|
|||
bottom -0.25em
|
||||
|
||||
img
|
||||
border 0
|
||||
border: 0
|
||||
|
||||
svg
|
||||
&:not(:root)
|
||||
overflow hidden
|
||||
|
||||
figure
|
||||
margin 1em 40px
|
||||
border: 0
|
||||
|
||||
hr
|
||||
-moz-box-sizing content-box
|
||||
|
|
|
@ -7,4 +7,4 @@
|
|||
transition transform ANIMATION_DURATION ANIMATION_EASE
|
||||
> section
|
||||
height : 100vh
|
||||
padding : (HEADER_HEIGHT + UNIT) UNIT UNIT UNIT
|
||||
padding : (HEADER_HEIGHT + UNIT) OFFSET OFFSET OFFSET
|
||||
|
|
Loading…
Reference in New Issue