anycoder-b4d156ce / index.html
cyberblaster's picture
Upload folder using huggingface_hub
fe7c2d5 verified
Raw
History Blame Contribute Delete
20.4 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TASKFLOW</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
:root {
--bg: #0a0a0b;
--bg-elevated: #131315;
--fg: #e8e8e8;
--muted: #6b6b6b;
--accent: #00ff88;
--accent-dim: rgba(0, 255, 136, 0.15);
--danger: #ff4757;
--border: #2a2a2d;
--card: #18181b;
}
* {
box-sizing: border-box;
}
body {
font-family: 'Space Grotesk', sans-serif;
background: var(--bg);
color: var(--fg);
min-height: 100vh;
margin: 0;
overflow-x: hidden;
}
/* Background Pattern */
.bg-pattern {
position: fixed;
inset: 0;
background-image:
linear-gradient(rgba(0, 255, 136, 0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(0, 255, 136, 0.03) 1px, transparent 1px);
background-size: 50px 50px;
pointer-events: none;
z-index: 0;
}
.bg-glow {
position: fixed;
top: -200px;
right: -200px;
width: 600px;
height: 600px;
background: radial-gradient(circle, rgba(0, 255, 136, 0.08) 0%, transparent 70%);
pointer-events: none;
z-index: 0;
}
.bg-glow-2 {
position: fixed;
bottom: -300px;
left: -200px;
width: 500px;
height: 500px;
background: radial-gradient(circle, rgba(0, 255, 136, 0.05) 0%, transparent 70%);
pointer-events: none;
z-index: 0;
}
/* Typography */
.font-mono {
font-family: 'JetBrains Mono', monospace;
}
/* Custom Scrollbar */
::-webkit-scrollbar {
width: 6px;
}
::-webkit-scrollbar-track {
background: var(--bg);
}
::-webkit-scrollbar-thumb {
background: var(--border);
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--muted);
}
/* Input Styling */
.todo-input {
background: var(--bg);
border: 2px solid var(--border);
color: var(--fg);
transition: all 0.2s ease;
}
.todo-input:focus {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 4px var(--accent-dim);
}
.todo-input::placeholder {
color: var(--muted);
}
/* Button Styling */
.btn-primary {
background: var(--accent);
color: var(--bg);
font-weight: 700;
transition: all 0.2s ease;
position: relative;
overflow: hidden;
}
.btn-primary::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
transform: translateX(-100%);
transition: transform 0.5s ease;
}
.btn-primary:hover::before {
transform: translateX(100%);
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(0, 255, 136, 0.3);
}
.btn-primary:active {
transform: translateY(0);
}
/* Filter Buttons */
.filter-btn {
background: transparent;
color: var(--muted);
border: 1px solid transparent;
transition: all 0.2s ease;
}
.filter-btn:hover {
color: var(--fg);
background: var(--bg-elevated);
}
.filter-btn.active {
color: var(--accent);
border-color: var(--accent);
background: var(--accent-dim);
}
/* Todo Item */
.todo-item {
background: var(--card);
border: 1px solid var(--border);
transition: all 0.3s ease;
animation: slideIn 0.4s ease forwards;
opacity: 0;
transform: translateY(20px);
}
.todo-item:hover {
border-color: rgba(0, 255, 136, 0.3);
transform: translateX(4px);
}
.todo-item.completed {
opacity: 0.5;
}
.todo-item.completed .todo-text {
text-decoration: line-through;
color: var(--muted);
}
.todo-item.removing {
animation: slideOut 0.3s ease forwards;
}
@keyframes slideIn {
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideOut {
to {
opacity: 0;
transform: translateX(100px);
}
}
/* Checkbox */
.checkbox-container {
position: relative;
width: 24px;
height: 24px;
flex-shrink: 0;
}
.checkbox-input {
position: absolute;
opacity: 0;
width: 100%;
height: 100%;
cursor: pointer;
z-index: 2;
}
.checkbox-custom {
position: absolute;
inset: 0;
border: 2px solid var(--border);
border-radius: 6px;
transition: all 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
}
.checkbox-input:hover + .checkbox-custom {
border-color: var(--accent);
}
.checkbox-input:checked + .checkbox-custom {
background: var(--accent);
border-color: var(--accent);
}
.checkbox-custom svg {
opacity: 0;
transform: scale(0);
transition: all 0.2s ease;
}
.checkbox-input:checked + .checkbox-custom svg {
opacity: 1;
transform: scale(1);
}
.checkbox-input:focus-visible + .checkbox-custom {
box-shadow: 0 0 0 3px var(--accent-dim);
}
/* Delete Button */
.delete-btn {
opacity: 0;
transition: all 0.2s ease;
color: var(--muted);
}
.todo-item:hover .delete-btn {
opacity: 1;
}
.delete-btn:hover {
color: var(--danger);
transform: scale(1.1);
}
/* Progress Bar */
.progress-bar {
height: 4px;
background: var(--border);
border-radius: 2px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, var(--accent), #00ccff);
transition: width 0.5s ease;
border-radius: 2px;
}
/* Stats Card */
.stat-card {
background: var(--card);
border: 1px solid var(--border);
transition: all 0.2s ease;
}
.stat-card:hover {
border-color: var(--accent);
}
/* Header Animation */
.header-title {
animation: glitch 3s infinite;
}
@keyframes glitch {
0%, 90%, 100% {
text-shadow: none;
}
92% {
text-shadow: -2px 0 var(--accent), 2px 0 #ff4757;
}
94% {
text-shadow: 2px 0 var(--accent), -2px 0 #ff4757;
}
96% {
text-shadow: none;
}
}
/* Empty State */
.empty-state {
animation: float 3s ease-in-out infinite;
}
@keyframes float {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-10px);
}
}
/* Stagger Animation */
.stagger-1 { animation-delay: 0.1s; }
.stagger-2 { animation-delay: 0.2s; }
.stagger-3 { animation-delay: 0.3s; }
.stagger-4 { animation-delay: 0.4s; }
/* Reduced Motion */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* Priority Indicators */
.priority-high { border-left: 3px solid var(--danger); }
.priority-medium { border-left: 3px solid #ffa502; }
.priority-low { border-left: 3px solid var(--accent); }
/* Priority Select */
.priority-select {
background: var(--bg);
border: 1px solid var(--border);
color: var(--fg);
transition: all 0.2s ease;
}
.priority-select:focus {
outline: none;
border-color: var(--accent);
}
</style>
</head>
<body>
<div class="bg-pattern"></div>
<div class="bg-glow"></div>
<div class="bg-glow-2"></div>
<div class="relative z-10 min-h-screen px-4 py-8 md:py-12">
<div class="max-w-2xl mx-auto">
<!-- Header -->
<header class="mb-10 md:mb-12">
<div class="flex items-center justify-between mb-2">
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" rel="noopener noreferrer"
class="text-xs font-mono text-[var(--muted)] hover:text-[var(--accent)] transition-colors">
Built with anycoder
</a>
<span class="font-mono text-xs text-[var(--muted)]" id="datetime"></span>
</div>
<h1 class="header-title text-4xl md:text-5xl font-bold tracking-tight">
TASK<span class="text-[var(--accent)]">FLOW</span>
</h1>
<p class="text-[var(--muted)] mt-2 font-mono text-sm">// your productivity terminal</p>
</header>
<!-- Stats -->
<div class="grid grid-cols-3 gap-3 mb-8" id="stats">
<div class="stat-card rounded-lg p-4">
<div class="text-2xl md:text-3xl font-bold text-[var(--accent)]" id="totalCount">0</div>
<div class="text-xs text-[var(--muted)] font-mono mt-1">TOTAL</div>
</div>
<div class="stat-card rounded-lg p-4">
<div class="text-2xl md:text-3xl font-bold" id="activeCount">0</div>
<div class="text-xs text-[var(--muted)] font-mono mt-1">ACTIVE</div>
</div>
<div class="stat-card rounded-lg p-4">
<div class="text-2xl md:text-3xl font-bold text-[var(--accent)]" id="completedCount">0</div>
<div class="text-xs text-[var(--muted)] font-mono mt-1">DONE</div>
</div>
</div>
<!-- Progress Bar -->
<div class="mb-8">
<div class="flex justify-between items-center mb-2">
<span class="text-xs font-mono text-[var(--muted)]">PROGRESS</span>
<span class="text-xs font-mono text-[var(--accent)]" id="progressPercent">0%</span>
</div>
<div class="progress-bar">
<div class="progress-fill" id="progressFill" style="width: 0%"></div>
</div>
</div>
<!-- Input Section -->
<div class="mb-8">
<form id="todoForm" class="flex flex-col sm:flex-row gap-3">
<input
type="text"
id="todoInput"
class="todo-input flex-1 px-4 py-3 rounded-lg text-base"
placeholder="What needs to be done?"
autocomplete="off"
aria-label="New todo input"
>
<select id="prioritySelect" class="priority-select px-4 py-3 rounded-lg font-mono text-sm" aria-label="Priority level">
<option value="low">LOW</option>
<option value="medium" selected>MED</option>
<option value="high">HIGH</option>
</select>
<button
type="submit"
class="btn-primary px-6 py-3 rounded-lg font-mono text-sm whitespace-nowrap"
aria-label="Add todo"
>
ADD TASK
</button>
</form>
</div>
<!-- Filters -->
<div class="flex gap-2 mb-6 overflow-x-auto pb-2" role="tablist" aria-label="Filter todos">
<button class="filter-btn active px-4 py-2 rounded-lg font-mono text-xs" data-filter="all" role="tab" aria-selected="true">
ALL
</button>
<button class="filter-btn px-4 py-2 rounded-lg font-mono text-xs" data-filter="active" role="tab" aria-selected="false">
ACTIVE
</button>
<button class="filter-btn px-4 py-2 rounded-lg font-mono text-xs" data-filter="completed" role="tab" aria-selected="false">
COMPLETED
</button>
</div>
<!-- Todo List -->
<div id="todoList" class="space-y-3" role="list" aria-label="Todo list">
<!-- Todos will be rendered here -->
</div>
<!-- Empty State -->
<div id="emptyState" class="hidden text-center py-16">
<div class="empty-state inline-block mb-4">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" class="text-[var(--muted)]">
<path d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"/>
</svg>
</div>
<p class="text-[var(--muted)] font-mono text-sm">NO TASKS YET</p>
<p class="text-[var(--muted)] font-mono text-xs mt-1 opacity-50">// add your first task above</p>
</div>
<!-- Clear Completed -->
<div class="mt-8 flex justify-between items-center" id="clearSection">
<span class="text-xs font-mono text-[var(--muted)]" id="itemsLeft">0 items left</span>
<button
id="clearCompleted"
class="text-xs font-mono text-[var(--danger)] hover:underline hidden"
aria-label="Clear completed tasks"
>
CLEAR COMPLETED
</button>
</div>
</div>
</div>
<script>
// Initialize todos array first
let todos = [];
let currentFilter = 'all';
// DOM Elements - get after initialization
const todoForm = document.getElementById('todoForm');
const todoInput = document.getElementById('todoInput');
const prioritySelect = document.getElementById('prioritySelect');
const todoList = document.getElementById('todoList');
const emptyState = document.getElementById('emptyState');
const filterBtns = document.querySelectorAll('.filter-btn');
const clearCompletedBtn = document.getElementById('clearCompleted');
const totalCountEl = document.getElementById('totalCount');
const activeCountEl = document.getElementById('activeCount');
const completedCountEl = document.getElementById('completedCount');
const progressFill = document.getElementById('progressFill');
const progressPercent = document.getElementById('progressPercent');
const itemsLeft = document.getElementById('itemsLeft');
const datetimeEl = document.getElementById('datetime');
// Load from localStorage
function loadTodos() {
const stored = localStorage.getItem('taskflow-todos');
if (stored) {
try {
todos = JSON.parse(stored);
} catch (e) {
todos = [];
}
}
}
// Save to localStorage
function saveTodos() {
localStorage.setItem('taskflow-todos', JSON.stringify(todos));
}
// Generate unique ID
function generateId() {
return Date.now().toString(36) + Math.random().toString(36).substr(2);
}
// Update Stats
function updateStats() {
const total = todos.length;
const completed = todos.filter(t => t.completed).length;
const active = total - completed;
const percent = total > 0 ? Math.round((completed / total) * 100) : 0;
totalCountEl.textContent = total;
activeCountEl.textContent = active;
completedCountEl.textContent = completed;
progressFill.style.width = percent + '%';
progressPercent.textContent = percent + '%';
itemsLeft.textContent = active + ' item' + (active !== 1 ? 's' : '') + ' left';
// Show/hide clear completed button
if (completed > 0) {
clearCompletedBtn.classList.remove('hidden');
} else {
clearCompletedBtn.classList.add('hidden');
}
}
// Render Todos
function renderTodos() {
const filtered = todos.filter(todo => {
if (currentFilter === 'active') return !todo.completed;
if (currentFilter === 'completed') return todo.completed;
return true;
});
if (filtered.length === 0) {
todoList.innerHTML = '';
emptyState.classList.remove('hidden');
} else {
emptyState.classList.add('hidden');
todoList.innerHTML = filtered.map((todo, index) => `
<div
class="todo-item rounded-lg p-4 flex items-center gap-4 priority-${todo.priority} ${todo.completed ? 'completed' : ''} stagger-${(index % 4) + 1}"
data-id="${todo.id}"
role="listitem"
>
<label class="checkbox-container">
<input
type="checkbox"
class="checkbox-input"
${todo.completed ? 'checked' : ''}
onchange="toggleTodo('${todo.id}')"
aria-label="${todo.completed ? 'Mark as incomplete' : 'Mark as complete'}"
>
<div class="checkbox-custom">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#0a0a0b" stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
</div>
</label>
<span class="todo-text flex-1 text-base">${escapeHtml(todo.text)}</span>
<span class="font-mono text-xs text-[var(--muted)] hidden sm:block">${todo.priority.toUpperCase()}</span>
<button
class="delete-btn p-2 rounded-lg hover:bg-[var(--bg-elevated)] transition-all"
onclick="deleteTodo('${todo.id}')"
aria-label="Delete task"
>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="3 6 5 6 21 6"></polyline>
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
</svg>
</button>
</div>
`).join('');
}
updateStats();
}
// Escape HTML to prevent XSS
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// Add Todo
function addTodo(text, priority) {
if (!text.trim()) return;
todos.unshift({
id: generateId(),
text: text.trim(),
completed: false,
priority: priority,
createdAt: new Date().toISOString()
});
saveTodos();
renderTodos();
}
// Toggle Todo
function toggleTodo(id) {
const todo = todos.find(t => t.id === id);
if (todo) {
todo.completed = !todo.completed;
saveTodos();
renderTodos();
}
}
// Delete Todo
function deleteTodo(id) {
const item = document.querySelector(`[data-id="${id}"]`);
if (item) {
item.classList.add('removing');
setTimeout(() => {
todos = todos.filter(t => t.id !== id);
saveTodos();
renderTodos();
}, 300);
}
}
// Clear Completed
function clearCompleted() {
todos = todos.filter(t => !t.completed);
saveTodos();
renderTodos();
}
// Update DateTime
function updateDateTime() {
const now = new Date();
const options = {
weekday: 'short',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
};
datetimeEl.textContent = now.toLocaleDateString('en-US', options).toUpperCase();
}
// Event Listeners
todoForm.addEventListener('submit', (e) => {
e.preventDefault();
addTodo(todoInput.value, prioritySelect.value);
todoInput.value = '';
todoInput.focus();
});
filterBtns.forEach(btn => {
btn.addEventListener('click', () => {
filterBtns.forEach(b => {
b.classList.remove('active');
b.setAttribute('aria-selected', 'false');
});
btn.classList.add('active');
btn.setAttribute('aria-selected', 'true');
currentFilter = btn.dataset.filter;
renderTodos();
});
});
clearCompletedBtn.addEventListener('click', clearCompleted);
// Keyboard Navigation
document.addEventListener('keydown', (e) => {
if (e.key === '/' && !['INPUT', 'TEXTAREA'].includes(document.activeElement.tagName)) {
e.preventDefault();
todoInput.focus();
}
});
// Initialize
loadTodos();
renderTodos();
updateDateTime();
setInterval(updateDateTime, 60000);
</script>
</body>
</html>