Skip to content

bexelbie/online-compact-calendar

Repository files navigation

Compact Calendar

Live Sites

Compact Calendar is a web-based, year-at-a-glance planner inspired by DSri Seah's Compact Calendar. It's designed for planning questions that regular calendars handle poorly — which weeks are completely free, how holidays and trips overlap, or whether you can turn two public holidays into a long stretch away from work.

Instead of maintaining a separate spreadsheet, Compact Calendar reads your existing calendars (ICS files or URLs) and renders them into a single-page grid of continuous Monday–Sunday weeks. Up to six calendars are color-coded with a colorblind-safe palette, making it easy to see committed versus possible time at a glance and print or share the result.

For more background on why this exists, see the blog post.

screenshot

Features

  • ISO 8601 week numbers, Monday start
  • Two event bands: Committed (green) and Possible (yellow)
  • Load events from ICS files or webcal/HTTPS URLs (e.g., iCloud published calendars)
  • Built-in demo data to explore the calendar without your own files
  • Country-selectable public holidays via Nager.Date API
  • Share your calendar view via a URL — settings are encoded in the URL fragment and never sent to any server
  • Font size controls and print-friendly layout
  • All data stays in the browser (localStorage for preferences and caching)
  • Server-side CORS proxy for fetching remote ICS URLs

Architecture

  • Frontend: Vanilla JavaScript, built with Vite
  • API: Azure Function (Node.js) providing a CORS proxy at /api/ics-proxy
  • Hosting: Azure Static Web Apps
  • Tests: Vitest

Development

npm install
npx vite          # Dev server at http://localhost:5173
npx vitest run    # Run tests
npx vite build    # Build to dist/

The Vite dev server includes a proxy at /api/ics-proxy for local development, mirroring the Azure Function in production.

Project Structure

src/
  calendar-grid.js   # Year grid generation (ISO 8601 weeks)
  holidays.js        # Holiday fetching, caching, country selection
  ics-parser.js      # ICS file parsing (VEVENT extraction)
  renderer.js        # DOM rendering, color precedence, event placement
  main.js            # App orchestration, UI controls, state management
  share.js           # URL-hash-based sharing (encode/decode config)
  styles.css         # Layout, colors, print styles
api/
  src/functions/
    ics-proxy.js     # Azure Function: CORS proxy for ICS URLs
public/
  green-sample.ics          # Demo data: Committed events
  yellow-sample.ics         # Demo data: Possible events
  staticwebapp.config.json  # Azure SWA routing and auth config
test/                # Vitest test suites
index.html           # Single-page app entry point

Deployment

Hosted on Azure Static Web Apps with GitHub Actions CI/CD. Pushes to main trigger automatic builds and deployments. The site is available at cc.bexelbie.com.

Infrastructure Setup

The Azure infrastructure was created with the Azure CLI. To recreate from scratch:

# Create resource group
az group create \
  --name rg-compact-calendar \
  --location westeurope

# Create Static Web App (free tier)
az staticwebapp create \
  --name compact-calendar \
  --resource-group rg-compact-calendar \
  --location westeurope

# Get the deployment token (store as AZURE_STATIC_WEB_APPS_API_TOKEN secret in GitHub)
az staticwebapp secrets list \
  --name compact-calendar \
  --resource-group rg-compact-calendar \
  --query "properties.apiKey" -o tsv

# Configure custom domain
az staticwebapp hostname set \
  --name compact-calendar \
  --resource-group rg-compact-calendar \
  --hostname cc.bexelbie.com

The custom domain requires a CNAME record pointing cc.bexelbie.com to the Static Web App's default hostname:

az staticwebapp show \
  --name compact-calendar \
  --resource-group rg-compact-calendar \
  --query "defaultHostname" -o tsv

The GitHub Actions workflow (.github/workflows/deploy.yml) uses the AZURE_STATIC_WEB_APPS_API_TOKEN secret to authenticate deployments.

Privacy

All preferences (country, calendar URLs, filter settings) are stored in your browser's localStorage. Nothing is sent to third parties or used for tracking.

Calendar URLs necessarily go through the server-side proxy because browsers won't fetch them directly (CORS). The proxy is a stateless pass-through — it does not persist calendar data, in the function or in your browser. Calendar URLs are sent via POST request body rather than query parameters so they are not captured in platform-level request logs. Error logging includes only the target hostname, never the full URL or authentication tokens. If your calendar URL contains authentication tokens (iCloud URLs do), understand that the proxy briefly sees them in transit.

Holiday data is fetched directly from Nager.Date and cached in your browser for 30 days.

License

MIT

About

Compact Calendar based on Dsri Seah's amazing work

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors