Hakim El Hattab
14 years ago
commit
fdd6b36f01
9 changed files with 732 additions and 0 deletions
@ -0,0 +1,4 @@ |
|||
.DS_Store |
|||
.svn |
|||
log/*.log |
|||
tmp/** |
@ -0,0 +1,19 @@ |
|||
Copyright (C) 2011 Hakim El Hattab, http://hakim.se |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
of this software and associated documentation files (the "Software"), to deal |
|||
in the Software without restriction, including without limitation the rights |
|||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the Software is |
|||
furnished to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in |
|||
all copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
THE SOFTWARE. |
@ -0,0 +1 @@ |
|||
# CSS 3D Slideshow |
Binary file not shown.
After Width: | Height: | Size: 55 KiB |
@ -0,0 +1,218 @@ |
|||
/** |
|||
* @author Hakim El Hattab |
|||
*/ |
|||
|
|||
|
|||
/********************************************* |
|||
* FONT-FACE DEFINITIONS |
|||
*********************************************/ |
|||
|
|||
@font-face { |
|||
font-family: 'League Gothic'; |
|||
src: url('../assets/fonts/leaguegothic/league_gothic-webfont.ttf') format('truetype'); |
|||
font-weight: normal; |
|||
font-style: normal; |
|||
} |
|||
|
|||
|
|||
/********************************************* |
|||
* GLOBAL STYLES |
|||
*********************************************/ |
|||
|
|||
html, body { |
|||
padding: 0; |
|||
margin: 0; |
|||
overflow: hidden; |
|||
|
|||
font-family: 'Crimson Text', Times, 'Times New Roman', serif; |
|||
font-size: 36px; |
|||
|
|||
background: #fff; |
|||
color: #222; |
|||
|
|||
width: 100%; |
|||
height: 100%; |
|||
|
|||
background-image: -webkit-gradient( |
|||
radial, |
|||
50% 50%, 0, |
|||
50% 50%, 1000, |
|||
from(rgba(245,245,245,1.0)), |
|||
to(rgba(100,100,100,1.0)) |
|||
); |
|||
|
|||
background-image: -moz-radial-gradient( |
|||
50% 50% 90deg, |
|||
rgba(245,245,245,1.0) 0%, |
|||
rgba(100,100,100,1.0) 100% |
|||
); |
|||
|
|||
} |
|||
|
|||
|
|||
/********************************************* |
|||
* HEADERS |
|||
*********************************************/ |
|||
h1, h2, h3, h4 { |
|||
margin: 0 0 20px 0; |
|||
font-family: 'League Gothic', Arial, Helvetica, sans-serif; |
|||
line-height: 0.9em; |
|||
letter-spacing: 0.02em; |
|||
text-transform: uppercase; |
|||
color: #222; |
|||
text-shadow: 0px 0px 2px #fff, 0px 0px 4px #bbb; |
|||
} |
|||
|
|||
h1 { font-size: 136px; } |
|||
h2 { font-size: 76px; } |
|||
h3 { font-size: 56px; } |
|||
h4 { font-size: 36px; } |
|||
|
|||
h1.inverted, |
|||
h2.inverted, |
|||
h3.inverted, |
|||
h4.inverted { |
|||
color: #fff; |
|||
text-shadow: 0px 0px 2px #fff, 0px 0px 2px #888; |
|||
} |
|||
|
|||
|
|||
/********************************************* |
|||
* SLIDES |
|||
*********************************************/ |
|||
#main { |
|||
position: absolute; |
|||
width: 800px; |
|||
height: 600px; |
|||
|
|||
left: 50%; |
|||
top: 50%; |
|||
margin-left: -400px; |
|||
margin-top: -320px; |
|||
|
|||
text-align: center; |
|||
|
|||
-webkit-perspective: 600px; |
|||
-webkit-perspective-origin: 50% 25%; |
|||
} |
|||
|
|||
#main>section, |
|||
#main>section>section { |
|||
display: none; |
|||
|
|||
position: absolute; |
|||
width: 100%; |
|||
min-height: 600px; |
|||
|
|||
-webkit-transform-style: preserve-3d; |
|||
|
|||
-webkit-transition: all 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985); |
|||
-moz-transition: all 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985); |
|||
-o-transition: all 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985); |
|||
transition: all 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985); |
|||
} |
|||
|
|||
#main section.past { |
|||
display: block; |
|||
opacity: 0; |
|||
|
|||
-webkit-transform: translate3d(-100%, 0, 0) |
|||
rotateY(-90deg) |
|||
translate3d(-100%, 0, 0); |
|||
} |
|||
|
|||
#main section.present { |
|||
display: block; |
|||
} |
|||
|
|||
#main section.future { |
|||
display: block; |
|||
opacity: 0; |
|||
|
|||
-webkit-transform: translate3d(100%, 0, 0) |
|||
rotateY(90deg) |
|||
translate3d(100%, 0, 0); |
|||
} |
|||
|
|||
#main section>section.past { |
|||
display: block; |
|||
opacity: 0; |
|||
|
|||
-webkit-transform: translate3d(0, -50%, 0) |
|||
rotateX(70deg) |
|||
translate3d(0, -50%, 0); |
|||
} |
|||
#main section>section.future { |
|||
display: block; |
|||
opacity: 0; |
|||
|
|||
-webkit-transform: translate3d(0, 50%, 0) |
|||
rotateX(-70deg) |
|||
translate3d(0, 50%, 0); |
|||
} |
|||
|
|||
|
|||
/********************************************* |
|||
* DEFAULT ELEMENT STYLES |
|||
*********************************************/ |
|||
|
|||
#main>section { |
|||
line-height: 1.2em; |
|||
text-shadow: 0px 0px 2px #fff, 0px 0px 4px #bbb; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
ol { |
|||
list-style: decimal; |
|||
list-style-position: inside; |
|||
} |
|||
|
|||
li, p { |
|||
margin-bottom: 10px; |
|||
} |
|||
|
|||
a:not(.image) { |
|||
color: #1b6263; |
|||
text-decoration: none; |
|||
border-bottom: 1px dashed rgba(0,0,0,0.3); |
|||
padding: 1px 3px; |
|||
} |
|||
|
|||
a:not(.image):hover { |
|||
color: #fff; |
|||
background: #2fa794; |
|||
text-shadow: none; |
|||
border: none; |
|||
} |
|||
|
|||
img { |
|||
margin: 30px 0 0 0; |
|||
background: rgba(255,255,255,0.12); |
|||
border: 4px solid #eee; |
|||
|
|||
-webkit-box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); |
|||
-moz-box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); |
|||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); |
|||
|
|||
-webkit-transition: all .11s linear; |
|||
-moz-transition: all .11s linear; |
|||
-o-transition: all .11s linear; |
|||
transition: all .11s linear; |
|||
} |
|||
|
|||
a.image:hover img { |
|||
background: rgba(255,255,255,0.2); |
|||
|
|||
-webkit-box-shadow: 0 0 20px rgba(0, 0, 0, 0.25); |
|||
-moz-box-shadow: 0 0 20px rgba(0, 0, 0, 0.25); |
|||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.25); |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
@ -0,0 +1,57 @@ |
|||
/* http://meyerweb.com/eric/tools/css/reset/ |
|||
v2.0 | 20110126 |
|||
License: none (public domain) |
|||
*/ |
|||
|
|||
html, body, div, span, applet, object, iframe, |
|||
h1, h2, h3, h4, h5, h6, p, blockquote, pre, |
|||
a, abbr, acronym, address, big, cite, code, |
|||
del, dfn, em, img, ins, kbd, q, s, samp, |
|||
small, strike, strong, sub, sup, tt, var, |
|||
b, u, i, center, |
|||
dl, dt, dd, ol, ul, li, |
|||
fieldset, form, label, legend, |
|||
table, caption, tbody, tfoot, thead, tr, th, td, |
|||
article, aside, canvas, details, embed, |
|||
figure, figcaption, footer, header, hgroup, |
|||
menu, nav, output, ruby, section, summary, |
|||
time, mark, audio, video { |
|||
margin: 0; |
|||
padding: 0; |
|||
border: 0; |
|||
font-size: 100%; |
|||
font: inherit; |
|||
vertical-align: baseline; |
|||
} |
|||
/* HTML5 display-role reset for older browsers */ |
|||
article, aside, details, figcaption, figure, |
|||
footer, header, hgroup, menu, nav, section { |
|||
display: block; |
|||
} |
|||
body { |
|||
line-height: 1; |
|||
} |
|||
ol, ul { |
|||
list-style: none; |
|||
} |
|||
blockquote, q { |
|||
quotes: none; |
|||
} |
|||
blockquote:before, blockquote:after, |
|||
q:before, q:after { |
|||
content: ''; |
|||
content: none; |
|||
} |
|||
table { |
|||
border-collapse: collapse; |
|||
border-spacing: 0; |
|||
} |
|||
|
|||
|
|||
/* HTML5BP: |
|||
These selection declarations have to be separate. |
|||
No text-shadow: twitter.com/miketaylr/status/12228805301 |
|||
Also: hot pink. */ |
|||
::-moz-selection{ background: #FF5E99; color:#fff; text-shadow: none; } |
|||
::selection { background:#FF5E99; color:#fff; text-shadow: none; } |
|||
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,282 @@ |
|||
/** |
|||
* Copyright (C) 2011 Hakim El Hattab, http://hakim.se
|
|||
* |
|||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
* of this software and associated documentation files (the "Software"), to deal |
|||
* in the Software without restriction, including without limitation the rights |
|||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
* copies of the Software, and to permit persons to whom the Software is |
|||
* furnished to do so, subject to the following conditions: |
|||
* |
|||
* The above copyright notice and this permission notice shall be included in |
|||
* all copies or substantial portions of the Software. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
* THE SOFTWARE. |
|||
*/ |
|||
|
|||
/** |
|||
* Handles the very minimal navigation logic involved in the |
|||
* slideshow. Including keyboard navigation, touch interaction |
|||
* and URL history behavior. |
|||
* |
|||
* Slides are given unique hash based URL's so that they can be |
|||
* opened directly. I didn't use the HTML5 History API for this |
|||
* as it would have required the addition of server side rewrite |
|||
* rules and hence require more effort for anyone to set up. |
|||
* |
|||
* This component can be called from other scripts via a tiny API: |
|||
* - Slideshow.navigateTo( indexh, indexv ); |
|||
* - Slideshow.navigateLeft(); |
|||
* - Slideshow.navigateRight(); |
|||
* - Slideshow.navigateUp(); |
|||
* - Slideshow.navigateDown(); |
|||
* |
|||
* |
|||
* version 0.1: |
|||
* - First release |
|||
* |
|||
* version 0.2: |
|||
* - Refactored code and added inline documentation |
|||
* - Slides now have unique URL's |
|||
* - A basic API to invoke navigation was added |
|||
* |
|||
* version 0.3: |
|||
* - Added licensing terms |
|||
* |
|||
* |
|||
* @author Hakim El Hattab |
|||
* @version 0.3 |
|||
*/ |
|||
var Slideshow = (function(){ |
|||
|
|||
var indexh = 0, |
|||
indexv = 0; |
|||
|
|||
/** |
|||
* Activates the main program logic. |
|||
*/ |
|||
function initialize() { |
|||
document.addEventListener('keydown', onDocumentKeyDown, false); |
|||
document.addEventListener('touchstart', onDocumentTouchStart, false); |
|||
window.addEventListener('hashchange', onWindowHashChange, false); |
|||
|
|||
// Read the initial state of the URL (hash)
|
|||
readURL(); |
|||
} |
|||
|
|||
/** |
|||
* Handler for the document level 'keydown' event. |
|||
* |
|||
* @param {Object} event |
|||
*/ |
|||
function onDocumentKeyDown( event ) { |
|||
|
|||
if( event.keyCode >= 37 && event.keyCode <= 40 ) { |
|||
|
|||
switch( event.keyCode ) { |
|||
case 37: navigateLeft(); break; // left
|
|||
case 39: navigateRight(); break; // right
|
|||
case 38: navigateUp(); break; // up
|
|||
case 40: navigateDown(); break; // down
|
|||
} |
|||
|
|||
slide(); |
|||
|
|||
event.preventDefault(); |
|||
|
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Handler for the document level 'touchstart' event. |
|||
* |
|||
* This enables very basic tap interaction for touch |
|||
* devices. Added mainly for performance testing of 3D |
|||
* transforms on iOS but was so happily surprised with |
|||
* how smoothly it runs so I left it in here. Apple +1 |
|||
* |
|||
* @param {Object} event |
|||
*/ |
|||
function onDocumentTouchStart( event ) { |
|||
|
|||
// We're only interested in one point taps
|
|||
if (event.touches.length == 1) { |
|||
event.preventDefault(); |
|||
|
|||
var point = { |
|||
x: event.touches[0].clientX, |
|||
y: event.touches[0].clientY |
|||
}; |
|||
|
|||
// Define the extent of the areas that may be tapped
|
|||
// to navigate
|
|||
var wt = window.innerWidth * 0.3; |
|||
var ht = window.innerHeight * 0.3; |
|||
|
|||
if( point.x < wt ) { |
|||
navigateLeft(); |
|||
} |
|||
else if( point.x > window.innerWidth - wt ) { |
|||
navigateRight(); |
|||
} |
|||
else if( point.y < ht ) { |
|||
navigateUp(); |
|||
} |
|||
else if( point.y > window.innerHeight - ht ) { |
|||
navigateDown(); |
|||
} |
|||
|
|||
slide(); |
|||
|
|||
} |
|||
} |
|||
|
|||
|
|||
/** |
|||
* Handler for the window level 'hashchange' event. |
|||
* |
|||
* @param {Object} event |
|||
*/ |
|||
function onWindowHashChange( event ) { |
|||
readURL(); |
|||
} |
|||
|
|||
/** |
|||
* Updates one dimension of slides by showing the slide |
|||
* with the specified index. |
|||
* |
|||
* @param {String} selector A CSS selector that will fetch |
|||
* the group of slides we are working with |
|||
* @param {Number} index The index of the slide that should be |
|||
* shown |
|||
* |
|||
* @return {Number} The index of the slide that is now shown, |
|||
* might differ from the passed in index if it was out of |
|||
* bounds. |
|||
*/ |
|||
function updateSlides( selector, index ) { |
|||
|
|||
// Select all slides and convert the NodeList result to
|
|||
// an array
|
|||
var slides = Array.prototype.slice.call( document.querySelectorAll( selector ) ); |
|||
|
|||
if( slides.length ) { |
|||
// Enforce max and minimum index bounds
|
|||
index = Math.max(Math.min(index, slides.length - 1), 0); |
|||
|
|||
slides[index].setAttribute('class', 'present'); |
|||
|
|||
// Any element previous to index is given the 'past' class
|
|||
slides.slice(0, index).map(function(element){ |
|||
element.setAttribute('class', 'past'); |
|||
}); |
|||
|
|||
// Any element subsequent to index is given the 'future' class
|
|||
slides.slice(index + 1).map(function(element){ |
|||
element.setAttribute('class', 'future'); |
|||
}); |
|||
} |
|||
else { |
|||
// Since there are no slides we can't be anywhere beyond the
|
|||
// zeroth index
|
|||
index = 0; |
|||
} |
|||
|
|||
return index; |
|||
|
|||
} |
|||
|
|||
/** |
|||
* Updates the visual slides to represent the currently |
|||
* set indices. |
|||
*/ |
|||
function slide() { |
|||
indexh = updateSlides( '#main>section', indexh ); |
|||
indexv = updateSlides( 'section.present>section', indexv ); |
|||
|
|||
writeURL(); |
|||
} |
|||
|
|||
/** |
|||
* Reads the current URL (hash) and navigates accordingly. |
|||
*/ |
|||
function readURL() { |
|||
// Break the hash down to separate components
|
|||
var bits = window.location.hash.slice(2).split('/'); |
|||
|
|||
// Read the index components of the hash
|
|||
indexh = bits[0] ? parseInt( bits[0] ) : 0; |
|||
indexv = bits[1] ? parseInt( bits[1] ) : 0; |
|||
|
|||
navigateTo( indexh, indexv ); |
|||
} |
|||
|
|||
/** |
|||
* Updates the page URL (hash) to reflect the current |
|||
* navigational state. |
|||
*/ |
|||
function writeURL() { |
|||
var url = '/'; |
|||
|
|||
// Only include the minimum possible number of components in
|
|||
// the URL
|
|||
if( indexh > 0 || indexv > 0 ) url += indexh |
|||
if( indexv > 0 ) url += '/' + indexv |
|||
|
|||
window.location.hash = url; |
|||
} |
|||
|
|||
/** |
|||
* Triggers a navigation to the specified indices. |
|||
* |
|||
* @param {Number} h The horizontal index of the slide to show |
|||
* @param {Number} v The vertical index of the slide to show |
|||
*/ |
|||
function navigateTo( h, v ) { |
|||
indexh = h === undefined ? indexh : h; |
|||
indexv = v === undefined ? indexv : v; |
|||
|
|||
slide(); |
|||
} |
|||
|
|||
function navigateLeft() { |
|||
indexh --; |
|||
indexv = 0; |
|||
slide(); |
|||
} |
|||
function navigateRight() { |
|||
indexh ++; |
|||
indexv = 0; |
|||
slide(); |
|||
} |
|||
function navigateUp() { |
|||
indexv --; |
|||
slide(); |
|||
} |
|||
function navigateDown() { |
|||
indexv ++; |
|||
slide(); |
|||
} |
|||
|
|||
// Initialize the program. Done right before returning to ensure
|
|||
// that any inline variable definitions are available to all
|
|||
// functions
|
|||
initialize(); |
|||
|
|||
// Expose some methods publicly
|
|||
return { |
|||
navigateTo: navigateTo, |
|||
navigateLeft: navigateLeft, |
|||
navigateRight: navigateRight, |
|||
navigateUp: navigateUp, |
|||
navigateDown: navigateDown |
|||
}; |
|||
|
|||
})(); |
|||
|
Loading…
Reference in new issue