This commit is contained in:
marko-kraemer 2025-04-01 00:50:46 -07:00
parent 977d44f04e
commit dac9f752d1
2 changed files with 529 additions and 42 deletions

View File

@ -3,31 +3,543 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World</title>
<link rel="stylesheet" href="styles.css">
<title>Fun Todo App</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Comic Sans MS', cursive, sans-serif;
}
body {
background: linear-gradient(135deg, #ff9a9e, #fad0c4);
color: #333;
display: flex;
justify-content: center;
padding: 40px 20px;
min-height: 100vh;
}
.container {
width: 100%;
max-width: 500px;
background-color: white;
border-radius: 16px;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
padding: 25px;
transform-style: preserve-3d;
perspective: 1000px;
}
h1 {
text-align: center;
margin-bottom: 20px;
color: #ff6b6b;
text-shadow: 2px 2px 0px #ffe66d;
font-size: 2.2em;
}
.input-group {
display: flex;
margin-bottom: 20px;
}
#todo-input {
flex: 1;
padding: 12px;
border: 3px solid #ffe66d;
border-radius: 12px 0 0 12px;
font-size: 16px;
background-color: #fff9e6;
}
#add-button {
padding: 12px 20px;
background-color: #ff6b6b;
color: white;
border: none;
border-radius: 0 12px 12px 0;
cursor: pointer;
transition: all 0.3s;
font-weight: bold;
font-size: 16px;
}
#add-button:hover {
background-color: #ff8e8e;
transform: scale(1.05);
}
ul {
list-style-type: none;
}
li {
display: flex;
align-items: center;
padding: 15px;
border-bottom: 2px dashed #ffe66d;
animation: fadeIn 0.5s ease-out;
transition: all 0.3s;
border-radius: 8px;
}
li:hover {
background-color: #fff9e6;
transform: translateY(-3px);
box-shadow: 0 5px 10px rgba(0,0,0,0.1);
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes celebrate {
0% { transform: scale(1); }
50% { transform: scale(1.2) rotate(5deg); }
100% { transform: scale(1); }
}
@keyframes confetti {
0% { transform: translateY(0) rotate(0deg); opacity: 1; }
100% { transform: translateY(100vh) rotate(720deg); opacity: 0; }
}
.todo-text {
flex: 1;
margin-left: 10px;
font-size: 18px;
}
.completed {
text-decoration: line-through;
color: #7f8c8d;
}
.completed::after {
content: " 🎉";
animation: celebrate 0.5s;
}
.delete-btn {
background-color: #ff6b6b;
color: white;
border: none;
border-radius: 50%;
width: 30px;
height: 30px;
cursor: pointer;
margin-left: 10px;
transition: all 0.3s;
font-size: 16px;
display: flex;
align-items: center;
justify-content: center;
}
.delete-btn:hover {
transform: rotate(90deg);
background-color: #ff8e8e;
}
.empty-state {
text-align: center;
color: #7f8c8d;
padding: 30px;
font-size: 18px;
}
input[type="checkbox"] {
width: 20px;
height: 20px;
cursor: pointer;
}
.confetti {
position: fixed;
width: 10px;
height: 10px;
background-color: #f00;
pointer-events: none;
z-index: 999;
}
.stats {
display: flex;
justify-content: space-between;
margin-top: 20px;
padding: 10px;
background-color: #fff9e6;
border-radius: 10px;
border: 2px dashed #ffe66d;
}
.filter-buttons {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 15px;
}
.filter-btn {
padding: 8px 12px;
background-color: #fff9e6;
border: 2px solid #ffe66d;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s;
}
.filter-btn.active {
background-color: #ffe66d;
font-weight: bold;
}
.priority {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 50%;
margin-right: 5px;
}
.priority-low {
background-color: #2ecc71;
}
.priority-medium {
background-color: #f39c12;
}
.priority-high {
background-color: #e74c3c;
}
.priority-selector {
display: flex;
align-items: center;
margin-top: 10px;
gap: 10px;
}
.priority-option {
cursor: pointer;
padding: 5px 10px;
border-radius: 5px;
transition: all 0.2s;
}
.priority-option:hover {
transform: scale(1.1);
}
.theme-toggle {
position: absolute;
top: 20px;
right: 20px;
background: none;
border: none;
font-size: 24px;
cursor: pointer;
}
</style>
</head>
<body>
<button class="theme-toggle" id="theme-toggle">🌙</button>
<div class="container">
<h1>Hello World</h1>
<p class="subtitle">Welcome to my simple webpage</p>
<h1>✨ Fun Todo List ✨</h1>
<div class="content">
<p>This is a demonstration of a styled HTML page with some interactive elements.</p>
<p>Click the button below to see something happen!</p>
<button id="colorButton">Change Colors</button>
<div class="info-box">
<h3>About This Page</h3>
<p>This page was created as a simple demonstration of HTML, CSS, and JavaScript working together.</p>
<div class="input-group">
<input type="text" id="todo-input" placeholder="Add something fun to do...">
<button id="add-button">Add ✅</button>
</div>
<div class="priority-selector">
<span>Priority:</span>
<div class="priority-option" data-priority="low">
<span class="priority priority-low"></span> Low
</div>
<div class="priority-option" data-priority="medium">
<span class="priority priority-medium"></span> Medium
</div>
<div class="priority-option" data-priority="high">
<span class="priority priority-high"></span> High
</div>
</div>
<footer>
<p>&copy; 2023 Simple Demo Page</p>
</footer>
<div class="filter-buttons">
<button class="filter-btn active" data-filter="all">All</button>
<button class="filter-btn" data-filter="active">Active</button>
<button class="filter-btn" data-filter="completed">Completed</button>
</div>
<ul id="todo-list">
<!-- Todo items will be added here -->
</ul>
<div id="empty-state" class="empty-state">
Your list is empty! 😮 Add something fun to do! 🚀
</div>
<div class="stats">
<div id="total-tasks">Total: 0</div>
<div id="completed-tasks">Completed: 0</div>
<div id="remaining-tasks">Remaining: 0</div>
</div>
</div>
<script src="script.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
const todoInput = document.getElementById('todo-input');
const addButton = document.getElementById('add-button');
const todoList = document.getElementById('todo-list');
const emptyState = document.getElementById('empty-state');
const container = document.querySelector('.container');
const themeToggle = document.getElementById('theme-toggle');
const totalTasksEl = document.getElementById('total-tasks');
const completedTasksEl = document.getElementById('completed-tasks');
const remainingTasksEl = document.getElementById('remaining-tasks');
const filterButtons = document.querySelectorAll('.filter-btn');
const priorityOptions = document.querySelectorAll('.priority-option');
// Fun emojis to add randomly
const emojis = ['🚀', '⭐', '🎯', '🎨', '🎮', '🍕', '🏄', '🎸', '📚', '🎬'];
// Current filter and priority
let currentFilter = 'all';
let currentPriority = 'medium';
// Dark mode state
let isDarkMode = false;
// Load todos from localStorage
let todos = JSON.parse(localStorage.getItem('todos')) || [];
// Render initial todos
renderTodos();
updateStats();
// Add 3D effect on mouse move
document.addEventListener('mousemove', (e) => {
const xAxis = (window.innerWidth / 2 - e.pageX) / 25;
const yAxis = (window.innerHeight / 2 - e.pageY) / 25;
container.style.transform = `rotateY(${xAxis}deg) rotateX(${yAxis}deg)`;
});
// Reset transform when mouse leaves
document.addEventListener('mouseleave', () => {
container.style.transform = 'rotateY(0deg) rotateX(0deg)';
});
// Add new todo
addButton.addEventListener('click', addTodo);
todoInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
addTodo();
}
});
// Theme toggle
themeToggle.addEventListener('click', toggleTheme);
// Filter buttons
filterButtons.forEach(btn => {
btn.addEventListener('click', () => {
filterButtons.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
currentFilter = btn.dataset.filter;
renderTodos();
});
});
// Priority selection
priorityOptions.forEach(option => {
option.addEventListener('click', () => {
currentPriority = option.dataset.priority;
priorityOptions.forEach(opt => opt.style.fontWeight = 'normal');
option.style.fontWeight = 'bold';
});
});
function addTodo() {
const todoText = todoInput.value.trim();
if (todoText) {
// Add a random emoji to the task
const randomEmoji = emojis[Math.floor(Math.random() * emojis.length)];
todos.push({
id: Date.now(),
text: `${todoText} ${randomEmoji}`,
completed: false,
priority: currentPriority,
createdAt: new Date().toISOString()
});
saveTodos();
renderTodos();
updateStats();
todoInput.value = '';
// Add a little bounce to the container
container.style.animation = 'celebrate 0.5s';
setTimeout(() => {
container.style.animation = '';
}, 500);
}
}
function toggleTodo(id) {
todos = todos.map(todo => {
if (todo.id === id) {
const newCompleted = !todo.completed;
if (newCompleted) {
createConfetti();
}
return { ...todo, completed: newCompleted };
}
return todo;
});
saveTodos();
renderTodos();
updateStats();
}
function deleteTodo(id) {
todos = todos.filter(todo => todo.id !== id);
saveTodos();
renderTodos();
updateStats();
}
function renderTodos() {
// Filter todos based on current filter
let filteredTodos = todos;
if (currentFilter === 'active') {
filteredTodos = todos.filter(todo => !todo.completed);
} else if (currentFilter === 'completed') {
filteredTodos = todos.filter(todo => todo.completed);
}
// Show/hide empty state
if (filteredTodos.length === 0) {
emptyState.style.display = 'block';
} else {
emptyState.style.display = 'none';
}
// Clear current list
todoList.innerHTML = '';
// Add todo items
filteredTodos.forEach(todo => {
const li = document.createElement('li');
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.checked = todo.completed;
checkbox.addEventListener('change', () => toggleTodo(todo.id));
const priorityIndicator = document.createElement('span');
priorityIndicator.className = `priority priority-${todo.priority || 'medium'}`;
const span = document.createElement('span');
span.textContent = todo.text;
span.className = 'todo-text';
if (todo.completed) {
span.classList.add('completed');
}
const deleteBtn = document.createElement('button');
deleteBtn.innerHTML = '×';
deleteBtn.className = 'delete-btn';
deleteBtn.addEventListener('click', () => deleteTodo(todo.id));
li.appendChild(checkbox);
li.appendChild(priorityIndicator);
li.appendChild(span);
li.appendChild(deleteBtn);
todoList.appendChild(li);
});
}
function saveTodos() {
localStorage.setItem('todos', JSON.stringify(todos));
}
function updateStats() {
const total = todos.length;
const completed = todos.filter(todo => todo.completed).length;
const remaining = total - completed;
totalTasksEl.textContent = `Total: ${total}`;
completedTasksEl.textContent = `Completed: ${completed}`;
remainingTasksEl.textContent = `Remaining: ${remaining}`;
}
function createConfetti() {
for (let i = 0; i < 50; i++) {
const confetti = document.createElement('div');
confetti.className = 'confetti';
// Random position
const x = Math.random() * window.innerWidth;
const y = Math.random() * window.innerHeight;
// Random color
const colors = ['#ff6b6b', '#ffe66d', '#4ecdc4', '#a29bfe', '#ff9a9e'];
const color = colors[Math.floor(Math.random() * colors.length)];
// Random size
const size = Math.random() * 10 + 5;
// Set styles
confetti.style.left = `${x}px`;
confetti.style.top = `${y}px`;
confetti.style.backgroundColor = color;
confetti.style.width = `${size}px`;
confetti.style.height = `${size}px`;
confetti.style.borderRadius = Math.random() > 0.5 ? '50%' : '0';
// Set animation
confetti.style.animation = `confetti ${Math.random() * 3 + 2}s linear forwards`;
document.body.appendChild(confetti);
// Remove after animation
setTimeout(() => {
confetti.remove();
}, 5000);
}
}
function toggleTheme() {
isDarkMode = !isDarkMode;
if (isDarkMode) {
document.body.style.background = 'linear-gradient(135deg, #2c3e50, #4a69bd)';
container.style.backgroundColor = '#34495e';
container.style.color = '#ecf0f1';
todoInput.style.backgroundColor = '#2c3e50';
todoInput.style.color = '#ecf0f1';
todoInput.style.borderColor = '#3498db';
themeToggle.textContent = '☀️';
} else {
document.body.style.background = 'linear-gradient(135deg, #ff9a9e, #fad0c4)';
container.style.backgroundColor = 'white';
container.style.color = '#333';
todoInput.style.backgroundColor = '#fff9e6';
todoInput.style.color = '#333';
todoInput.style.borderColor = '#ffe66d';
themeToggle.textContent = '🌙';
}
}
});
</script>
</body>
</html>

View File

@ -1,25 +0,0 @@
body {
font-family: 'Arial', sans-serif;
background-color: #f0f0f0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
h1 {
color: #333;
font-size: 3rem;
text-align: center;
padding: 20px;
background-color: white;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
animation: fadeIn 1.5s ease-in-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-20px); }
to { opacity: 1; transform: translateY(0); }
}