anycoder-f5f6f813 / index.html
akhaliq's picture
akhaliq HF Staff
Upload folder using huggingface_hub
d0c7707 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Todo - Apple Style</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--primary-color: #007AFF;
--secondary-color: #5856D6;
--success-color: #34C759;
--danger-color: #FF3B30;
--warning-color: #FF9500;
--background: #F2F2F7;
--surface: #FFFFFF;
--text-primary: #1C1C1E;
--text-secondary: #8E8E93;
--text-tertiary: #C7C7CC;
--border-color: #D1D1D6;
--shadow-sm: 0 2px 10px rgba(0, 0, 0, 0.04);
--shadow-md: 0 4px 20px rgba(0, 0, 0, 0.08);
--shadow-lg: 0 10px 40px rgba(0, 0, 0, 0.12);
--radius-sm: 8px;
--radius-md: 12px;
--radius-lg: 16px;
--transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
@media (prefers-color-scheme: dark) {
:root {
--background: #000000;
--surface: #1C1C1E;
--text-primary: #FFFFFF;
--text-secondary: #8E8E93;
--text-tertiary: #48484A;
--border-color: #38383A;
--shadow-sm: 0 2px 10px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 20px rgba(0, 0, 0, 0.4);
--shadow-lg: 0 10px 40px rgba(0, 0, 0, 0.5);
}
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
background: var(--background);
color: var(--text-primary);
min-height: 100vh;
display: flex;
flex-direction: column;
line-height: 1.6;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
header {
background: var(--surface);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-bottom: 1px solid var(--border-color);
padding: 20px;
position: sticky;
top: 0;
z-index: 100;
box-shadow: var(--shadow-sm);
}
.header-content {
max-width: 800px;
margin: 0 auto;
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
display: flex;
align-items: center;
gap: 12px;
font-size: 24px;
font-weight: 600;
color: var(--text-primary);
}
.logo-icon {
width: 32px;
height: 32px;
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 20px;
}
.header-actions {
display: flex;
gap: 8px;
}
.theme-toggle {
background: var(--background);
border: 1px solid var(--border-color);
border-radius: var(--radius-sm);
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: var(--transition);
font-size: 18px;
}
.theme-toggle:hover {
background: var(--border-color);
transform: scale(1.05);
}
main {
flex: 1;
padding: 40px 20px;
max-width: 800px;
width: 100%;
margin: 0 auto;
}
.todo-container {
background: var(--surface);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-md);
overflow: hidden;
animation: slideUp 0.5s ease-out;
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.todo-header {
padding: 24px;
border-bottom: 1px solid var(--border-color);
}
.todo-input-wrapper {
display: flex;
gap: 12px;
margin-bottom: 20px;
}
.todo-input {
flex: 1;
padding: 14px 16px;
border: 2px solid var(--border-color);
border-radius: var(--radius-md);
font-size: 16px;
background: var(--background);
color: var(--text-primary);
transition: var(--transition);
outline: none;
}
.todo-input:focus {
border-color: var(--primary-color);
background: var(--surface);
box-shadow: 0 0 0 4px rgba(0, 122, 255, 0.1);
}
.add-btn {
padding: 14px 24px;
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
color: white;
border: none;
border-radius: var(--radius-md);
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: var(--transition);
display: flex;
align-items: center;
gap: 8px;
box-shadow: var(--shadow-sm);
}
.add-btn:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}
.add-btn:active {
transform: translateY(0);
}
.filter-tabs {
display: flex;
gap: 8px;
padding: 4px;
background: var(--background);
border-radius: var(--radius-md);
}
.filter-tab {
flex: 1;
padding: 10px;
background: transparent;
border: none;
border-radius: var(--radius-sm);
font-size: 14px;
font-weight: 500;
color: var(--text-secondary);
cursor: pointer;
transition: var(--transition);
}
.filter-tab.active {
background: var(--surface);
color: var(--primary-color);
box-shadow: var(--shadow-sm);
}
.filter-tab:hover:not(.active) {
color: var(--text-primary);
}
.todo-list {
min-height: 300px;
max-height: 500px;
overflow-y: auto;
padding: 16px;
}
.todo-list::-webkit-scrollbar {
width: 6px;
}
.todo-list::-webkit-scrollbar-track {
background: var(--background);
}
.todo-list::-webkit-scrollbar-thumb {
background: var(--border-color);
border-radius: 3px;
}
.todo-item {
display: flex;
align-items: center;
gap: 12px;
padding: 16px;
background: var(--background);
border-radius: var(--radius-md);
margin-bottom: 8px;
transition: var(--transition);
animation: fadeIn 0.3s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateX(-20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
.todo-item:hover {
background: var(--surface);
box-shadow: var(--shadow-sm);
transform: translateX(4px);
}
.todo-checkbox {
width: 24px;
height: 24px;
border: 2px solid var(--border-color);
border-radius: 50%;
cursor: pointer;
transition: var(--transition);
position: relative;
flex-shrink: 0;
}
.todo-checkbox:hover {
border-color: var(--primary-color);
transform: scale(1.1);
}
.todo-checkbox.checked {
background: var(--success-color);
border-color: var(--success-color);
}
.todo-checkbox.checked::after {
content: 'βœ“';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-size: 14px;
font-weight: bold;
}
.todo-text {
flex: 1;
font-size: 16px;
color: var(--text-primary);
transition: var(--transition);
cursor: text;
padding: 4px;
border-radius: var(--radius-sm);
outline: none;
}
.todo-text.completed {
text-decoration: line-through;
color: var(--text-tertiary);
}
.todo-text:focus {
background: var(--surface);
padding: 4px 8px;
}
.todo-actions {
display: flex;
gap: 8px;
opacity: 0;
transition: var(--transition);
}
.todo-item:hover .todo-actions {
opacity: 1;
}
.action-btn {
width: 32px;
height: 32px;
border: none;
background: var(--surface);
border-radius: var(--radius-sm);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: var(--transition);
color: var(--text-secondary);
}
.action-btn:hover {
background: var(--danger-color);
color: white;
transform: scale(1.1);
}
.empty-state {
text-align: center;
padding: 60px 20px;
color: var(--text-secondary);
}
.empty-icon {
font-size: 64px;
margin-bottom: 16px;
opacity: 0.5;
}
.empty-text {
font-size: 18px;
margin-bottom: 8px;
}
.empty-subtext {
font-size: 14px;
color: var(--text-tertiary);
}
.todo-footer {
padding: 20px;
border-top: 1px solid var(--border-color);
display: flex;
justify-content: space-between;
align-items: center;
font-size: 14px;
color: var(--text-secondary);
}
.todo-count {
font-weight: 500;
}
.clear-btn {
padding: 8px 16px;
background: transparent;
border: 1px solid var(--border-color);
border-radius: var(--radius-sm);
color: var(--text-secondary);
cursor: pointer;
transition: var(--transition);
font-size: 14px;
}
.clear-btn:hover {
background: var(--danger-color);
border-color: var(--danger-color);
color: white;
transform: scale(1.05);
}
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 16px;
margin-top: 24px;
}
.stat-card {
background: var(--surface);
padding: 20px;
border-radius: var(--radius-md);
text-align: center;
box-shadow: var(--shadow-sm);
transition: var(--transition);
}
.stat-card:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-md);
}
.stat-value {
font-size: 32px;
font-weight: 600;
color: var(--primary-color);
margin-bottom: 4px;
}
.stat-label {
font-size: 14px;
color: var(--text-secondary);
}
@media (max-width: 640px) {
main {
padding: 20px 16px;
}
.todo-input-wrapper {
flex-direction: column;
}
.add-btn {
width: 100%;
justify-content: center;
}
.filter-tabs {
flex-wrap: wrap;
}
.stats {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<header>
<div class="header-content">
<div class="logo">
<div class="logo-icon">βœ“</div>
<span>Todo</span>
</div>
<div class="header-actions">
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" style="text-decoration: none; color: var(--text-secondary); font-size: 14px; margin-right: 12px;">
Built with anycoder
</a>
<button class="theme-toggle" onclick="toggleTheme()">πŸŒ™</button>
</div>
</div>
</header>
<main>
<div class="todo-container">
<div class="todo-header">
<div class="todo-input-wrapper">
<input
type="text"
class="todo-input"
id="todoInput"
placeholder="What needs to be done?"
onkeypress="handleInputKeypress(event)"
>
<button class="add-btn" onclick="addTodo()">
<span>+</span>
<span>Add</span>
</button>
</div>
<div class="filter-tabs">
<button class="filter-tab active" onclick="filterTodos('all')">All</button>
<button class="filter-tab" onclick="filterTodos('active')">Active</button>
<button class="filter-tab" onclick="filterTodos('completed')">Completed</button>
</div>
</div>
<div class="todo-list" id="todoList">
<div class="empty-state">
<div class="empty-icon">πŸ“</div>
<div class="empty-text">No tasks yet</div>
<div class="empty-subtext">Add your first task to get started</div>
</div>
</div>
<div class="todo-footer">
<div class="todo-count">
<span id="activeCount">0</span> active tasks
</div>
<button class="clear-btn" onclick="clearCompleted()">Clear Completed</button>
</div>
</div>
<div class="stats">
<div class="stat-card">
<div class="stat-value" id="totalTasks">0</div>
<div class="stat-label">Total Tasks</div>
</div>
<div class="stat-card">
<div class="stat-value" id="completedTasks">0</div>
<div class="stat-label">Completed</div>
</div>
<div class="stat-card">
<div class="stat-value" id="completionRate">0%</div>
<div class="stat-label">Completion Rate</div>
</div>
</div>
</main>
<script>
let todos = JSON.parse(localStorage.getItem('todos')) || [];
let currentFilter = 'all';
let editingId = null;
function generateId() {
return Date.now().toString(36) + Math.random().toString(36).substr(2);
}
function saveTodos() {
localStorage.setItem('todos', JSON.stringify(todos));
updateStats();
}
function addTodo() {
const input = document.getElementById('todoInput');
const text = input.value.trim();
if (text === '') {
input.focus();
return;
}
const todo = {
id: generateId(),
text: text,
completed: false,
createdAt: new Date().toISOString()
};
todos.unshift(todo);
saveTodos();
renderTodos();
input.value = '';
input.focus();
}
function handleInputKeypress(event) {
if (event.key === 'Enter') {
addTodo();
}
}
function toggleTodo(id) {
const todo = todos.find(t => t.id === id);
if (todo) {
todo.completed = !todo.completed;
saveTodos();
renderTodos();
}
}
function deleteTodo(id) {
todos = todos.filter(t => t.id !== id);
saveTodos();
renderTodos();
}
function startEdit(id) {
if (editingId && editingId !== id) {
finishEdit(editingId);
}
editingId = id;
const todo = todos.find(t => t.id === id);
if (todo) {
const textElement = document.querySelector(`[data-id="${id}"] .todo-text`);
textElement.contentEditable = true;
textElement.focus();
// Select all text
const range = document.createRange();
range.selectNodeContents(textElement);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
textElement.addEventListener('blur', () => finishEdit(id));
textElement.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
e.preventDefault();
textElement.blur();
}
});
}
}
function finishEdit(id) {
const textElement = document.querySelector(`[data-id="${id}"] .todo-text`);
if (textElement) {
const newText = textElement.textContent.trim();
const todo = todos.find(t => t.id === id);
if (todo && newText !== '') {
todo.text = newText;
saveTodos();
}
textElement.contentEditable = false;
}
editingId = null;
}
function filterTodos(filter) {
currentFilter = filter;
// Update active tab
document.querySelectorAll('.filter-tab').forEach(tab => {
tab.classList.remove('active');
});
event.target.classList.add('active');
renderTodos();
}
function clearCompleted() {
todos = todos.filter(t => !t.completed);
saveTodos();
renderTodos();
}
function getFilteredTodos() {
switch (currentFilter) {
case 'active':
return todos.filter(t => !t.completed);
case 'completed':
return todos.filter(t => t.completed);
default:
return todos;
}
}
function renderTodos() {
const todoList = document.getElementById('todoList');
const filteredTodos = getFilteredTodos();
if (filteredTodos.length === 0) {
todoList.innerHTML = `
<div class="empty-state">
<div class="empty-icon">${currentFilter === 'completed' ? 'πŸŽ‰' : 'πŸ“'}</div>
<div class="empty-text">${currentFilter === 'completed' ? 'All done!' : 'No tasks yet'}</div>
<div class="empty-subtext">${currentFilter === 'completed' ? 'Great job completing everything!' : 'Add your first task to get started'}</div>
</div>
`;
return;
}
todoList.innerHTML = filteredTodos.map(todo => `
<div class="todo-item" data-id="${todo.id}">
<div class="todo-checkbox ${todo.completed ? 'checked' : ''}" onclick="toggleTodo('${todo.id}')"></div>
<div class="todo-text ${todo.completed ? 'completed' : ''}" onclick="startEdit('${todo.id}')">${todo.text}</div>
<div class="todo-actions">
<button class="action-btn" onclick="deleteTodo('${todo.id}')">πŸ—‘οΈ</button>
</div>
</div>
`).join('');
updateActiveCount();
}
function updateActiveCount() {
const activeCount = todos.filter(t => !t.completed).length;
document.getElementById('activeCount').textContent = activeCount;
}
function updateStats() {
const total = todos.length;
const completed = todos.filter(t => t.completed).length;
const rate = total > 0 ? Math.round((completed / total) * 100) : 0;
document.getElementById('totalTasks').textContent = total;
document.getElementById('completedTasks').textContent = completed;
document.getElementById('completionRate').textContent = rate + '%';
}
function toggleTheme() {
const body = document.body;
const themeToggle = document.querySelector('.theme-toggle');
if (body.style.filter === 'invert(1) hue-rotate(180deg)') {
body.style.filter = '';
themeToggle.textContent = 'πŸŒ™';
} else {
body.style.filter = 'invert(1) hue-rotate(180deg)';
themeToggle.textContent = 'β˜€οΈ';
}
}
// Initialize
renderTodos();
updateStats();
document.getElementById('todoInput').focus();
</script>
</body>
</html>