1
0
Fork 0

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:
Kjell Tore Guttormsen 2026-03-15 16:04:07 +01:00
commit ec708ba943
10 changed files with 1089 additions and 0 deletions

150
README.md Normal file
View 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.
![Todo app screenshot](examples/screenshot.png)
## 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
View 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
View 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()">&times;</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">&times;</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
View 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">&times;</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
View 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.

View 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
View 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

View 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

View 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
View 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.