Project 2 - A Social News Web Page

Project Overview

Build a fully functional social news website with:

Functional Requirements

Technical Requirements

Project Structure

news-app/
├── index.html
├── style.css
├── script.js
└── data.js

HTML Structure

<!DOCTYPE html>
<html>
<head>
    <title>Social News</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <header>
        <h1>Social News</h1>
        <nav>
            <button class="filter-btn" data-category="all">All</button>
            <button class="filter-btn" data-category="tech">Tech</button>
            <button class="filter-btn" data-category="science">Science</button>
        </nav>
    </header>

    <main>
        <div id="articles" class="articles-container"></div>
    </main>

    <script src="data.js"></script>
    <script src="script.js"></script>
</body>
</html>

JavaScript Implementation

class NewsApp {
    constructor() {
        this.articles = [];
        this.currentFilter = "all";
        this.init();
    }

    init() {
        this.loadArticles();
        this.render();
        this.attachEventListeners();
    }

    loadArticles() {
        this.articles = [
            {
                id: 1,
                title: "JavaScript Tips",
                content: "10 tips to improve...",
                category: "tech",
                likes: 45,
                comments: []
            }
            // More articles...
        ];
    }

    render() {
        let container = document.getElementById("articles");
        container.innerHTML = "";

        let filtered = this.currentFilter === "all"
            ? this.articles
            : this.articles.filter(a => a.category === this.currentFilter);

        filtered.forEach(article => {
            container.innerHTML += this.createArticleHTML(article);
        });
    }

    createArticleHTML(article) {
        return `
            <article class="article" data-id="${article.id}">
                <h2>${article.title}</h2>
                <p>${article.content}</p>
                <div class="actions">
                    <button class="like-btn">👍 ${article.likes}</button>
                    <button class="comment-btn">💬 ${article.comments.length}</button>
                </div>
            </article>
        `;
    }

    attachEventListeners() {
        // Filter buttons
        document.querySelectorAll(".filter-btn").forEach(btn => {
            btn.addEventListener("click", (e) => {
                this.currentFilter = e.target.dataset.category;
                this.render();
            });
        });

        // Like buttons
        document.addEventListener("click", (e) => {
            if (e.target.classList.contains("like-btn")) {
                let articleId = e.target.closest(".article").dataset.id;
                this.likeArticle(articleId);
            }
        });
    }

    likeArticle(articleId) {
        let article = this.articles.find(a => a.id == articleId);
        if (article) {
            article.likes++;
            this.render();
        }
    }
}

new NewsApp();

CSS Styling

body {
    font-family: Arial, sans-serif;
    margin: 0;
    background: #f5f5f5;
}

header {
    background: #333;
    color: white;
    padding: 20px;
    text-align: center;
}

.articles-container {
    max-width: 1000px;
    margin: 20px auto;
}

.article {
    background: white;
    padding: 20px;
    margin-bottom: 20px;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.article h2 {
    margin: 0 0 10px 0;
}

.actions button {
    margin-right: 10px;
    padding: 8px 16px;
    border: none;
    background: #007bff;
    color: white;
    border-radius: 4px;
    cursor: pointer;
}

@media (max-width: 600px) {
    .article {
        padding: 15px;
    }
}

Extended Features

Add Comments

addComment(articleId, commentText) {
    let article = this.articles.find(a => a.id == articleId);
    if (article) {
        article.comments.push({
            text: commentText,
            timestamp: new Date()
        });
        this.render();
    }
}

Search Functionality

searchArticles(query) {
    return this.articles.filter(a =>
        a.title.includes(query) ||
        a.content.includes(query)
    );
}

Learning Outcomes

After completing this project, you should be able to:


Next Module: Module 21 - Building Web Applications