Module 04 PROJECTS ● Intermediate → Advanced 3 projects

Build Three Real-World Projects

Employers don't care about what you know — they care about what you've built. These three projects cover every skill you've learned and are designed to be the core of your developer portfolio.

ℹ️ How to approach these projects
Each project below gives you the architecture blueprint and core logic. Your job is to implement the full design using the HTML, CSS, and JS skills from Modules 1–3. Don't copy-paste — type every line yourself.
1

Portfolio Website

Objective: Build a personal brand site that showcases who you are and what you've built. This is the first thing every employer will ask to see.

Skills Practiced

HTML
Semantic structure
Header, nav, sections for hero, projects, and contact.
CSS
Grid + Flexbox layout
Responsive project cards, sticky navigation, dark mode.
JavaScript
Theme toggle
Scroll animations and smooth anchor navigation.
Deployment
GitHub Pages
Push to a public repo and enable Pages in Settings.

Key Implementation: Dark Mode Toggle

javascript
const toggleBtn = document.querySelector('#themeToggle');
const root = document.documentElement;

// On load: restore saved preference
const saved = localStorage.getItem('theme') || 'dark';
root.setAttribute('data-theme', saved);

toggleBtn.addEventListener('click', () => {
    const current = root.getAttribute('data-theme');
    const next = current === 'dark' ? 'light' : 'dark';
    root.setAttribute('data-theme', next);
    localStorage.setItem('theme', next);
});

Key Implementation: Scroll-Triggered Animation

javascript — IntersectionObserver
const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            entry.target.classList.add('visible');
        }
    });
}, { threshold: 0.1 });

document.querySelectorAll('.project-card').forEach(card => {
    observer.observe(card);
});
css — Fade-in animation
.project-card {
    opacity: 0;
    transform: translateY(24px);
    transition: opacity 0.5s ease, transform 0.5s ease;
}

.project-card.visible {
    opacity: 1;
    transform: translateY(0);
}
2

TaskFlow — Task Manager App

Objective: Build a fully-functional task management app using only vanilla JavaScript. No libraries. This project tests your ability to manage application state.

Skills Practiced

Core Concept
State Management
Keep your data (tasks array) as the single source of truth and always re-render from it.
Core Concept
Data Persistence
Save tasks to localStorage so they survive a page refresh.
CRUD Operations
Create, Read, Update, Delete
The core operations of every real-world application.
UX Feature
Filtering
Filter tasks by "All", "Active", and "Completed" status.

The Core Architecture

javascript — State-Driven UI Pattern
// 1. STATE — the single source of truth
let tasks = JSON.parse(localStorage.getItem('tasks')) || [];

// 2. RENDER — always re-draw from state (never mutate the DOM directly)
const renderTasks = (filter = 'all') => {
    const list = document.querySelector('#taskList');
    const filtered = tasks.filter(t => {
        if (filter === 'active')    return !t.completed;
        if (filter === 'completed') return t.completed;
        return true; // 'all'
    });

    list.innerHTML = filtered.map((task, i) => `
        <li class="task ${task.completed ? 'done' : ''}">
            <input type="checkbox" 
                   ${task.completed ? 'checked' : ''} 
                   onchange="toggleTask(${i})">
            <span>${task.text}</span>
            <button onclick="deleteTask(${i})">✕</button>
        </li>
    `).join('');
};

// 3. ACTIONS — modify state, then re-render
const addTask = (text) => {
    tasks.push({ text, completed: false, id: Date.now() });
    save();
    renderTasks();
};

const toggleTask = (index) => {
    tasks[index].completed = !tasks[index].completed;
    save();
    renderTasks();
};

const deleteTask = (index) => {
    tasks.splice(index, 1);
    save();
    renderTasks();
};

// 4. PERSIST — sync state to localStorage
const save = () => localStorage.setItem('tasks', JSON.stringify(tasks));

// 5. INIT — render on page load
renderTasks();
3

WeatherPulse — API Dashboard

Objective: Build a real-time weather dashboard that fetches live data from the OpenWeatherMap API. This project proves you can work with external services.

Setup — Getting Your Free API Key

  1. Go to openweathermap.org and create a free account.
  2. Navigate to My API Keys and copy your key.
  3. Store it in your JS file as a constant (never commit real keys to public GitHub repos).

The Core Fetch Logic

javascript — Full Fetch with Loading States
const API_KEY = 'YOUR_API_KEY_HERE';
const BASE_URL = 'https://api.openweathermap.org/data/2.5/weather';

const getWeather = async (city) => {
    const spinner = document.querySelector('.spinner');
    const errorEl = document.querySelector('.error-msg');

    // Show loading state
    spinner.classList.remove('hidden');
    errorEl.classList.add('hidden');

    try {
        const url = `${BASE_URL}?q=${city}&appid=${API_KEY}&units=metric`;
        const res  = await fetch(url);

        if (!res.ok) throw new Error('City not found');

        const data = await res.json();
        renderWeather(data);

    } catch (err) {
        errorEl.textContent = err.message;
        errorEl.classList.remove('hidden');

    } finally {
        spinner.classList.add('hidden');
    }
};

const renderWeather = (data) => {
    document.querySelector('#city-name').textContent  = data.name;
    document.querySelector('#temp').textContent       = `${Math.round(data.main.temp)}°C`;
    document.querySelector('#condition').textContent  = data.weather[0].description;
    document.querySelector('#humidity').textContent   = `${data.main.humidity}%`;
    document.querySelector('#wind').textContent       = `${data.wind.speed} m/s`;
};

// Trigger on search form submit
document.querySelector('#searchForm').addEventListener('submit', (e) => {
    e.preventDefault();
    const city = document.querySelector('#cityInput').value.trim();
    if (city) getWeather(city);
});
💡 Portfolio Tip
Add geolocation using navigator.geolocation.getCurrentPosition() to detect the user's city automatically on page load. This single feature makes the project feel like a professional app.