Leopard With jQuery

Adding to Our Leopard Desktop with jQuery

Sep 30th, 2008 in JavaScript & AJAX by Harley

Last Week I got you all to create a neat looking Dashboard/Desktop. You guys are gonna totally FLIP when you hear what's in this jam packed tutorial! More focus on the Dashboard (I swear it's cooler than it sounds, and requires a lot of code), and I'll even go into how to create a stack (seperate from the dock, sorry jqDock doesn't like nestled <ul>s), and some extra little bits to make it all click.

PG

Author: Harley

I'm Harley! I like to call myself a jQueryfied WordPress designer! What a mouthful, huh? I'm based in Australia and have been working with (X)HTML/CSS, Flash, Illustrator and Photoshop for over 3 years, and have found a now year and a half old obsession with WordPress and jQuery. Be sure to get some more info on me on my site!

Preface

As with the previous tutorial, I must note this disclaimer! I don't own any of the images used in this tutorial, nor do you. They are copyright to their vendors, whether it be Apple, inc, Adobe, etc. Using icons is a bit of an integrity issue, so don't abuse it!

Secondly, a new jQuery.UI file will replace the draggable js file. This is basically all the interaction packs. Download jQuery.UI code. You'll also need the final product of last week's tutorial! Make sure you expand that into it's own directory! We'll be adding onto that. A whole lot if images are needed too. New Images. Make sure you expand that zip into the 'images' directory, so that any new folders are merged with their counter parts from last week. I apologise for the confusion with this. Stupid file structure, my bad. So. Files that need adding:

Just the same, the jQuery.ui links need editing.

<script src="js/jquery.ui.interaction.min.js" type="text/javascript"></script>

Plan of Attack

Though it might not look like it, a whole lot of code is needed for these few things:

  1. Stacks
  2. Dashboard
    1. Opening/Closing the Adding Widgets Panel
    2. Dragging Widgets onto the Dashboard list
    3. Closing Widgets
  3. Some extra bits (improving dock, adding desktop items)

Changes

Just before we start, I really do apologise, but there were a few things that needed changing from last week. the #dock css should read:

#dock{
	position: fixed;
	margin: 0 auto;
	bottom: 38px;
	left: 40%;
	z-index: 0;
	list-style: none;
}

The #closeZone's zIndex in dashboard.js on line 24 should be 99 not 9999

Step 1 - Stacks

So lets dive right into it, and start with Stacks. Or more a Stack. Unfortunately due to the way that jqDock works, it's impossible to nestle stacks within the jqDock without editing the core js, which is much further than this tutorial intends. So instead, we'll be creating a stack to the bottom right of the page. The harder parts of coding stacks is a) the incrementing height for each item, and the curve. Luckily, a loop combined with maths can do this hard work for us.

Step 1:1 - HTML

