Minimal, fast, and elegant personal start page for work. It gives you:
- Quick access to your daily links
- A Google search box that can drive the embedded mini-browser or open a new tab
- A
go/launcher for intranet shortcuts (e.g.,go/,go/PAM, orPAM) - A command palette (Quick Launcher) with fuzzy search and keyboard shortcuts
- Auto/light/dark theme with optional cycling wallpapers
- Command palette (Quick Launcher): Press Mod+K (Ctrl/Cmd+K) to fuzzy-search all links and
go/keys. - Google search: Type a query and either open in the mini browser or a new tab.
go/intranet shortcuts: Typego/,go/KEY, orKEYto jump to your mapped destinations.- Mini browser: A movable, resizable embedded browser with URL bar and target select (Embed/New Tab). You can disable it via
miniBrowser.enable. - Theming: Auto resolves from system preference, with manual toggle and persistence.
- Wallpapers: Optional image cycler with separate light/dark sets and graceful crossfade.
- Privacy-friendly analytics (optional): Local-only counts in
localStorageto improve Quick Launcher ranking.
flowchart TD
A[index.html] --> B[app.js]
B --> C[config-loader.js]
C --> D[(config.json / config.yaml / config.js / config.example.js)]
B --> E[UI: Links grid, Search forms, Quick Launcher, Keyboard shortcuts]
B --> F[Mini Browser iframe]
B --> G[Service Worker: sw.js]
B --> H[Wallpapers cycler]
F --> I[(External sites)]
G --> J[(Cache: app shell & assets)]
At load time, app.js merges config sources in order with a deep-merge strategy:
- Built-in defaults defined in code
window.DASHBOARD_DEFAULT_CONFIGfromconfig.example.js- File-based config if present:
config.jsonorconfig.yaml/config.yml - Your overrides from
window.DASHBOARD_CONFIGinconfig.js(optional)
Then it initializes:
- Theme: Reads saved theme or system preference; toggling updates
localStorageand background cycler. - Background cycler: Creates two overlapping layers and crossfades between images every
cycleMs. Honorsprefers-reduced-motion. - Sections/links: Renders cards from
config.sectionsinto#linksGridwith icons and labels. - Google form: Builds the search URL from
google.baseUrlandgoogle.queryParam; opens in mini browser or new tab. go/form: Resolves keys usinggo.keyToUrl, falls back togo.fallbackSearchUrlif provided, orgo.homepageUrl.- Mini browser: Initializes from
miniBrowser.defaultUrlifminiBrowser.enable !== false; Enter in the URL bar opens in embed or new tab. - Quick Launcher: Indexes all links and
go/keys; fuzzy-search with scoring, keyboard navigation, and open-in-tab.
Security-conscious defaults:
- Strict Content Security Policy in
index.htmlallows only same-origin scripts/styles and HTTPS images/frames. - Strong
referrerpolicyandrelattributes on external links.
- Build:
npm run build- Compiles TypeScript from
src/todist/. - Runs a postbuild step that copies key artifacts to the project root for hosting:
dist/app.js→app.jsdist/sw.js→sw.js- Source maps are copied if present.
- If any required outputs are missing, the script exits with a list of missing files.
- Compiles TypeScript from
- Local dev caching: the
startscript useshttp-server -c-1to disable caching so you always see fresh assets. If you are testing service worker updates, consider clearing site data in your browser devtools between changes.
git clone https://github.com/yourusername/work-dashboard.git
cd work-dashboard
npm install
npm run build
npm run start- Clone/download this project.
- Choose a config method and customize:
- Easiest: create
config.json(orconfig.yaml) in the project root and add only the fields you want to change - Alternative: copy
config.example.js→config.jsand edit it (kept out of git) - To disable the mini browser entirely, set the field in your config:
- JSON/YAML:
{ "miniBrowser": { "enable": false } } - JS:
window.DASHBOARD_CONFIG = { miniBrowser: { enable: false } };
- JSON/YAML:
- Open it:
- Easiest: open
index.htmldirectly in your browser - Recommended:
npm run start→ visithttp://localhost:8000(localhost-only; not accessible over LAN)
Note:
config.jsis git-ignored so your work-specific links remain private.
Tip: Only override what you need; unspecified fields fall back to defaults.
- The dev server binds to
127.0.0.1and is only reachable from the local machine. - To change the port, edit the
startscript inpackage.jsonor runnpx http-server -p 3000 -c-1 -a 127.0.0.1 ..
- Open/close Quick Launcher: k
- Close Quick Launcher: Escape
- Next result: ArrowDown
- Previous result: ArrowUp
- Open selection: Enter
- Toggle theme: t
- Focus Google: /
- Focus
go/: g
You can change these in config.json/config.yaml under keybinds (or in config.js).
- Aliases:
gh,mdn,so,yt,aur,wiki,r/,npm,unpkg,bp,go(viagoresolver). - Parameterized templates:
gh acc/repo i 123→https://github.com/acc/repo/issues/123 - Shorthands:
pr 42→ opens PR #42 in yourcommandDsl.defaults.defaultRepoABC-123→ opens issue incommandDsl.defaults.trackerUrlby{id}r/learnprogramming→ opens subredditpkg react@18→ opens npm, unpkg, and bundlephobia
- Multi-target pipes:
mdn fetch | so "js fetch cors" | gh code fetch- Enter opens the first target; Shift+Enter opens all targets.
- Template transforms:
urlencode(),lower(),kebab()usable inside{ ... }in templates. - Local actions:
time 25→ starts a local focus timer overlay (no integrations).
Configuration lives under commandDsl in your config.json/config.yaml (or config.js). Example:
{
"commandDsl": {
"templates": {
"gh {owner}/{repo} i {num}": "https://github.com/{owner}/{repo}/issues/{num}",
"gh {owner}/{repo} pr {num}": "https://github.com/{owner}/{repo}/pull/{num}",
"mdn {q}": "https://developer.mozilla.org/en-US/search?q={urlencode(q)}",
"so {q}": "https://stackoverflow.com/search?q={urlencode(q)}",
"r/{sub}": "https://www.reddit.com/r/{sub}/",
"go {key}": ""
},
"macros": { "pkg {pkg}": ["npm {pkg}", "unpkg {pkg}", "bp {pkg}"] },
"defaults": {
"defaultRepo": "your-org/your-repo",
"defaultTrackerPrefix": "ABC-",
"trackerUrl": "https://your-tracker.example.com/browse/{id}"
}
}
}Notes:
go {key}with an empty string will use yourgomapping/fallbacks.- The last placeholder in a pattern can capture the rest of the text (e.g.,
{q}inmdn {q}).
Place images under wallpapers/light/ and wallpapers/dark/ (existing folders are included). Then reference them in config.js backgrounds.light and backgrounds.dark arrays. The active set switches automatically with the theme.
Motion accessibility: if a user has prefers-reduced-motion: reduce, auto-cycling pauses.
This is a static site. Host it anywhere that can serve static files:
- GitHub Pages, Netlify, Vercel, S3 + CloudFront, or your internal static host.
Ensure your host serves the files with the correct MIME types and preserves the directory structure.
This site can be installed as a PWA and works offline for the app shell and cached wallpapers.
- Manifest:
manifest.webmanifest - Service worker:
sw.js(caches app shell + same‑origin assets) - Install prompt: small button appears when installable
To disable PWA, remove the <link rel="manifest"> and service worker registration in index.html.
No external analytics. If analytics.enableLocal is true in your config.json/config.yaml (or config.js), simple usage counters are stored in localStorage only and used to improve Quick Launcher ranking on your device.
The default CSP currently includes style-src 'unsafe-inline' due to dynamic UI transitions and minimal inline script for the service worker registration. We are actively replacing ad‑hoc inline styles with CSS classes/variables (e.g., background crossfade uses a no-transition class), which will allow removal of 'unsafe-inline' in a future release. If you self‑host with a stricter CSP today, consider adding a nonce/hash and moving the small inline registration into app.js.
- "Why do I need a local server?" — Opening
index.htmldirectly works, but a local server provides a proper origin which can avoid CSP and caching quirks. - "Where do I put company-specific links?" — In
config.js. It stays out of version control.
