Experimental responsive interface.
Created
August 14, 2014 22:23
-
-
Save mattborn/251d5e9fa2ac422b1940 to your computer and use it in GitHub Desktop.
Menu, Pages + Dialogs UI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>Menu, Pages + Dialogs UI</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"> | |
<style> | |
/* Helpers */ | |
$cinema: "(min-width: 1441px)"; | |
$desktop: "(max-width: 1024px)"; | |
$tablet: "(max-width: 768px)"; | |
$phone: "(max-width: 568px)"; | |
/* Reset */ | |
*, | |
*::before, | |
*::after { box-sizing: border-box; } | |
body { margin: 0; } | |
p { margin: 0; } | |
button { | |
background: 0; | |
border: 0; | |
cursor: pointer; | |
font: inherit; | |
margin: 0; | |
overflow: visible; | |
padding: 0; | |
text-align: inherit; | |
} | |
[hidden] { display: none; } | |
/* Base */ | |
html, | |
body { height: 100%; } | |
button { | |
min-width: 120px; | |
background: rgba(0,0,0,.1); | |
border-radius: 15px; | |
color: inherit; | |
display: inline-block; | |
font-size: 13px; | |
letter-spacing: inherit; | |
line-height: 30px; | |
margin: 5px; | |
padding: 0 15px; | |
text-align: center; | |
vertical-align: top; | |
} | |
/* UI */ | |
.ui { | |
height: 100%; | |
color: rgba(0,0,0,.7); | |
font: 100%/1 'Proxima Nova', 'Helvetica Neue', Arial, sans-serif; | |
-webkit-font-smoothing: antialiased; | |
letter-spacing: .02em; | |
overflow: hidden; | |
padding-left: 200px; | |
text-rendering: optimizeLegibility; | |
-webkit-text-size-adjust: none; | |
-webkit-transform: translateZ(0); | |
-webkit-transition: .5s cubic-bezier(.2,1,.2,1); | |
&-text { | |
font-size: 18px; | |
font-weight: 600; | |
line-height: 40px; | |
position: absolute; | |
top: 50%; | |
left: 50%; | |
-webkit-transform: translateX(-50%) translateY(-20px); | |
} | |
&-theme { | |
position: absolute; | |
bottom: 10px; | |
right: 10px; | |
} | |
} | |
%sticky { | |
width: 100%; | |
height: 40px; | |
line-height: 40px; | |
position: absolute; | |
top: 0; | |
left: 0; | |
} | |
%scroll { | |
overflow-y: auto; | |
-webkit-overflow-scrolling: touch; | |
} | |
.menu { | |
@extend %scroll; | |
width: 200px; | |
height: 100%; | |
position: absolute; | |
top: 0; | |
left: 0; | |
-webkit-transition: inherit; | |
&-content { | |
height: auto; | |
min-height: 100%; | |
margin-bottom: -200px; | |
padding-bottom: 200px; | |
position: relative; | |
} | |
&-body { position: relative; } | |
&-foot { | |
width: 100%; | |
height: 200px; | |
position: absolute; | |
bottom: 0; | |
left: 0; | |
} | |
} | |
/* Pages */ | |
.pages { | |
width: 100%; | |
height: 100%; | |
position: relative; | |
left: 0; | |
-webkit-transition: inherit; | |
} | |
.page { | |
&-top, | |
&-head { @extend %sticky; } | |
&-top { display: none; } | |
&-content { | |
@extend %scroll; | |
height: 100%; | |
position: relative; | |
} | |
&-body { | |
max-width: 700px; | |
margin: 0 auto; | |
position: relative; | |
} | |
} | |
%single { | |
width: 100%; | |
height: 100%; | |
background: #fff; | |
position: relative; | |
} | |
%series { | |
width: 50%; | |
height: 100%; | |
position: absolute; | |
-webkit-transition: inherit; | |
} | |
.aaa { | |
&-page { | |
@extend %series; | |
left: 0; | |
} | |
} | |
.bbb { | |
&-page { | |
@extend %series; | |
left: 50%; | |
.back-button, | |
.back-button-ccc { display: none; } | |
} | |
} | |
.ccc { | |
&-page { | |
@extend %series; | |
padding: 0; | |
left: 100%; | |
.page-top { display: block; } | |
} | |
} | |
.ddd { | |
&-page { @extend %single; } | |
} | |
.eee { | |
&-page { @extend %single; } | |
} | |
.dialog { | |
@extend %scroll; | |
width: 100%; | |
height: 100%; | |
background: rgba(0,0,0,.7); | |
position: absolute; | |
top: 0; | |
left: 0; | |
text-align: center; | |
&::before { | |
width: 1px; | |
height: 100%; | |
content: ''; | |
display: inline-block; | |
margin-right: -1px; | |
vertical-align: middle; | |
} | |
&-top { | |
@extend %sticky; | |
background: #fff; | |
display: none; | |
text-align: initial; | |
} | |
&-content { | |
min-width: 320px; | |
max-width: 720px; | |
background: #fff; | |
display: inline-block; | |
position: relative; | |
text-align: left; | |
vertical-align: middle; | |
} | |
&-head, | |
&-body, | |
&-foot { | |
padding: 20px; | |
position: relative; | |
} | |
} | |
/* States */ | |
.menu-open .menu { left: 0; } | |
.bbb-open .aaa-page .next-button, | |
.ccc-open .bbb-page .next-button { display: none; } | |
.ccc-open .bbb-page .back-button-ccc { display: block; } | |
.ccc-open .aaa-page { left: -50%; } | |
.ccc-open .bbb-page { left: 0; } | |
.ccc-open .ccc-page { left: 50%; } | |
.eee-open .ddd-page { display: none; } | |
/* Responsive */ | |
@media #{$cinema} { | |
.menu { z-index: 2; } | |
.aaa-page { | |
width: 620px; | |
z-index: 1; | |
} | |
.bbb-page { | |
width: 100%; | |
left: 0; | |
padding-left: 620px; | |
z-index: 0; | |
} | |
.ccc-open .bbb-page { | |
width: 50%; | |
padding-left: 0; | |
} | |
} | |
@media #{$desktop} { | |
.ui { padding: 0; } | |
.menu { left: -200px; } | |
.menu-open .pages { left: 200px; } | |
.page-top { display: block; } | |
.aaa-page, | |
.bbb-page, | |
.ddd-page, | |
.eee-page { padding-top: 40px; } | |
.ccc-page .back-button { display: none; } | |
} | |
@media #{$tablet} { | |
.ui { padding-left: 200px; } | |
.menu { left: 0; } | |
.menu-open .pages { left: 0; } | |
.aaa-page .back-button, | |
.ddd-page .back-button, | |
.eee-page .page-top .back-button { display: none; } | |
.bbb-page .back-button, | |
.ccc-page .back-button { display: block; } | |
.aaa-page, | |
.bbb-page, | |
.ccc-page { width: 100%; } | |
.bbb-page { left: 100%; } | |
.bbb-open .aaa-page { left: -100%; } | |
.bbb-open .bbb-page { left: 0; } | |
.ccc-open .bbb-page { left: -100%; } | |
.ccc-open .ccc-page { left: 0; } | |
} | |
@media #{$phone} { | |
.ui { padding: 0; } | |
.menu { left: -200px; } | |
.menu-open .pages { left: 200px; } | |
.menu-open .pane-body, | |
.menu-open .page-body { pointer-events: none; } | |
.aaa-page .back-button, | |
.ddd-page .back-button, | |
.eee-page .page-top .back-button { display: block; } | |
.dialog { padding-top: 40px; } | |
.dialog-top { display: block; } | |
.dialog-content { | |
width: 100%; | |
min-height: 100%; | |
} | |
} | |
/* Themes */ | |
.bare { | |
.menu, | |
.dialog-head { | |
background: #333; | |
color: #fff; | |
} | |
.menu-foot { border-top: 1px solid #444; } | |
.page-top, | |
.page-head { border-bottom: 1px solid #eee; } | |
.aaa-page, | |
.bbb-page { border-right: 1px solid #eee; } | |
.dialog-foot { border-top: 1px solid #eee; } | |
} | |
.fresh { | |
.menu, | |
.dialog-head, | |
.ddd-page .page-top, | |
.eee-page .page-top { | |
background: #345; | |
color: #fff; | |
} | |
.aaa-page { background: #eee; } | |
.bbb-page { border-right: 1px solid #eee; } | |
.aaa-page .page-top, | |
.bbb-page .page-top { | |
background: #eee; | |
border-bottom: 1px solid #ddd; | |
} | |
.ccc-page .page-top { | |
background: #0be; | |
color: #fff; | |
} | |
.ddd-page .page-head, | |
.eee-page .page-head { background: #eee; } | |
.dialog-foot { | |
background: #4b6; | |
color: #fff; | |
} | |
} | |
/* Demo only */ | |
.menu-body, | |
.page-body, | |
.dialog-body { min-height: 400px; } | |
.menu-body, | |
.menu-foot, | |
.page-body, | |
.a-page .page-body, | |
.b-page .page-body, | |
.c-page .page-body { padding: 20px; } | |
</style> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/sass.js/0.4.0/sass.min.js"></script> | |
<script> | |
// this allows the styles above to retain css code coloring in a | |
// text editor instead of having everything in this script tag | |
var head = document.getElementsByTagName('head')[0], | |
style = document.getElementsByTagName('style')[0], | |
css = Sass.compile(style.innerHTML); | |
head.removeChild(style); | |
document.write("<style>"+ css +"</style>"); | |
</script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/react/0.11.0/react-with-addons.min.js"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/react/0.11.0/JSXTransformer.js"></script> | |
<script type="text/jsx"> | |
/** @jsx React.DOM */ | |
var UI = React.createClass({ | |
getInitialState: function () { | |
return { | |
menu_open: false, | |
bbb_open: false, | |
ccc_open: false, | |
ddd_open: false, | |
eee_open: false, | |
dialog_open: false, | |
theme: 'bare' | |
}; | |
}, | |
render: function () { | |
var classes = React.addons.classSet({ | |
'ui': true, | |
'menu-open': this.state.menu_open, | |
'bbb-open': this.state.bbb_open, | |
'ccc-open': this.state.ccc_open, | |
'ddd-open': this.state.ddd_open, | |
'eee-open': this.state.eee_open, | |
'dialog-open': this.state.dialog_open | |
}); | |
classes += ' '+ this.state.theme; | |
return ( | |
<div className={classes}> | |
<div className="pages"> | |
<div className="aaa-page"> | |
<div className="page-content"> | |
<div className="page-body"> | |
<button className="next-button" data-target="bbb" onClick={this.open}>Open Page B</button> | |
<p className="ui-text">Page A Body</p> | |
</div> | |
</div> | |
<div className="page-top"> | |
<button className="back-button" data-target="menu" onClick={this.toggle}>Toggle Menu</button> | |
<p className="ui-text">Page A Top</p> | |
</div> | |
</div> | |
<div className="bbb-page"> | |
<div className="page-content" hidden={!this.state.bbb_open}> | |
<div className="page-body"> | |
<button className="next-button" data-target="ccc" onClick={this.open}>Open Page C</button> | |
<p className="ui-text">Page B Body</p> | |
</div> | |
</div> | |
<div className="page-top"> | |
<button className="back-button" data-target="bbb" onClick={this.close}>Close Page B</button> | |
<button className="back-button-ccc" data-target="ccc" onClick={this.close}>Close Page C</button> | |
<p className="ui-text">Page B Top</p> | |
</div> | |
</div> | |
<div className="ccc-page"> | |
<div className="page-content" hidden={!this.state.ccc_open}> | |
<div className="page-body"> | |
<p className="ui-text">Page C Body</p> | |
</div> | |
</div> | |
<div className="page-top"> | |
<button className="back-button" data-target="ccc" onClick={this.close}>Close Page C</button> | |
<p className="ui-text">Page C Top</p> | |
</div> | |
</div> | |
<div className="ddd-page" hidden={!this.state.ddd_open}> | |
<div className="page-content"> | |
<div className="page-body"> | |
<p className="ui-text">Page D Body</p> | |
</div> | |
<div className="page-head"> | |
<button className="next-button" data-target="eee" onClick={this.open}>Open Page E</button> | |
<p className="ui-text">Page D Head</p> | |
</div> | |
</div> | |
<div className="page-top"> | |
<button className="back-button" data-target="menu" onClick={this.toggle}>Toggle Menu</button> | |
<p className="ui-text">Page D Top</p> | |
</div> | |
</div> | |
<div className="eee-page" hidden={!this.state.eee_open}> | |
<div className="page-content"> | |
<div className="page-body"> | |
<p className="ui-text">Page E Body</p> | |
</div> | |
<div className="page-head"> | |
<button className="back-button" data-target="eee" onClick={this.close}>Open Page D</button> | |
<p className="ui-text">Page E Head</p> | |
</div> | |
</div> | |
<div className="page-top"> | |
<button className="back-button" data-target="menu" onClick={this.toggle}>Toggle Menu</button> | |
<p className="ui-text">Page E Top</p> | |
</div> | |
</div> | |
</div> | |
<div className="menu"> | |
<div className="menu-content"> | |
<div className="menu-body"> | |
<button data-target="ddd" onClick={this.close}>Open Page A</button> | |
<button data-target="ddd" onClick={this.open}>Open Page D</button> | |
<p className="ui-text">Menu Body</p> | |
</div> | |
<div className="menu-foot"> | |
<button data-target="dialog" onClick={this.open}>Open Dialog</button> | |
<p className="ui-text">Menu Foot</p> | |
</div> | |
</div> | |
</div> | |
<div className="dialog" hidden={!this.state.dialog_open} data-target="dialog" onClick={this.toggle}> | |
<div className="dialog-content" onClick={this.stopPropagation}> | |
<div className="dialog-head"> | |
<p className="ui-text">Dialog Head</p> | |
</div> | |
<div className="dialog-body"> | |
<p className="ui-text">Dialog Body</p> | |
</div> | |
<div className="dialog-foot"> | |
<p className="ui-text">Dialog Foot</p> | |
</div> | |
</div> | |
<div className="dialog-top"> | |
<button className="back-button" data-target="dialog" onClick={this.close}>Close Dialog</button> | |
<p className="ui-text">Dialog Top</p> | |
</div> | |
</div> | |
<button className="ui-theme" onClick={this.theme}>ϟ</button> | |
</div> | |
); | |
}, | |
stopPropagation: function (ev) { | |
return false; | |
}, | |
open: function (ev) { | |
var target = ev.currentTarget.dataset.target, | |
open = {}; | |
open[target +'_open'] = true; | |
this.setState(open); | |
this.checks(target); | |
}, | |
close: function (ev) { | |
var target = ev.currentTarget.dataset.target, | |
close = {}; | |
close[target +'_open'] = false; | |
this.setState(close); | |
this.checks(target); | |
}, | |
toggle: function (ev) { | |
var target = ev.currentTarget.dataset.target; | |
if (this.state[target +'_open']) { | |
this.close(ev); | |
} else { | |
this.open(ev); | |
} | |
}, | |
checks: function (target) { | |
if (target !== 'menu') { | |
this.setState({menu_open: false}); | |
} | |
if (target === 'ddd') { | |
this.setState({eee_open: false}); | |
} | |
}, | |
theme: function () { | |
var themes = ['bare', 'fresh', 'null'], | |
current = themes.indexOf(this.state.theme), | |
n = themes.length - 1; | |
if (current++ < n) { | |
this.setState({theme: themes[current]}); | |
} else { | |
this.setState({theme: themes[0]}); | |
} | |
} | |
}); | |
React.renderComponent(<UI />, document.body); | |
</script> | |
</head> | |
<body> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment