Spaces:
Running
Running
| <html lang="ru"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Личная Панель Продуктивности</title> | |
| <!-- Подключаем иконки FontAwesome --> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| /* --- Современные CSS Переменные --- */ | |
| :root { | |
| --bg-gradient: linear-gradient(135deg, #1e1e2f 0%, #2a2a40 100%); | |
| --glass-bg: rgba(255, 255, 255, 0.05); | |
| --glass-border: rgba(255, 255, 255, 0.1); | |
| --glass-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37); | |
| --accent-color: #6c5ce7; | |
| --accent-hover: #5649c0; | |
| --text-primary: #ffffff; | |
| --text-secondary: #a0a0b0; | |
| --danger-color: #ff7675; | |
| --success-color: #00b894; | |
| --font-main: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; | |
| --card-radius: 16px; | |
| } | |
| /* --- Базовый сброс и стили --- */ | |
| * { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| body { | |
| font-family: var(--font-main); | |
| background: var(--bg-gradient); | |
| color: var(--text-primary); | |
| min-height: 100vh; | |
| display: flex; | |
| flex-direction: column; | |
| overflow-x: hidden; | |
| background-attachment: fixed; /* Фон зафиксирован при скролле */ | |
| } | |
| /* --- Header --- */ | |
| header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| padding: 20px 5%; | |
| background: rgba(30, 30, 47, 0.8); | |
| backdrop-filter: blur(10px); | |
| border-bottom: 1px solid var(--glass-border); | |
| position: sticky; | |
| top: 0; | |
| z-index: 100; | |
| } | |
| .logo { | |
| font-size: 1.5rem; | |
| font-weight: 700; | |
| background: linear-gradient(to right, #a29bfe, #74b9ff); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .anycoder-link { | |
| color: var(--text-secondary); | |
| text-decoration: none; | |
| font-size: 0.9rem; | |
| transition: color 0.3s ease; | |
| display: flex; | |
| align-items: center; | |
| gap: 5px; | |
| } | |
| .anycoder-link:hover { | |
| color: var(--text-primary); | |
| } | |
| /* --- Main Layout (Grid) --- */ | |
| main { | |
| flex: 1; | |
| padding: 40px 5%; | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); | |
| gap: 30px; | |
| max-width: 1400px; | |
| margin: 0 auto; | |
| width: 100%; | |
| } | |
| /* --- Карточки (Glassmorphism) --- */ | |
| .card { | |
| background: var(--glass-bg); | |
| backdrop-filter: blur(12px); | |
| -webkit-backdrop-filter: blur(12px); | |
| border: 1px solid var(--glass-border); | |
| border-radius: var(--card-radius); | |
| padding: 25px; | |
| box-shadow: var(--glass-shadow); | |
| transition: transform 0.3s ease, box-shadow 0.3s ease; | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .card:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 12px 40px 0 rgba(0, 0, 0, 0.5); | |
| } | |
| .card-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 20px; | |
| font-size: 1.2rem; | |
| font-weight: 600; | |
| color: var(--text-primary); | |
| border-bottom: 1px solid rgba(255,255,255,0.05); | |
| padding-bottom: 10px; | |
| } | |
| .card-header i { | |
| color: var(--accent-color); | |
| } | |
| /* --- Widget 1: Clock --- */ | |
| .clock-container { | |
| text-align: center; | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: center; | |
| height: 100%; | |
| padding: 20px 0; | |
| } | |
| .time { | |
| font-size: 3.5rem; | |
| font-weight: 700; | |
| letter-spacing: 2px; | |
| text-shadow: 0 0 20px rgba(108, 92, 231, 0.5); | |
| } | |
| .date { | |
| font-size: 1.1rem; | |
| color: var(--text-secondary); | |
| margin-top: 10px; | |
| } | |
| .greeting { | |
| margin-top: 20px; | |
| font-size: 1.2rem; | |
| font-style: italic; | |
| color: var(--accent-color); | |
| } | |
| /* --- Widget 2: To-Do List --- */ | |
| .todo-input-group { | |
| display: flex; | |
| gap: 10px; | |
| margin-bottom: 20px; | |
| } | |
| input[type="text"] { | |
| flex: 1; | |
| background: rgba(0, 0, 0, 0.2); | |
| border: 1px solid var(--glass-border); | |
| border-radius: 8px; | |
| padding: 12px; | |
| color: white; | |
| outline: none; | |
| transition: border-color 0.3s; | |
| } | |
| input[type="text"]:focus { | |
| border-color: var(--accent-color); | |
| } | |
| .btn { | |
| background: var(--accent-color); | |
| color: white; | |
| border: none; | |
| padding: 10px 20px; | |
| border-radius: 8px; | |
| cursor: pointer; | |
| font-weight: 600; | |
| transition: background 0.3s, transform 0.1s; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 5px; | |
| } | |
| .btn:hover { | |
| background: var(--accent-hover); | |
| } | |
| .btn:active { | |
| transform: scale(0.95); | |
| } | |
| .todo-list { | |
| list-style: none; | |
| overflow-y: auto; | |
| max-height: 300px; | |
| padding-right: 5px; | |
| } | |
| /* Кастомный скроллбар */ | |
| .todo-list::-webkit-scrollbar { | |
| width: 6px; | |
| } | |
| .todo-list::-webkit-scrollbar-thumb { | |
| background: rgba(255,255,255,0.2); | |
| border-radius: 3px; | |
| } | |
| .todo-item { | |
| background: rgba(255, 255, 255, 0.03); | |
| margin-bottom: 10px; | |
| padding: 12px; | |
| border-radius: 8px; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| transition: background 0.2s; | |
| animation: fadeIn 0.3s ease; | |
| } | |
| .todo-item:hover { | |
| background: rgba(255, 255, 255, 0.08); | |
| } | |
| .todo-item.completed span { | |
| text-decoration: line-through; | |
| color: var(--text-secondary); | |
| } | |
| .todo-actions button { | |
| background: transparent; | |
| border: none; | |
| color: var(--text-secondary); | |
| cursor: pointer; | |
| margin-left: 8px; | |
| font-size: 1rem; | |
| transition: color 0.2s; | |
| } | |
| .todo-actions button.check:hover { color: var(--success-color); } | |
| .todo-actions button.delete:hover { color: var(--danger-color); } | |
| /* --- Widget 3: Pomodoro Timer --- */ | |
| .timer-display { | |
| font-size: 4rem; | |
| font-weight: 700; | |
| text-align: center; | |
| margin: 20px 0; | |
| font-family: monospace; /* Чтобы цифры не прыгали */ | |
| } | |
| .timer-controls { | |
| display: flex; | |
| justify-content: center; | |
| gap: 15px; | |
| } | |
| .btn-outline { | |
| background: transparent; | |
| border: 2px solid var(--accent-color); | |
| color: var(--accent-color); | |
| } | |
| .btn-outline:hover { | |
| background: var(--accent-color); | |
| color: white; | |
| } | |
| .timer-status { | |
| text-align: center; | |
| margin-top: 15px; | |
| font-size: 0.9rem; | |
| color: var(--text-secondary); | |
| } | |
| /* --- Widget 4: Quotes --- */ | |
| .quote-container { | |
| text-align: center; | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: center; | |
| height: 100%; | |
| } | |
| .quote-text { | |
| font-size: 1.2rem; | |
| font-style: italic; | |
| margin-bottom: 20px; | |
| line-height: 1.5; | |
| } | |
| .quote-author { | |
| font-size: 1rem; | |
| color: var(--accent-color); | |
| font-weight: 600; | |
| margin-bottom: 30px; | |
| } | |
| /* --- Footer --- */ | |
| footer { | |
| text-align: center; | |
| padding: 20px; | |
| color: var(--text-secondary); | |
| font-size: 0.8rem; | |
| border-top: 1px solid var(--glass-border); | |
| background: rgba(30, 30, 47, 0.8); | |
| } | |
| /* --- Toast Notification --- */ | |
| .toast-container { | |
| position: fixed; | |
| bottom: 20px; | |
| right: 20px; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 10px; | |
| z-index: 1000; | |
| } | |
| .toast { | |
| background: rgba(30, 30, 47, 0.95); | |
| color: white; | |
| padding: 15px 25px; | |
| border-radius: 8px; | |
| border-left: 4px solid var(--accent-color); | |
| box-shadow: 0 5px 15px rgba(0,0,0,0.3); | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| animation: slideIn 0.3s ease, fadeOut 0.3s ease 2.7s forwards; | |
| min-width: 250px; | |
| } | |
| /* Анимации */ | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| @keyframes slideIn { | |
| from { transform: translateX(100%); opacity: 0; } | |
| to { transform: translateX(0); opacity: 1; } | |
| } | |
| @keyframes fadeOut { | |
| to { opacity: 0; pointer-events: none; } | |
| } | |
| /* Адаптивность */ | |
| @media (max-width: 768px) { | |
| .time { font-size: 2.5rem; } | |
| header { padding: 15px 20px; } | |
| main { padding: 20px; } | |
| .timer-display { font-size: 3rem; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- Header --> | |
| <header> | |
| <div class="logo"> | |
| <i class="fa-solid fa-layer-group"></i> MyDashboard | |
| </div> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link"> | |
| Built with anycoder <i class="fa-solid fa-external-link-alt"></i> | |
| </a> | |
| </header> | |
| <!-- Main Content --> | |
| <main> | |
| <!-- Widget 1: Clock --> | |
| <section class="card"> | |
| <div class="card-header"> | |
| <span>Текущее время</span> | |
| <i class="fa-regular fa-clock"></i> | |
| </div> | |
| <div class="clock-container"> | |
| <div class="time" id="clock-time">00:00:00</div> | |
| <div class="date" id="clock-date">Загрузка даты...</div> | |
| <div class="greeting" id="greeting-text">Добрый день!</div> | |
| </div> | |
| </section> | |
| <!-- Widget 2: To-Do List --> | |
| <section class="card"> | |
| <div class="card-header"> | |
| <span>Мои задачи</span> | |
| <i class="fa-solid fa-list-check"></i> | |
| </div> | |
| <div class="todo-input-group"> | |
| <input type="text" id="todo-input" placeholder="Новая задача..." onkeypress="handleEnter(event)"> | |
| <button class="btn" onclick="addTodo()"> | |
| <i class="fa-solid fa-plus"></i> | |
| </button> | |
| </div> | |
| <ul class="todo-list" id="todo-list"> | |
| <!-- Задачи будут добавлены через JS --> | |
| </ul> | |
| </section> | |
| <!-- Widget 3: Pomodoro Timer --> | |
| <section class="card"> | |
| <div class="card-header"> | |
| <span>Фокус Таймер</span> | |
| <i class="fa-solid fa-hourglass-half"></i> | |
| </div> | |
| <div class="timer-display" id="timer">25:00</div> | |
| <div class="timer-controls"> | |
| <button class="btn" id="start-btn" onclick="startTimer()"> | |
| <i class="fa-solid fa-play"></i> Старт | |
| </button> | |
| <button class="btn btn-outline" onclick="pauseTimer()"> | |
| <i class="fa-solid fa-pause"></i> Пауза | |
| </button> | |
| <button class="btn btn-outline" onclick="resetTimer()"> | |
| <i class="fa-solid fa-rotate-right"></i> Сброс | |
| </button> | |
| </div> | |
| <div class="timer-status" id="timer-status">Готов к работе</div> | |
| </section> | |
| <!-- Widget 4: Quotes --> | |
| <section class="card"> | |
| <div class="card-header"> | |
| <span>Вдохновение</span> | |
| <i class="fa-solid fa-quote-left"></i> | |
| </div> | |
| <div class="quote-container"> | |
| <p class="quote-text" id="quote-text">"Цитата появится здесь..."</p> | |
| <p class="quote-author" id="quote-author">Автор</p> | |
| <button class="btn btn-outline" onclick="generateQuote()" style="width: 100%;"> | |
| Новая цитата | |
| </button> | |
| </div> | |
| </section> | |
| </main> | |
| <!-- Footer --> | |
| <footer> | |
| © 2023 Personal Dashboard. Создано с помощью HTML, CSS и JS. | |
| </footer> | |
| <!-- Toast Container --> | |
| <div class="toast-container" id="toast-container"></div> | |
| <!-- JavaScript Logic --> | |
| <script> | |
| /* --- 1. Часы и Дата --- */ | |
| function updateClock() { | |
| const now = new Date(); | |
| const timeString = now.toLocaleTimeString('ru-RU'); | |
| const dateString = now.toLocaleDateString('ru-RU', { | |
| weekday: 'long', | |
| year: 'numeric', | |
| month: 'long', | |
| day: 'numeric' | |
| }); | |
| document.getElementById('clock-time').textContent = timeString; | |
| document.getElementById('clock-date').textContent = dateString; | |
| // Приветствие | |
| const hour = now.getHours(); | |
| let greeting = 'Доброй ночи!'; | |
| if (hour >= 5 && hour < 12) greeting = 'Доброе утро!'; | |
| else if (hour >= 12 && hour < 18) greeting = 'Добрый день!'; | |
| else if (hour >= 18 && hour < 23) greeting = 'Добрый вечер!'; | |
| document.getElementById('greeting-text').textContent = greeting; | |
| } | |
| setInterval(updateClock, 1000); | |
| updateClock(); | |
| /* --- 2. Список задач (To-Do) --- */ | |
| let todos = JSON.parse(localStorage.getItem('myTodos')) || []; | |
| function renderTodos() { | |
| const list = document.getElementById('todo-list'); | |
| list.innerHTML = ''; | |
| todos.forEach((todo, index) => { | |
| const li = document.createElement('li'); | |
| li.className = `todo-item ${todo.completed ? 'completed' : ''}`; | |
| li.innerHTML = ` | |
| <span onclick="toggleTodo(${index})" style="cursor:pointer; flex:1;">${todo.text}</span> | |
| <div class="todo-actions"> | |
| <button class="check" onclick="toggleTodo(${index})" title="Выполнено"> | |
| <i class="fa-solid fa-check"></i> | |
| </button> | |
| <button class="delete" onclick="deleteTodo(${index})" title="Удалить"> | |
| <i class="fa-solid fa-trash"></i> | |
| </button> | |
| </div> | |
| `; | |
| list.appendChild(li); | |
| }); | |
| localStorage.setItem('myTodos', JSON.stringify(todos)); | |
| } | |
| function addTodo() { | |
| const input = document.getElementById('todo-input'); | |
| const text = input.value.trim(); | |
| if (text) { | |
| todos.push({ text, completed: false }); | |
| input.value = ''; | |
| renderTodos(); | |
| showToast('Задача добавлена', 'success'); | |
| } else { | |
| showToast('Введите текст задачи', 'error'); | |
| } | |
| } | |
| function toggleTodo(index) { | |
| todos[index].completed = !todos[index].completed; | |
| renderTodos(); | |
| } | |
| function deleteTodo(index) { | |
| todos.splice(index, 1); | |
| renderTodos(); | |
| showToast('Задача удалена', 'info'); | |
| } | |
| function handleEnter(e) { | |
| if (e.key === 'Enter') addTodo(); | |
| } | |
| // Инициализация | |
| renderTodos(); | |
| /* --- 3. Таймер Помодоро --- */ | |
| let timerInterval; | |
| let timeLeft = 25 * 60; // 25 минут в секундах | |
| let isRunning = false; | |
| function updateTimerDisplay() { | |
| const minutes = Math.floor(timeLeft / 60); | |
| const seconds = timeLeft % 60; | |
| document.getElementById('timer').textContent = | |
| `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; | |
| } | |
| function startTimer() { | |
| if (!isRunning) { | |
| isRunning = true; | |
| document.getElementById('timer-status').textContent = 'Время фокусировки!'; | |
| document.getElementById('start-btn').style.background = '#00b894'; // Зеленый при работе | |
| timerInterval = setInterval(() => { | |
| if (timeLeft > 0) { | |
| timeLeft--; | |
| updateTimerDisplay(); | |
| } else { | |
| clearInterval(timerInterval); | |
| isRunning = false; | |
| document.getElementById('timer-status').textContent = 'Время вышло! Сделайте перерыв.'; | |
| showToast('Пора отдохнуть!', 'success'); | |
| // Здесь можно добавить звук | |
| } | |
| }, 1000); | |
| } | |
| } | |
| function pauseTimer() { | |
| if (isRunning) { | |
| clearInterval(timerInterval); | |
| isRunning = false; | |
| document.getElementById('timer-status').textContent = 'На паузе'; | |
| document.getElementById('start-btn').style.background = ''; // Сброс цвета | |
| } | |
| } | |
| function resetTimer() { | |
| clearInterval(timerInterval); | |
| isRunning = false; | |
| timeLeft = 25 * 60; | |
| updateTimerDisplay(); | |
| document.getElementById('timer-status').textContent = 'Готов к работе'; | |
| document.getElementById('start-btn').style.background = ''; | |
| } | |
| /* --- 4. Генератор Цитат --- */ | |
| const quotes = [ | |
| { text: "Единственный способ делать великие дела — любить то, что вы делаете.", author: "Стив Джобс" }, | |
| { text: "Будущее принадлежит тем, кто верит в красоту своей мечты.", author: "Элеонора Рузвельт" }, | |
| { text: "Успех — это не конец, неудача — не фатальна: важна лишь смелость продолжать.", author: "Уинстон Черчилль" }, | |
| { text: "Не считай дни, извлекай из них пользу.", author: "Мухаммед Али" }, | |
| { text: "Простота — высшая форма изысканности.", author: "Леонардо да Винчи" }, | |
| { text: "Твоё время ограничено, не трать его, живя чужой жизнью.", author: "Стив Джобс" } | |
| ]; | |
| function generateQuote() { | |
| const randomIndex = Math.floor(Math.random() * quotes.length); | |
| const quote = quotes[randomIndex]; | |
| // Эффект затухания | |
| const textEl = document.getElementById('quote-text'); | |
| const authorEl = document.getElementById('quote-author'); | |
| textEl.style.opacity = 0; | |
| authorEl.style.opacity = 0; | |
| setTimeout(() => { | |
| textEl.textContent = `"${quote.text}"`; | |
| authorEl.textContent = `— ${quote.author}`; | |
| textEl.style.opacity = 1; | |
| authorEl.style.opacity = 1; | |
| }, 300); | |
| } | |
| // Сначала показываем одну цитату | |
| generateQuote(); | |
| /* --- 5. Система уведомлений (Toast) --- */ | |
| function showToast(message, type = 'info') { | |
| const container = document.getElementById('toast-container'); | |
| const toast = document.createElement('div'); | |
| toast.className = 'toast'; | |
| let icon = 'fa-info-circle'; | |
| let color = 'var(--accent-color)'; | |
| if (type === 'success') { icon = 'fa-check-circle'; color = 'var(--success-color)'; } | |
| if (type === 'error') { icon = 'fa-exclamation-circle'; color = 'var(--danger-color)'; } | |
| toast.style.borderLeftColor = color; | |
| toast.innerHTML = `<i class="fa-solid ${icon}" style="color:${color}"></i> ${message}`; | |
| container.appendChild(toast); | |
| // Удаляем через 3 секунды (время анимации) | |
| setTimeout(() => { | |
| toast.remove(); | |
| }, 3000); | |
| } | |
| </script> | |
| </body> | |
| </html> |