# Librefang Website

This repository contains the Librefang marketing website and install entrypoints. It is not the core Rust codebase.

- Website: `https://librefang.ai`
- Docs: `https://docs.librefang.ai`
- Core repository: `https://github.com/librefang/librefang`

## Overview

This project is a React + TypeScript + Vite single-page site for presenting Librefang's product positioning, features, installation flow, GitHub community stats, visit metrics, and localized content.

The repository currently covers:

- Landing page marketing content and product comparison
- Language-prefixed routes
- Latest GitHub release and community stats display
- Dynamic registry data with build-time fallback
- Static distribution of install scripts and install metadata
- PWA setup and baseline SEO metadata
- Cloudflare Workers for site stats and visit counting

## Tech Stack

- React 19
- TypeScript (strict mode)
- Vite 7
- Tailwind CSS 3
- zustand (state management)
- @tanstack/react-query (data fetching)
- framer-motion (animations)
- zod (runtime validation)
- clsx + tailwind-merge (className utilities)
- lucide-react (icons)
- Cloudflare Workers + KV for stats and registry proxy

## Requirements

- Node.js LTS
- pnpm
- Wrangler CLI if you need to deploy or manage the workers

## Architecture

The production setup is split into three parts:

1. Static Vite site
   - Serves the landing page, localized routes, metadata, install scripts, and PWA assets
2. GitHub stats worker
   - Proxies GitHub data, adds caching, and stores daily history in KV
3. Visit counter worker
   - Tracks page visits and serves a small tracking script consumed by the website

### Registry data

Agent registry data is fetched at runtime from `stats.librefang.ai/api/registry`. A build-time fallback is generated by `scripts/fetch-registry.ts`, which writes `public/registry.json`. Both `pnpm dev` and `pnpm build` run this fetch automatically via pre-scripts, so the static fallback stays reasonably fresh.

### Internationalization

The site supports 7 languages: en, zh, zh-TW, ja, ko, de, es. Translations live in `src/i18n.ts`. Language detection is path-prefix-based (e.g. `/ja/`, `/zh-TW/`).

CJK locales (zh, zh-TW, ja, ko) trigger per-language font loading at runtime. The store in `src/store.ts` lazily injects the appropriate Google Fonts stylesheet (Noto Sans SC, TC, JP, or KR) only when the user switches to or lands on a CJK locale. Non-CJK locales use the base `Outfit` font and do not load extra font resources.

The frontend is intentionally thin. Most dynamic behavior is read-only and based on remote fetches rather than local application state.

## Local Development

### Install dependencies

```bash
pnpm install
```

### Start the dev server

```bash
pnpm dev
```

### Build for production

```bash
pnpm build
```

The production output is written to `dist/`.

### Preview the production build

```bash
pnpm preview
```

### Fetch registry data manually

```bash
pnpm fetch-registry
```

## Project Structure

```text
.
├── src/
│   ├── App.tsx            # Main page sections, UI, and data fetching
│   ├── i18n.ts            # Translations and language list
│   ├── store.ts           # Zustand store (language state, CJK font loading)
│   ├── useRegistry.ts     # Registry data hook (remote + fallback)
│   ├── index.css          # Global styles and Tailwind component styles
│   ├── main.tsx           # React entrypoint and React Query provider
│   ├── vite-env.d.ts      # Vite client type declarations
│   └── lib/
│       └── utils.ts       # clsx + tailwind-merge helper
├── scripts/
│   └── fetch-registry.ts  # Build-time registry.json fetcher
├── public/
│   ├── _headers           # Static hosting response headers
│   ├── _redirects         # Static hosting redirects
│   ├── registry.json      # Build-time registry fallback data
│   ├── install.sh         # Public shell installer
│   ├── install.ps1        # Public PowerShell installer
│   ├── install-manifest.json # Install metadata
│   ├── sitemap.xml        # Sitemap
│   └── ...                # Logo, OG image, PWA assets, and other static files
├── workers/
│   ├── github-stats-worker/
│   └── visit-counter-worker/
├── vite.config.ts         # Vite and PWA configuration
├── tsconfig.json          # TypeScript config (strict mode)
├── tsconfig.node.json     # TypeScript config for Node scripts
├── tailwind.config.js     # Tailwind CSS configuration
├── postcss.config.js      # PostCSS configuration
└── eslint.config.js       # ESLint configuration
```

## External Services Used At Runtime

The site runs locally without extra setup, but some sections depend on external services. If those services are unavailable, the related data will be empty or degraded.

- GitHub Releases API
  - The Hero section requests `https://api.github.com/repos/librefang/librefang/releases/latest`
- GitHub stats worker
  - The page requests `https://stats.librefang.ai/api/github`
- Registry API
  - The page requests `https://stats.librefang.ai/api/registry`
  - Falls back to the static `public/registry.json` if the remote is unavailable
- Visit counter worker
  - The page requests `https://counter.librefang.ai/api`
  - `index.html` also loads `https://counter.librefang.ai/script.js`
