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.
- Why this exists
- Features
- Screenshots
- Prerequisites
- Quick start
- Repository layout
- The meeting timer
- Optional: live Google Calendar feed (no API key)
- Customizing the dashboard
- Favicon
- Troubleshooting
- Credits & license
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 can turn it on, and making your work calendar public is usually a non-starter.
So instead of fighting the calendar, this repo 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, no admin. (If you do have a private .ics link, there's a ready-made
block to switch to a real live feed — see below.)
- 🕒 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 — red pulsing dot + "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 with a background image, blurred cards, and weather/system widgets.
- Docker and Docker Compose
- Port
8080free on the host (change it indocker-compose.ymlif needed)
git clone https://github.com/<your-username>/<repo-name>.git
cd <repo-name>
# Create your local config from the templates (these hold personal links,
# so they're 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 -dOpen http://localhost:8080, then edit config/services.yaml (your links) and
config/custom.js (your meetings).
To apply config changes later:
docker compose restart homepageHomepage hot-reloads most
config/*.yamlchanges, butcustom.js/custom.cssand the favicon are cached by the browser — do a hard refresh (Ctrl/Cmd + Shift + R) after editing.
.
├── 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)
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…
];| 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.
| Situation | Card shows |
|---|---|
| Before the meeting | Standup · today · 8:30 PM — starts in 2h 05m 12s |
| During the meeting | 🔴 Standup · live — 30m 00s left (red pulse) |
| 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.
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 timezoneIf 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: greenHomepage's calendar widget supports only unauthenticated
.ics(and the *arr apps) — no CalDAV, OAuth, basic-auth, or custom headers. The public.icsaddress works too but exposes event details to anyone with the link.
- Services / links →
config/services.yaml - Info widgets (weather, clock, resources, search) →
config/widgets.yaml - Title, theme, colors, background, layout →
config/settings.yaml - Bookmarks →
config/bookmarks.yaml
See the Homepage docs for every available option.
Set in config/settings.yaml:
favicon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/homepage.pngPrefer 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.
| 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. |
- Built on gethomepage/homepage (GPL-3.0).
- Icons from homarr-labs/dashboard-icons.
- The meeting timer (
custom.js/custom.css) is provided as-is — use, fork, and adapt freely.
