DEV Community

Zayan Mohamed
Zayan Mohamed

Posted on

Homepage Dev Control Center

Are you tired of fighting with restrictive Google Workspace calendar permissions just to see your next daily standup on your dashboard? You are not alone. Building a clean developer start page should not require exposing your private schedule to the public internet or wrestling with complex OAuth flows.

I put together a ready-to-run gethomepage/homepage dashboard config that includes a self-contained meeting countdown and live timer. It needs no API key, no public calendar, and no OAuth – it is pure JavaScript injected through Homepage's custom.js.

Point it at a service, get a clean developer start page. The bonus is a floating card that counts down to your next meeting and turns into a live "30m left" timer while it is running.


Why This Exists

Homepage's built-in Calendar widget can only read an unauthenticated .ics feed. On a Google Workspace account, the private or secret iCal address is disabled by default. Usually, only an admin can turn it on, and making your work calendar public is simply a non-starter for most professionals.

So instead of fighting the calendar, this repository ships a dependency-free timer: you declare your recurring meeting once in config/custom.js and get a live countdown on the dashboard – no keys, no sharing, and no admin approval required.

(If you do have a private .ics link, there is a ready-made block to switch to a real live feed – see the Optional section below.)


Features

  • Meeting timer – counts down to the next occurrence, flips to a live "time left" timer during the meeting, then rolls to the next one.
  • Recurring & multi-meeting – per-meeting weekday rules ([1,2,3,4,5] for weekdays, etc.) and as many meetings as you want.
  • Live state – a pulsing indicator and "click to join" (opens your Meet/Zoom link) while running.
  • Zero credentials – no API key, no OAuth, no public calendar required.
  • Docker Compose – one command to run.
  • Dark, glassy theme – configured with a background image, blurred cards, and weather/system widgets.

Screenshot

Here is a look at the dashboard in action:

GitHub logo Zayan-Mohamed / homepage-dev-dashboard

A self-hosted gethomepage/homepage dashboard with a zero-dependency meeting countdown & live timer — no API key, no public calendar, no OAuth. Pure custom.js.

Homepage Dev Control Center — with a no-API-key Meeting Timer

A ready-to-run gethomepage/homepage dashboard config, plus a self-contained meeting countdown / live timer that needs no API key, no public calendar, and no OAuth — it's pure JavaScript injected through Homepage's custom.js.

Point it at a service, get a clean developer start page. The bonus is a floating card that counts down to your next meeting and turns into a live "🔴 30m left" timer while it's running.


Table of contents


Why this exists

Homepage's built-in Calendar widget can only read an unauthenticated .ics feed. On a Google Workspace account the private/secret iCal address is disabled by default and only an admin…


Prerequisites

  • Docker and Docker Compose
  • Port 8080 free on the host (change it in docker-compose.yml if needed)

Quick Start

git clone https://github.com/Zayan-Mohamed/homepage-dev-dashboard.git

cd homepage-dev-dashboard/

# Create your local config from the templates (these hold personal links,
# so they are git-ignored – the repo ships *.example versions).
cp config/services.yaml.example config/services.yaml
cp config/custom.js.example      config/custom.js

docker compose up -d

Enter fullscreen mode Exit fullscreen mode

Open http://localhost:8080, then edit config/services.yaml (your links) and config/custom.js (your meetings).

To apply config changes later:

docker compose restart homepage

Enter fullscreen mode Exit fullscreen mode

