Skip to content

Latest commit

 

History

106 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

hash-calendar logo

hash-calendar

hash-calendar is a privacy-first, client-only calendar.
Your data lives in the URL hash, so sharing is just copying a link.

Live site: https://hash-calendar.netlify.app/
GitHub: https://github.com/supunlakmal/hash-calendar

Demo

hash-calendar demo video

Highlights

  • Multi-language UI (English, Sinhala, Tamil, Italian)
  • Mobile drawer menu with quick icon actions
  • Timeline view with zoom controls and minimap navigation
  • Command palette (Ctrl/Cmd+K) and dedicated event search modal
  • Starter template gallery for opening prebuilt schedules
  • Optional browser notifications for upcoming events
  • World Planner modal (multi-timezone planning grid with scrubber and 12h/24h toggle)
  • App launcher menu in the top bar
  • PWA support (manifest + service worker cache)
  • JSON bridge page (json.html) for raw JSON -> hash URL redirect
  • Direct-link event creation from human-readable URL paths

Features

Calendar and planning

  • Day, week, month, year, agenda, and timeline views
  • Create, edit, delete, recurring, all-day, and cross-day timed events
  • Color palette support and editable calendar title
  • Focus mode overlay with timer and upcoming list
  • "Up Next" countdown widget
  • Timeline controls: zoom in/out, zoom slider, minimap scrubber, and "Center Today"

Search and productivity

  • Command palette (Ctrl/Cmd+K) for quick actions and view switching
  • Event search modal with keyboard navigation
  • Advanced event filters: date range, recurrence, color, and timezone
  • Template gallery modal with curated ready-to-use calendar links

Read-only mode

  • Dedicated read-only toggle (switch between edit and read-only)
  • In read-only mode, edit-heavy controls are hidden on desktop and mobile:
    • Add event actions
    • Add world-clock/timezone actions
    • Share and export section
    • Danger zone section
  • Read-only state is saved in the URL hash (s.r) so shared links open with the same mode

Share and portability

  • URL-hash state with LZ-String compression
  • Copy-link and QR share (with URL length guard)
  • View/copy JSON and raw hash from modal
  • Export JSON
  • Import .ics (supports daily/weekly/monthly/yearly RRULE frequency mapping)
  • One-time import from hash-path URLs, then auto-save to compressed hash

Timezone tools

  • World Clock sidebar with saved zones
  • Timezone search by city/region or UTC offset
  • World Planner with timezone comparison grid

Privacy and security

  • Optional password lock using AES-GCM + PBKDF2 (150k iterations, SHA-256)
  • Encrypted links start with #ENC:
  • No backend, no accounts, no server-side storage
  • Analytics is configured to avoid sending URL hash data

UX and platform

  • Theme toggle (light/dark)
  • Week start toggle (Sunday/Monday)
  • Optional browser notifications for upcoming events
  • URL length meter + warning
  • Mobile hamburger drawer + quick action buttons
  • Installable PWA with offline caching of app assets

Screenshots

hash-calendar demo 1 hash-calendar demo 2
hash-calendar demo 3 hash-calendar demo 4
hash-calendar demo 5 hash-calendar demo 6
hash-calendar demo 7 hash-calendar demo 8
hash-calendar demo 9 hash-calendar demo 10
hash-calendar demo 11 hash-calendar demo 12
hash-calendar demo 13

Getting started

Open index.html directly, or run a local server:

npx serve .

Alternative:

python -m http.server 8080

Docker run

docker compose up --build

Default ports are 80 and 443 (override with HOST_PORT_HTTP / HOST_PORT_HTTPS).

E2E testing (Playwright)

Install dependencies and browsers once:

npm install
npm run test:e2e:install

Run the E2E suite:

npm run test:e2e

Useful local modes:

npm run test:e2e:chromium
npm run test:e2e:mobile
npm run test:e2e:cross
npm run test:e2e:headed
npm run test:e2e:ui
npm run test:e2e:debug
npm run test:e2e:report

Notes:

  • test:e2e runs all configured Playwright projects.
  • Firefox/WebKit run the cross-browser smoke suite (tests/e2e/smoke.cross.e2e.spec.js).
  • Full feature coverage runs on Chromium desktop, plus mobile-focused coverage on the mobile Chromium project.

JSON bridge (json.html)

Use json.html to pass JSON payloads via query params (json, data, state, payload) and auto-redirect to a compressed hash URL.

Direct-link event creation (hash-path URLs)

You can create events directly from hash-path URLs. Use a hash-path beginning with /, for example:

  • #/2025/12/25/10/30/Open-Presents

Supported patterns:

Pattern Scenario Example
YYYY/MM/DD/HH/mm/Title Full precision #/2025/12/25/10/30/Open-Presents
YYYY/MM/DD/Title All-day #/2025/12/25/Christmas-Day
YYYY/MM/DD/HH/mm+Minutes/Title Timed with explicit duration #/2025/12/25/10/00+90/Family-Brunch
Event1,Event2 Multi-event in one link #/2025/01/01/Gym,2025/01/01/10/00/Clean

Behavior notes:

  • URL segments are decoded (decodeURIComponent), and dashes in titles become spaces.
  • If title is missing, it falls back to New Event (URL).
  • Parsed events are appended once, then the hash-path is cleaned and state is persisted as the normal compressed URL hash.

How it works

  1. State is serialized to JSON.
  2. JSON is compacted and compressed into the URL hash.
  3. Optional password encryption wraps the compressed payload.
  4. Opening the link restores the full calendar state in-browser.

If there is no non-default calendar data (events, saved timezones, or changed settings), the hash is cleared automatically.

URL hash payload (compact schema)

Example (before compression):

{
  "t": "Acme Schedule",
  "c": { "1": "2ecc71", "3": "e74c3c" },
  "e": [
    [28930080, 30, "Daily standup", 1, "d"],
    [28930200, 0, "Launch day", 3],
    [28930800, 90, "Design review"]
  ],
  "s": { "d": 1, "m": 1, "v": "week", "l": "en", "r": 1, "n": 1 },
  "mp": {
    "h": "America/Los_Angeles",
    "z": ["UTC", "Asia/Tokyo", "Europe/London"],
    "s": 1769721600000,
    "d": "2026-01-30",
    "f24": 1
  }
}

Key fields:

  • t: title
  • c: color overrides by palette index (hex without #)
  • e: events as [startMin, duration, title, colorIndex?, recurrence?]
  • s: settings (d theme, m week start, v last view, l language, r read-only mode, n notifications toggle)
  • mp: optional world-time snapshot (h home zone, z saved zones, s scrubber timestamp, d planner date, f24 24-hour mode)

Recurrence values: d (daily), w (weekly), m (monthly), y (yearly)

Legacy compatibility: older payloads with top-level z / timezones / tz are still read and migrated into mp.z.

Project structure

  • index.html - main app UI
  • script.js - app state, events, rendering orchestration
  • json.html - JSON payload bridge page
  • styles.css, styles-i18n.css, styles-logo.css - styles
  • sw.js, manifest.json - PWA setup
  • locales/ - translation dictionaries
  • modules/
    • calendarRender.js - month/week/day/year rendering
    • agendaRender.js - agenda rendering
    • timelineRender.js - timeline rendering and event lane layout
    • constants.js - shared app constants
    • cacheElements.js - centralized DOM element lookup
    • recurrenceEngine.js - recurrence expansion
    • countdownManager.js - "Up Next" widget
    • eventSearchModule.js - event search modal controller
    • focusMode.js - focus overlay
    • modalManager.js - reusable password/JSON modal controllers
    • stateSaveManager.js - debounced state persistence orchestration
    • responsiveFeatures.js - mobile drawer and responsive helpers
    • timezoneManager.js - timezone helpers
    • worldPlannerModule.js - world planner modal logic
    • qrCodeManager.js - QR modal logic
    • icsImporter.js - .ics parser
    • templateGallery.js - template gallery modal + link handling
    • template-gallery-links.json - built-in starter templates
    • hashcalUrlManager.js - compact/read/write hash state
    • cryptoManager.js - encryption/decryption helpers
    • i18n.js - localization engine
    • app_launcher.js - app launcher menu
    • pathImportManager.js - one-time hash-path import + rewrite logic
    • urlPathEventParser.js - readable URL path parser for event creation
    • lz-string.min.js - compression library
  • demo/ - screenshot assets
  • tests/e2e/ - Playwright end-to-end coverage for desktop/mobile/cross-browser flows
  • Dockerfile, docker-compose.yaml, Caddyfile - containerized deployment

License

MIT. See LICENSE.

About

lightweight, client-only calendar web application. All data persists in the URL hash for instant sharing, No backend required. Optional AES-GCM password protection keeps shared links locked without a server

Resources

Code of conduct

Contributing

Security policy

Stars

70 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages