Projects

Hobby Blog Website

JavaScript HTML CSS Node.js Express

Description

This project is a full-stack blog site with filtering and post creation functionality. Built with Express and EJS on the back end, and styled using custom CSS. Posts are saved locally in the browser using localStorage, allowing users to view their entries during a single session.

Features

  • A responsive grid layout with tag-based filtering
  • A modal interface for creating posts
  • “Read more” functionality with detailed post view
  • Local session-based storage for simplicity
  • Ability to create posts and set tags
  • Matching hand-drawn illustrations to each hobby tag automatically

Handles user form submissions, builds a new blog post object, saves it to localStorage, and updates the DOM in real time:

createPostForm.addEventListener('submit', (e) => {
  e.preventDefault();

  const newPost = {
    title: document.getElementById('postTitle').value,
    author: document.getElementById('postAuthor').value,
    content: document.getElementById('postContent').value,
    tag: document.getElementById('postTag').value,
    date: new Date().toLocaleDateString(),
    image: tagImages[document.getElementById('postTag').value]
  };

  const userPosts = JSON.parse(localStorage.getItem('userPosts') || '[]');
  userPosts.unshift(newPost);
  localStorage.setItem('userPosts', JSON.stringify(userPosts));

  addNewPostToPage(newPost);
  modal.style.display = 'none';
  createPostForm.reset();
});

Implements dynamic filtering of blog posts by category tag (e.g., ART, FOOD) through interactive tag buttons:

categoryTags.forEach(tag => {
  tag.addEventListener('click', () => {
    categoryTags.forEach(t => t.classList.remove('active'));
    tag.classList.add('active');

    const selectedTag = tag.dataset.tag;

    document.querySelectorAll('.blog-post').forEach(post => {
      if (selectedTag === 'ALL' || post.dataset.tag === selectedTag) {
        post.style.display = 'flex';
      } else {
        post.style.display = 'none';
      }
    });
  });
});

Defines and serves hard-coded sample blog posts from the Express server using EJS templating:

const samplePosts = [
  {
    date: 'May 22, 2025',
    tag: 'ART',
    image: '/tag-images/Art_Tag.png',
    title: 'Trying Out Oil Pastels',
    author: 'Zainab Ahmed',
    content: "I've been wanting to try out oil pastels..."
  },
  // other sample posts
];

app.get('/', (req, res) => {
  res.render('index', { 
    posts: samplePosts,
    tagImages: tagImages 
  });
});

Outcome

A smooth, interactive frontend experience with full functionality for posting and browsing, perfect for testing full-stack skills.

Hobby Blog site screenshot 1 Hobby Blog site screenshot 2 Hobby Blog site screenshot 3 Hobby Blog site screenshot 4