Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel is required to process package imports. If you need a different preprocessor remove all packages first.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML Settings

Here you can Sed posuere consectetur est at lobortis. Donec ullamcorper nulla non metus auctor fringilla. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

HTML

            
              <div class="container">
  <section class="clear">
    			<header class="list-header">
      				<div class="circles">
        					<div></div>
        					<div></div>
        					<div></div>
      				</div>
					
      				<h1>Things To Do</h1>

      				<div class="menu">
        					<div></div>
        					<div></div>
        					<div></div>
      				</div>
    			</header>
				
    			<ul class="task-list">
      				<li class="task">
        					Click and drag this item right to mark it as complete
      				</li>
      				<li class="task">
        					Drag left to delete an item
      				</li>
      				<li class="task">
        					Don't edit anything in the HTML or CSS
      				</li>
      				<li class="task">
        					Try to use only JavaScript, no third-party libraries
      				</li>
    			</ul>
  		</section>
	</div>
            
          
!

CSS

            
              /* RESETTING */

html { box-sizing: border-box; font-size: 62.5%;  }
*, *:before, *:after { box-sizing: inherit; }
body { font-size: 1.6rem; font-weight: 300; line-height: 1.6; font-family: 'Open Sans', sans-serif; }
h1 { font-size: 2rem; }
a { color: inherit; }


/* LAYOUT */

.container { width: 90%; max-width: 500px; margin: 100px auto; }

/* CLEAR ELEMENT */
.clear { margin: 30px 0; }

.list-header { display: flex; align-items: center; background-color: #e0dee0; border-top-left-radius: 5px; border-top-right-radius: 5px; padding: 10px 20px; }

.list-header div { width: 20%; }

.list-header .circles div { height: 15px; width: 15px; border-radius: 50%; display: inline-block; margin-right: 5px; }

.list-header .circles div:nth-child(1) { background-color: #fc615d; }

.list-header .circles div:nth-child(2) { background-color: #fec342; }

.list-header .circles div:nth-child(3) { background-color: #34c749; }

.list-header .menu { display: flex; align-items: flex-end; flex-direction: column; }

.list-header .menu div { width: 25px; height: 3px; background-color: #a9a9a9; border-radius: 3px; }

.list-header .menu div:nth-child(2) { margin: 4px 0; }

.list-header h1 { width: 60%; text-align: center; }

/* Task List */
.task-list { background-color: #272822; min-height: 400px; overflow: hidden; }

/* Individual Task */
.task { user-select: none; cursor: move; color: #fff; width: 100%; height: auto; min-height: 50px; line-height: 2; position: relative; padding: 8px 20px; height: auto; transition: background-color 1s; }

.task:before, .task:after { position: absolute; top: 0; width: 40px; height: 50px; line-height: 50px; text-align: center; }

.task:before { content: "\2714"; left: -40px; }

.task:after { content: "\2718"; right: -40px; }

.task:not(.completed):not(.completing) { border-bottom: 2px solid #d44a29; }

.task:nth-child(1) { background-color: #e3252c; }

.task:nth-child(2) { background-color: #dc342a; }

.task:nth-child(3) { background-color: #e7522e; }

.task:nth-child(4) { background-color: #e86d2f; }

.task:nth-child(5) { background-color: #e86d2f; }

.task.completing { text-decoration: line-through; background-color: green; }

.task.completed { opacity: 0.5; text-decoration: line-through; background-color: #323232; }

.task.completed:before { content: ""; }

.task.deleting { background-color: #323232; }

            
          
!

JS

            
              /*
 * Include everything in an immediately invoked
 * function declaration for scope safety!
 *
 * "demand" and "provide" are the main methods
 * of my personal module loader Qoopido.demand
 * (a mixture of require.js and basket)
 * available on github:
 * https://github.com/dlueth/qoopido.demand
 *
 * Qoopido.demand gets loaded via the settings
 * panel of the JS editor!
 */
//
(function(global, document, demand, provide) {
	'use strict';

	/*
	 * Configure demand to load Qoopido.nucleus
	 * (atomic/modular js utility library) via
	 * jsdelivr - also available on github:
	 * https://github.com/dlueth/qoopido.nucleus
	 */
	demand.configure({
		cache: false,
		pattern: {
			'/nucleus': '//cdn.jsdelivr.net/npm/qoopido.nucleus@3.1.0/dist'
		}
	});

	/*
	 * Load Qoopido.nucleus /dom/element module
	 * (in an async, promise like way) which
	 * handles DOM abstraction (including DOM/CSS
	 * manipulation and event abstraction)
	 */
	demand('/nucleus/dom/element')
		.then(function(DomElement) {
			var // Storage for all instantiated tasks
				storage = {},
				// Current task being swiped
				current;
		
			/*
			 * Simple module to handle swipe state & math
			 * (basically vector math)
			 */
			function Swipe() {}

			Swipe.prototype = {
				ot: null, // start time
				ox: null, // start x
				oy: null, // start y
				lt: null, // last time
				lx: null, // last x
				ly: null, // last y
				// (re-) initialize swipe state
				start: function(x, y, time) {
					this.ot = time;
					this.ox = x;
					this.oy = y;
				},
				// update swipe state
				update: function(x, y, time) {
					this.lt = time;
					this.lx = x;
					this.ly = y;
				},
				get duration() {
					return this.lt - this.ot;
				},
				get delta() {
					return Math.sqrt(Math.pow(this.deltaX, 2) + Math.pow(this.deltaY, 2));
				},
				get deltaX() {
					return this.lx - this.ox;
				},
				get deltaY() {
					return this.ly - this.oy;
				},
				get velocityX() {
					return (this.deltaX / this.duration) || 0;
				},
				get velocityY() {
					return (this.deltaY / this.duration) || 0;
				},
				get velocity() {
					return Math.sqrt(Math.pow(this.velocityX, 2) + Math.pow(this.velocityY, 2));
				},
				get angle() {
					return Math.abs(Math.atan2(this.deltaY, this.deltaX) * 180 / Math.PI);
				}
			};

			/*
			 * Main module for every Task entry extending
			 * Qoopido.nucleus /dom/element and therefore
			 * inheriting all its methods
			 */
			function Task(element) {
				var // Call parent constructor
					self = DomElement.call(this, element);

				// instantiate swipe module
				self.swipe = new Swipe();

				// Globally store instance
				storage[self.uuid] = self;

				// Important: return instance modified by parent constructor
				return self;
			}

			// Task prototype
			Task.prototype = {
				swipe: null,
				/*
				 * Initiates swipe action on touchstart/mousedown
				 */
				start: function(event) {
					var self    = this,
						swipe   = self.swipe,
						touches = event.targetTouches;

					// either pass first touch clientX/Y or events general clientX/Y to swipe module
					swipe.start(
						(touches && touches[0].clientX) || event.clientX,
						(touches && touches[0].clientY) || event.clientY,
						event.timeStamp
					);

					return self;
				},
				/*
				 * Updates swipe action on touchmove/mousemove and
				 * sets classes according to swipe direction
				 */
				move: function(event) {
					var self    = this,
						swipe   = self.swipe,
						touches = event.targetTouches,
						angle;

					// either pass first touch clientX/Y or events general clientX/Y to swipe module
					swipe.update(
						(touches && touches[0].clientX) || event.clientX,
						(touches && touches[0].clientY) || event.clientY,
						event.timeStamp
					);

					// move task element on x-axis according to current swipe distance
					self.setStyle('transform', 'translateX(' + swipe.deltaX + 'px)');

					angle = swipe.angle;

					if(angle > -20 && angle < 20) {
						// a right swipe has an angle of 0° and +/- 20° seems a reasonable treshold
						self.addClass('completing');
					} else if(angle > 160 && angle < 200) {
						// a left swipe has an angle of 180° and +/- 20° seems a reasonable treshold
						self.addClass('deleting');
					}

					return self;
				},
				/*
				 * Ends a swipe action and animates DOM element,
				 * adds classes etc according to swipe direction
				 */
				end: function() {
					var self  = this,
						swipe = self.swipe,
						angle;

					/*
					 * Apply reasonable tresholds to make sure user
					 * interaction was really ment to be a swipe
					 * action
					 */
					if(swipe.delta > 10 && swipe.velocity > 0.3) {
						angle = swipe.angle;

						if(angle > -20 && angle < 20) {
							// a right swipe has an angle of 0° and +/- 20° seems a reasonable treshold
							self
								// set transition style
								.setStyle('transition', 'all 500ms cubic-bezier(0.250, 0.460, 0.450, 0.940)')
								// register a once-only listener for transitionend
								.one('transitionend', function() {
									self
										// add completed class
										.addClass('completed')
										// move element from its current position in DOM to be the last child of its parent
										.appendTo(self.getParent())
										// cleanup afterwards
										.cancel();
								})
								// set transform style to animate element to the right
								.setStyle('transform', 'translateX(100%)');
						} else if(angle > 160 && angle < 200) {
							// a left swipe has an angle of 180° and +/- 20° seems a reasonable treshold
							self
								// set transition style
								.setStyle('transition', 'all 500ms cubic-bezier(0.250, 0.460, 0.450, 0.940)')
								// register a once-only listener for transitionend
								.one('transitionend', function() {
									// remove element from DOM
									self.detach();
								})
								// set transform style to animate element to the left
								.setStyle('transform', 'translateX(-100%)');
						} else {
							// cleanup / reset
							self.cancel();
						}
					} else {
						// cleanup / reset
						self.cancel();
					}

					return self;
				},
				/*
				 * Cancels / resets a swipe action
				 */
				cancel: function() {
					var self = this;

					self
						.removeClass('completing')
						.removeClass('deleting')
						.removeStyle('transform')
						.one('transitionend', function() {
							self.removeStyle('transition');
						});

					return self;
				}
			};

			/*
			 * Make Task extend Qoopido.nucleus /domm/element module
			 */
			Task.extends(DomElement);

			/*
			 * Instantiate /dom/element module of document.body
			 */
			new DomElement(document.body)
			/*
				 * Register event listener to start a Task's swipe action
				 * Note: This must(!) be the only event using event
				 * delegation for ".task" elements because "move" and
				 * "end" events may occur outside of the specific element
				 */
				.on('mousedown touchstart', '.task', function(event) {
					var self = this,
						uuid = self.uuid; // predefined by /dom/element

					/*
					 * Initialize a new "Task" instance if none exists yet
					 * Note: So no pre-instanciation is needed, any task
					 * will be instanciated on demand only
					 */
					if(!uuid || !storage[uuid]) {
						uuid = (new Task(self)).uuid;
					}

					// set "current" task and pass event to its "start" method
					current = storage[uuid].start(event);
				})
				/*
				 * Register "move" event listeners and pass
				 * event to "current" tasks "move" method
				 */
				.on('mousemove touchmove', function(event) {
					if(current) {
						current.move(event);
					}
				})
				/*
				 * Register "up" event listeners and pass
				 * event to "current" tasks "end" method
				 */
				.on('mouseup touchend', function(event) {
					if(current) {
						current.end(event);

						current = null;
					}
				})
				/*
				 * Special listener for "cancel" of touch events
				 */
				.on('touchcancel', function(event) {
					if(current) {
						current.cancel(event);

						current = null;
					}
				});
		});
	}(this, document, demand, provide));
            
          
!
999px

Console