Skip to content

amirzenoozi/dad-joke-ext

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

25 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ˜„ Dad Joke

A New Tab extension for Chrome, Edge & Firefox that greets every new tab with a fresh dad joke.

Powered by icanhazdadjoke.com Β· four card themes Β· a sky that changes with the hour Β· recent-bookmark shortcuts Β· on-device translation Β· one-click image export.

License: AGPL-3.0 Built with WXT TypeScript Permissions: bookmarks Β· favicon

Basic theme Twitter theme

Contents

Features

  • πŸƒ A fresh dad joke on every new tab, with an Another one button for the next.
  • 🎨 Four card themes β€” Basic, Terminal, DOS, and Twitter β€” switchable from a dock at the bottom.
  • πŸŒ— Dark mode β€” auto (follows your OS), light, or dark.
  • πŸŒ… Dreamy fluid gradient that shifts colour with the hour, from midnight indigo to dawn rose to midday sky to dusk magenta.
  • πŸ•’ Time & date β€” a live clock on the Basic card, a timestamp on the Twitter card, both localized.
  • πŸ”– Recent bookmarks β€” your five latest bookmarks as quick-launch circles under the card, with site favicons (a coloured monogram where none is available).
  • 🌍 Auto-translation into your browser's language, running on-device (Chrome 138+).
  • ⬇️ Download the current card as a PNG, rendered locally β€” nothing is uploaded.
  • πŸ”’ On-device only β€” no accounts, no tracking, no data collection; two read-only permissions, no network beyond the joke API.

Every preference β€” theme, dark-mode setting, and translation toggle β€” is saved in localStorage, so the extension needs no storage permission. It reads your recent bookmarks (and their cached favicons) locally to render the shortcuts; nothing about them ever leaves your device.

Themes

Every theme presents the same joke as a card with its own personality. All cards share one width, and the Another one button sits centred just below the card (so it stays out of the exported image).

Theme Look
Basic Clean frosted card with a brand + live clock on the dreamy gradient
Terminal macOS terminal window β€” $ dadjoke --random with a blinking caret
DOS Retro MS-DOS blue screen β€” C:\JOKES>, box border, block cursor
Twitter Presented as a tweet β€” avatar, verified badge, timestamp, action row
Terminal theme DOS theme Twitter theme, dark mode Basic theme

Terminal and DOS use their own opaque cards; the time-of-day gradient shows softly around them. Basic and Twitter sit directly on it. Twitter follows dark mode with a proper light/dark card.

The time-of-day gradient

The background is a smooth function of the clock. Eight colour anchors spaced every three hours β€” midnight β†’ deep night β†’ dawn β†’ morning β†’ midday β†’ afternoon β†’ dusk β†’ evening β€” are linearly interpolated by the exact minute, so 07:45 sits three quarters of the way from dawn toward morning. Three slowly drifting, blurred blobs paint the sky, and the foreground ink colour is chosen from the resulting luminance so text stays legible at every hour and in every mode.

See lib/daylight.ts.

Translation

Jokes arrive from the API in English. When your browser is set to another language, Dad Joke translates the joke (and the small UI labels) into it using Chrome's built-in Translator API (Chrome 138+). The model runs on-device β€” no network request, no API key, and no permission.

  • A DE / FR / … chip appears in the switcher; tap it to flip back to the original English at any time.
  • The first translation of a new language may need a one-time model download, which the browser grants on your first click; until then the joke shows in English.
  • Where the API isn't available (e.g. Firefox), the joke simply stays in English β€” nothing breaks.

See lib/translate.ts.

Download as image

The ⬇ button in the switcher exports the current card as a PNG (dad-joke-<theme>.png). Rendering is done locally with html-to-image β€” the card is drawn to a canvas in your browser and downloaded directly, so nothing is uploaded and no capture permission is required. The Another one button lives outside the card, so it never appears in the exported image.

Privacy & permissions

Dad Joke declares just two permissions, both used entirely on-device:

Permission Why
bookmarks Read your five most recent bookmarks to show them as shortcuts. Never transmitted.
favicon (Chrome/Edge) Show each bookmark's icon from the local favicon cache β€” no network request.

Everything else needs no permission:

  • The joke API returns Access-Control-Allow-Origin: *, so the New Tab page fetches a joke directly β€” no host permission.
  • Preferences live in localStorage β€” no storage permission.
  • Translation (built-in Translator API) and PNG export (html-to-image) both run on-device β€” no network, no permission.

