aboutsummaryrefslogtreecommitdiffstats

ccc

Coffee Cups Contributions. A single-file, dependency-free coffee intake tracker with a GitHub-style heatmap. No build step, no framework, plain HTML, CSS, and JavaScript.

Live at coffee.gumx.cc. Source at git.gumx.cc/ccc.


Features

  • Contributions heatmap: 53 x 7 grid (Sunday-aligned) covering the past 52 weeks, rendered in SVG. Month labels along the top, Mon/Wed/Fri labels on the left. Today's cell has a visible outline.
  • 5-level greyscale scale: cup counts are bucketed proportionally to MAX_CUPS using Math.round. A legend is shown below the heatmap.
  • Hover tooltips: hovering any cell shows the date and cup count in a fixed-position tooltip.
  • Two modes: local mode (full editing, localStorage) or static site mode (read-only, fetches from a remote URL).
  • Stats: today's cups, current streak, total cups, and daily average.
  • Light and dark mode: full prefers-color-scheme support via CSS custom properties. The heatmap re-renders if the OS theme changes mid-session.

Files

File Description
ccc.html The entire application: one self-contained HTML file
data.json Example data file for static site mode
README.md This document
LICENSE MIT licence

Local Mode

Local mode is active when DATA_URL is set to "" (the default). All data is persisted to localStorage under the key ccc_v1.

Logging Coffee

A − / count / + adjuster lets you set how many cups to log (1–10). The + button disables when logCount would exceed the remaining cups for today. The log coffee button disables when today has already reached MAX_CUPS. Both controls re-evaluate after every action.

Clicking log coffee adds the selected count to today's total, hard-capped at MAX_CUPS.

Editing Past Days

Click any heatmap cell to open an inline popover for that day. The popover shows:

  • The date
  • − / number input / + to adjust the count (0–MAX_CUPS)
  • set and cancel buttons

Keyboard shortcuts work inside the popover: Enter confirms, Escape cancels. Clicking anywhere outside the popover also cancels. Setting a day's count to 0 removes the entry entirely.

A hint below the log controls reads: "click any cell to edit that day's count".

Import and Export

  • Export JSON: downloads your current data as ccc-data.json.
  • Import JSON: opens a file picker; selecting a valid JSON file replaces the current data. Invalid files show an alert.

The data format is described below.


Static Site Mode

Static site mode is active when DATA_URL is set to a non-empty URL string. On load, the app fetches data.json (or whatever file is at that URL) and renders the heatmap from it.

In static site mode:

  • All editing controls are hidden.
  • Import and export are unavailable.
  • A "static site mode: read-only" notice appears below the title.
  • Data is never written to localStorage.

To use static site mode, host ccc.html and data.json on any static hosting service (GitHub Pages, Netlify, etc.), then set DATA_URL to the full URL of data.json.


Configuration

The CONFIG block is at the top of the <script> tag in ccc.html:

const CONFIG = {
  DATA_URL: "",   // "" = local mode | "<url>" = static site mode
  MAX_CUPS: 6,    // maximum cups allowed per day
  WEEK_START: 1,  // first day of the week: 0=Sun, 1=Mon, 2=Tue, 3=Wed, 4=Thu, 5=Fri, 6=Sat
};
Option Type Default Description
DATA_URL string "" URL to fetch data.json from. Empty string activates local mode.
MAX_CUPS integer 6 Maximum cups allowed per day. Controls the colour scale and log/edit caps.
WEEK_START integer 1 First day of the week. 0 = Sunday, 1 = Monday (ISO default), through 6 = Saturday. Affects the heatmap column alignment and day labels.

Data Format

Data is stored as a JSON object with a single entries key. Each entry is a date string (YYYY-MM-DD) mapped to a cup count (integer, 1–MAX_CUPS). Days with zero cups are omitted.

{
  "entries": {
    "2026-04-07": 3,
    "2026-04-08": 2
  }
}
  • Dates must match the pattern YYYY-MM-DD.
  • Values must be positive integers. Zero or negative values are ignored on import.
  • Values exceeding MAX_CUPS are clamped on import.
  • Deleting an entry (setting it to 0 via the cell editor) removes the key entirely.

Licence

MIT. see LICENSE.