правим/добавляем в скрипте, все понятно (легко подстраивается и фейс/стили):
class="char-group" - группа
class="char-name" - название
class="task" - задача :
id="mag_daily" - людое уникальное, нагляднее составное от группы и таска
data-cooldown="daily" - тип кд, варианты daily (сброс по указанному в RESET_HOUR), число часов, или async - вручную
class="cooldown"> - текстовый вар-т
Код HTML:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>WoW ToDo Трекер (lite)</title>
<style>
body { font-family: 'Segoe UI', Arial, sans-serif; background: #121212; color: #e0e0e0; padding: 25px; margin: 0; }
.container { max-width: 1500px; margin: 0 auto; background: #1e1e1e; padding: 20px; border-radius: 8px; box-shadow: 0 4px 15px rgba(0,0,0,0.5); }
.header-box { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #333; padding-bottom: 15px; margin-bottom: 20px; }
h1 { color: #f5a623; font-size: 22px; margin: 0; }
/* Кнопка ручного сброса всех галочек */
.reset-btn { background: #c0392b; color: #fff; border: none; padding: 8px 15px; border-radius: 4px; font-weight: bold; cursor: pointer; transition: background 0.2s; }
.reset-btn:hover { background: #e74c3c; }
/* Сетка в два столбца для групп персонажей */
.columns-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; }
/* Адаптивность: если окно узкое, переключит в 1 столбец */
[MENTION=275396]MeDiA[/MENTION] (max-width: 768px) {
.columns-grid { grid-template-columns: 1fr; }
}
.char-group { border: 1px solid #2a2a2a; border-radius: 6px; background: #161616; padding: 15px; display: flex; flex-direction: column; }
.char-name { font-weight: bold; color: #4a90e2; font-size: 16px; margin-bottom: 12px; border-bottom: 1px dashed #333; padding-bottom: 6px; }
.task { display: flex; align-items: center; margin: 6px 0; font-size: 14px; }
input[type="checkbox"] { margin-right: 12px; width: 18px; height: 18px; cursor: pointer; accent-color: #f5a623; flex-shrink: 0; }
.cooldown { color: #888; font-size: 11px; margin-left: auto; background: #222; padding: 2px 6px; border-radius: 4px; border: 1px solid #333; flex-shrink: 0; }
.checked { color: #666; text-decoration: line-through; }
</style>
</head>
<body>
<div class="container">
<div class="header-box">
<h1>Персонажи</h1>
<button class="reset-btn" id="clear_all_btn">Сбросить всё вручную</button>
</div>
<!-- НАЧАЛО СЕТКИ В ДВА СТОЛБЦА -->
<div class="columns-grid">
<!-- СТОЛБЕЦ 1: ПЕРСОНАЖ 1 -->
<div class="char-group">
<div class="char-name">Маг (Начертание / Алхимия)</div>
<div class="task"><input type="checkbox" id="mag_daily" data-cooldown="daily"> <span>Дейлик в кулинарию</span> <span class="cooldown">6:00</span></div>
<div class="task"><input type="checkbox" id="mag_ink" data-cooldown="daily"> <span>Исследование начертания</span> <span class="cooldown">6:00</span></div>
<div class="task"><input type="checkbox" id="mag_titan" data-cooldown="20"> <span>Трансмутация: Титановая сталь</span> <span class="cooldown">20 ч</span></div>
</div>
<!-- СТОЛБЕЦ 2: ПЕРСОНАЖ 2 -->
<div class="char-group">
<div class="char-name">Паладин (Ювелирка)</div>
<div class="task"><input type="checkbox" id="pal_daily" data-cooldown="daily"> <span>Ювелирный дейлик</span> <span class="cooldown">6:00</span></div>
<div class="task"><input type="checkbox" id="pal_heroic" data-cooldown="daily"> <span>рандом ППг</span> <span class="cooldown">6:00</span></div>
</div>
<!-- СТОЛБЕЦ 1 (ПРОДОЛЖЕНИЕ): ПЕРСОНАЖ 3 -->
<div class="char-group">
<div class="char-name">Друид (Травничество)</div>
<div class="task"><input type="checkbox" id="dru_olo" data-cooldown="2.5"> <span>Проверить траву на ОЛО</span> <span class="cooldown">2.5 ч</span></div>
</div>
<!-- СТОЛБЕЦ 2 (ПРОДОЛЖЕНИЕ): ПЕРСОНАЖ 4 -->
<div class="char-group">
<div class="char-name">Жрец (Портняжное дело)</div>
<div class="task"><input type="checkbox" id="priest_cloth" data-cooldown="async"> <span>Сшить Иссиня-черную ткань</span> <span class="cooldown">Без КД</span></div>
<div class="task"><input type="checkbox" id="priest_weekly" data-cooldown="async"> <span>Сдать реги на еженедельник</span> <span class="cooldown">Вручную</span></div>
</div>
</div> <!-- КОНЕЦ СЕТКИ -->
</div>
<script>
const RESET_HOUR = 6; // Час ежедневного сброса WoW
// Функция проверки наступления 6 утра
function isDailyResetPast(savedTime) {
const lastCheck = new Date(savedTime);
const now = new Date();
const todayReset = new Date(now.getFullYear(), now.getMonth(), now.getDate(), RESET_HOUR, 0, 0);
if (now < todayReset) todayReset.setDate(todayReset.getDate() - 1);
return lastCheck < todayReset;
}
// Инициализация и автоматическая проверка КД при открытии страницы
function initTracker() {
document.querySelectorAll('input[type="checkbox"]').forEach(cb => {
const savedData = localStorage.getItem(cb.id);
const taskText = cb.nextElementSibling;
if (savedData) {
const data = JSON.parse(savedData);
const type = cb.getAttribute('data-cooldown');
const now = Date.now();
let shouldReset = false;
if (type === 'daily') {
shouldReset = isDailyResetPast(data.time);
} else if (type !== 'async') {
// Почасовое КД (20 часов, 2.5 часа и т.д.)
const hoursInMs = parseFloat(type) * 60 * 60 * 1000;
shouldReset = (now - data.time) >= hoursInMs;
}
if (shouldReset) {
localStorage.removeItem(cb.id);
cb.checked = false;
taskText.classList.remove('checked');
} else {
cb.checked = data.checked;
if (data.checked) taskText.classList.add('checked');
}
}
// Навешиваем клик на чекбокс (если еще не навешан)
if (!cb.dataset.hasListener) {
cb.addEventListener('change', () => {
const tText = cb.nextElementSibling;
if (cb.checked) {
tText.classList.add('checked');
localStorage.setItem(cb.id, JSON.stringify({ checked: true, time: Date.now() }));
} else {
tText.classList.remove('checked');
localStorage.removeItem(cb.id);
}
});
cb.dataset.hasListener = "true";
}
});
}
// Логика для кнопки полного сброса
document.getElementById('clear_all_btn').addEventListener('click', () => {
if (confirm('Вы уверены, что хотите сбросить ВСЕ задачи для всех персонажей?')) {
// Удаляем из локальной памяти только ключи задач (оставляем системные, если будут)
document.querySelectorAll('input[type="checkbox"]').forEach(cb => {
localStorage.removeItem(cb.id);
cb.checked = false;
cb.nextElementSibling.classList.remove('checked');
});
}
});
// Запуск при старте
initTracker();
</script>
</body>
</html>
[свернуть]