Skip to content

Latest commit

 

History

45 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OpenTools

CI

A public directory of tools and websites — Product Hunt style reference with a Notion-like table, ⌘K command palette search and per-tool detail pages. Dark-only, English-only.

Built by @BastianMR with Astro 5, React 19, Tailwind CSS 4 and shadcn/ui. Fully static output — no backend required.

Features

  • 📋 Catalog table — server-rendered rows (SEO-friendly), sortable columns.
  • 🗂️ Library sidebar — categories with counts (tools can have several), multi-select tag chips.
  • ⌘K Command palette — fuzzy live search over name/description/tags, keyboard-first.
  • 📄 Detail pages — every tool gets its own shareable URL /tools/<slug>; on desktop it opens as a side panel (Sheet) with full browser-history support; on mobile it navigates directly.
  • 🔗 Shareable filters — active category/tags sync to the URL (?category=design&tags=notes).
  • 🌗 Dark-only design — consistent shadcn/ui dark theme, no theme switching.
  • Validated content — one markdown file per tool; the build fails naming file + field if data is invalid. Bad data never ships.
  • 🔍 SEO ready — sitemap, RSS feed, per-page Open Graph tags.

Quickstart (< 5 minutes)

git clone https://github.com/BastianMR/OpenTools.git
cd OpenTools
npm install
npm run dev      # http://localhost:4321

You'll see 6 demo tools. Replace them with your own (next section) or keep exploring.

Adding a tool

Create src/content/tools/<slug>.md (slug = kebab-case URL):

---
name: "Excalidraw" # required
url: "https://excalidraw.com" # required, must be http(s)
categories: ["design", "tools"] # required, one or more
added: 2026-08-22 # required, ISO date
description: "..." # required, max 500 chars
tags: ["diagrams"] # optional
comment: "..." # optional, your personal take
---

Commit to main → deploy runs automatically. If a field is invalid the build fails naming the file and field. Full contract: specs/001-opentools-catalog-site/data-model.md.

Customizing your instance

What Where
Site name, tagline, author src/lib/site-config.ts
UI strings src/lib/i18n.ts
Colors / theme tokens src/styles/global.css
Categories & tags free-form in each entry's frontmatter

More details: docs/customization.md.

Deploy to Cloudflare Pages

  1. Push this repo to your GitHub account.
  2. In Cloudflare Dashboard: Workers & Pages → Create → Pages → Connect to Git.
  3. Pick the repo, framework preset Astro, build command npm run build, output dist/.
  4. Save — every push to main deploys production; PRs get preview URLs.

Works identically on Netlify/Vercel (any static host).

Self-hosting (Docker)

No cloud needed — run it on your own machine, NAS or VPS:

docker compose up -d --build

Open http://localhost:8080. The container serves the static build with nginx (immutable caching for hashed assets, gzip, custom 404) and restarts on reboot.

Useful commands:

docker compose logs -f        # follow logs
docker compose down           # stop
docker compose up -d --build  # rebuild after pulling changes

Prefer plain nginx/caddy? Point it at the output of npm run build (dist/) — see nginx.conf for the recommended cache and try_files rules.

Automating content (n8n)

Publish entries from an n8n workflow via the GitHub API:

PUT https://api.github.com/repos/{owner}/{repo}/contents/src/content/tools/{slug}.md
Authorization: Bearer <token>          # token lives ONLY in n8n credentials
{ "message": "feat(content): add {slug}", "content": "<base64 .md>", "branch": "main" }

If the frontmatter is invalid, the deploy fails but the last good build stays online.

Scripts

Command Action
npm run dev Dev server at localhost:4321
npm run build Production build (validates content schema)
npm test Unit tests (Vitest)
npm run test:e2e E2E tests (Playwright, builds first)
npm run lint Type check + Prettier
npm run graph:update Refresh codebase knowledge graph (graphify)

Project structure

src/
├── content/tools/*.md       ← your catalog entries (the data)
├── lib/
│   ├── content-source.ts    ← ONLY place that reads content (swap for a DB later)
│   ├── site-config.ts       ← branding: name, tagline, author
│   ├── schema.ts            ← frontmatter contract (Zod)
│   └── i18n.ts              ← UI strings
├── components/
│   ├── CatalogExplorer.tsx  ← interactive island (table + ⌘K + sheet panel)
│   └── ui/                  ← shadcn/ui primitives
├── layouts/Base.astro       ← head/SEO/header/footer
└── pages/                   ← routes (/, /tools/[slug], rss.xml, 404)

The content layer is deliberately isolated: today it reads markdown files via Astro Content Collections; swapping in Supabase/Turso/any backend later means changing exactly one file (src/lib/content-source.ts) — no page or component changes.

Contributing

Issues and PRs welcome — see CONTRIBUTING.md and specs/ for how features are specified before they're built.

License

Code: MIT. Demo seed entries ship as examples; replace them with your own content.

About

A public directory of tools and websites — Product Hunt style reference with Notion-like table, ⌘K search and per-tool detail pages. Astro + React + Tailwind + shadcn/ui.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages