<!
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-
scale=1.0, user-scalable=no">
<title>Forest Productivity Tracker</title>
<script src="[Link]
<link rel="stylesheet" href="[Link]
[Link]">
<style>
:root {
--bg-forest: #f8faf9;
--primary: #1e3799;
--prod-intense: #1b5e20;
--waste-intense: #b71c1c;
--sleep-intense: #0d47a1;
--empty: #dfe6e9;
--shadow: 0 4px 15px rgba(0,0,0,0.08);
}
/* STRETCH FIX: Prevent horizontal scroll entirely */
* { box-sizing: border-box; }
body, html {
margin: 0; padding: 0; height: 100%; width: 100%;
background-color: var(--bg-forest);
font-family: -apple-system, system-ui, sans-serif;
overflow-x: hidden;
}
.app-container {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
.content-view {
flex: 1;
overflow-y: auto;
padding: 12px;
padding-bottom: 100px;
-webkit-overflow-scrolling: touch;
}
.week-header {
display: flex; justify-content: space-between; align-items: center;
padding: 10px; background: white; border-radius: 12px;
box-shadow: var(--shadow); margin-bottom: 10px;
}
.week-header h3 { margin: 0; color: var(--primary); font-size: 0.9rem; }
.nav-btn { background: none; border: none; color: var(--primary); font-size: 1.1rem; cursor:
pointer; }
/* DAY PILLS: Responsive container */
.day-selector {
display: flex;
justify-content: space-between;
margin-bottom: 12px;
gap: 4px;
width: 100%;
}
.day-pill {
background: white; border-radius: 8px;
padding: 6px 0;
flex: 1;
min-width: 0;
text-align: center; cursor: pointer;
box-shadow: var(--shadow); border: 2px solid transparent;
}
.day-pill span { display: block; font-size: 0.5rem; color: #7f8c8d; }
.day-pill b { font-size: 0.8rem; color: #2d3436; }
.[Link] { background: var(--primary); border-color: #4a69bd; }
.[Link] span, .[Link] b { color: white; }
/* GRID FIX: Calc width to prevent right-edge leakage */
.hour-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 8px;
margin-bottom: 15px;
width: calc(100% - 2px);
}
.hour-box {
background: var(--empty); border-radius: 10px;
aspect-ratio: 1/1; display: flex; flex-direction: column;
align-items: center; justify-content: center;
cursor: pointer; position: relative; border: 1px solid rgba(0,0,0,0.05);
}
.hour-label { font-size: 0.42rem; font-weight: 800; position: absolute; bottom: 4px; width:
100%; text-align: center; color: inherit; }
.[Link]-1 { background-color: var(--prod-intense) !important; color: white; }
.[Link]-2 { background-color: var(--waste-intense) !important; color: white; }
.[Link]-3 { background-color: var(--sleep-intense) !important; color: white; }
/* ICON FIX: Using FontAwesome for all states to avoid symbols failing */
.icon-box {
font-size: 1.2rem;
margin-top: -6px;
display: flex;
align-items: center;
justify-content: center;
}
.card { background: white; border-radius: 15px; padding: 12px; box-shadow: var(--
shadow); margin-bottom: 12px; width: 100%; }
.stats-row { display: flex; justify-content: space-around; text-align: center; font-size:
0.8rem; }
.home-chart-container { height: 110px; width: 100%; }
.ana-chart-container { height: 160px; width: 100%; }
.analytics-nav { display: flex; background: #eee; border-radius: 8px; padding: 3px; margin-
bottom: 15px; }
.analytics-nav button { flex: 1; border: none; padding: 8px; border-radius: 6px; font-size:
0.75rem; cursor: pointer; background: transparent; }
.analytics-nav [Link] { background: white; color: var(--primary); box-shadow: var(--
shadow); }
.bottom-nav { position: fixed; bottom: 0; left: 0; right: 0; background: white; display: flex;
justify-content: space-around; padding: 10px 0 25px; border-top: 1px solid #eee; z-index: 100; }
.nav-item { border: none; background: none; color: #b2bec3; font-size: 0.75rem; font-
weight: bold; cursor: pointer; }
.[Link] { color: var(--primary); }
.nav-item i { display: block; font-size: 1.3rem; margin-bottom: 4px; }
.hidden { display: none !important; }
</style>
</head>
<body>
<div class="app-container">
<div id="main-content" class="content-view">
<div id="home-section">
<div class="week-header">
<button class="nav-btn" onclick="changeWeek(-1)"><i class="fas
fa-chevron-left"></i></button>
<h3 id="week-label">---</h3>
<button class="nav-btn" onclick="changeWeek(1)"><i class="fas fa-chevron-
right"></i></button>
</div>
<div class="day-selector" id="day-pill-container"></div>
<div class="hour-grid" id="grid-container"></div>
<div class="card"><div class="stats-row">
<div style="color: var(--prod-intense);"><b>Focus</b><br><span id="sum-
prod">0h</span></div>
<div style="color: var(--sleep-intense);"><b>Sleep</b><br><span id="sum-
sleep">0h</span></div>
<div style="color: var(--waste-intense);"><b>Waste</b><br><span id="sum-
waste">0h</span></div>
</div></div>
<div class="card"><div class="home-chart-container"><canvas
id="homeDayChart"></canvas></div></div>
</div>
<div id="analytics-section" class="hidden">
<div class="analytics-nav">
<button id="tab-weekly" class="active"
onclick="setScope('weekly')">Weekly</button>
<button id="tab-monthly" onclick="setScope('monthly')">Monthly</button>
<button id="tab-yearly" onclick="setScope('yearly')">Yearly</button>
<button id="tab-custom" onclick="setScope('custom')">Custom</button>
</div>
<div id="custom-date-picker" class="hidden custom-range-box">
<div class="range-inputs">
<div class="range-row"><label>FROM:</label><input type="date" id="start-date"
onchange="renderAnalyticsCharts('custom')"></div>
<div class="range-row"><label>TO:</label><input type="date" id="end-date"
onchange="renderAnalyticsCharts('custom')"></div>
</div>
</div>
<div class="card"><div class="ana-chart-container"><canvas
id="anaBarChart"></canvas></div></div>
<div class="card"><div class="ana-chart-container"><canvas
id="anaLineChart"></canvas></div></div>
</div>
</div>
<nav class="bottom-nav">
<button id="nav-home" class="nav-item active" onclick="switchView('home')"><i
class="fas fa-home"></i>Home</button>
<button id="nav-analytics" class="nav-item" onclick="switchView('analytics')"><i
class="fas fa-chart-pie"></i>Analytics</button>
</nav>
</div>
<script>
const hours = ["6AM-7AM", "7AM-8AM", "8AM-9AM", "9AM-10AM", "10AM-11AM",
"11AM-12PM", "12PM-1PM", "1PM-2PM", "2PM-3PM", "3PM-4PM", "4PM-5PM", "5PM-
6PM", "6PM-7PM", "7PM-8PM", "8PM-9PM", "9PM-10PM", "10PM-11PM", "11PM-12AM",
"12AM-1AM", "1AM-2AM", "2AM-3AM", "3AM-4AM", "4AM-5AM", "5AM-6AM"];
let currentDate, selectedDate;
let masterData = [Link]([Link]('forestData')) || {};
let homeChart, anaBar, anaLine;
function save() { [Link]('forestData', [Link](masterData)); }
function getDBKey(date) {
const y = [Link]();
const m = String([Link]() + 1).padStart(2, '0');
const d = String([Link]()).padStart(2, '0');
return `${y}-${m}-${d}`;
}
function initApp() {
const today = new Date();
currentDate = new Date([Link](), [Link](), [Link]());
selectedDate = new Date(currentDate);
const startOfMonth = new Date([Link](), [Link](), 1);
[Link]('start-date').value = getDBKey(startOfMonth);
[Link]('end-date').value = getDBKey(today);
renderDayPills();
renderGrid();
}
function renderDayPills() {
const container = [Link]('day-pill-container');
[Link] = '';
const start = new Date(currentDate);
[Link]([Link]() - [Link]());
for (let i = 0; i < 7; i++) {
const d = new Date(start); [Link]([Link]() + i);
const pill = [Link]('div');
[Link] = `day-pill ${[Link]() === [Link]() ? 'active' :
''}`;
[Link] = () => { selectedDate = new Date(d); renderDayPills(); renderGrid(); };
[Link] =
`<span>${[Link]('en-US',{weekday:'short'})}</span><b>${[Link]()}</b>`;
[Link](pill);
}
[Link]('week-label').innerText = [Link]('en-
US', { month:'long', year:'numeric'});
}
function renderGrid() {
const grid = [Link]('grid-container');
[Link] = '';
const key = getDBKey(selectedDate);
if (!masterData[key]) masterData[key] = Array(24).fill(0);
masterData[key].forEach((state, i) => {
const box = [Link]('div');
[Link] = `hour-box state-${state}`;
let iconHtml = '';
// State Symbols: Green = Tree, Red = Times, Blue = Moon
if(state === 1) iconHtml = '<i class="fas fa-leaf"></i>';
else if(state === 2) iconHtml = '<i class="fas fa-times"></i>';
else if(state === 3) iconHtml = '<i class="fas fa-moon"></i>';
[Link] = `<div class="icon-box">${iconHtml}</div><div class="hour-
label">${hours[i]}</div>`;
[Link] = () => {
masterData[key][i] = (masterData[key][i] + 1) % 4;
save();
renderGrid();
if(.[Link]('hidden')) {
renderAnalyticsCharts([Link]('.analytics-nav
[Link]').[Link]('tab-', ''));
}
};
[Link](box);
});
updateSummary(masterData[key]);
drawHomeChart(masterData[key]);
}
function drawHomeChart(data) {
const ctx = [Link]('homeDayChart').getContext('2d');
if (homeChart) [Link]();
homeChart = new Chart(ctx, {
type: 'bar',
data: {
labels: [Link](h => [Link]('-')[0]),
datasets: [{
data: [Link](s => s === 1 ? 1 : (s === 2 ? 0.3 : (s === 3 ? 0.6 : 0.05))),
backgroundColor: [Link](s => s === 1 ? '#1b5e20' : (s === 2 ? '#b71c1c' : (s ===
3 ? '#0d47a1' : '#dfe6e9'))),
borderRadius: 2
}]
},
options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false
} }, scales: { y: { display: false }, x: { grid: { display: false }, ticks: { font: { size: 6 } } } } }
});
}
function setScope(scope) {
[Link]('.analytics-nav button').forEach(b =>
[Link]('active'));
[Link](`tab-${scope}`).[Link]('active');
[Link]('custom-date-picker').[Link]('hidden', scope !==
'custom');
renderAnalyticsCharts(scope);
}
function getProdHours(date) {
const key = getDBKey(date);
return (masterData[key] || []).filter(s => s === 1).length;
}
function renderAnalyticsCharts(scope) {
if (anaBar) [Link]();
if (anaLine) [Link]();
let labels = [], dataValues = [];
if (scope === 'weekly') {
labels = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
const startOfWeek = new Date(currentDate); [Link]([Link]()
- [Link]());
for(let i=0; i<7; i++) {
let d = new Date(startOfWeek); [Link]([Link]() + i);
[Link](getProdHours(d));
}
} else if (scope === 'custom') {
const startStr = [Link]('start-date').value;
const endStr = [Link]('end-date').value;
if(!startStr || !endStr) return;
let d = new Date(startStr);
const end = new Date(endStr);
while (d <= end) {
[Link]([Link]('en-US', { month: 'short', day: 'numeric' }));
[Link](getProdHours(d));
[Link]([Link]() + 1);
}
} else if (scope === 'yearly') {
labels = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
dataValues = [Link](() => [Link]([Link]() * 80)); // Placeholder for yearly
data
} else { // monthly
for(let i=29; i>=0; i--) {
let d = new Date(); [Link]([Link]() - i);
[Link]([Link]());
[Link](getProdHours(d));
}
}
const commonOpts = { responsive: true, maintainAspectRatio: false, scales: { x: { ticks:
{ font: { size: [Link] > 10 ? 6 : 8 } } } } };
anaBar = new Chart([Link]('anaBarChart'), {
type: 'bar',
data: { labels, datasets: [{ label: 'Focus Hours', data: dataValues, backgroundColor:
'#1b5e20', borderRadius: 4 }] },
options: commonOpts
});
anaLine = new Chart([Link]('anaLineChart'), {
type: 'line',
data: { labels, datasets: [{ label: 'Trend', data: dataValues, borderColor: '#1e3799',
tension: 0.4, fill: true, backgroundColor: 'rgba(30, 55, 153, 0.1)' }] },
options: commonOpts
});
}
function switchView(view) {
[Link]('home-section').[Link]('hidden', view !== 'home');
[Link]('analytics-section').[Link]('hidden', view !==
'analytics');
[Link]('nav-home').[Link]('active', view === 'home');
[Link]('nav-analytics').[Link]('active', view === 'analytics');
if(view === 'analytics') renderAnalyticsCharts([Link]('.analytics-nav
[Link]').[Link]('tab-', ''));
}
function changeWeek(dir) {
[Link]([Link]() + (dir * 7));
selectedDate = new Date(currentDate);
renderDayPills();
renderGrid();
}
function updateSummary(data) {
[Link]('sum-prod').innerText = [Link](s => s === 1).length + 'h';
[Link]('sum-waste').innerText = [Link](s => s === 2).length + 'h';
[Link]('sum-sleep').innerText = [Link](s => s === 3).length + 'h';
}
initApp();
</script>
</body>
</html>