Skip to content
This repository has been archived by the owner on Dec 12, 2024. It is now read-only.

Commit

Permalink
Add theme toggle functionality and dark mode support
Browse files Browse the repository at this point in the history
  • Loading branch information
29deepanshutyagi committed Oct 14, 2024
1 parent e398a6b commit 78837bd
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 68 deletions.
76 changes: 45 additions & 31 deletions javascript/dwa-starter-vanillajs-vite/components.js
Original file line number Diff line number Diff line change
@@ -1,57 +1,71 @@
// components.js
function AboutPage() {
// Create the main container
// Create the theme toggle button
function ThemeToggleButton() {
const button = document.createElement('button');
button.setAttribute('aria-label', 'Toggle dark mode');
button.textContent = 'Toggle Theme';
button.classList.add('p-2', 'rounded', 'border', 'bg-gray-200', 'dark:bg-gray-700');

// Add click event to toggle dark mode
button.addEventListener('click', () => {
document.documentElement.classList.toggle('dark');
const isDarkMode = document.documentElement.classList.contains('dark');
localStorage.setItem('theme', isDarkMode ? 'dark' : 'light');
});

return button;
}

// Append the theme toggle button to the page
function addThemeToggleToPage() {
const toggleButton = ThemeToggleButton();
document.body.prepend(toggleButton); // Add the toggle button to the body
}

// Create About page
function AboutPage() {
const container = document.createElement('div');
container.classList.add('space-y-4', 'p-6', 'text-center');

// Create the main title

const title = document.createElement('h1');
title.textContent = 'DWA Starter Vanilla';
title.classList.add('text-3xl', 'font-bold', 'mb-4');

// Create the first paragraph

const para1 = document.createElement('p');
para1.textContent = "Decentralized Web App: it's a Web5 Progressive Web App.";
para1.classList.add('text-lg');

// Create the subtitle

const subtitle = document.createElement('h2');
subtitle.textContent = 'Why PWA?';
subtitle.classList.add('text-2xl', 'font-semibold', 'mt-4');

// Create the second paragraph

const para2 = document.createElement('p');
para2.textContent = 'It\'s a perfect match with Web5 DWNs since a PWA can work offline and DWN has a synced local storage.';
para2.classList.add('text-lg');

// Append elements to the container

container.appendChild(title);
container.appendChild(para1);
container.appendChild(subtitle);
container.appendChild(para2);

// Return the container element

return container;
}

export function Home() {
export function Home() {
document.getElementById('app').innerHTML = `<h1>Home</h1>`;
}

export function About() {
}
export function About() {
const app = document.getElementById('app');
app.innerHTML = ''; // Clear the current content

// Create and append the About page
const aboutPage = AboutPage(); // Call the AboutPage function to get the component
app.innerHTML = '';
const aboutPage = AboutPage();
app.appendChild(aboutPage);
}

export function Settings() {
}
export function Settings() {
document.getElementById('app').innerHTML = `<h1>Settings</h1>`;
}

export function NotFound() {
}
export function NotFound() {
document.getElementById('app').innerHTML = `<h1>404 - Page Not Found</h1>`;
}

}
68 changes: 40 additions & 28 deletions javascript/dwa-starter-vanillajs-vite/main.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,49 @@
// main.js
// Function to check system preference and localStorage for theme preference
function applyTheme() {
const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)").matches;
const currentTheme = localStorage.getItem("theme") || (prefersDarkScheme ? "dark" : "light");

import { Home, About, Settings, NotFound } from './components.js';
// Toggle dark mode based on the stored or system preference
document.documentElement.classList.toggle('dark', currentTheme === 'dark');
}