Lets begin with adding the HTML structure of the stack. Now due to the nature of the stack, if you wish to use it on a different website, you can! Basically anything inline within the <li>s work. The positioning just needs tweaking. Regardless, we use spans (and you could always wrap the images in <a>s!

<div class="stack">
	<img src="http://nettuts.s3.cdn.plus.org/082_leopard2/images/stack.png" alt="stack"/>
	<ul id="stack1">
		<li><span>Acrobat</span><img src="http://nettuts.s3.cdn.plus.org/082_leopard2/images/adobeAcrobat.png" alt="" /></li>
		<li><span>Aperture</span><img src="http://nettuts.s3.cdn.plus.org/082_leopard2/images/aperture.png" alt="" /></li>
		<li><span>Photoshop</span><img src="http://nettuts.s3.cdn.plus.org/082_leopard2/images/photoshop.png" alt="" /></li>
		<li><span>Safari</span><img src="http://nettuts.s3.cdn.plus.org/082_leopard2/images/safari.png" alt="" /></li>
		<li><span>Finder</span><img src="http://nettuts.s3.cdn.plus.org/082_leopard2/images/finder.png" alt="" /></li>
	</ul>
</div>

The first image is the folder placeholder. This is what activates the dock, so it's necessary. (When we use the jQuery selectors, however, I'm sure you could use :first to get the first dock item if you /really/ don't want a containing basket).

Step 1:2 - CSS

Contrary to the first tutorial, I'm going to include the CSS and jQuery for each step, just so the design doesn't muddle up completely. Open up style.css from last week and add to the bottom:

.stack{
	position: absolute;
	bottom: 0;
	right: 100px;
}

.stack ul{
	list-style: none;
	position: absolute;
	top: -30px;
	z-index: -9;
}

.stack ul li{
	position: absolute;
}

.stack ul li span{
	display: none;
}

/*I'm for the jquery*/
.stack .openStack li span{
	display:block;
	position:absolute;
	top: 17px;
	right:60px;
	height: 14px;
	line-height: 14px;
	border: 0;
	background-color:#000;
	color: #fcfcfc;
	text-align: center;
	opacity: .85;
	padding: 3px 10px;
	border-radius: 10px;
	-webkit-border-radius: 10px;
	-moz-border-radius: 10px;
	opera-border-radius: 10px;
	text-shadow: #000 1px 1px 1px;
}

Your stack will now look like a closed stack, but you can't open it. This just stacks (hah, no pun intended) all the icons on top of each other, so they're compressed into a small square. The last selector is for the jQuery. When the stack is opened, the class 'openStack is added to the ul. I apologise to those CSS3 haters, It's the fastest most efficient way to get it right in most modern browsers.

Step 1:3 - jQuery

In plain english, the stack needs to open when the img is clicked, pushing each (hint...) li up in incrememnts, and to the right a little, whilst resizing to a smaller size. Then when clicked again, everything returns to normal.

$('.stack>img').toggle(function(){
	//this function, for each element increases the top position to by 50px,
	//and across using, the equation: value = (value+1)*2. Both variables
	//start at 0.
	
}, function(){
	//this one just reverses the above.
	
});

The second function is easy, but the first is a pain.

var vertical = 0;
var horizontal = 0;
$('~ul>li'this).each(function(){
	$(this).animate({top: '-' +vertical + 'px', left: horizontal + 'px'}, 300);
	vertical = vertical + 50;
	horizontal = (horizontal+1)*2;
});
$('~ul', this).animate({top: '-50px', left: '10px'}, 300).addClass('openStack');
$('~ul>li>img', this).animate({width: '50px', marginLeft: '9px'}, 300);

Woo, jampacked with string interrupting, variables and math. Interesting selectors, huh? The ~ is 'siblings of' Erg. Math. Let me explain. The first 2 variables are for the vertical position and the horizontal position (curve).

Top incrementing is the same each time, where as unless you want a horizontal straight line, each horizontal position has to be slightly more than the rest. In this case, it increases by the previous number plus one, times 2. so it'll go 2, 6, 14, 30, 62, 126, etc. I know they're weird numbers, but it works. Use any equation you like!

The 'each' function is similar to, say a WordPress loop. This function happens every time the next element is used. The equation 'value = (value+1)*2', means 'new value equals old value plus one, then this times two.

The first animate line adds the variables (within the plus) every time it's looped via string splitting. The last two lines are just the size. The other half of the toggle function, just resets everything back to normal:

$('~ul', this).removeClass('openStack').children('li').animate({top: '20px', left: '-10px'}, 300);
$('~ul>li>img', this).animate({width: '79px', marginLeft: '0'}, 300);

Simple! Now your jQuery stacks will successfully animate, even curving! Unfortunately rotation is a tad more difficult. Though when HTML5 comes out in 2022 (-_-) the canvas tag might have full support for that.

Step 2 - Dashboard

So we're gonna add to the Dashboard a bit. Firstly, an Add Widgets Panel (Wont do the actual adding til later). After that, closing of the widgets will be possible when this panel is open. Finally, being able to add your own widgets from this panel. Uses some very different selecting methods. Adding the widgets also covers Droppables extensively, as the drop function is rather large.

Step 2:1 - Add Widget Panel

Firstly, the HTML. Add this just before the closing #dashboardWrapper div.

<div id="addWidgets">
<span id="openAddWidgets">Add/remove widgets</span>
<div id="dashPanel">
    <ul>
    	<li><img src="http://nettuts.s3.cdn.plus.org/082_leopard2/images/widgets/thumbs/sticky.png" alt="" id="sticky" class="widgetThumb" /><span>Sticky</span></li>
    	<li><img src="http://nettuts.s3.cdn.plus.org/082_leopard2/images/widgets/thumbs/clock.png" alt="" id="clock" class="widgetThumb" /><span>Clock</span></li>
    	<li><img src="http://nettuts.s3.cdn.plus.org/082_leopard2/images/widgets/thumbs/weather.png" alt="" id="weather" class="widgetThumb" /><span>Weather</span></li>
    </ul>
</div>
</div>

The 'openAddWidgets' is the little cross/plus that opens and closes the Panel. The list items are the available widgets (create as many as you'd like!). The images you downloaded are the little thumbs. These will become draggables, and you will be able to drop them onto the #closeZone and eventually, widgets appended to the #widgets list.

At the moment, this looks like a bit of a mess;

But with some CSS we'll fix that right up.

#addWidgets{
	position: absolute;
	z-index: 9999;
	bottom: 0;
	left: 0;
	width: 96%;
	height: 164px;
	background: url(images/dashpanel.png) bottom repeat-x;
	padding: 0 2%;
}

#openAddWidgets{
	display: block;
	width: 36px;
	height: 36px;
	background: url(images/opendashpanel.png) center;
	position: relative;
	z-index: 9999;
	text-indent: -9999em;
}