The only network request is the single joke fetch per new tab. No accounts, no analytics, no trackers, no data collection β€” and your bookmarks never leave your device. Full details in PRIVACY.md.

Install

From the stores:

From source (unpacked):

npm install
npm run build            # Chrome/Edge  β†’ .output/chrome-mv3
npm run build:firefox    # Firefox      β†’ .output/firefox-mv2
  • Chrome/Edge: open chrome://extensions, enable Developer mode, click Load unpacked, and select .output/chrome-mv3.
  • Firefox: open about:debugging β†’ This Firefox β†’ Load Temporary Add-on, and pick any file inside .output/firefox-mv2.

Project structure

Version 2 is built with WXT and TypeScript. WXT generates a per-browser manifest from wxt.config.ts plus the files in entrypoints/, and handles building, zipping, and store submission from a single codebase. The New Tab page is auto-wired as chrome_url_overrides.newtab.

entrypoints/
  newtab/
    index.html         # card markup (chrome for each theme lives here)
    main.ts            # wiring: fetch, theme/mode/lang switcher, clock, download
    style.css          # all four themes + the gradient + switcher
lib/
  joke.ts              # fetch a random joke from the API
  config.ts            # API endpoint + user agent
  daylight.ts          # time-of-day gradient palette engine
  themes.ts            # the four theme definitions
  translate.ts         # on-device translation (built-in Translator API)
  bookmarks.ts         # recent bookmarks + local favicons
  prefs.ts             # theme + dark-mode + translate prefs (localStorage)
public/icon/           # 16 / 32 / 48 / 128 px extension icons
screenshots/           # theme screenshots used in this README
wxt.config.ts          # manifest config
.github/workflows/     # CI (build) + Release (zip & publish)

Runtime dependency: html-to-image (card β†’ PNG export). Everything else is dev-only (wxt, typescript).

Development

Requires Node 22+.

npm install            # installs deps and runs `wxt prepare`
npm run dev            # live-reload dev build for Chrome
npm run dev:firefox    # live-reload dev build for Firefox
npm run compile        # type-check only (tsc --noEmit)

Build & package

npm run build          # production build (Chrome, .output/chrome-mv3)
npm run build:firefox  # production build (Firefox, .output/firefox-mv2)

npm run zip            # Chrome store zip
npm run zip:firefox    # Firefox store zip + sources zip
npm run zip:edge       # Edge store zip
npm run package        # all three at once

Zips land in .output/.

Release / publish

Publishing is automated by .github/workflows/release.yml. Bump version in package.json, then push a matching tag:

# e.g. for version 2.0
git tag v2.0
git push origin v2.0

The workflow verifies the tag matches package.json, type-checks, zips all three targets, uploads them as build artifacts, and runs wxt submit for any store whose secrets are configured. Steps for stores without secrets are skipped, so Chrome-only or Firefox-only releases work out of the box.

Store Required repository secrets
Chrome CHROME_EXTENSION_ID, CHROME_CLIENT_ID, CHROME_CLIENT_SECRET, CHROME_REFRESH_TOKEN
Firefox FIREFOX_EXTENSION_ID, FIREFOX_JWT_ISSUER, FIREFOX_JWT_SECRET
Edge EDGE_PRODUCT_ID, EDGE_CLIENT_ID, EDGE_API_KEY

Continuous integration (.github/workflows/ci.yml) type-checks and builds both browsers on every push and pull request.

Firefox note: set your own browser_specific_settings.gecko.id in wxt.config.ts before publishing to AMO.

Roadmap

  • Dad joke preview + Another one
  • Four card themes (Basic, Terminal, DOS, Twitter)
  • Dark mode (auto / light / dark)
  • Time-of-day fluid gradient
  • Time & date view
  • On-device auto-translation
  • Download card as PNG
  • Recent-bookmark quick-launch shortcuts
  • Random background
  • More themes

Contributing

Issues and pull requests are welcome. Please keep the permission footprint minimal (and on-device β€” no new network calls) and run npm run compile before opening a PR. Adding a theme is mostly a new entry in lib/themes.ts plus a data-theme block in entrypoints/newtab/style.css.

License

AGPL-3.0-or-later Β© Amir Douzandeh.

Jokes courtesy of icanhazdadjoke.com.

About

A Simple Extension For Chrome New Tab With DadJoke API.

Topics

Resources

License

Stars

2 stars

Watchers

1 watching

Forks

Sponsor this project

Packages

 
 
 

Contributors