Ad-supported hub of free, client-side developer tools. Built with Astro 7 + React 19 + Tailwind 4; every page is static HTML with a small React island for the interactive tool.
| Command | What it does |
|---|---|
pnpm dev |
Dev server at http://localhost:4321 |
pnpm build |
Generates OG images, then static build to dist/ (also generates sitemap-index.xml) |
pnpm og |
Regenerate social-card PNGs only (public/og.png, public/og/<slug>.png) — add --force to redo all |
pnpm preview |
Serve dist/ locally |
pnpm astro check |
Type-check .astro and .tsx files |
src/
config.ts # Site name, URL, contact, ad settings ← edit before deploying
data/tools.ts # Tool registry: metadata + SEO copy for every tool page
layouts/Base.astro # <head> (meta, canonical, OG, JSON-LD), header, footer
components/
AdSlot.astro # AdSense unit, or a labelled placeholder while ads are disabled
Header.astro / Footer.astro / ToolCard.astro
ToolSearch.tsx # Home-page search island
tools/
ui.tsx # Shared primitives (Button, TextArea, CopyButton, …)
<ToolName>.tsx # One React component per tool
lib/ # Pure helpers (md5, case conversion) — unit-testable
pages/
index.astro # Home
tools/index.astro # All tools
tools/[slug].astro # Generates /tools/<slug>/ for every entry in data/tools.ts
about / contact / privacy / terms / 404
public/
robots.txt, favicon.svg
scripts/
og.mjs, fonts/ # Build-time Open Graph image generator (satori + resvg)
- Create
src/components/tools/MyTool.tsx(default-export a React component; use primitives fromui.tsx). - Add an entry to
TOOLSinsrc/data/tools.ts— slug, name, description, keywords,howTo,about,faq,related. This copy is what ranks, so write it for a real reader. - Import the component in
src/pages/tools/[slug].astroand add one line to the slug → component block. (Astro must see a static tag to hydrate an island, which is why this is not a map lookup.) pnpm build— the page, sitemap entry and JSON-LD are generated automatically.
src/config.ts: setSITE.urlto your domain (drives canonical URLs + sitemap), plus name/contact email.public/robots.txt: update the Sitemap URL.- Deploy
dist/to Cloudflare Pages, Vercel or Netlify (all free for static sites). Build commandpnpm build, output dirdist.
All ad wiring lives in src/config.ts → ADS.
- Apply to AdSense. Set
ADS.adsenseClient = 'ca-pub-…'and push. This loads the AdSense script on every page (required for verification) and generatespublic/ads.txtat build time. Nothing visible changes yet. - After approval, create ad units in the AdSense dashboard (display ads, responsive) and paste each unit's
data-ad-slotID intoADS.slots:headerBanner(home + all-tools page),inToolTop/inToolBottom(above and below every tool),sidebar(300×250 next to the tool on desktop). A slot renders as soon as it has an ID; empty slots render nothing in production. - Optional:
ADS.autoAds = truelets Google place extra units automatically. - Consent for EEA/UK visitors: enable Google's built-in CMP under AdSense → Privacy & messaging → GDPR — no code changes needed, it injects with the same script.
Once you pass ~50k sessions/month, apply to a premium network (Raptive, Mediavine/Journey, Ezoic) — RPMs are typically 3–5× AdSense.