#dashPanel ul{
	list-style: none;
	margin-top: 27px;
}

#dashPanel ul li{
	float: left;
	padding-right: 30px;
}

#dashPanel ul li img{
	display: block;
}

#dashPanel ul li span{
	width: 74px;
	display: block;
	text-align: center;
	font-weight: bold;
	text-shadow: #fff 1px 0 1px;
	color: #17243e;
	padding-top: 10px;
}

Heavy on with positioning, z-indexing and floating, this should gather an effect like this (Panel's there, not hidden):

Finally, the jQuery to hide and show it. Add the following under the comment '//draggables definition' (for the sake of organisation):

$('#addWidgets ul li img').draggable({helper: 'clone'});

And add this under the '//initial hiding of dashboard + addition of 'closeZone'' block:

//initial hiding of #dashPanel and addable widgets
$('#addWidgets').css({bottom: '-118px'});

Now for the toggle code. In english, when the 'open' button is clicked, slide the panel up. When it's clicked again, slide the panel down. Let's start with the toggle.

//open/closing of the dashpanel
$('#openAddWidgets').toggle(function(){
	//this opens the dashboard, animation and all
	
}, function(){
	//opposite to above
	
});

Thus the opening function will be in the first gap, whilst the closing in the second. The first:

$(this).css({background: 'url(images/closedashpanel.png)'});
$('#addWidgets').animate({bottom: '0px'}, 500);

And the second, reversing above:

$(this).css({background: 'url(images/opendashpanel.png)'});
$('#addWidgets').animate({bottom: '-118px'}, 500);

Finally, like Leopard, it should close when the user returns to the Desktop, right? Add this to //#closeZone's job: closing the Dashboard' function (within it!):

$('#openAddWidgets').css({background: 'url(images/opendashpanel.png)'});
$('#addWidgets').animate({bottom: '-118px'}, 500);

Now if you click the little plus in the bottom left when the Dashboard is open, it should animate! Awesome!

Step 2:2 - Adding Widgets to the Dashboard List

This proved a beast and a half. Lots of code for this... Yay! Luckily, It's only jQuery! Let's start by defining the Droppable; #closeZone. Place this under the Draggables definitions:

//droppable definition
$('#closeZone').droppable({
	accept: '.widgetThumb',
	drop: function(ev, ui){
			
	}
});

Basically, #closeZone can now accept the thumbs in the Panel as droppables, and we're about to delve into what happens on the drop.

In understandable language, this is how it goes. Variables for the mouse position need to be found so the position of the drop can be where we want it. Another variable for the type of widget to append is needed. On drop, the Widget needs to be appended, a different image depending on the widgetType variable. Now to be different, the stickies will be editable (No way!). A textarea will be appended, to allow writing. Because all the draggable definitions happen on the load of the document, they'll need to be re-defined every time a widget is appended to the DOM, so that it's applied to the newest one of such.

We'll start with the variables.

var x = ev.clientX - 100;
var y = ev.clientY - 50;
var widgetType = $(ui.draggable).attr('id');

Sadly we can't get the width and height of the image that's about to be appended too easily (to center the drop). So instead we need to guess, by offsetting the position of the mouse by 100 and 50, so it's not in the top left. The JavaScript variables 'cleintX' and 'clientY' are basically the mouse position. And that interesting selector; ui.draggable, is the element that has just been dragged! Thanks jQuery.ui! Now for appendage:

$('#widgets').append('<li class="widget '+widgetType+'Widget" style="left: '+ x +'px; top: '+ y +'px;"><img src="http://nettuts.s3.cdn.plus.org/082_leopard2/images/widgets/'+widgetType+'.png" alt="" /></li>');
$('.stickyWidget').append('<textarea></textarea>');//needed to add textarea to newest DOM member
$('.widget').draggable(); //needed to 'draggable' the newest DOM member

Allow me to explain how the variables work in the appending. To give a class to the new widget for customisation, adding "...'+widgetType+'Widget'..." will return a class similar to 'stickyWidget' or 'weatherWidget'. The inline style (so sorry it's inline! Don't shoot me!) determines the absolute position of the widget by the variables, which are of course the mouse coordinates. As I mentioned, the newest DOM members need any jQuery modifications or appendages [made on the document load] re-applied, as jQuery doesn't recognise new DOM members. For the last two lines, jQuery needs to append the textarea (so you can edit the text) and the new Widget needs to become a draggable.

In order for all this to work, some CSS is needed. Replace, in style.css, the '.widget' selector and attributes with:

.widget{
	position: absolute;
	z-index: 9999;
	float: left;
	margin: 1em;
	list-style: none;
}

.stickyWidget{
	padding: 15px 20px;
	width: 185px;
	height: 155px;
	background: url(images/widgets/sticky.png) no-repeat center;
}

.stickyWidget>img{
	display: none;
}

.stickyWidget textarea{
	height: 100%;
	width: 100%;
	background: 0;
	border: 0;
	outline: 0;
	font-size: 16px;
	font-family: 'Marker Felt';
	overflow: hidden;
}

This makes the sticky all looking like a sticky. The you either will or wont have the Marker Felt font, that's what the actually sticky widget uses. For the original widget to remain pretty, wrap the text, rather than in <p>s but with:

<textarea rows="10" cols="10">
...
<textarea>

And give the li an extra class of 'stickyWidget' to match the css (The li'll now have 2 classes).

All goes according to plan, you should now be able to a) edit stickies, and b) add new widgets to the Dashboard.

Step 2:3 - Closing widgets

Why give this part a whole section to itself? Because the workings of this are weaved into all of the previous functions, clicks, and appendages. So instead of being confused adding this throughout all the parts, why not keep it in one?

Right. So basically a small span'll be applied to widgets when the panel opens, and when a new widget is added to the Dashboard. When this is clicked, the parent widget will disappear! Awesome, huh? When the Add Widgets Panel closes, the crosses will disappear into the realms of .hide().

Working down the document for integrating the close button, we begin with the #closeZone's function. Underneath the #addWidget's disappearing act (code), add:

$('.closeWidget').hide();

Next up, within the droppable definition. This snippet of code will apply a close widget button and it's function to all widgets when a new one is dragged on. Underneath the newest draggable definition for the newly created widget (within the drop function), add:

$('.widget').append('<span class="closeWidget"><img src="http://nettuts.s3.cdn.plus.org/082_leopard2/images/closebox.png" alt=""/></span>');
//click function of newest DOM element.
$('.closeWidget').click(function(){
	$(this).parent().animate({opacity: '0'}, 300).animate({left: '-9999em'},1);
});

Finally, the open/close panel function is where it really matters, as this will append the thing to all Widgets on open of the Panel (like Leopard). Below both animates, add respectively:

$('.widget').append('<span class="closeWidget"><img src="http://nettuts.s3.cdn.plus.org/082_leopard2/images/closebox.png" alt=""/></span>');
//click function of newest DOM element.
$('.closeWidget').click(function(){
	$(this).parent().animate({opacity: '0'}, 300).animate({left: '-9999em'},1);
});
and
$('.closeWidget').hide();

Now, when the Panel is opened, a little clickable cross goes to the bottom right of the Widget, and when you drag a new Widget on, it'll seemingly duplicate. To fix all this, add this CSS:

.closeWidget{
	position: absolute;
	z-index: 99999;
	top: -5px;
	left: -5px;
}

And TADA! You now have widgets that close, and can reform when you want them too! Awesome stuff!

Step 3 - Some Extra Bits

This is really just for visuals sake, but we'll be adding a Desktop Item that you can create your own function when double clicked, and making the Dock a bit speedier.

