cssAudio - Activefile-genericCSS - ActiveGeneric - ActiveHTML - ActiveImage - ActiveJS - ActiveSVG - ActiveText - Activefile-genericVideo - ActiveLovehtmlicon-new-collectionicon-personicon-teamlog-outoctocatpop-outspinnerstartv

Pen Settings

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

You're using npm packages, so we've auto-selected Babel for you here, which we require to process imports and make it all work. If you need to use a different JavaScript preprocessor, remove the packages in the npm tab.

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

Use npm Packages

We can make npm packages available for you to use in your JavaScript. We use webpack to prepare them and make them available to import. We'll also process your JavaScript with Babel.

⚠️ This feature can only be used by logged in users.

Code Indentation

     

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.

            
              // If you like this app, feel free to hit 
// the heart button :)
#app

            
          
!
            
              $black: #333
$purple: #6d639a
$pink: #d63f74
$white: #fefefe
$grey: rgba($black, .5)

*
	font-family: Bungee Hairline !important
	font-weight: bold
	color: $black
	border-color: $black 
	line-height: 1.5

\::-webkit-input-placeholder
	color: rgba($pink, .5)

\:-moz-placeholder
	color: rgba($pink, .5)

\::-moz-placeholder
	color: rgba($pink, .5)

\:-ms-input-placeholder
	color: rgba($pink, .5)

body
	background: #fefefe

.textCenter
	text-align: center

.removeBtn
	position: absolute
	right: 8px
	top: 50%
	transform: translateY(-50%)

#container
	margin: auto
	text-align: center
	max-width: 700px
	margin: 60px auto 0 auto
	padding: 0px 20px
	
	h2
		margin-bottom: 30px
		color: $black
	
	#form
		margin-bottom: 50px
		
	#info
		padding: 7px
		text-align: left
		color: $grey

	input
		background: transparent
		border: solid 1px
		padding: 7px 10px
		border-right: none
		width: 70%
		color: $black
		border-color: $pink
		&:focus, &:active
			outline: none

	button
		border: solid 1px $pink
		padding: 7px 10px
		background: rgba($pink, .8)
		cursor: pointer
		width: 15%
		min-width: 20px
		transition: all 100ms linear 80ms
		color: $white
		line-height: 1
		font-size: 18px
		&:focus, &:active
			outline: none
		&:hover, &:active
			background: rgba($pink, 1)

	
	button, input
		vertical-align: middle
		height: 35px
		box-sizing: border-box
	
	#acu
		text-align: left
		padding: 7px
	
	#footer
		margin: 50px 0 30px 0
		padding-top: 30px
		text-align: left
		border-top: dotted 2px $pink 
		p
			padding: 7px
			display: inline-block
			color: $black
			transition: all 100ms linear 80ms
			&:hover
				color: $pink
				&:before, &:after
					color: $purple
			&:before
				content: '<'
			&:after
				content: '/>'
		
	.todos
		transition: all 100ms linear 100ms
		position: relative
		text-align: left
		margin: 30px auto
		padding: 7px
		padding-right: 28px
		border: solid 1px transparent
		color: $purple
		
		&:hover
			cursor: pointer
			border: solid 1px  
			span
				visibility: visible
				color: inherit
		
		span
			transition: all 100ms linear 100ms	
			visibility: hidden
			&:hover
				cursor: pointer
			
			
            
          
!
            
              // Component Structure
// --------------------
// Container
// --> Title
// --> Form
// --> List
// ----> Todo
// --> Footer

// stateless component
const Title = () => {
	return (
		<div id="titleWrapper">
			<h2 className="textCenter">To-do List</h2>
		</div>
	);
};


class Form extends React.Component {
	constructor(props) {
		super(props);
		this.state = {
			value: ''
		};
		this.handleChange = this.handleChange.bind(this);
		this.handleNewTodoAddition = this.handleNewTodoAddition.bind(this);
	}
	
	handleChange(event) {
		this.setState({
			value: event.target.value
		});
	}
	
	handleNewTodoAddition() {
		if(this.input.value !== '') {
			this.props.addTodo(this.input.value);
			this.setState({
				value: ''
			});
			this.input.placeholder = "Add todo here...";
		}
	}
	
