McTweak.ai

Final Project: Interactive Mood Changer App

CHAPTER 6: EPISODE 10

Final Project: Mood Changer App

TrashyMcTweak
TrashyMcTweak

CHECK OUT my REVOLUTIONARY mood changer app! I've added 127 themes including "Radioactive Slime," "Unicorn Vomit," and "Existential Dread Pink!" Each one automatically changes your system clock, browser history, AND wifi password!

CodyMcTweak
CodyMcTweak

Um... I thought we were just making a simple theme switcher? You know, for the Chapter 6 final project? With like... five themes max?

GrumpyMcTweak
GrumpyMcTweak

DO YOU HAVE ANY IDEA how many SECURITY VULNERABILITIES you've introduced?! Changing system settings through a WEB APP?! This is EXACTLY how SkyNet gets admin privileges on nuclear launch systems! ONE CLICK on "Radioactive Slime" and we're ALL DOOMED!

AllyMcTweak
AllyMcTweak

Actually, if we analyze the requirements, we need just three things: multiple theme options, live preview, and saved preferences. I've prepared a 42-slide presentation on optimal theme implementation strategies based on user experience research...

FattyMcTweak
FattyMcTweak

Pfff... if you want a REAL mood changer, you need the Premium Experience™. My version has haptic feedback that literally makes your monitor vibrate when you select "Earthquake Mode." That's what separates the basic users from the PREMIUM ones.

AshleyMcTweak
AshleyMcTweak

According to the WCAG accessibility guidelines, all our themes must maintain a minimum contrast ratio of 4.5:1 for normal text. Also, I've drafted a 37-page user agreement for the preference saving feature to ensure GDPR compliance...

GarbageMcTweak
GarbageMcTweak

In my day, we had ONE theme: green text on a black screen. And if you wanted to save a preference, you wrote it down ON PAPER. Let me show you how to build a simple, functional mood changer without all this nonsense.

TrashyMcTweak
TrashyMcTweak

FINE! But I'm keeping my "Unicorn Vomit" theme. It took me THREE HOURS to get the gradient just right!

Final Project Overview

Mood Changer App Requirements:

  • Multiple theme options - Create different color schemes users can select
  • Live preview - Show theme changes in real-time
  • Save preference - Remember the user's theme choice for future visits

In this final project, we'll bring together everything we've learned about JavaScript events to create an interactive mood changer app. This practical application will demonstrate how to manipulate the DOM, handle events, and save user preferences.

GarbageMcTweak
GarbageMcTweak

Let's break this down into small, manageable steps. The first thing we need is a set of themes with different colors and styles.

Interactive Demo

Try it yourself:

Mood Changer App

Welcome to your personalized space!

This is a sample content area where you can see how your theme affects text and layout. Different themes change the colors, fonts, and overall mood of your application.

Your theme preference will be saved automatically.

AllyMcTweak
AllyMcTweak

Notice how the theme changes are applied immediately when you click a button? That's our live preview requirement. Now let's look at how to implement these features.

Building the Mood Changer App

Step 1: Create the HTML Structure

First, we need to set up the basic HTML structure for our app:


<div class="mood-changer-app" id="moodChanger">
  <div class="app-header">
    <h2 class="app-title">Mood Changer App</h2>
  </div>
  
  <div class="app-body">
    
    <div class="app-controls">
      <button class="theme-btn" data-theme="cyberpunk">Cyberpunk</button>
      <button class="theme-btn" data-theme="pastel">Pastel</button>
      <button class="theme-btn" data-theme="forest">Forest</button>
      <button class="theme-btn" data-theme="ocean">Ocean</button>
      <button class="theme-btn" data-theme="sunset">Sunset</button>
    </div>
    
    
    <div class="sample-content">
      <h3 class="content-header">Welcome to your space!</h3>
      <p>This is where you can see your theme in action.</p>
    </div>
  </div>
</div>
CodyMcTweak
CodyMcTweak

Notice how we're using data-theme attributes on our buttons? That's a great way to store which theme each button should apply!

Step 2: Define Theme Styles with CSS Variables

CSS variables (custom properties) make it easy to switch themes by changing just a few values:

/* Theme Variables in CSS */
:root {
  /* Default theme variables */
  --theme-bg: #05080f;
  --theme-text: white;
  --theme-primary: #18e6ff;
  --theme-secondary: #b266ff;
  --theme-accent: #ff71ce;
  --theme-border: rgba(24, 230, 255, 0.3);
}

/* Cyberpunk theme */
.theme-cyberpunk {
  --theme-bg: #05080f;
  --theme-text: white;
  --theme-primary: #18e6ff;
  --theme-secondary: #b266ff;
  --theme-accent: #ff71ce;
  --theme-border: rgba(24, 230, 255, 0.3);
}

/* Pastel theme */
.theme-pastel {
  --theme-bg: #f0f4f8;
  --theme-text: #5a5a5a;
  --theme-primary: #a5b4fc;
  --theme-secondary: #fda4af;
  --theme-accent: #c084fc;
  --theme-border: rgba(165, 180, 252, 0.3);
}

