Mobile-first Bitcoin knowledge base frontend (Next.js + MDX) with a premium editorial design.
A comprehensive, balanced knowledge base helping people understand Bitcoin through well-researched, fair content. Clear answers, fair objections, and primary sources.
A premium, modern "linkable in conversations" Q&A wiki where users land on a specific question page and get a clear answer fast. Optimized for "user finds a useful answer in < 30 seconds."
- Premium editorial vibe: Generous whitespace, strong typography, high contrast
- Mobile-first: Big tap targets, sticky navigation, search-first UX
- Dark mode built-in: Not an afterthought
- Trust cues: Sources, last updated dates, balanced perspectives
- One accent color: Bitcoin orange (#F7931A)
- Node.js 18+
- pnpm (recommended) or npm
# Clone the repository
git clone https://github.com/jorisstrakeljahn/thereforbitcoin.git
cd thereforbitcoin
# Install dependencies
pnpm install
# Start development server
pnpm devOpen http://localhost:3000 to see the app.
thereforbitcoin/
βββ content/ # MDX content files
β βββ en/ # English content
β βββ beginner/ # Beginner-level articles
β βββ criticism/ # Criticism articles
β βββ lightning/ # Lightning Network articles
β βββ mining/ # Mining articles
β βββ money/ # Sound money articles
βββ public/ # Static assets (clean - no default files)
βββ src/
β βββ app/ # Next.js App Router pages
β β βββ api/ # API routes
β β βββ articles/ # Article pages
β β βββ glossary/ # Glossary page
β β βββ paths/ # Learning paths page
β β βββ search/ # Search page
β β βββ sources/ # Sources library page
β β βββ topics/ # Topic pages
β βββ components/
β β βββ article/ # Article-specific components
β β βββ icons/ # Lucide-style SVG icon components
β β βββ layout/ # Header, Footer
β β βββ mdx/ # MDX components (TLDRBox, etc.)
β β βββ search/ # Search modal
β β βββ ui/ # UI primitives
β βββ lib/
β β βββ content/ # Content loader & schema
β β βββ hooks/ # React hooks
β β βββ search/ # Search functionality
β βββ styles/ # Global CSS & tokens
βββ ...config files
Content is stored as MDX files in the content/ directory with Zod-validated frontmatter.
---
slug: what-is-bitcoin
title: What is Bitcoin?
summary: A digital currency without banks... (max 300 chars)
tags: [basics, introduction]
topic: basics # basics, security, mining, lightning, economics, criticism, money, dev
level: beginner # beginner, intermediate, advanced
type: qa # qa, explainer, criticism, glossary, source
language: en
lastUpdated: "2024-01-15"
tldr: # Max 5 bullet points
- Point one
- Point two
whyPeopleAsk: Why users search for this
whatIsTrue: [verified facts]
whatIsUncertain: [debated points]
sources:
- title: Source Name
url: https://example.com
author: Author Name
type: primary # primary, secondary, video, book, article, podcast
---- Create a new
.mdxfile in the appropriatecontent/en/[category]/folder - Add the required frontmatter
- Write your content using markdown + MDX components
- The article will automatically appear in the relevant topic page
<TLDRBox items={[...]} />- Bullet-point summary box<Callout type="info|warning|success|error|tip">...</Callout><SourcesList sources={[...]} /><KeyTakeaways items={[...]} /><InlineTerm term="satoshi">satoshis</InlineTerm>- Glossary popover
Uses a custom Lucide-style SVG icon system located in src/components/icons/.
import {
// Navigation
Menu, X, Search, Sun, Moon, ChevronRight, ChevronDown, ArrowLeft, ArrowRight,
// Topics
Bitcoin, Shield, Lock, Pickaxe, Zap, TrendingUp, HelpCircle, Coins, Code,
// Content
BookOpen, FileText, Video, Headphones, Library, GraduationCap,
// Actions
Check, Copy, ExternalLink, Share, Info, AlertCircle, AlertTriangle,
// Misc
Clock, Calendar, List, Hash, Tag, Sparkles, Scale, Quote
} from '@/components/icons';import { Bitcoin, Search } from '@/components/icons';
// Basic usage
<Bitcoin size={24} />
// Custom props
<Search size={18} strokeWidth={2.5} className={styles.icon} />For topic-specific icons:
import { TopicIcon } from '@/components/icons';
<TopicIcon topic="lightning" size={20} />Uses plain CSS with CSS Modules and CSS custom properties (no Tailwind).
Located in src/styles/tokens.css:
- Colors (with dark mode variants)
- Typography scale
- Spacing scale
- Border radii
- Shadows
- Transitions
- Z-index scale
Supports:
- System preference detection (
prefers-color-scheme) - Manual toggle (persisted to localStorage)
[data-theme="dark"]attribute on<html>
Respects prefers-reduced-motion media query.
Local search implementation using frontmatter + content indexing.
- Searches titles, summaries, and tags
- Supports filtering by topic, type, and level
- Keyboard navigation (βK to open, arrows to navigate)
- Highlighting of matched terms
- Mobile-first CSS
- Breakpoints: 640px, 768px, 1024px, 1280px
- Collapsible navigation on mobile
- Sticky mobile navigation button for article TOC
- Per-page metadata & Open Graph tags
- Dynamic sitemap (
/sitemap.xml) - Robots.txt (
/robots.txt) - Semantic HTML structure
- Clean, human-readable URLs
# Development server
pnpm dev
# Type checking
pnpm type-check
# Linting
pnpm lint
# Build for production
pnpm build
# Start production server
pnpm startThe project uses a comprehensive test suite with BDD-style E2E tests and unit tests.
- E2E Tests: Playwright with Cucumber/Gherkin via
playwright-bdd - Unit Tests: Vitest with
@testing-library/react
# Run all tests (unit + E2E)
pnpm test
# Run unit tests only
pnpm test:unit
# Run unit tests in watch mode
pnpm test:unit:watch
# Run E2E tests (headless) - Desktop + Mobile
pnpm test:e2e
# Run only Desktop tests
pnpm exec playwright test --project=chromium
# Run only Mobile tests
pnpm exec playwright test --project=mobile
# Run E2E tests with browser UI
pnpm test:e2e:headed
# Run E2E tests with Playwright UI
pnpm test:e2e:ui| Project | Device | Viewport | Tests |
|---|---|---|---|
chromium |
Desktop Chrome | 1280Γ720 | All tests (46) |
mobile |
Pixel 5 | 393Γ851 | Excluding @desktop-only (41) |
Tests tagged with @desktop-only are skipped on mobile because they test features not visible on mobile (e.g., header navigation links).
tests/
βββ e2e/
β βββ features/ # Gherkin feature files
β β βββ homepage.feature
β β βββ navigation.feature
β β βββ search.feature
β β βββ search-results.feature
β β βββ article.feature
β β βββ topics.feature
β β βββ sources.feature
β β βββ language-switching.feature
β β βββ theme-toggle.feature
β βββ steps/ # Step definitions
β β βββ common.steps.ts
β β βββ homepage.steps.ts
β β βββ navigation.steps.ts
β β βββ search.steps.ts
β β βββ search-results.steps.ts
β β βββ article.steps.ts
β β βββ topics.steps.ts
β β βββ sources.steps.ts
β β βββ language.steps.ts
β β βββ theme.steps.ts
β βββ fixtures/ # Page objects
β βββ pages.ts
βββ unit/
β βββ lib/
β β βββ content.test.ts
β β βββ search.test.ts
β βββ setup.ts
βββ playwright.config.ts
βββ vitest.config.ts
E2E tests use Gherkin syntax for human-readable scenarios:
Feature: Search
As a user I want to search for Bitcoin articles
Scenario: Hero search shows results
Given I am on the homepage
When I type "bitcoin" in the hero search field
Then I see search results in the dropdown
And the first result contains "Bitcoin"Use tags to control which tests run on which devices:
# This test only runs on Desktop (chromium)
@desktop-only
Scenario: Header navigation is visible
Then I see the navigation links
# This test runs on both Desktop and Mobile
Scenario: Logo leads to homepage
When I click on the logo
Then I should be on the homepage| Tag | Description |
|---|---|
@desktop-only |
Skipped on mobile - tests desktop-specific features |
All interactive components have data-testid attributes for reliable test selectors:
| Component | Test IDs |
|---|---|
| Hero Section | hero-title, hero-search-input, hero-search-dropdown, hero-search-result-{index} |
| Search Modal | search-modal, search-modal-input, search-modal-close, search-result-{index} |
| Header | header, header-logo, header-search-button, header-nav-topics, theme-toggle, language-toggle |
| Article | article-title, article-content, article-toc, article-back-button |
| Topics | topics-grid, topic-card-{id}, topic-title, topic-articles |
| Sources | sources-page, sources-grid, sources-filters, sources-filter-{type} |
| Search Page | search-page, search-page-input, search-results, search-page-result-{index} |
Tests run automatically on every push and pull request via GitHub Actions:
- Lint & Type Check - ESLint and TypeScript validation
- Unit Tests - Vitest unit test suite
- E2E Tests - Playwright browser tests
- Build - Production build verification
Add to src/app/layout.tsx:
import posthog from 'posthog-js';
if (typeof window !== 'undefined') {
posthog.init('YOUR_POSTHOG_KEY', {
api_host: 'https://app.posthog.com',
});
}- Install Supabase client:
pnpm add @supabase/supabase-js - Create
src/lib/supabase/client.ts - Add environment variables
- Implement auth, user progress tracking, etc.
The content structure already supports multiple languages:
- Add
content/de/for German - Update content loader to accept language parameter
- Implement language switcher component
Consider using Capacitor or React Native to wrap the web app for mobile distribution.
Contributions are welcome! Please read the contributing guidelines first.
MIT License - see LICENSE file for details.
Built with β€οΈ for the Bitcoin community.