// Define routes and their corresponding components
const routes = {
'/': Home,
'/about': About,
'/settings': Settings,
};
// Function to add the theme toggle functionality to the page
function addThemeToggleToPage() {
const toggleButton = document.querySelector("#theme-toggle");

// Function to handle navigation
function navigateTo(url) {
history.pushState(null, null, url);
router();
}
// Listen for the toggle button click
toggleButton.addEventListener("click", () => {
const isDarkMode = document.documentElement.classList.contains('dark');
const newTheme = isDarkMode ? 'light' : 'dark';

// Router function to render components based on the current URL
function router() {
const path = window.location.pathname;
const route = routes[path] || NotFound;
route();
// Toggle the theme and save to localStorage
document.documentElement.classList.toggle('dark', newTheme === 'dark');
localStorage.setItem("theme", newTheme);
});
}

// Event delegation for link clicks
document.addEventListener('click', (e) => {
if (e.target.matches('[data-link]')) {
e.preventDefault();
navigateTo(e.target.href);
}
// Apply the theme on page load
window.addEventListener("DOMContentLoaded", () => {
applyTheme();
addThemeToggleToPage();
});

// Listen to popstate event (back/forward navigation)
window.addEventListener('popstate', router);
// Router logic
const routes = {
'/': () => `<h1>Home</h1>`,
'/about': () => `<h1>DWA Starter Vanilla</h1>`,
'/settings': () => `<h1>Settings</h1>`,
'*': () => `<h1>404 - Page Not Found</h1>`,
};

function handleRoute() {
const path = window.location.pathname;
const route = routes[path] || routes['*'];
document.getElementById('app').innerHTML = route();
}

// Handle back/forward navigation
window.addEventListener('popstate', handleRoute);

// Initial call to router to render the correct component on page load
document.addEventListener('DOMContentLoaded', router);
// Initial page load
handleRoute();
14 changes: 13 additions & 1 deletion javascript/dwa-starter-vanillajs-vite/style.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* styles.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
Expand Down Expand Up @@ -38,3 +37,16 @@ nav a:hover {
#app {
padding: 20px;
}

/* Dark mode styles */
.dark nav {
background-color: #222;
}

.dark nav a {
color: #bbb;
}

.dark nav a:hover {
background-color: #444;
}
1 change: 1 addition & 0 deletions javascript/dwa-starter-vanillajs-vite/tailwind.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: 'class',
content: [
"./index.html",
"./components.js",
Expand Down
62 changes: 54 additions & 8 deletions javascript/dwa-starter-vanillajs-vite/tests/main.spec.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,72 @@
// tests/router.spec.js
import { test, expect } from '@playwright/test';

test.describe('Vanilla Router', () => {
// Before all tests, start a local server if necessary

test('should navigate to Home', async ({ page }) => {
await page.goto('/');
await page.goto('http://localhost:5173/');
expect(await page.textContent('h1')).toBe('Home');
});

test('should navigate to About', async ({ page }) => {
await page.goto('/about');
expect(await page.textContent('h1')).toBe('DWA Starter Vanilla');
await page.goto('http://localhost:5173/about');
expect(await page.textContent('h1')).toBe('DWA Starter Vanilla');
});

test('should navigate to Settings', async ({ page }) => {
await page.goto('/settings');
await page.goto('http://localhost:5173/settings');
expect(await page.textContent('h1')).toBe('Settings');
});

test('should show Not Found for undefined routes', async ({ page }) => {
await page.goto('/undefined-route');
await page.goto('http://localhost:5173/undefined-route');
expect(await page.textContent('h1')).toBe('404 - Page Not Found');
});
});

test.describe('Theme Toggle Functionality', () => {
test('should toggle dark mode and remember preference', async ({ page }) => {
await page.goto('http://localhost:5173/');

// Check initial state
const initialIsDarkMode = await page.evaluate(() => document.documentElement.classList.contains('dark'));

// Toggle the theme
await page.click('#theme-toggle');

// Verify that the theme was toggled
const isDarkModeAfterToggle = await page.evaluate(() => document.documentElement.classList.contains('dark'));
expect(isDarkModeAfterToggle).toBe(!initialIsDarkMode);

// Reload the page to check if preference is remembered
await page.reload();
const isDarkModeAfterReload = await page.evaluate(() => document.documentElement.classList.contains('dark'));
expect(isDarkModeAfterReload).toBe(isDarkModeAfterToggle);
});

test('should load with correct theme based on system preference when no localStorage is set', async ({ page }) => {
// Clear localStorage
await page.evaluate(() => localStorage.removeItem('theme'));

await page.goto('http://localhost:5173/');

// Get system preference
const prefersDarkMode = await page.evaluate(() => window.matchMedia('(prefers-color-scheme: dark)').matches);

// Check if the page loads with the correct theme based on system preference
const isDarkMode = await page.evaluate(() => document.documentElement.classList.contains('dark'));
expect(isDarkMode).toBe(prefersDarkMode);
});

test('should persist theme across different routes', async ({ page }) => {
await page.goto('http://localhost:5173/');

// Toggle to dark mode
await page.click('#theme-toggle');
const isDarkMode = await page.evaluate(() => document.documentElement.classList.contains('dark'));
expect(isDarkMode).toBe(true);

// Navigate to a different route
await page.goto('http://localhost:5173/about');
const isDarkModeOnNewRoute = await page.evaluate(() => document.documentElement.classList.contains('dark'));
expect(isDarkModeOnNewRoute).toBe(true);
});
});

0 comments on commit 78837bd

Please sign in to comment.