Step 3:1 - Desktop Item

Add some HTML, make this the first thing after the opening #wrapper div:

<ul id="desktopItems">
	<li id="macintoschHD"><span>Macintosch HD</span></li>
</ul>

Give it some CSS to look snazzy:

#desktopItems{
	list-style: none;
	width: 100%;
	height: 100%;
}

#macintoschHD{
	background: url(images/macHD.png) no-repeat center top;
	padding-top: 128px;
	width: 138px;
	margin: 20px;
	text-align: center;
	position: absolute;
	right: 0;
	color: white;
	font-weight: bold;
	text-shadow: #000 1px 1px 2px;
}

And finally some jQuery to execute your double-click function (honestly, change the alert to whatever you please):

//Open finder from desktop item
$('#macintoschHD').dblclick(function(){
	alert("Hey... Gimme a break, I've worked hard at this!");
});

Step 3:2 - Improve the Dock

So last week some of you complained about the clunky Dock, and I maintain there isn't a lot I can do about it. However, to trick your eyes to think it's smooth, you can increase the speed. Simply change the jqDock declaration in dashboard.js to:

var jqDockOpts = {duration: 200};
$('#dock').jqDock(jqDockOpts);

And now you should have a faster dock!

Wrap Up

What a mighty tutorial to write... That was tough. But hey! We did it! I'll just use this space to note a few things from last week that came up in comments.

IE. That Bastard. Shame on jQuery too, for not being cross browser like it's meant to. I get the feeling from some of you that complain think my code is shoddy in the regard that it doesn't work in YOUR browsers that YOU code for. I wrote an article about it on my website discussing browser specific coders. Obviously I know that you should be adept at all browsers... But nobody's perfect.

Practability. Obviously, this is just meant to be fun. Stacks might be an option for a site, but ultimately it's meant to be fun. Let me quote a comment from last week (Not shameless promotion I promise!).

Thanks for taking the time to write this tutorial, jQuery is great and its nice to take some time as developers and have some fun with all the code libraries floating around. Lighten up people and have some fun with it, it isnt meant to be practical, just fun and inspiring. Great tut.

Regards,

Drew

I think that's it. Hope y'all (No I'm not TEXAN!) enjoyed this tutorial, wasn't too hard to keep up with, and are gonna get straight back into practical thinking right now!

  • Subscribe to the NETTUTS RSS Feed for more daily web development tuts and articles.


Related Posts

Check out some more great tutorials and articles that you might like

Enjoy this Post?

Your vote will help us grow this site and provide even more awesomeness

Plus Members

Source Files, Bonus Tutorials and
More for $9 a month for all TUTS+
sites in one subscription.

Join Now

User Comments

( ADD YOURS )
  1. PG

    Craigsnedeker September 30th

    Nice work! Thanks!

    ( Reply )
  2. PG

    raskar September 30th

    impressive work
    thanks !

    ( Reply )
  3. PG

    Jonathan September 30th

    Do you know what is scary… One day this will be practical.
    I am loving this… nice job.
    Jon

    ( Reply )
  4. PG

    Kevin Quillen September 30th

    Wow man, thats pretty damn sweet work with jquery + javascript.

    ( Reply )
  5. PG

    Roshan September 30th

    Great, pretty nice trick.
    Jquery rules all the way.

    Thank you.

    ( Reply )
  6. PG

    Jesse Freeman September 30th

    With all the new “netbooks” and small “net” desktops with linux powered web focused OSs I can see this really being useful in the future. Imaging a mini OS sitting on top of a computer powered only by a web browser. Google’s Chrome seems to be really geared toward this idea because of the way it handles tabs. Keep up the good work, very impressive.

    ( Reply )
  7. PG

    w1sh September 30th

    Awh noice! I’m crappin’ my pants as we speak.

    ( Reply )
  8. PG

    Shane September 30th

    It doesn’t look too good on IE7, XP.

    On Firefox 2, the Stack doesn’t appear to work. Does it require Firefox 3?

    ( Reply )
  9. PG

    bhaarat September 30th

    Thats flipping awesome. I dont know about the whole thing but the stack module can definitely be used on website.

    ( Reply )
  10. PG

    James September 30th

    I must say it’s getting better!

    ( Reply )
  11. PG

    Brian September 30th

    Amazing job! Works like the real thing.

    If you’re having issues ‘people’ just assume its the XP or Vista you’re running!!

    ( Reply )
  12. PG

    Jammer September 30th

    Really cool tutorial, Thanks lol!!

    ( Reply )
  13. PG

    dlv September 30th

    OMG !!!
    awesome

    ( Reply )
  14. PG

    ashvin September 30th

    yep very impressive never seen before on a website :o

    ( Reply )
  15. PG

    Applinux September 30th

    Awesome! @_@ I love it!

    Thanks for tutorial, i will use it on my site ^_^ /

    ( Reply )
  16. PG

    Ben Griffiths September 30th

    Looking good :)

    ( Reply )
  17. PG

    Chad September 30th

    The stack idea is nice concept but there are some serious browser issues with this.

    ( Reply )
  18. PG

    insic September 30th

    wow, very smooth effect. good work.

    ( Reply )
  19. PG

    matt October 1st

    This is fantastic work!!

    Love it, awesome resource to learn jquery in genearl as well.

    ( Reply )
  20. PG

    farishta October 1st

    Wow !!!!! really really nice work !!! Congrats this is freakin’ awesome !!!!
    Thanks man for sharing your knowledge, i’am very thankful :D

    ( Reply )
  21. PG

    cheese October 1st

    Still doesn’t work in IE

    ( Reply )
  22. PG

    Taylor Satula October 1st

    I love this one. Much better than last week’s dock. I am not at my computer so I can’t scroll over is the jerkyness of the dock fixed

    ( Reply )
  23. PG

    Shane October 1st

    Does anybody have a list of browsers on which this is fully functional?

    ( Reply )
  24. PG

    insic October 1st

    it works in all my browsers

    ( Reply )
  25. PG

    ericb October 1st

    great follow up, Harley!! question though: how can you get rid of the scroll bars when you view it in IE7? thanks for sharing this!

    ( Reply )
  26. PG

    Harley Alexander October 1st

    @Taylor: It’s kinda fixed. The animation is just faster so it’s harder to see the jerkyness. If you looked real hard though, you can still see it. This solution for the jerky dock is the best I could do with jqDock.

    @Shane: Safari, Google Chrome I think, and most of it works in FF3 and Opera 9.

    @ericb: The jQuery should already fix that, however if you don’t plan to make it even slightly degrade for non-JS users, add this line to your css file:

    body{
    overflow: hidden;
    }

    This should get rid of the scroll bars, as it’s telling the browser to hide anything outside the viewport of the window.

    Thanks for the awesome feedback guys!

    ( Reply )
  27. PG

    jdeveloper October 2nd

    Awnsone, just great, have no words

    ( Reply )
  28. PG

    holden October 3rd

    This is kindof neat, but why? Don’t you want those 17 hours of your life back?

    ( Reply )
  29. PG

    Paddy October 3rd

    AWESOME!

    ( Reply )
  30. PG

    Roshan October 3rd

    I am gonna try his one on my new project. :)

    Roshan
    Freelance Developer
    http://www.instantshift.com

    ( Reply )
  31. PG

    pooya October 5th

    part of this practice doesn’t work in opera

    ( Reply )
  32. PG

    James October 5th

    @Roshan – I hope you mean just a *fun* project for yourself, not an actual real project for a client!? It’s not meant for that!

    ( Reply )
  33. PG

    Harley October 6th

    @Holden: It was only about 6 :P Not to be money focussed, but it’s worth it… 250AUD / 6 = ~$42/hr

    ( Reply )
  34. PG

    Taylor Satula October 9th

    @Harley thanks. I looked at it on my pc and the jerkyness of it was gone i was on my iPhone.

    ( Reply )
  35. PG

    Taylor Satula October 9th

    It looks like someone spelled Macintosh wrong

    ( Reply )
  36. PG

    Isaac Alcocer October 19th

    Tiene un bug en el post it cuando deceas maximizarlo simplemente arrastra esa imagen

    ( Reply )
  37. PG

    the.lorrr October 25th

    is this going to be continued? that would really be great!!!

    ( Reply )
  38. PG

    Devon Govett November 20th

    You could add a rotational effect by changing the toggle method in the javascript to the following. This only works in safari:

    $(‘.stack>img’).toggle(function(){
    var vertical = 0;
    var horizontal = 0;
    var rotation = 0;
    $(‘~ul>li’, this).each(function(){
    $(this).animate({top: ‘-’ +vertical + ‘px’, left: horizontal + ‘px’}, 300);
    $(this).css(“-webkit-transform”, “rotate(“+rotation+”deg)”);
    rotation = rotation + 4;
    vertical = vertical + 50;
    horizontal = (horizontal+1)*2;
    });
    $(‘~ul’, this).animate({top: ‘-50px’, left: ‘10px’}, 300).addClass(‘openStack’);
    $(‘~ul>li>img’, this).animate({width: ‘50px’, marginLeft: ‘9px’}, 300);
    }, function(){
    //reverse above
    $(‘~ul’,this).removeClass(‘openStack’).children(‘li’).animate({top: ‘20px’, left: ‘-10px’}, 300);
    $(‘~ul>li>img’,this).animate({width: ‘79px’, marginLeft: ‘0′}, 300);
    $(‘-ul>li’,this).css(“-webkit-transform”, “rotate(0deg)”);
    $(‘~ul’,this).children(‘li’).css(“-webkit-transform”, “rotate(0deg)”);
    //width: 50px;
    });

    Just uses -webkit-transform: rotate(123deg);

    Nice work!

    ( Reply )
  39. PG

    kareem November 23rd

    this is wonderful tutorial i will put acopy of this lesson on
    my site here
    http://www.as7ap4you.com

    ( Reply )
  40. PG

    maddin December 27th

    those files are not here anymore…

    ( Reply )
  41. PG

    Kevin December 30th

    The jquery.ui.interaction.min.js file can be downloaded off http://nettuts.s3.amazonaws.com/082_leopard2/preview/js/jquery.ui.interaction.min.js but I can’t get the newimages… T.T

    ( Reply )
  42. PG

    paul.rostorp January 11th

    Fantastic, great.

    Can someone explain me how to do it with cookies?

    thanks

    ( Reply )
  43. PG

    Saulo January 21st

    ai caraio

    ( Reply )
  44. PG

    love February 4th

    It’s superb man.
    Thanks

    ( Reply )
  45. PG

    Paul February 4th

    Wooow. Owesome!
    Thanks a lot for this tut!

    Paul

    ( Reply )
  46. PG

    ozgur February 17th

    very very very very very
    good good good
    work

    ( Reply )
  47. PG

    cssrain February 20th

    真cool。

    ( Reply )
  48. PG

    henrique February 20th

    o seu trabalho e muito bom!

    ( Reply )
  49. PG

    Angel March 15th

    Nice work! Thanks!

    ( Reply )
  50. PG

    Beth March 24th

    oh god! nice man…

    ( Reply )
  51. PG

    Izzy-dev April 2nd

    Http://izzy-dev.com

    Thanks

    ( Reply )
  52. PG

    Elad Meidar April 6th

    Windows are not moveable on FF3, but awesome rocking job… loved the stack

    ( Reply )
  53. PG

    dtz April 15th

    真不错,很好

    Very good

    ( Reply )
  54. PG

    mick May 26th

    Not so good as they think.
    But funny.

    ( Reply )
  55. PG

    wpdigger June 3rd

    Nice & impressive work. !I am loving this… nice job. thanks

    ( Reply )
  56. PG

    akkis June 22nd

    This is wonderful man! Just perfect!!

    Flash is dead!

    ( Reply )
  57. PG

    Swenflea July 4th

    How do you add more things to the desktop?

    ( Reply )
  58. PG

    Swenflea July 4th

    one more thing how do you make more widgits?

    ( Reply )
  59. PG

    Swenflea July 8th

    what do people think of what iv’e done so far using this tutorial

    http://test.swenflea.com/apple mac theme/index.html

    ( Reply )
  60. Now I’m thinking how to use it.
    This kit have many chances.

    ( Reply )
  61. PG

    medyum August 16th

    With all the new “netbooks” and small “net” desktops with linux powered web focused OSs I can see this really being useful in the future. Imaging a mini OS sitting on top of a computer powered only by a web browser. Google’s Chrome seems to be really geared toward this idea because of the way it handles tabs. Keep up the good work, very impressive.

    ( Reply )
  62. PG

    araç sorgulama December 29th

    Nice & impressive work. !I am loving this… nice job. thanks

    ( Reply )
  1. Arrow
    Gravatar

    Your Name
    December 29th