- Google Fonts
  - The `Outfit` font is loaded from `fonts.googleapis.com` and `fonts.gstatic.com`
  - CJK fonts (Noto Sans SC/TC/JP/KR) are loaded on demand for zh, zh-TW, ja, ko locales
- Google Analytics
  - `index.html` includes `gtag`

In local development, these requests still target the production external endpoints unless you change the source code.

## Content Maintenance

### Copy and translations

Most page copy lives in `src/i18n.ts`, including:

- Translations for each language
- Navigation labels
- FAQ content
- GitHub/community section text
- Docs section text
- Language switcher entries

### Page structure

`src/App.tsx` owns the page structure, including:

- Header, Hero, Features, Comparison, Install, FAQ, and other sections
- GitHub stats requests
- Visit counter requests
- Path-prefix-based language detection

### SEO and third-party scripts

`index.html` contains:

- `title` and `description`
- Open Graph and Twitter Card metadata
- `canonical`
- Initial language detection script
- Google Analytics
- Visit counter script injection

### Static assets and install files

`public/` contains:

- Logo, mascot, OG image, and PWA assets
- `robots.txt`
- `sitemap.xml`
- Public `install.sh` and `install.ps1`

`public/install-manifest.json` records installer channels and binary download metadata.

## Localized Routes

Current path prefixes:

- `/` -> English
- `/zh/` -> Simplified Chinese
- `/zh-TW/` -> Traditional Chinese
- `/de/` -> Deutsch
- `/ja/` -> Japanese
- `/ko/` -> Korean
- `/es/` -> Spanish

If you add a new language, update at least these locations:

1. Add translations and a `languages` entry in `src/i18n.ts`
2. Add path detection in `src/store.ts`
3. Add path detection in the bootstrap script inside `index.html`
4. Add the new URL to `public/sitemap.xml`

## PWA and Build Notes

PWA support is configured in `vite.config.ts` through `vite-plugin-pwa`:

- Auto-updating service worker registration
- Pre-caching for common static assets
- `manifest.webmanifest` output
- App name, theme color, and icon configuration

The build also creates basic vendor chunks:

- `vendor-react`
- `vendor-query`

## Workers

### `workers/github-stats-worker`

Purpose:

- Aggregates GitHub stars, forks, issues, PRs, and downloads
- Caches responses in KV
- Records daily history through a cron trigger

Endpoint:

- `GET /api/github`

Dependencies:

- KV binding: `KV`
- Optional secret: `GITHUB_TOKEN`

### `workers/visit-counter-worker`

Purpose:

- Tracks site visits
- Exposes a stats endpoint for the frontend
- Serves an embeddable tracking script

Endpoints:

- `GET /api`
- `POST /api/track`
- `GET /script.js`

Dependencies:

- KV binding: `VISIT_COUNTER`

### Before deploying workers

- Replace the `account_id` and KV namespace IDs in each `wrangler.toml` before using a different Cloudflare account
- If worker domains change, update:
  - `src/App.tsx`
  - `index.html`
  - `public/_headers`

Example commands:

```bash
cd workers/github-stats-worker
wrangler deploy
wrangler secret put GITHUB_TOKEN

cd ../visit-counter-worker
wrangler deploy
```

## Static Deployment

This is a standard Vite static site. A typical production deploy flow is:

```bash
pnpm build
```

Then deploy `dist/` to any static hosting provider.

If your platform supports `_headers` and `_redirects`, you can reuse the files in `public/`. The repository already includes:

- Security headers
- CSP rules
- Static asset cache policies

## Update Workflow

Common maintenance tasks usually fall into one of these buckets:

### Landing page copy or visuals

- Update copy in `src/i18n.ts`
- Update layout or section logic in `src/App.tsx`
- Replace or add assets in `public/`

### Installer or release metadata

- Update `public/install-manifest.json`
- Keep root and `public/` installer scripts aligned
- Verify any public install URLs shown in the UI still match the actual hosted installer endpoints

### Analytics or stats infrastructure

- Update worker code under `workers/`
- Re-deploy the affected worker
- Update hardcoded frontend endpoints and CSP if domains changed

## Known Maintenance Constraints

- Some install-related files exist in both the repository root and `public/`; changing only one copy is usually incorrect
- Stats and visit APIs are hardcoded to production domains in the frontend
- CSP in `public/_headers` can block new third-party assets or scripts if you forget to allowlist them
- Worker deployment is not wired into the frontend build; it is a separate operational step

## Maintenance Notes

- When changing installer resources, check the root scripts, the matching files under `public/`, and `public/install-manifest.json`
- When changing stats domains, verify the CSP allowlist in `public/_headers`
- When changing locale paths, update both `sitemap.xml` and the initial language detection logic
- When adding third-party scripts, update CSP before shipping

## Command Quick Reference

```bash
pnpm dev
pnpm build
pnpm preview
pnpm fetch-registry
```