	render() {
		return (
			// ref should be passed a callback
			// with underlying dom element as its
			// argument to get its reference 
			<div id="form">
				<input 
					ref={node => {
						this.input = node;
					}}
					value={this.state.value}
					placeholder="Add todos here..."
					autocomplete="off"
					onChange={this.handleChange}
				/>

				<button 
					onClick={this.handleNewTodoAddition}
				>	
					+
				</button>	
			</div>
		);
	}
}

const Todo = ({todo, remove}) => {
	// single todo 
	return (
		<p className="todos">
			{todo.value}
			<span 
				className="removeBtn"
				onClick={()=> {
					remove(todo.id)
				}}>
				x
			</span>
		</p>
	);
};

const List = ({todos, remove}) => {
	let allTodos = [];
	
	if(todos.length > 0) {
		allTodos = todos.map(todo => {
			// passing todo and remove method reference
			return (<Todo todo={todo} remove={remove} />);
			//return (<p>{todo.value}</p>);
		});
	} else {
		allTodos.push(<h3 id="acu">All caught up !</h3>);	
	}
	
	return (
		<div id="list">
			<p id="info"> Your Todos: </p>
			{allTodos}
		</div>
	);
};

const Footer = () => {
	return (
		<div id="footer">
			<a href="http://iamarshad.com" target="_blank">
				<p>
					Arshad Khan
				</p>
			</a>
		</div>
	);
};

class Container extends React.Component {
	constructor(props) {
		super(props);
		// data for introduction to app
		// for new users
		const introData = [
			{
				id: -3, 
				value: "Hi! This is a simple todo list app made by REACT <3"
			},
			{
				id: -2,
				value: "Hover over todos and click on `X` to delete them!"
			},
			{
				id: -1,
				value: "Add new todos and come back any time later, I will save them for you!"
			}
		];
		
		const localData = localStorage.todos && JSON.parse(localStorage.todos);

		this.state = { 
			data: localData || introData
		};
		
		// binding methods
		this.addTodo = this.addTodo.bind(this);
		this.removeTodo = this.removeTodo.bind(this);
	}
	// Handler to update localStorage
	updateLocalStorage() {
		if (typeof(Storage) !== "undefined")
			localStorage.todos = JSON.stringify(this.state.data);
	}
	// Handler to add todo
	addTodo(val) {
		let id;
		// if localStorage is available then increase localStorage count
		// else use global window object's id variable
		if (typeof(Storage) !== "undefined") {
			id = Number(localStorage.count);
			localStorage.count = Number(localStorage.count) + 1;
		} else {
			id = window.id++;
		}
		
		const todo = { 
			value: val, 
			id: id 
		};
		
		this.state.data.push(todo);
		// update state
		this.setState({
			data: this.state.data
		}, () => {
			// update localStorage
			this.updateLocalStorage();
		});
	}
	// Handler to remove todo
	removeTodo(id) {
		// filter out the todo that has to be removed
		const list = this.state.data.filter(todo => {
			if (todo.id !== id)
				return todo;
		});
		// update state
		this.setState({
			data: list
		}, () => {
			// update localStorage
			this.updateLocalStorage();
		});
	}
	
	componentDidMount() {
		localStorage.clear();
		if (typeof(Storage) !== "undefined") {
			if(!localStorage.todos) {
				localStorage.todos = JSON.stringify(this.state.data);
			}
			if(!localStorage.count) {
				localStorage.count = 0;
			}

		} else {
			 console.log("%cApp will not remember todos created as LocalStorage Is Not Available",
							 "color: hotpink; background: #333; font-size: x-large;font-family: Courier;");
			window.id = 0;
		}
	}
	
	render() {
		return (
			<div id="container">
				<Title />
				<Form addTodo={this.addTodo} />
				<List todos={this.state.data} remove={this.removeTodo} />
				<Footer />
			</div>
		);
	}
}

ReactDOM.render(<Container />, app);
            
          
!
999px
🕑 One or more of the npm packages you are using needs to be built. You're the first person to ever need it! We're building it right now and your preview will start updating again when it's ready.
Loading ..................

Console