Homepage hot-reloads most config/*.yaml changes, but custom.js, custom.css, and the favicon are cached by the browser – do a hard refresh (Ctrl/Cmd + Shift + R) after editing.


Repository Layout

.
├── docker-compose.yml        # Homepage container (port 8080 -> 3000)
├── images/                   # Static assets served at /images (background, icons)
│   └── anime-bg.jpg          # Dashboard background
└── config/
    ├── settings.yaml         # Title, theme, background, layout, favicon
    ├── services.yaml         # Service cards (Meetings, Dev, Cloud, AI, …)
    ├── widgets.yaml          # Info widgets (weather, clock, resources, search)
    ├── bookmarks.yaml        # Bookmark links
    ├── docker.yaml           # Docker integration
    ├── custom.css            # Styles for the meeting-timer card
    ├── services.yaml.example # Template -> copy to services.yaml
    └── custom.js.example     # Template -> copy to custom.js (the meeting timer)

Enter fullscreen mode Exit fullscreen mode

The Meeting Timer

Configuring Your Meetings

Open config/custom.js and edit the MEETINGS array near the top:

const MEETINGS = [
  {
    title: "Standup",
    start: "20:30",                 // 24-hour "HH:MM", dashboard host's local time
    end:   "21:15",
    days:  [0, 1, 2, 3, 4, 5, 6],   // 0=Sun … 6=Sat. Use [1,2,3,4,5] for weekdays
    join:  "https://meet.google.com/your-room",  // optional – card becomes clickable
  },
  // add more meetings as needed…
];

Enter fullscreen mode Exit fullscreen mode
Field Meaning
title Label shown on the card
start Start time, 24-hour HH:MM
end End time, 24-hour HH:MM
days Array of weekdays it recurs on (0=Sunday … 6=Saturday)
join Optional URL; while live/soon the whole card links to it (new tab)

When several meetings are defined, a live one always wins; otherwise, the soonest upcoming meeting is shown.

How It Behaves

Situation Card Shows
Before the meeting Standup · today · 8:30 PMstarts in 2h 05m 12s
During the meeting Standup · live30m 00s left (pulsing indicator)
After it ends rolls forward to the next occurrence
No meeting scheduled No meetings scheduled

The card is a fixed element in the bottom-right (full-width on mobile). Restyle it in config/custom.css under the #meeting-timer selector.

Timezone Note

Times are evaluated in the timezone of the machine running the container, not your browser. If the host clock differs from where you actually are, set the container timezone in docker-compose.yml:

    environment:
      HOMEPAGE_ALLOWED_HOSTS: localhost:8080
      TZ: Asia/Colombo        # <- your timezone

Enter fullscreen mode Exit fullscreen mode

Optional: Live Google Calendar Feed (No API Key)

If your Google admin enables "Share all information, but outsiders cannot change calendars", you get a Secret address in iCal format (private, not publicly discoverable, no API key).
config/services.yaml already contains a commented-out block – paste your link into url: and uncomment it:

- Upcoming:
    widget:
      type: calendar
      view: agenda
      maxEvents: 10
      showTime: true
      integrations:
        - type: ical
          url: https://calendar.google.com/calendar/ical/you%40example.com/private-XXXXXXXX/basic.ics
          name: Meetings
          color: green

Enter fullscreen mode Exit fullscreen mode

Homepage's calendar widget supports only unauthenticated .ics (and the arr apps) – no CalDAV, OAuth, basic-auth, or custom headers. The **public* .ics address works too but exposes event details to anyone with the link.


Customizing the Dashboard

  • Services / linksconfig/services.yaml
  • Info widgets (weather, clock, resources, search) – config/widgets.yaml
  • Title, theme, colors, background, layoutconfig/settings.yaml
  • Bookmarksconfig/bookmarks.yaml

See the Homepage docs for every available option.

Favicon

Set in config/settings.yaml:

favicon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/homepage.png

Enter fullscreen mode Exit fullscreen mode

Prefer a PNG over SVG – Chrome renders PNG tab icons more reliably. To use your own, drop a file in images/ and reference it as favicon: /images/favicon.png.


Troubleshooting

Symptom Fix
Timer/favicon not updating Hard refresh (Ctrl/Cmd + Shift + R); the browser caches both.
Timer never appears Check docker compose logs homepage; confirm custom.js has no JS error.
Times are off by hours Set TZ in docker-compose.yml (see Timezone note).
Calendar widget shows an error The .ics URL is unreachable/private – see the calendar section above.
Config change not reflected docker compose restart homepage.

Credits & License

Top comments (0)