/* Additional themes defined similarly... */

/* Apply theme variables to elements */
.app-header {
  background-color: var(--theme-bg);
  color: var(--theme-text);
  border-bottom: 1px solid var(--theme-border);
  transition: all 0.3s ease;
}

.app-title {
  color: var(--theme-primary);
  transition: all 0.3s ease;
}

/* More styled elements using these variables... */
AllyMcTweak
AllyMcTweak

CSS variables are perfect for theme switching! Notice how we define the variables once, then reference them throughout the stylesheet. Now we only need to change the class on our container element to apply an entire theme.

TrashyMcTweak
TrashyMcTweak

Don't forget my UNICORN VOMIT theme! It needs at LEAST seven gradient layers and animated sparkles!

GarbageMcTweak
GarbageMcTweak

Let's stick with these five themes for now. Adding the transition property ensures smooth theme changes instead of jarring flashes.

Step 3: Add JavaScript for Theme Switching

Now we need to add event listeners to our theme buttons:

// JavaScript for theme switching
document.addEventListener('DOMContentLoaded', function() {
  // Get references to our elements
  const moodChanger = document.getElementById('moodChanger');
  const themeButtons = document.querySelectorAll('.theme-btn');
  
  // Add click event listeners to all theme buttons
  themeButtons.forEach(function(button) {
    button.addEventListener('click', function() {
      // Get the theme name from the button's data attribute
      const theme = this.getAttribute('data-theme');
      
      // Apply the theme by changing the class
      applyTheme(theme);
    });
  });
  
  // Function to apply a theme
  function applyTheme(theme) {
    // Remove all existing theme classes
    moodChanger.classList.remove('theme-cyberpunk', 'theme-pastel', 'theme-forest', 'theme-ocean', 'theme-sunset');
    
    // Add the selected theme class
    moodChanger.classList.add(`theme-${theme}`);
    
    // Save the user's preference (we'll implement this next)
    saveThemePreference(theme);
  }
});
GrumpyMcTweak
GrumpyMcTweak

AT LEAST you're removing the old theme classes before adding new ones! One small security blessing in this OCEAN OF VULNERABILITY! Still doesn't protect against MALICIOUS CSS INJECTION though!

AshleyMcTweak
AshleyMcTweak

Using template literals for the class name is clean, but you should always validate user inputs if accepting custom themes. This implementation is fine since we're using fixed theme options.

Step 4: Save User Preferences with localStorage

To remember the user's theme choice between visits, we'll use localStorage:

// Save theme preference to localStorage
function saveThemePreference(theme) {
  // Store the theme name in localStorage
  localStorage.setItem('preferredTheme', theme);
}

// Load saved theme preference on page load
function loadSavedTheme() {
  // Try to get the saved theme from localStorage
  const savedTheme = localStorage.getItem('preferredTheme');
  
  // If a theme was saved, apply it
  if (savedTheme) {
    applyTheme(savedTheme);
    
    // Optional: Update UI to show the active theme
    const activeButton = document.querySelector(`.theme-btn[data-theme="${savedTheme}"]`);
    if (activeButton) {
      activeButton.classList.add('active');
    }
  }
}

// Call this function when the page loads
document.addEventListener('DOMContentLoaded', function() {
  // Set up event listeners like before...
  
  // Load the saved theme preference
  loadSavedTheme();
});
FattyMcTweak
FattyMcTweak

localStorage is like a free version of my Premium Cloud Syncing Service™. Limited, but gets the basic job done. For only $29.99 per month, you could store user preferences across ALL devices...

GarbageMcTweak
GarbageMcTweak

localStorage is more than enough for this project. It's simple, doesn't require a server, and works across page refreshes. Just remember it's specific to the domain and browser.

Step 5: Final Touches and Best Practices

Let's improve our code with some final touches:

// Complete Mood Changer implementation with best practices
const MoodChanger = {
  // Store all our elements and state
  elements: {
    container: null,
    buttons: null
  },
  
  themes: ['cyberpunk', 'pastel', 'forest', 'ocean', 'sunset'],
  currentTheme: 'cyberpunk', // Default theme
  
  // Initialize the app
  init: function() {
    // Get DOM elements
    this.elements.container = document.getElementById('moodChanger');
    this.elements.buttons = document.querySelectorAll('.theme-btn');
    
    if (!this.elements.container) {
      console.error('Mood changer container not found!');
      return;
    }
    
    // Load saved theme first
    this.loadSavedTheme();
    
    // Set up event listeners
    this.bindEvents();
    
    console.log('Mood Changer initialized!');
  },
  
  // Set up all event listeners
  bindEvents: function() {
    const self = this; // Store reference to use in event callbacks
    
    this.elements.buttons.forEach(function(button) {
      button.addEventListener('click', function() {
        const theme = this.getAttribute('data-theme');
        self.applyTheme(theme);
      });
    });
  },
  
  // Apply a theme to the app
  applyTheme: function(theme) {
    // Validate the theme name
    if (!this.themes.includes(theme)) {
      console.error(`Unknown theme: ${theme}`);
      return;
    }
    
    // Remove all existing theme classes
    this.themes.forEach(themeName => {
      this.elements.container.classList.remove(`theme-${themeName}`);
    });
    
    // Add the new theme class
    this.elements.container.classList.add(`theme-${theme}`);
    this.currentTheme = theme;
    
    // Update active button state
    this.updateActiveButton();
    
    // Save to localStorage
    this.saveThemePreference();
    
    // Show feedback to the user
    console.log(`Theme changed to: ${theme}`);
  },
  
  // Update which button appears active
  updateActiveButton: function() {
    // Remove active class from all buttons
    this.elements.buttons.forEach(button => {
      button.classList.remove('active');
    });
    
    // Add active class to current theme's button
    const activeButton = document.querySelector(`.theme-btn[data-theme="${this.currentTheme}"]`);
    if (activeButton) {
      activeButton.classList.add('active');
    }
  },
  
  // Save current theme to localStorage
  saveThemePreference: function() {
    localStorage.setItem('preferredTheme', this.currentTheme);
  },
  
  // Load saved theme from localStorage
  loadSavedTheme: function() {
    const savedTheme = localStorage.getItem('preferredTheme');
    
    if (savedTheme && this.themes.includes(savedTheme)) {
      this.applyTheme(savedTheme);
    }
  }
};

// Initialize when the DOM is ready
document.addEventListener('DOMContentLoaded', function() {
  MoodChanger.init();
});
AllyMcTweak
AllyMcTweak

This object-oriented approach is much cleaner! Notice how we've organized the code into methods, added error checking, and made it more maintainable.

Activity: Build Your Own Mood Changer

Now it's your turn to build a Mood Changer app! Use the code examples and concepts you've learned to create your own version with at least three different themes.

Complete the following steps:

1. Create the HTML structure

Create an HTML file with:

  • A container for your mood changer app
  • Theme selection buttons
  • Content areas that will change with each theme

Don't forget to link your CSS and JavaScript files!

2. Define your themes in CSS

In your CSS file:

  • Create CSS variables for each theme
  • Define theme classes that change these variables
  • Apply the variables to your page elements
  • Add transitions for smooth theme changes
3. Add theme switching with JavaScript

In your JavaScript file:

  • Select your theme buttons and container
  • Add click event listeners to the buttons
  • Create a function to apply the selected theme
  • Test that themes change when buttons are clicked
4. Implement theme preference saving

Enhance your JavaScript to:

  • Save the selected theme to localStorage
  • Load the saved theme when the page loads
  • Make sure the active theme button is highlighted
5. Test and refine

Final testing and enhancements:

  • Test in different browsers
  • Make sure the theme is saved between page refreshes
  • Add visual feedback when a theme is selected
  • Consider adding theme descriptions or preview images

Challenge Extensions:

  • Allow users to create and save their own custom themes
  • Add animations when switching between themes
  • Create a theme that changes based on the time of day
  • Add a random theme button that selects a random theme

Final Approval

TrashyMcTweak
TrashyMcTweak

Well I STILL think we should add my "Unicorn Vomit" theme, but I guess this will do. The localStorage part is pretty cool though, not gonna lie.

GrumpyMcTweak
GrumpyMcTweak

I suppose it's MARGINALLY secure enough to pass inspection. But I'll be monitoring for any suspicious theme-related activities!

AllyMcTweak
AllyMcTweak

My user research indicates an 89% satisfaction rate with this implementation. The code structure is clean and the theme transitions are smooth. I approve.

CodyMcTweak
CodyMcTweak

I actually understood all of this code! That's a first for me. It's simple but effective.

AshleyMcTweak
AshleyMcTweak

I've reviewed the terms of service implications and can confirm that storing theme preferences falls within acceptable user data practices. Legally compliant!

FattyMcTweak
FattyMcTweak

It's... serviceable. Not PREMIUM quality, but it gets the job done. I suppose not everything needs to be gold-plated.

GarbageMcTweak
GarbageMcTweak

Clean, functional, and to the point. It does exactly what it needs to without unnecessary complications. I approve. Now let's call in the boss.

SnowzieMcTweak

WOOF! WOOF!

*tail wagging intensifies*

CODE IS COMMITTED!

Chapter 6 Summary

Congratulations! You've completed Chapter 6: JavaScript Events – Click, Hover & Fun Reactions! In this chapter, you learned how to:

  • Understand and navigate the Document Object Model (DOM)
  • Select elements using getElementById and querySelector
  • Change content dynamically with innerHTML and textContent
  • Handle click events with onclick and event listeners
  • Work with mouse events like onmouseover and onmouseout
  • Modify element styles through JavaScript
  • Toggle classes to create dynamic effects
  • Select and manipulate multiple elements
  • Use advanced event listeners for complex interactions
  • Build a complete Mood Changer app that remembers user preferences

You're now ready to move on to Chapter 7, where you'll learn about drawing with JavaScript using the Canvas API!

Previous Lesson Home Next Chapter