suna/backend/agent/workspace/index.html

545 lines
18 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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>✨ Fun Todo List ✨</h1>
<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>
<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>
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>