Initial commit: todo app guide with 5 prompts and examples
Complete companion repo for "Your First Hour with Claude Code" article. Includes step-by-step prompts, example output, troubleshooting, and cost guide. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
ec708ba943
10 changed files with 1089 additions and 0 deletions
150
README.md
Normal file
150
README.md
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
# Build Your First Project with Claude Code
|
||||
|
||||
A todo app in 15 minutes. No coding experience needed.
|
||||
|
||||
## What You Will Build
|
||||
|
||||
A fully working todo app that runs in your browser. Dark mode, saves your tasks between sessions, mark tasks as done, delete them. All from a single sentence typed into Claude Code.
|
||||
|
||||
Then you will iterate on it: add categories, search, due dates, and mobile layout. Each step is one prompt.
|
||||
|
||||

|
||||
|
||||
## What You Need
|
||||
|
||||
- A Claude subscription (Pro at $20/month is enough)
|
||||
- A computer (Mac, Windows, or Linux)
|
||||
- About 15-30 minutes
|
||||
|
||||
That is it. No programming language to install. No frameworks. No package managers. No git.
|
||||
|
||||
## Step 1: Install Claude Code
|
||||
|
||||
Open your terminal:
|
||||
- **Mac:** Press `Cmd + Space`, type `Terminal`, press Enter
|
||||
- **Windows:** Press the Windows key, type `Terminal`, press Enter
|
||||
- **Linux:** Press `Ctrl + Alt + T`
|
||||
|
||||
Paste this and press Enter:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://claude.ai/install.sh | bash
|
||||
```
|
||||
|
||||
**Windows alternative** (if curl does not work):
|
||||
```powershell
|
||||
winget install Anthropic.ClaudeCode
|
||||
```
|
||||
|
||||
**Do not want to use a terminal?** Download the [Claude Code desktop app](https://claude.ai/download) or use [claude.ai/code](https://claude.ai/code) in your browser. Both work the same way.
|
||||
|
||||
A browser window opens to sign in. Complete the sign-in process and return to your terminal.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
If you see a "command not found" error after installing:
|
||||
1. Close your terminal completely (not just the tab)
|
||||
2. Open a new terminal window
|
||||
3. Type `claude` and press Enter
|
||||
|
||||
This fixes it almost every time. The installer adds Claude Code to your PATH, but the current terminal session does not pick it up until restarted.
|
||||
|
||||
## Step 2: Create a Project Folder
|
||||
|
||||
```bash
|
||||
mkdir my-todo-app
|
||||
cd my-todo-app
|
||||
claude
|
||||
```
|
||||
|
||||
This starts Claude Code inside your new folder. You will see a prompt where you can type in plain English.
|
||||
|
||||
## Step 3: Build the Todo App (one prompt)
|
||||
|
||||
Copy and paste this prompt:
|
||||
|
||||
> Create a todo app as a single index.html file. Requirements: dark mode with a charcoal background, modern clean design, add/complete/delete tasks, tasks saved to localStorage so they survive page refresh. No external dependencies.
|
||||
|
||||
Claude Code will:
|
||||
1. Read your (empty) folder
|
||||
2. Plan the app structure
|
||||
3. Write the HTML, CSS, and JavaScript
|
||||
4. Create the file
|
||||
|
||||
It asks permission before creating the file. Type `y` to approve.
|
||||
|
||||
**Open the result:** Find `index.html` in your project folder and double-click it. It opens in your browser.
|
||||
|
||||
You now have a working todo app built from one sentence.
|
||||
|
||||
## Step 4: Add Categories (iteration)
|
||||
|
||||
This is where it gets interesting. Copy the prompt from [prompts/02-add-categories.md](prompts/02-add-categories.md), or simply type:
|
||||
|
||||
> Add color-coded categories to the todo app: Work (blue), Personal (green), Health (orange), Learning (purple). Each task gets a category dropdown. Filter buttons at the top to show only one category.
|
||||
|
||||
Claude Code reads the existing file, understands the current design, and adds categories while keeping everything else working. One prompt, one iteration.
|
||||
|
||||
## Step 5: Add Search
|
||||
|
||||
Copy the prompt from [prompts/03-add-search.md](prompts/03-add-search.md), or type:
|
||||
|
||||
> Add a search bar at the top that filters tasks in real time as you type. It should search both task text and category names.
|
||||
|
||||
Watch how Claude reads the now-larger file, finds the right place to add the search input, writes the filtering logic, and tests that it does not break anything.
|
||||
|
||||
## Keep Going
|
||||
|
||||
Each file in `prompts/` is another iteration:
|
||||
|
||||
| Prompt | What It Adds |
|
||||
|--------|-------------|
|
||||
| [01-create-todo.md](prompts/01-create-todo.md) | Base todo app (dark mode, localStorage) |
|
||||
| [02-add-categories.md](prompts/02-add-categories.md) | Color-coded categories with filters |
|
||||
| [03-add-search.md](prompts/03-add-search.md) | Real-time search bar |
|
||||
| [04-add-due-dates.md](prompts/04-add-due-dates.md) | Due dates with overdue highlighting |
|
||||
| [05-make-responsive.md](prompts/05-make-responsive.md) | Mobile-friendly layout |
|
||||
|
||||
After these five, try your own ideas:
|
||||
- Drag-and-drop reordering
|
||||
- Export tasks as a text file
|
||||
- Dark/light mode toggle
|
||||
- Task priority levels
|
||||
- Daily task count chart
|
||||
|
||||
The point is not the todo app itself. The point is learning how Claude Code works: you describe what you want, it builds it, you iterate with another sentence.
|
||||
|
||||
## How Claude Code Works
|
||||
|
||||
When you give Claude Code a task, it does not just generate text. It runs a loop:
|
||||
|
||||
1. **Read** your files to understand the current state
|
||||
2. **Think** about what needs to change
|
||||
3. **Act** by editing files or running commands
|
||||
4. **Check** the result
|
||||
5. **Repeat** until the task is done
|
||||
|
||||
This is called the **agent loop**. It is what makes Claude Code fundamentally different from a chatbot. A chatbot gives advice. Claude Code takes action.
|
||||
|
||||
Read more: [Your First Hour with Claude Code](https://thedharmalab.com) (article on The Dharma Lab)
|
||||
|
||||
## Example Output
|
||||
|
||||
The `examples/` folder contains what Claude Code typically produces:
|
||||
|
||||
- [index.html](examples/index.html) - After prompt 01 (base todo app)
|
||||
- [index-v2.html](examples/index-v2.html) - After prompts 02 + 03 (categories + search)
|
||||
|
||||
Your results will look different. Claude Code generates fresh code each time. The functionality will be the same, but the exact styling and structure will vary.
|
||||
|
||||
## What It Costs
|
||||
|
||||
See [costs.md](costs.md) for a full breakdown. Short version: Pro at $20/month is the lowest-risk way to start.
|
||||
|
||||
## Common Problems
|
||||
|
||||
See [troubleshooting.md](troubleshooting.md) for solutions to the most common issues people run into during their first session.
|
||||
|
||||
---
|
||||
|
||||
Part of [The Dharma Lab](https://thedharmalab.com) Claude Code article series.
|
||||
44
costs.md
Normal file
44
costs.md
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
# What Claude Code Costs
|
||||
|
||||
## Subscription Plans
|
||||
|
||||
| Plan | Price | Best For |
|
||||
|------|-------|----------|
|
||||
| **Pro** | $20/month | Trying Claude Code, casual use, learning |
|
||||
| **Max 5x** | $100/month | Regular daily use, side projects |
|
||||
| **Max 20x** | $200/month | Heavy professional use, full workdays |
|
||||
|
||||
All plans include access to Claude Code in terminal, VS Code, desktop app, and browser.
|
||||
|
||||
## Which Plan to Start With
|
||||
|
||||
**Pro at $20/month.** It gives you enough usage to complete this entire guide and explore for a few weeks. If you hit usage limits, you will see a message telling you to wait or upgrade. Nothing breaks, nothing gets charged extra.
|
||||
|
||||
## API Access (Alternative)
|
||||
|
||||
If you prefer pay-per-use instead of a subscription:
|
||||
|
||||
- Average cost: about $6 per day for typical use
|
||||
- 90% of users spend less than $12 per day
|
||||
- You pay for exactly what you use, nothing when idle
|
||||
- Requires setting up an Anthropic API key
|
||||
|
||||
The subscription is simpler and almost always cheaper for regular use. API access makes more sense for automation and CI/CD pipelines.
|
||||
|
||||
## What Uses More Tokens (and Costs More)
|
||||
|
||||
- Long sessions without clearing context
|
||||
- Reading very large files
|
||||
- Running many tools in a row (complex multi-file changes)
|
||||
- Using Opus model instead of Sonnet for every task
|
||||
|
||||
## What Uses Less
|
||||
|
||||
- Starting fresh sessions for new tasks (`/clear`)
|
||||
- Giving clear, specific prompts
|
||||
- Using Sonnet for routine tasks (rename, format, simple bugs)
|
||||
- Keeping CLAUDE.md concise (under 200 lines)
|
||||
|
||||
## Bottom Line
|
||||
|
||||
For this guide, any plan works. Pro is the safest way to start. You can upgrade later if you use it daily.
|
||||
415
examples/index-v2.html
Normal file
415
examples/index-v2.html
Normal file
|
|
@ -0,0 +1,415 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Todo App</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: #1a1a2e;
|
||||
color: #e0e0e0;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 2rem 1rem;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
max-width: 540px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.75rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 1.5rem;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.search-row {
|
||||
position: relative;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.search-row input {
|
||||
width: 100%;
|
||||
padding: 0.625rem 2.5rem 0.625rem 1rem;
|
||||
background: #16213e;
|
||||
border: 1px solid #2a2a4a;
|
||||
border-radius: 8px;
|
||||
color: #e0e0e0;
|
||||
font-size: 0.9rem;
|
||||
outline: none;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
.search-row input:focus {
|
||||
border-color: #4DB8A4;
|
||||
}
|
||||
|
||||
.search-row input::placeholder {
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.search-clear {
|
||||
position: absolute;
|
||||
right: 0.75rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background: none;
|
||||
border: none;
|
||||
color: #555;
|
||||
font-size: 1.1rem;
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.search-clear.visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.search-clear:hover {
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
.filters {
|
||||
display: flex;
|
||||
gap: 0.375rem;
|
||||
margin-bottom: 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.filter-btn {
|
||||
padding: 0.375rem 0.75rem;
|
||||
background: #16213e;
|
||||
border: 1px solid #2a2a4a;
|
||||
border-radius: 6px;
|
||||
color: #888;
|
||||
font-size: 0.8rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.filter-btn:hover {
|
||||
border-color: #4DB8A4;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
.filter-btn.active {
|
||||
background: #4DB8A4;
|
||||
color: #1a1a2e;
|
||||
border-color: #4DB8A4;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.input-row {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.input-row input[type="text"] {
|
||||
flex: 1;
|
||||
padding: 0.75rem 1rem;
|
||||
background: #16213e;
|
||||
border: 1px solid #2a2a4a;
|
||||
border-radius: 8px;
|
||||
color: #e0e0e0;
|
||||
font-size: 1rem;
|
||||
outline: none;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
.input-row input[type="text"]:focus {
|
||||
border-color: #4DB8A4;
|
||||
}
|
||||
|
||||
.input-row input[type="text"]::placeholder {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.input-row select {
|
||||
padding: 0.75rem 0.5rem;
|
||||
background: #16213e;
|
||||
border: 1px solid #2a2a4a;
|
||||
border-radius: 8px;
|
||||
color: #e0e0e0;
|
||||
font-size: 0.85rem;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.input-row button {
|
||||
padding: 0.75rem 1.25rem;
|
||||
background: #4DB8A4;
|
||||
color: #1a1a2e;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.input-row button:hover {
|
||||
background: #3da897;
|
||||
}
|
||||
|
||||
.task-list {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.task-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.875rem 1rem;
|
||||
background: #16213e;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 0.5rem;
|
||||
transition: opacity 0.3s, transform 0.3s;
|
||||
animation: slideIn 0.3s ease;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from { opacity: 0; transform: translateY(-10px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
.task-item.completed .task-text {
|
||||
text-decoration: line-through;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.task-checkbox {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 2px solid #4DB8A4;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.task-item.completed .task-checkbox {
|
||||
background: #4DB8A4;
|
||||
}
|
||||
|
||||
.task-item.completed .task-checkbox::after {
|
||||
content: '\2713';
|
||||
color: #1a1a2e;
|
||||
font-size: 0.75rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.category-dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.category-dot.work { background: #5B9FD6; }
|
||||
.category-dot.personal { background: #4DB8A4; }
|
||||
.category-dot.health { background: #E87020; }
|
||||
.category-dot.learning { background: #A87BDB; }
|
||||
|
||||
.task-text {
|
||||
flex: 1;
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.4;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.delete-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #555;
|
||||
cursor: pointer;
|
||||
font-size: 1.25rem;
|
||||
padding: 0.25rem;
|
||||
line-height: 1;
|
||||
transition: color 0.2s;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.delete-btn:hover {
|
||||
color: #e74c3c;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
color: #555;
|
||||
padding: 2rem;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.task-count {
|
||||
text-align: center;
|
||||
color: #555;
|
||||
font-size: 0.8rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Todo</h1>
|
||||
|
||||
<div class="search-row">
|
||||
<input type="text" id="searchInput" placeholder="Search tasks...">
|
||||
<button class="search-clear" id="searchClear" onclick="clearSearch()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="filters" id="filters">
|
||||
<button class="filter-btn active" onclick="setFilter('all')">All</button>
|
||||
<button class="filter-btn" onclick="setFilter('work')">Work</button>
|
||||
<button class="filter-btn" onclick="setFilter('personal')">Personal</button>
|
||||
<button class="filter-btn" onclick="setFilter('health')">Health</button>
|
||||
<button class="filter-btn" onclick="setFilter('learning')">Learning</button>
|
||||
</div>
|
||||
|
||||
<div class="input-row">
|
||||
<input type="text" id="taskInput" placeholder="What needs to be done?" autofocus>
|
||||
<select id="categorySelect">
|
||||
<option value="work">Work</option>
|
||||
<option value="personal">Personal</option>
|
||||
<option value="health">Health</option>
|
||||
<option value="learning">Learning</option>
|
||||
</select>
|
||||
<button onclick="addTask()">Add</button>
|
||||
</div>
|
||||
|
||||
<ul class="task-list" id="taskList"></ul>
|
||||
<div class="task-count" id="taskCount"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let tasks = JSON.parse(localStorage.getItem('todos-v2') || '[]');
|
||||
let activeFilter = 'all';
|
||||
let searchQuery = '';
|
||||
|
||||
const categoryLabels = {
|
||||
work: 'Work',
|
||||
personal: 'Personal',
|
||||
health: 'Health',
|
||||
learning: 'Learning'
|
||||
};
|
||||
|
||||
function saveTasks() {
|
||||
localStorage.setItem('todos-v2', JSON.stringify(tasks));
|
||||
}
|
||||
|
||||
function getFilteredTasks() {
|
||||
return tasks.filter(task => {
|
||||
const matchesFilter = activeFilter === 'all' || task.category === activeFilter;
|
||||
const matchesSearch = !searchQuery ||
|
||||
task.text.toLowerCase().includes(searchQuery) ||
|
||||
(categoryLabels[task.category] || '').toLowerCase().includes(searchQuery);
|
||||
return matchesFilter && matchesSearch;
|
||||
});
|
||||
}
|
||||
|
||||
function renderTasks() {
|
||||
const list = document.getElementById('taskList');
|
||||
const countEl = document.getElementById('taskCount');
|
||||
const filtered = getFilteredTasks();
|
||||
|
||||
if (filtered.length === 0) {
|
||||
const msg = tasks.length === 0
|
||||
? 'No tasks yet. Add one above.'
|
||||
: 'No tasks found.';
|
||||
list.innerHTML = `<li class="empty-state">${msg}</li>`;
|
||||
countEl.textContent = '';
|
||||
return;
|
||||
}
|
||||
|
||||
list.innerHTML = filtered.map((task) => {
|
||||
const idx = tasks.indexOf(task);
|
||||
return `
|
||||
<li class="task-item ${task.completed ? 'completed' : ''}">
|
||||
<div class="task-checkbox" onclick="toggleTask(${idx})"></div>
|
||||
<div class="category-dot ${task.category || 'work'}"></div>
|
||||
<span class="task-text">${escapeHtml(task.text)}</span>
|
||||
<button class="delete-btn" onclick="deleteTask(${idx})" title="Delete">×</button>
|
||||
</li>
|
||||
`}).join('');
|
||||
|
||||
const active = tasks.filter(t => !t.completed).length;
|
||||
countEl.textContent = `${active} task${active !== 1 ? 's' : ''} remaining`;
|
||||
}
|
||||
|
||||
function addTask() {
|
||||
const input = document.getElementById('taskInput');
|
||||
const select = document.getElementById('categorySelect');
|
||||
const text = input.value.trim();
|
||||
if (!text) return;
|
||||
|
||||
tasks.unshift({
|
||||
text,
|
||||
completed: false,
|
||||
category: select.value,
|
||||
id: Date.now()
|
||||
});
|
||||
input.value = '';
|
||||
saveTasks();
|
||||
renderTasks();
|
||||
}
|
||||
|
||||
function toggleTask(index) {
|
||||
tasks[index].completed = !tasks[index].completed;
|
||||
saveTasks();
|
||||
renderTasks();
|
||||
}
|
||||
|
||||
function deleteTask(index) {
|
||||
tasks.splice(index, 1);
|
||||
saveTasks();
|
||||
renderTasks();
|
||||
}
|
||||
|
||||
function setFilter(filter) {
|
||||
activeFilter = filter;
|
||||
document.querySelectorAll('.filter-btn').forEach(btn => {
|
||||
btn.classList.toggle('active', btn.textContent.toLowerCase() === filter);
|
||||
});
|
||||
renderTasks();
|
||||
}
|
||||
|
||||
function clearSearch() {
|
||||
document.getElementById('searchInput').value = '';
|
||||
searchQuery = '';
|
||||
document.getElementById('searchClear').classList.remove('visible');
|
||||
renderTasks();
|
||||
}
|
||||
|
||||
function escapeHtml(text) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
document.getElementById('taskInput').addEventListener('keypress', (e) => {
|
||||
if (e.key === 'Enter') addTask();
|
||||
});
|
||||
|
||||
document.getElementById('searchInput').addEventListener('input', (e) => {
|
||||
searchQuery = e.target.value.toLowerCase();
|
||||
document.getElementById('searchClear').classList.toggle('visible', searchQuery.length > 0);
|
||||
renderTasks();
|
||||
});
|
||||
|
||||
renderTasks();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
248
examples/index.html
Normal file
248
examples/index.html
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Todo App</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: #1a1a2e;
|
||||
color: #e0e0e0;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 2rem 1rem;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
max-width: 540px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.75rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 1.5rem;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.input-row {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.input-row input {
|
||||
flex: 1;
|
||||
padding: 0.75rem 1rem;
|
||||
background: #16213e;
|
||||
border: 1px solid #2a2a4a;
|
||||
border-radius: 8px;
|
||||
color: #e0e0e0;
|
||||
font-size: 1rem;
|
||||
outline: none;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
.input-row input:focus {
|
||||
border-color: #4DB8A4;
|
||||
}
|
||||
|
||||
.input-row input::placeholder {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.input-row button {
|
||||
padding: 0.75rem 1.25rem;
|
||||
background: #4DB8A4;
|
||||
color: #1a1a2e;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.input-row button:hover {
|
||||
background: #3da897;
|
||||
}
|
||||
|
||||
.task-list {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.task-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.875rem 1rem;
|
||||
background: #16213e;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 0.5rem;
|
||||
transition: opacity 0.3s, transform 0.3s;
|
||||
animation: slideIn 0.3s ease;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.task-item.completed .task-text {
|
||||
text-decoration: line-through;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.task-checkbox {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 2px solid #4DB8A4;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.task-item.completed .task-checkbox {
|
||||
background: #4DB8A4;
|
||||
}
|
||||
|
||||
.task-item.completed .task-checkbox::after {
|
||||
content: '\2713';
|
||||
color: #1a1a2e;
|
||||
font-size: 0.75rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.task-text {
|
||||
flex: 1;
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.4;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.delete-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #555;
|
||||
cursor: pointer;
|
||||
font-size: 1.25rem;
|
||||
padding: 0.25rem;
|
||||
line-height: 1;
|
||||
transition: color 0.2s;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.delete-btn:hover {
|
||||
color: #e74c3c;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
color: #555;
|
||||
padding: 2rem;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.task-count {
|
||||
text-align: center;
|
||||
color: #555;
|
||||
font-size: 0.8rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Todo</h1>
|
||||
<div class="input-row">
|
||||
<input type="text" id="taskInput" placeholder="What needs to be done?" autofocus>
|
||||
<button onclick="addTask()">Add</button>
|
||||
</div>
|
||||
<ul class="task-list" id="taskList"></ul>
|
||||
<div class="task-count" id="taskCount"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let tasks = JSON.parse(localStorage.getItem('todos') || '[]');
|
||||
|
||||
function saveTasks() {
|
||||
localStorage.setItem('todos', JSON.stringify(tasks));
|
||||
}
|
||||
|
||||
function renderTasks() {
|
||||
const list = document.getElementById('taskList');
|
||||
const countEl = document.getElementById('taskCount');
|
||||
|
||||
if (tasks.length === 0) {
|
||||
list.innerHTML = '<li class="empty-state">No tasks yet. Add one above.</li>';
|
||||
countEl.textContent = '';
|
||||
return;
|
||||
}
|
||||
|
||||
list.innerHTML = tasks.map((task, i) => `
|
||||
<li class="task-item ${task.completed ? 'completed' : ''}">
|
||||
<div class="task-checkbox" onclick="toggleTask(${i})"></div>
|
||||
<span class="task-text">${escapeHtml(task.text)}</span>
|
||||
<button class="delete-btn" onclick="deleteTask(${i})" title="Delete">×</button>
|
||||
</li>
|
||||
`).join('');
|
||||
|
||||
const active = tasks.filter(t => !t.completed).length;
|
||||
countEl.textContent = `${active} task${active !== 1 ? 's' : ''} remaining`;
|
||||
}
|
||||
|
||||
function addTask() {
|
||||
const input = document.getElementById('taskInput');
|
||||
const text = input.value.trim();
|
||||
if (!text) return;
|
||||
|
||||
tasks.unshift({ text, completed: false, id: Date.now() });
|
||||
input.value = '';
|
||||
saveTasks();
|
||||
renderTasks();
|
||||
}
|
||||
|
||||
function toggleTask(index) {
|
||||
tasks[index].completed = !tasks[index].completed;
|
||||
saveTasks();
|
||||
renderTasks();
|
||||
}
|
||||
|
||||
function deleteTask(index) {
|
||||
tasks.splice(index, 1);
|
||||
saveTasks();
|
||||
renderTasks();
|
||||
}
|
||||
|
||||
function escapeHtml(text) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
document.getElementById('taskInput').addEventListener('keypress', (e) => {
|
||||
if (e.key === 'Enter') addTask();
|
||||
});
|
||||
|
||||
renderTasks();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
37
prompts/01-create-todo.md
Normal file
37
prompts/01-create-todo.md
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# Prompt 01: Create the Todo App
|
||||
|
||||
Copy and paste this into Claude Code:
|
||||
|
||||
---
|
||||
|
||||
Create a todo app as a single index.html file. Requirements:
|
||||
|
||||
- Dark mode with a charcoal background (#1a1a2e or similar)
|
||||
- Modern, clean design with good spacing and readable fonts
|
||||
- Add new tasks with a text input and an "Add" button (also works on Enter)
|
||||
- Mark tasks as complete (strikethrough + muted color)
|
||||
- Delete tasks with a small delete button
|
||||
- All tasks saved to localStorage so they survive page refresh
|
||||
- Smooth transitions when adding/completing/deleting tasks
|
||||
- No external dependencies (no CDN links, no frameworks)
|
||||
- The whole app in one file: HTML, CSS, and JavaScript together
|
||||
|
||||
---
|
||||
|
||||
## What Happens
|
||||
|
||||
Claude Code will:
|
||||
1. Create `index.html` with embedded CSS and JavaScript
|
||||
2. Ask for your permission before creating the file
|
||||
3. You approve, and the file appears in your folder
|
||||
|
||||
## What to Expect
|
||||
|
||||
Open `index.html` in your browser. You should see:
|
||||
- A dark-themed input field at the top
|
||||
- Type a task and press Enter to add it
|
||||
- Click a task to mark it done
|
||||
- Click the delete button to remove it
|
||||
- Refresh the page and your tasks are still there
|
||||
|
||||
If something does not look right, tell Claude Code what is wrong. For example: "The delete button is too close to the task text, add more spacing." It will fix it.
|
||||
33
prompts/02-add-categories.md
Normal file
33
prompts/02-add-categories.md
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# Prompt 02: Add Categories
|
||||
|
||||
Copy and paste this into Claude Code:
|
||||
|
||||
---
|
||||
|
||||
Add color-coded categories to the todo app. Requirements:
|
||||
|
||||
- Four categories: Work (blue #5B9FD6), Personal (green #4DB8A4), Health (orange #E87020), Learning (purple #A87BDB)
|
||||
- When adding a task, show a dropdown to pick the category
|
||||
- Each task shows a small colored dot or badge indicating its category
|
||||
- Add filter buttons at the top: "All", "Work", "Personal", "Health", "Learning"
|
||||
- Clicking a filter shows only tasks in that category
|
||||
- "All" shows everything
|
||||
- Active filter button should be visually highlighted
|
||||
- Categories are saved in localStorage along with the tasks
|
||||
- Keep the existing dark mode design
|
||||
|
||||
---
|
||||
|
||||
## What Happens
|
||||
|
||||
Claude Code reads the existing `index.html`, understands the current structure, and adds the category system without breaking anything that already works.
|
||||
|
||||
This is the agent loop in action: it does not start from scratch. It reads what exists, plans the changes, and edits precisely.
|
||||
|
||||
## What to Expect
|
||||
|
||||
- A category dropdown appears next to the task input
|
||||
- Colored filter buttons appear above the task list
|
||||
- Each task shows its category color
|
||||
- Switching filters instantly shows/hides tasks
|
||||
- Old tasks (without categories) still work
|
||||
25
prompts/03-add-search.md
Normal file
25
prompts/03-add-search.md
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# Prompt 03: Add Search
|
||||
|
||||
Copy and paste this into Claude Code:
|
||||
|
||||
---
|
||||
|
||||
Add a search bar to the todo app. Requirements:
|
||||
|
||||
- Search input at the top, above the category filter buttons
|
||||
- Filters tasks in real time as the user types (no search button needed)
|
||||
- Searches both the task text and the category name
|
||||
- Works together with the category filters (search within the active category)
|
||||
- Subtle search icon or placeholder text "Search tasks..."
|
||||
- Clear button (x) to reset the search
|
||||
- If no tasks match, show a "No tasks found" message
|
||||
- Keep the existing design
|
||||
|
||||
---
|
||||
|
||||
## What to Expect
|
||||
|
||||
- A search field appears at the top of the app
|
||||
- Typing immediately filters the visible tasks
|
||||
- Search combines with category filters (search "meeting" in "Work" category)
|
||||
- Clearing the search shows all tasks in the current filter again
|
||||
25
prompts/04-add-due-dates.md
Normal file
25
prompts/04-add-due-dates.md
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# Prompt 04: Add Due Dates
|
||||
|
||||
Copy and paste this into Claude Code:
|
||||
|
||||
---
|
||||
|
||||
Add due dates to the todo app. Requirements:
|
||||
|
||||
- Optional date picker when adding a task
|
||||
- Due date displayed next to each task in a subtle format (e.g., "Mar 20")
|
||||
- Overdue tasks highlighted with a red accent (text or border, not the whole background)
|
||||
- Tasks due today highlighted with an amber accent
|
||||
- Sort option: by date added (default) or by due date
|
||||
- Tasks without a due date sort to the bottom when sorting by due date
|
||||
- Due dates saved in localStorage
|
||||
- Keep the existing design, categories, and search working
|
||||
|
||||
---
|
||||
|
||||
## What to Expect
|
||||
|
||||
- A date picker appears in the task input area
|
||||
- Tasks show their due date on the right side
|
||||
- Overdue tasks get a red indicator
|
||||
- A sort toggle lets you switch between "added" and "due date" order
|
||||
26
prompts/05-make-responsive.md
Normal file
26
prompts/05-make-responsive.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# Prompt 05: Make It Mobile-Friendly
|
||||
|
||||
Copy and paste this into Claude Code:
|
||||
|
||||
---
|
||||
|
||||
Make the todo app responsive and mobile-friendly. Requirements:
|
||||
|
||||
- Works well on phone screens (375px wide and up)
|
||||
- Touch-friendly: buttons and inputs are at least 44px tall
|
||||
- Category filters wrap to multiple lines on small screens
|
||||
- Search bar is full width on mobile
|
||||
- Task text does not overflow, long text wraps properly
|
||||
- Add a proper viewport meta tag if missing
|
||||
- Swipe-to-delete would be a bonus but not required
|
||||
- Test: the app should look good on both a phone screen and a desktop monitor
|
||||
- Keep all existing functionality working
|
||||
|
||||
---
|
||||
|
||||
## What to Expect
|
||||
|
||||
- Open `index.html` on your phone (or use browser dev tools to simulate a phone screen)
|
||||
- Everything fits and is easy to tap
|
||||
- No horizontal scrolling
|
||||
- Filter buttons wrap neatly on small screens
|
||||
86
troubleshooting.md
Normal file
86
troubleshooting.md
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
# Troubleshooting
|
||||
|
||||
Common problems during your first Claude Code session and how to fix them.
|
||||
|
||||
## Installation Issues
|
||||
|
||||
### "command not found" after installing
|
||||
|
||||
Close your terminal completely and open a new one. The installer adds Claude Code to your PATH, but the current session does not pick it up.
|
||||
|
||||
If that does not work:
|
||||
1. Check if the binary exists: `ls ~/.claude/local/bin/claude`
|
||||
2. Add it to your PATH manually: `export PATH="$HOME/.claude/local/bin:$PATH"`
|
||||
3. Add that line to your `~/.zshrc` (Mac) or `~/.bashrc` (Linux) to make it permanent
|
||||
|
||||
### Windows: curl command fails
|
||||
|
||||
Use the Windows package manager instead:
|
||||
|
||||
```powershell
|
||||
winget install Anthropic.ClaudeCode
|
||||
```
|
||||
|
||||
Or download the [desktop app](https://claude.ai/download) to skip the terminal entirely.
|
||||
|
||||
### "Permission denied" on Mac/Linux
|
||||
|
||||
Run with explicit permissions:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://claude.ai/install.sh | bash
|
||||
```
|
||||
|
||||
If that fails, try:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://claude.ai/install.sh -o install.sh
|
||||
chmod +x install.sh
|
||||
./install.sh
|
||||
```
|
||||
|
||||
## Authentication Issues
|
||||
|
||||
### Browser does not open for sign-in
|
||||
|
||||
1. Copy the URL that Claude Code prints in the terminal
|
||||
2. Paste it into your browser manually
|
||||
3. Complete the sign-in and return to the terminal
|
||||
|
||||
### "Not authenticated" error
|
||||
|
||||
Run `claude auth login` and complete the browser sign-in again.
|
||||
|
||||
## During Your Session
|
||||
|
||||
### Claude Code seems stuck or takes a long time
|
||||
|
||||
It is thinking. Complex tasks can take 30-60 seconds. If it has been more than two minutes with no output, press `Ctrl+C` to cancel and try again with a simpler prompt.
|
||||
|
||||
### The generated app does not work
|
||||
|
||||
Tell Claude Code what is wrong. Be specific:
|
||||
- "The add button does nothing when I click it"
|
||||
- "Tasks are not saved when I refresh the page"
|
||||
- "The dark mode background is white instead of dark"
|
||||
|
||||
Claude Code will read the file, find the bug, and fix it.
|
||||
|
||||
### Claude Code asks permission for everything
|
||||
|
||||
This is normal and good. It asks before creating files and running commands. Type `y` to approve.
|
||||
|
||||
If you want fewer prompts, press `Shift+Tab` to switch to a faster permission mode. But for your first session, keep the default mode so you can see exactly what it does.
|
||||
|
||||
### "Context window limit" warning
|
||||
|
||||
Your session is getting long. Start a new one:
|
||||
|
||||
1. Type `/clear` to reset the conversation
|
||||
2. Or exit with `Ctrl+C` and run `claude` again
|
||||
|
||||
Your files are saved on disk. A new session reads them fresh.
|
||||
|
||||
## Still Stuck?
|
||||
|
||||
Describe your problem to Claude Code itself. Paste the error message and ask what went wrong. It usually knows.
|
||||
Loading…
Add table
Add a link
Reference in a new issue