A frameless desktop widget showing your GitHub contribution heatmap and recent commits. Sits on your desktop, resizable and draggable, with a system tray icon for show/hide. Works on Windows and Linux.
- 26-week contribution heatmap with tooltips
- Today's contribution count, yearly total, streak counter
- Last 2 commits with repo, branch, SHA — click to open in browser
- Dark and Glassmorphism themes, persisted across restarts
- OAuth Device Flow auth — no PATs, no expiry
- Auto-refreshes every 10 minutes
- System tray icon — left-click or right-click → Show/Hide to restore after closing
- Node.js 18+
- A GitHub OAuth App (free, one-time)
- Go to GitHub → Settings → Developer settings → OAuth Apps → New OAuth App
- Fill in:
- Application name: GitHub Widget
- Homepage URL:
https://github.com/epsilon003/github-widget - Authorization callback URL:
https://github.com/epsilon003/github-widget(unused but required)
- Check Enable Device Flow
- Click Register application and copy the Client ID
Open renderer/app.js and replace:
const GITHUB_CLIENT_ID = 'YOUR_OAUTH_APP_CLIENT_ID';The Client ID is public — safe to commit. No Client Secret needed for device flow.
git clone https://github.com/epsilon003/github-widget
cd github-widget
npm install
npm startOn first launch, click Sign in with GitHub. Your browser opens to github.com/login/device — enter the code shown in the widget and authorize. Done.
Clicking the × hides the window — the app keeps running in the system tray. To bring it back:
- Left-click the green tray icon
- Or right-click the tray icon → Show / Hide
The window is frameless and transparent, so it doesn't get real OS titlebar/resize-border chrome. Both are reimplemented manually:
- Drag — grab anywhere on the top bar (not the icon buttons) and move. Handled by polling the cursor position from the main process at 60fps and calling
setPosition(). - Resize — grab an edge or corner (right, left, bottom, bottom-right, bottom-left; no top handles, since the top bar already owns that space). Same polling pattern, calling
setBounds().
On some Linux desktop environments (and Windows, via Aero Snap), dragging a window whose edge gets close to the screen boundary can trigger the OS's own edge-tiling/snap-preview, which visibly resizes the window while you're still holding the mouse button — independent of anything the app is doing. Because our drag calls setPosition() rapidly, it can look like a real user-driven move to the OS and trigger this.
Mitigations already in place:
- The widget spawns with extra margin from the right edge of the screen (
x: sw - 540), rather than sitting almost flush against it. mainWindow.setResizable(false)is toggled on during drag and restored on release — most OS snap/tile features only engage on resizable windows, so this suppresses the false trigger without affecting our ownsetPosition/setBoundscalls (those are unaffected by theresizableflag).- Symmetrically,
setMovable(false)is toggled during resize and restored after.
If you still see it on your machine, it's almost certainly your desktop environment's own edge-tiling/snapping feature, not an app bug — worth confirming by temporarily disabling it and reproducing:
- GNOME:
gsettings set org.gnome.mutter edge-tiling false(revert with... edge-tiling true) - XFCE: Window Manager Tweaks → Accessibility → uncheck "Snap windows"
- KDE Plasma: System Settings → Window Management → Window Behavior → Screen Edges
- Windows: Settings → System → Multitasking → turn off "Snap windows"
Switch between Dark and Glass using the pills in the widget footer or on the setup screen. The choice persists across restarts.
The Glass theme uses backdrop-filter: blur() for a frosted glass look — works best with a colorful wallpaper behind it.
Releases are fully automated via GitHub Actions. To publish a new version:
# Bump the version in package.json first, then:
git add package.json
git commit -m "chore: bump version to 1.x.x"
git tag v1.x.x
git push origin main --tagsThat's it. The release.yml workflow triggers on the tag, builds Windows (.exe) and Linux (.AppImage + .deb) binaries in parallel, auto-generates a changelog from commits since the last tag, and publishes everything to the GitHub Releases page. Pre-release tags like v1.0.0-beta.1 are automatically flagged as pre-release.
No secrets to configure — the workflow uses the built-in GITHUB_TOKEN that Actions provides automatically.
github-widget/
├── main.js # Electron main process
├── preload.js # IPC context bridge
├── renderer/
│ ├── index.html # Widget + setup screen markup
│ ├── style.css # Dark + Glass themes
│ └── app.js # OAuth, API calls, render logic
├── .github/
│ ├── workflows/
│ │ ├── ci.yml # Lint + validate on push/PR
│ │ └── release.yml # Build + publish on tag
│ └── dependabot.yml # Weekly dep updates
├── .gitignore
└── package.json
- Windows:
%APPDATA%\github-widget\config.json - Linux:
~/.config/github-widget/config.json
Stores token, username, and theme preference. Delete to reset.
OAuth tokens don't expire on a schedule. They stay valid until revoked at GitHub → Settings → Applications. If revoked, the widget detects the 401 on next load and drops back to the sign-in screen automatically.