👋 Hey there! We want to give you a heads up that the source code that accompanies this series is no longer available to download. We still think there are valuable bits of information to get from the series, but given that we’re 10+ years down the road, we also think it’s worth considering a modern PHP framework (like Laravel) or even a JavaScript framework (like React or Vue) to create a progressive web app.
It’s time to get our hands dirty with some markup!
We know we have a couple different pages to deal with here. The main page of course, which acts as both our list page and sales page depending on login status. But then we have sign in and sign up pages and account pages. So let’s be smart and work modularity. That means we’ll make files like “header.php” and “close.php” that we can include on multiple pages so we don’t have to repeat common code (e.g. the DOCTYPE, analytics code, and ubiquitous things like that.
Article Series
- Planning the App: Basic Idea and Design
- Planning the App: Database Architecture and Development Approach
- Designing the App: Workflow Map and Photoshop Design
- Designing the App: HTML and CSS
- Developing the App: User Interaction
- Developing the App: Adding AJAX Interactivity
- Developing the App: List Interaction
- Security & The Future
Web Root Organization
This is what we have for files at the root of our web directory so far. All the major views have their own PHP files. We have subdirectories for images and “common” files. and we have a few loose files like CSS and the favicon.
Our developer will surely be adding more files. He’s going to need PHP files for interacting with the database and doing all the list interactions.
Header
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Colored Lists | <!-- Do Something Smart Here --></title>
<link rel="stylesheet" href="style.css" type="text/css" />
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<script type='text/javascript' src='//ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js?ver=1.3.2'></script>
</head>
<body>
<div id="page-wrap">
<div id="header">
<h1><a href="/">Colored Lists</a></h1>
<div id="control">
<!-- IF LOGGED IN -->
<p><a href="/logout.php" class="button">Log out</a> <a href="/account.php" class="button">Your Account</a></p>
<!-- IF LOGGED OUT -->
<p><a class="button" href="/signup.php">Sign up</a> <a class="button" href="/login.php">Log in</a></p>
<!-- END OF IF STATEMENT -->
</div>
</div>
Right away in the header we’ve run across a few things where we need to be smart and leave notes for the developer, but give him the things he needs. In the page title, we’ve left a note to do something smart there. Different pages need different page titles, so clearly something dynamic needs to happen there. Then with our control buttons (e.g. Account / Logout) those buttons will be different depending on the logged in state of the user. So we’ll just let the developer jump in there and make those things function correctly.
So at this point we have the top of a page. We are leaving the body, html, and #page-wrap elements open, as beyond that is the main content of the page. Before we get into that main content, let’s toss in the sidebar and footer areas so we have a complete skin.
Footer
Our design doesn’t call for much of a footer, so we’ll just close up those open elements and add a note to put analytics here.
</div>
<!-- Analytics here -->
</body>
</html>
Sidebar
Our design calls for a bit of a sidebar. Right now, all we’ll use it for is a few notes on using the application. But it’s nice to have some open room for content, as it’s extremely likely that room will be needed for additional things as the app grows.
<div id="ribbon">
Reminders
<ul>
<li>Your list automatically saves</li>
<li>Double-click list items to edit them</li>
</ul>
</div>
Main Page
Now that we have our “modules” complete, let’s dig into a real page. The template for building any page will be like this:
<?php include_once "common/header.php"; ?>
<div id="main">
<noscript>This site just doesn't work, period, without JavaScript</noscript>
<!-- IF LOGGED IN -->
<!-- Content here -->
<!-- IF LOGGED OUT -->
<!-- Alternate content here -->
</div>
<?php include_once "common/sidebar.php"; ?>
<?php include_once "common/footer.php"; ?>
Logged in (The List)
<ul id="list">
<li class="colorRed">
<span>Walk the dog</span>
<div class="draggertab tab"></div>
<div class="colortab tab"></div>
<div class="deletetab tab"></div>
<div class="donetab tab"></div>
</li>
<li class="colorBlue">
<span>Pick up dry cleaning</span>
<div class="draggertab tab"></div>
<div class="colortab tab"></div>
<div class="deletetab tab"></div>
<div class="donetab tab"></div>
</li>
<li class="colorGreen">
<span>Milk</span>
<div class="draggertab tab"></div>
<div class="colortab tab"></div>
<div class="deletetab tab"></div>
<div class="donetab tab"></div>
</li>
</ul>
The list itself will just be a regular ol’ unordered list. We’ll use CSS class names for the colors. But then we need a bunch of controls for the list items. That’s what all those divs are inside the list items. There are empty divs for dragging, changing color, deleting, and checking off list items. We need these for the CSS so we can target them and style them.
We’re smart designers though, we know this markup is merely temporary. These lists will be dynamically generated by the application. Just looking at all those empty control divs; we know that those are probably automatically generated by the JavaScript. That’s fine, we need the HTML in there now to set the stage and have everyone on the same page.
Why the spans inside the list items? Just being smart. Because the list items wrap more than just the text, it’s likely we’ll need some kind of hook to target just the text later on.
Now we need to get an input on this page for adding new list items. Our developer will be all over this, but we’ll put the basics in so we can style them.
<form action="" id="add-new">
<div>
<input type="text" id="new-list-item-text" name="new-list-item-text" />
<input type="submit" id="add-new-submit" value="Add" class="button" />
</div>
</form>
Then one of our applications features is having sharable public URL’s for our lists. Let’s put that in here too.
<div id="share-area">
<p>Public list URL: <a href="#">URL GOES HERE</a>
<small>(Nobody but YOU will be able to edit this list)</small></p>
</div>
Ahhh, more work for the developer! But he’s ready for it. This public URL business leads us into another possible scenario. We need this main page to be capable of displaying a list without showing the input form or all the list controls. Basically you can just look at the list but not interact with it. (Like if you wanted to send your mom your Christmas list!)
Logged out (Public list)
<ul id="list">
<li class="colorRed">
<span>Walk the dog</span>
</li>
<li class="colorBlue">
<span>Pick up dry cleaning</span>
</li>
<li class="colorGreen">
<span>Milk</span>
</li>
</ul>
This will be exactly the same as the list above, only no control tabs, no form to add new items, and no public URL area (hey, they are already here, what do they need the URL for). We know this this probably will just be a change in how the backend code outputs the list. But whatever, if we create this, everybody is on the same page.
Logged out (Sales)
We might do something fancy someday for this, but for now, our big idea is just a cool graphic showing that this area is potentially where your new list will be and a big ol’ arrow showing people where they can sign up.
<img src="/images/newlist.jpg" alt="Your new list here!" />
Account Page
As a quick reminder, we us this structure for all pages, including this one.
<?php include_once "common/header.php"; ?>
<div id="main">
<!-- IF LOGGED IN -->
<!-- Content here -->
<!-- IF LOGGED OUT -->
<!-- Alternate content here -->
</div>
<?php
include_once "common/sidebar.php";
include_once "common/footer.php";
?>
That’s the beauty of working modularly, all common content is included so updates down the line are much easier.
The account page is going to have several forms on it: one for updating email, one for updating password, and a button for users to delete their accounts. Again, our developer will be all over these forms filling them up with hidden inputs that pass along data and adding in action URLs and methods and all that. We’ll leave that to him, but this gives us enough to style.
<h2>Your Account</h2>
<form action="">
<div>
<input type="text" name="username" id="username" />
<label for="username">Change Email Address</label>
<input type="submit" name="change-email-submit" id="change-email-submit" value="Change Email" class="button" />
</div>
</form>
<hr />
<h2>Change Password</h2>
<form action="#">
<div>
<label for="password">New Password</label>
<input type="password" name="r" id="repeat-new-password" />
<label for="password">Repeat New Password</label>
<input type="submit" name="change-password-submit" id="change-password-submit" value="Change Password" class="button" />
</div>
</form>
<hr />
<form action="" id="delete-account-form">
<div>
<input type="submit" name="delete-account-submit" id="delete-account-submit" value="Delete Account?" class="button" />
</div>
</form>
Other “Form” Pages
Now that we’ve done the account page, we have pretty much covered all the bases for the other “form” style pages. Sign up, sign in, forgot your password, they are all just simpler versions of the account page. Since we’ll have styled the basic label/input format, the header format, and the “button” format, the developer can easily create these pages himself copying the basic format and CSS classes from the account page.
The CSS
Reset
/*
RESET
*/
* { margin: 0; padding: 0; }
body { font: 14px/1.1 Helvetica, Sans-Serif; background: url(images/stripe.png) repeat-x; }
.clear { clear: both; }
img, a img { border: none; }
input { outline: none; }
Just getting things cleaned up.
Structure
/*
STRUCTURE
*/
body { font: 14px/1.1 Helvetica, Sans-Serif; background: url(images/stripe.png) repeat-x; }
#page-wrap { width: 960px; margin: 6px auto 50px; position: relative; }
hr { height: 1px; background: #ccc; clear: both; margin: 20px 0; border: none; display: block; }
Not too much complicated formatting for our little one-page app.
Typography
/*
TYPOGRAPHY
*/
a { text-decoration: none; color: #900; border-bottom: 1px dotted #900; outline: none; }
h1 { font: bold 36px Helvetica, Sans-Serif; margin: 0 0 8px 0; }
h2 { margin: 0 0 10px 0; }
p { margin: 0 0 6px 0; }
.button { background: url(/images/button-bg.png) repeat-x; -moz-border-radius: 5px; padding: 6px 12px; border: none; color: white; cursor: pointer; text-shadow: 0 1px 1px #666; -webkit-border-radius: 5px; -webkit-box-shadow: 0 1px 3px #999; -moz-box-shadow: 0 1px 3px #999; font: bold 16px Helvetica; }
.button:hover { background-position: bottom left; }
.red { background: red; color: white; font-size: 12px; padding: 3px; }
This isn’t really a content-based app, so we don’t have a whole heck of a lot of text formatting. However we do have page headers, links, and buttons, so we’ll set those up here.
Header
/*
HEADER
*/
#header { height: 68px; position: relative; }
#header h1 { position: absolute; top: 0; left: 0; z-index: 2; text-indent: -9999px; overflow: hidden; }
#header h1 a { display: block; text-indent: -9999px; width: 200px; height: 38px; border: none; background: url(/images/logo.png) no-repeat; }
#control { width: 500px; float: right; padding: 10px 237px 0 0; text-align: right; }
Our little stripe header doesn’t take much. Just a little CSS image replacement for the logo and placement of our control buttons.
Lists
/*
LISTS
*/
#list { list-style: none; }
#list li { position: relative; margin: 0 0 8px 0; padding: 0 0 0 70px; width: 607px; }
#list li span { padding: 8px; -moz-border-radius: 5px; -webkit-border-radius: 5px; width: 589px; display: block; position: relative; }
.colorBlue span { background: rgb(115, 184, 191); }
.colorYellow span { background: rgb(255, 255, 255); }
.colorRed span { background: rgb(187, 49, 47); color: white; }
.colorGreen span { background: rgb(145, 191, 75); }
.tab { background: url(images/minibuttons.png) no-repeat; height: 21px; top: 4px; }
.draggertab { position: absolute; left: 0px; width: 31px; cursor: move; }
.draggertab:hover { background-position: 0 -21px; }
.colortab { position: absolute; left: 34px; width: 34px; background-position: -31px 0; cursor: pointer; }
.colortab:hover { background-position: -31px -21px; }
.deletetab { position: absolute; right: -35px; width: 15px; background-position: -82px 0; cursor: pointer; }
.deletetab:hover { background-position: -82px -21px; }
.donetab { position: absolute; right: -17px; width: 16px; background-position: -65px 0; cursor: pointer; }
.donetab:hover { background-position: -65px -21px; }
.crossout { position: absolute; top: 50%; left: 0; height: 1px; }
#share-area { margin: 20px 0 0 69px; width: 600px; }
A lot more stuff needed here. Here we’ll set up how the lists look: the colors, the spacing, the rounded corners, etc. We’ll also position all the little helper controls and give them appropriate backgrounds. Notice only a single image is used, minibuttons.png. A single CSS Sprite for mad efficiency!
Forms
/*
FORM STUFF
*/
label { background: #999; color: white; padding: 3px; }
input[type="text"], input[type="password"] { width: 324px; border: 3px solid #999; font-size: 18px; padding: 7px; display: block; }
#add-new input[type="text"] { width: 532px; float: left; margin: 0 10px 0 69px; }
#add-new input[type="text"]:focus { border-color: #73B8BF; }
#add-new input[type="submit"] { padding: 10px 12px; }
ul#list li span input[style] { width: 90% !important; }
Forms across our whole site will be the same, so we set that up here. The one exception is the “Add New” area on our lists, which is basically the same as any other input except bigger and is floated to the left to accommodate the “Add” button. Since we plan to use click-to-edit, the list items temporarily turn into text inputs when doing that, so we’ll plan for that by shortening the length of them to accommodate for a “Save” button.
Messaging
/*
MESSAGING
*/
.message { padding: 10px; margin: 0 0 10px 0; width: 607px; }
.good { background: #9ff5b6; }
.bad { color: #ef0040; }
We haven’t talked too much about error messaging, but we can assume that because this is a web app, there will be some of it (for example, you enter in a wrong password, your passwords don’t match, you have successfully done something, etc). We’ll set up one class for messages in general and then classes for good and bad versions.
Sidebar
/*
SIDEBAR
*/
#ribbon { position: absolute; right: 0; width: 125px; padding: 60px 30px 0 47px; height: 756px; top: -6px; background: url(/images/ribbon-bg.png) no-repeat; }
#ribbon ul { list-style: none; }
#ribbon ul li { background: rgba(0,0,0,0.8); color: white; padding: 5px; margin: 0 0 5px 0; font-size: 12px; }
Just some simple stuff for our list of reminders.
Moving Along
Our developer now has plenty to work with to make this app functional. Next, we’ll tackle user account interaction.
Nice Chris, keep it on!
One suggestion,
Why not place all module files in a folder of their own (/account)
That way, if you decide to add another module ..(/permissions for instance) you end up with a tidier set of files.
just my 2 cents;-)
The series is GREAT!
Can’t see any of the content on the ennui site…
Are you on IE6?
I had decided to officially drop support for IE6, but then I realized that the fix for the IE6 problems on my site was 12 lines of CSS. It should be working now.
Sorry about that!
This guide is really good and well written, it is becoming a little bible for me xD
Wow! Can’t wait for the rest.
Now that’s a blog post!
I think u missed an Input field after the repeat new password label
Repeat New Password
it should be
Repeat New Password
great guide.
sorry for the double post but i don`t know why my code didn`t appear anyway i post it here
http://pastie.org/713197
thanks
Wait.. Part four already? What happened to two and three?
Never mind I’m sorry. They’re on the other site it appears..
Thank you Chris and thank you Jason. This is one of the most useful web design blogs out there, and i’ve seen a few. Can’t wait for the next parts!
Yeah first comment :D
Great series Chris & Jason !
Can’t say otherwise, this is gonna be a friggin’ awesome thing I’ll probebly refer to lot.
So many things come together here, and you two just go for it. All-inclusive tutorial.
— TeMc
nice work, guys :D
Chris, Jason… you rock!
Thanks Chris and Jason! Good, no great, articles.
Funny, I just started on my new web app the other day, so this has been a great help. I’ve already learned a lot. Keep up the good work!
You forgot “Amen.” at the end of your post Chris ;-)
Nice one! Finally a good “series” post.
By the way.. Part 9, 10 and 11 will be about IE compatibility? ;-) Lol. Saw some nice techniques there but most of them aren’t that cross-broser. :(
so does this app only allow one list per user? or did I miss something?
or does it work like tadalist?
thanks
You are right, this first version of the app only supports one list per user. However, it’s built in such a way that expanding beyond that is possible in future versions.
thanks
how about adding an option to sign up with facebook and twitter?
A quick sanity check here please (for a learner). These are the both ok in terms of coding? (class and href being written in a different sequence)
Any reason why they are different, and not written in the same order?
OK, my code doesnt show up :-(
Account Page
As a quick reminder, we us_e_ this structure for all pages, including this one.
Small typo fix, big thumbs up =] Keep up the good work
I’m trying to follow along with this and I’m not really sure where you are placing all of these files because the the file structure image does not match up to what the sections are being called.
For instance I am wondering if the Logged In stuff it’s own php file or is it the base.php or is it the index.php file.?
The account page makes since because you outline that it is the account and you just do the same for the other form pages.
Agree with chad, I’m not entirely sure where I should be putting the ‘main’ code either – any chance you could revisit this and make the file structure really obvious? Would be a great help!
I tried to look at your part 5 for User Interaction but it looks like the hosting is down….
Don’t know if authors still are around here but hopefully somebody will answer.
I’m completely new to app developing and, after this tutorial, I don’t understand how the directory structure should look like.
Are all these “parts” included only in one php file inside commons?
Or are we creating 1 php file for each part (“header” “footer” etc…)
Exactly my question, too. And is the directory structure created manually or was there a certain framework used?
Posting this on behalf of Jay Hughes, who wrote in:
Leon & Ricofranco:
Some very good questions. No tutorial is perfect but this one is, by far, A++++++ quality. I frequently refer to Jason and Chris when I’m researching ideas or best practices. I develop web based data apps on the fly for “one of those agencies” in the Washington DC area. And I frequently check out their work for inspiration and ideas.
Keep referring to Jason and Chris and you’ll learn more in a short period of time for free than you will sitting in a university classroom being taught by a professor who learned FORTRAN and COBOL 30 years ago while spending thousands of dollars in tuition, fees and books.
Hopefully you got your questions answered since they are about a year old but here are some quick pointers just in case you didn’t and Chris will allow this to be posted since he closed off the comments.
First, Leon, you will want to make header, footer, etc. separate php files. So you’ll have header.php, footer.php, etc. This is so the include statements you see peppered throughout Jason’s code can reference a specific file for a specific task or purpose. This is slightly different than the “methods” you see in his two big classes: class.users.inc.php and class.lists.inc.php, where you can put a whole bunch of methods in the same file.
Second, Ricofranco, you will need to manually create the folder heirarchy on your server using whatever File Transfer Protocol (FTP) app you have. I use FileZilla but there’s a whole bunch of open source, freeware ones you can use…just google it. Don’t let the term FTP freak you out. It’s basically a way to move files like you do in Windows Explorer or any other file manager. The big difference with FTP is your files to a completely different machine whereas for Windows Explorer you’re just moving them around on your computer. Let’s say you’re using FileZilla. You’ll see the format and organization is virtually identical to Windows Explorer so you’ll want to click through the folder icons to get to where you want to create the different folders you need. Now here’s the not so fun part. You will need to name the folders exactly as Jason has done in order for the include statements to work. So you’re going to need to read through each php file and where ever you see an include statement write down the folder names and the php files stored within them. For instance, if you open up the accountverify.php file, up at the top you can see two include statements with a directory pathway “common/base.php”. So you’ll need to create a folder named “common” and put “base.php” file inside of it. You’ll need to be sure you spell those folder names exactly as Jason has. If you misspell “common” or try to add a number to it, it won’t work. So you’ll need to visually review each php file to be sure you see every folder name you’ll need to create. I strongly recommend as you review each of the 14 or so php files you write down every time you see a folder/file.php situation. That way you can be sure you have a checklist of every folder you need to create and the files you need to place in those folders. It’s tedious but you will need to be thorough.
Next, there are some php files referred to in a few include statements that Jason doesn’t seem to provide code for in his step-by-step explanations. Based on my review (and I could be wrong) they are: ads.php, close.php and gone.php. A quick and easy work-around would be to simply create each file and place inside of it a comment. Again, you will need to determine which folder they should be placed in.
For ads.php it would look like this:
And you just do the same thing for the other two files. The one line between the php tags is a comment so you can put any language you want inside the /* */. I would just alter the comment to switch out “ads” and put in the name of the specific file.
Well I hope this helps. Thanks to Chris and Jason for this huge labor of love!