Web App
Next.js web application. Route groups, API routes, and documentation site.
A server-rendered Next.js app that hosts the landing page, web app, documentation site, and API routes. Also serves as a PWA with offline support via Serwist.
Directory Structure
Route Groups
Pages are split into three route groups under [locale], each with its own layout:
| Group | Paths | Layout |
|---|---|---|
(landing) | /, /download | Marketing layout (no sidebar) |
(app) | /home, /dashboard/*, /settings | Sidebar-based app shell |
(docs) | /docs/... | Fumadocs documentation layout |
API routes live outside [locale] and skip the i18n middleware entirely.
Next.js Configuration
import type { NextConfig } from "next";
import createNextIntlPlugin from "@workspace/i18n/plugin";
import { createMDX } from "fumadocs-mdx/next";
import { withSerwist } from "@serwist/turbopack";
const withNextIntl = createNextIntlPlugin();
const withMDX = createMDX();
const nextConfig: NextConfig = {
transpilePackages: ["@workspace/ui", "@workspace/core", "@workspace/i18n"],
};
export default withSerwist(withNextIntl(withMDX(nextConfig)));Three plugins chained together:
| Plugin | What it does |
|---|---|
withMDX | Processes MDX content for Fumadocs |
withNextIntl | Enables locale-based routing and message loading |
withSerwist | Generates the service worker for PWA/offline support |
Middleware
import createMiddleware from "@workspace/i18n/middleware";
import { routing } from "@workspace/i18n/routing";
const intlMiddleware = createMiddleware(routing);
export default function proxy(request: import("next/server").NextRequest) {
return intlMiddleware(request);
}
export const config = {
matcher: "/((?!api|trpc|_next|_vercel|serwist|~offline|.*\\..*).*)",
};Handles locale detection and URL rewriting. The matcher excludes API routes, Next.js internals, Serwist service worker paths, and static files.
API Routes
POST /api/greet — Demo endpoint. Accepts a JSON body with a name field, validates and sanitizes input, returns a { message_key, name, source } response. The client uses message_key to resolve the translated greeting via next-intl. Server-side equivalent of the native app's Tauri greet command.
GET /api/search — Fumadocs search index:
import { source } from "@/lib/source";
import { createFromSource } from "fumadocs-core/search/server";
export const { GET } = createFromSource(source, {
localeMap: {
// Japanese and Chinese are not supported by Orama's stemmer,
// so we fall back to English stemming for search indexing.
ja: "english",
zh: "english",
},
});The localeMap handles languages where Orama's built-in stemmer has no support.
Documentation System
import { defineDocs, defineConfig } from "fumadocs-mdx/config";
import { remarkMdxMermaid } from "fumadocs-core/mdx-plugins";
export const docs = defineDocs({
dir: "content/docs",
});
export default defineConfig({
mdxOptions: {
remarkPlugins: [remarkMdxMermaid],
},
});MDX files in content/docs/ are processed at build time. The remarkMdxMermaid plugin enables Mermaid diagrams in MDX.
import { docs } from "fumadocs-mdx:collections/server";
import { loader } from "fumadocs-core/source";
import { createElement } from "react";
import { icons } from "lucide-react";
import { locales, routing } from "@workspace/i18n/routing";
export const source = loader({
baseUrl: "/docs",
source: docs.toFumadocsSource(),
i18n: {
languages: [...locales],
defaultLanguage: routing.defaultLocale,
fallbackLanguage: routing.defaultLocale,
},
icon(iconString) {
if (iconString && iconString in icons) {
return createElement(icons[iconString as keyof typeof icons] as any);
}
return undefined;
},
});Connects MDX content to the docs UI. The icon function resolves frontmatter icon fields to Lucide React components. Falls back to the default locale if a translation is missing.
Lib
| File | What it provides |
|---|---|
animations.ts | Shared Motion animation presets for landing page transitions |
detect-platform.ts | User-agent based OS detection for the download page |
github-releases.ts | Fetches release assets from the GitHub API for download links |
source.ts | Fumadocs content source loader (see Documentation System above) |
App Layout
The (app) route group wraps all app pages in AppLayout from @workspace/core, passing locale-aware Link and usePathname from @workspace/i18n/navigation. The sidebar, header, and navigation all come from the shared core and UI packages. See Core Package and UI Package for component details.