initial commit

edit
Hakim El Hattab 2011-06-07 21:10:59 +02:00
commit fdd6b36f01
9 changed files with 732 additions and 0 deletions

4
.gitignore vendored 100644
View File

@ -0,0 +1,4 @@
.DS_Store
.svn
log/*.log
tmp/**

19
LICENSE 100644
View File

@ -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.

1
README.md 100644
View File

@ -0,0 +1 @@
# CSS 3D Slideshow

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

218
css/main.css 100644
View File

@ -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);
}

57
css/reset.css 100644
View File

@ -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; }

151
index.html 100644

File diff suppressed because one or more lines are too long

282
js/slideshow.js 100644
View File

@ -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
};
})();