From 91179199f7164179188bc9d6b2f6af05c6b8ce4b Mon Sep 17 00:00:00 2001 From: Mathis HERRIOT <197931332+0x485254@users.noreply.github.com> Date: Mon, 5 Jan 2026 01:23:00 +0100 Subject: [PATCH] refactor: migrate documentation to support multi-language structure with i18n integration --- documentation/biome.json | 73 +++++------ .../content/docs/conception/index.fr.mdx | 116 ++++++++++++++++++ .../content/docs/conception/index.mdx | 116 ++++++++++++++++++ .../content/docs/conception/meta.en.json | 3 + .../content/docs/conception/meta.json | 3 + documentation/content/docs/index.fr.mdx | 13 ++ documentation/content/docs/index.mdx | 18 +-- documentation/content/docs/stack/index.fr.mdx | 17 +++ documentation/content/docs/stack/index.mdx | 17 +++ documentation/content/docs/stack/meta.en.json | 3 + documentation/content/docs/stack/meta.json | 3 + documentation/content/docs/test.mdx | 17 --- documentation/next.config.mjs | 4 +- documentation/package.json | 68 +++++----- documentation/postcss.config.mjs | 6 +- documentation/source.config.ts | 33 ++--- documentation/src/app/(home)/layout.tsx | 6 - documentation/src/app/(home)/page.tsx | 16 --- .../src/app/[lang]/(home)/layout.tsx | 6 + documentation/src/app/[lang]/(home)/page.tsx | 16 +++ .../src/app/[lang]/docs/[[...slug]]/page.tsx | 54 ++++++++ documentation/src/app/[lang]/docs/layout.tsx | 11 ++ documentation/src/app/[lang]/global.css | 3 + documentation/src/app/[lang]/layout.tsx | 38 ++++++ documentation/src/app/api/search/route.ts | 10 +- .../src/app/docs/[[...slug]]/page.tsx | 47 ------- documentation/src/app/docs/layout.tsx | 11 -- documentation/src/app/global.css | 3 - documentation/src/app/layout.tsx | 17 --- documentation/src/app/llms-full.txt/route.ts | 8 +- .../src/app/og/docs/[...slug]/route.tsx | 45 ++++--- documentation/src/components/mdx/mermaid.tsx | 56 +++++++++ documentation/src/lib/i18n.ts | 6 + documentation/src/lib/layout.shared.tsx | 14 ++- documentation/src/lib/source.ts | 28 +++-- documentation/src/mdx-components.tsx | 25 +++- documentation/src/proxy.ts | 10 ++ documentation/tsconfig.json | 80 ++++++------ 38 files changed, 705 insertions(+), 315 deletions(-) create mode 100644 documentation/content/docs/conception/index.fr.mdx create mode 100644 documentation/content/docs/conception/index.mdx create mode 100644 documentation/content/docs/conception/meta.en.json create mode 100644 documentation/content/docs/conception/meta.json create mode 100644 documentation/content/docs/index.fr.mdx create mode 100644 documentation/content/docs/stack/index.fr.mdx create mode 100644 documentation/content/docs/stack/index.mdx create mode 100644 documentation/content/docs/stack/meta.en.json create mode 100644 documentation/content/docs/stack/meta.json delete mode 100644 documentation/content/docs/test.mdx delete mode 100644 documentation/src/app/(home)/layout.tsx delete mode 100644 documentation/src/app/(home)/page.tsx create mode 100644 documentation/src/app/[lang]/(home)/layout.tsx create mode 100644 documentation/src/app/[lang]/(home)/page.tsx create mode 100644 documentation/src/app/[lang]/docs/[[...slug]]/page.tsx create mode 100644 documentation/src/app/[lang]/docs/layout.tsx create mode 100644 documentation/src/app/[lang]/global.css create mode 100644 documentation/src/app/[lang]/layout.tsx delete mode 100644 documentation/src/app/docs/[[...slug]]/page.tsx delete mode 100644 documentation/src/app/docs/layout.tsx delete mode 100644 documentation/src/app/global.css delete mode 100644 documentation/src/app/layout.tsx create mode 100644 documentation/src/components/mdx/mermaid.tsx create mode 100644 documentation/src/lib/i18n.ts create mode 100644 documentation/src/proxy.ts diff --git a/documentation/biome.json b/documentation/biome.json index 593467c..383bfff 100644 --- a/documentation/biome.json +++ b/documentation/biome.json @@ -1,41 +1,34 @@ { - "$schema": "https://biomejs.dev/schemas/2.3.11/schema.json", - "vcs": { - "enabled": true, - "clientKind": "git", - "useIgnoreFile": true - }, - "files": { - "ignoreUnknown": true, - "includes": [ - "**", - "!node_modules", - "!.next", - "!dist", - "!build", - "!.source" - ] - }, - "formatter": { - "enabled": true, - "indentStyle": "tab", - "indentWidth": 1 - }, - "linter": { - "enabled": true, - "rules": { - "recommended": true - }, - "domains": { - "next": "recommended", - "react": "recommended" - } - }, - "assist": { - "actions": { - "source": { - "organizeImports": "on" - } - } - } -} \ No newline at end of file + "$schema": "https://biomejs.dev/schemas/2.3.11/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "ignoreUnknown": true, + "includes": ["**", "!node_modules", "!.next", "!dist", "!build", "!.source"] + }, + "formatter": { + "enabled": true, + "indentStyle": "tab", + "indentWidth": 1 + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + }, + "domains": { + "next": "recommended", + "react": "recommended" + } + }, + "assist": { + "actions": { + "source": { + "organizeImports": "on" + } + } + } +} diff --git a/documentation/content/docs/conception/index.fr.mdx b/documentation/content/docs/conception/index.fr.mdx new file mode 100644 index 0000000..71e3e2e --- /dev/null +++ b/documentation/content/docs/conception/index.fr.mdx @@ -0,0 +1,116 @@ +--- +title: Conception de la Base de Données +description: MCD, MLD et MPD de MemeGoat. +--- + +## Modèle Conceptuel des Données (MCD) +Le MCD définit les entités et leurs relations. + +```mermaid +erDiagram + UTILISATEUR ||--o{ MEME : "crée" + UTILISATEUR ||--o{ COMMENTAIRE : "écrit" + MEME ||--o{ COMMENTAIRE : "reçoit" + MEME }o--o{ TAG : "possède" + + UTILISATEUR { + string pseudo + string email + string mot_de_passe + datetime date_creation + } + MEME { + string titre + string url_image + datetime date_creation + } + TAG { + string nom + } + COMMENTAIRE { + string contenu + datetime date_creation + } +``` + +## Modèle Logique des Données (MLD) +Le MLD traduit le MCD en tables avec les clés étrangères. + +```mermaid +erDiagram + users ||--o{ memes : "user_id" + users ||--o{ comments : "user_id" + memes ||--o{ comments : "meme_id" + memes ||--o{ meme_tags : "meme_id" + tags ||--o{ meme_tags : "tag_id" + + users { + uuid id PK + varchar username + varchar email + text password_hash + timestamp created_at + } + memes { + uuid id PK + varchar title + text image_url + uuid user_id FK + timestamp created_at + } + tags { + uuid id PK + varchar name + } + meme_tags { + uuid meme_id FK + uuid tag_id FK + } + comments { + uuid id PK + text content + uuid user_id FK + uuid meme_id FK + timestamp created_at + } +``` + +## Modèle Physique des Données (MPD) +Implémentation SQL pour PostgreSQL. + +```sql +CREATE TABLE users ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + username VARCHAR(50) UNIQUE NOT NULL, + email VARCHAR(255) UNIQUE NOT NULL, + password_hash TEXT NOT NULL, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE memes ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + title VARCHAR(255) NOT NULL, + image_url TEXT NOT NULL, + user_id UUID REFERENCES users(id) ON DELETE SET NULL, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE tags ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name VARCHAR(50) UNIQUE NOT NULL +); + +CREATE TABLE meme_tags ( + meme_id UUID REFERENCES memes(id) ON DELETE CASCADE, + tag_id UUID REFERENCES tags(id) ON DELETE CASCADE, + PRIMARY KEY (meme_id, tag_id) +); + +CREATE TABLE comments ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + content TEXT NOT NULL, + user_id UUID REFERENCES users(id) ON DELETE SET NULL, + meme_id UUID REFERENCES memes(id) ON DELETE CASCADE, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP +); +``` diff --git a/documentation/content/docs/conception/index.mdx b/documentation/content/docs/conception/index.mdx new file mode 100644 index 0000000..67509b4 --- /dev/null +++ b/documentation/content/docs/conception/index.mdx @@ -0,0 +1,116 @@ +--- +title: Database Design +description: MCD, MLD and MPD for MemeGoat. +--- + +## Conceptual Data Model (MCD) +The MCD defines entities and their relationships. + +```mermaid +erDiagram + USER ||--o{ MEME : "creates" + USER ||--o{ COMMENT : "writes" + MEME ||--o{ COMMENT : "receives" + MEME }o--o{ TAG : "has" + + USER { + string username + string email + string password + datetime created_at + } + MEME { + string title + string image_url + datetime created_at + } + TAG { + string name + } + COMMENT { + string content + datetime created_at + } +``` + +## Logical Data Model (MLD) +The MLD translates the MCD into tables with foreign keys. + +```mermaid +erDiagram + users ||--o{ memes : "user_id" + users ||--o{ comments : "user_id" + memes ||--o{ comments : "meme_id" + memes ||--o{ meme_tags : "meme_id" + tags ||--o{ meme_tags : "tag_id" + + users { + uuid id PK + varchar username + varchar email + text password_hash + timestamp created_at + } + memes { + uuid id PK + varchar title + text image_url + uuid user_id FK + timestamp created_at + } + tags { + uuid id PK + varchar name + } + meme_tags { + uuid meme_id FK + uuid tag_id FK + } + comments { + uuid id PK + text content + uuid user_id FK + uuid meme_id FK + timestamp created_at + } +``` + +## Physical Data Model (MPD) +SQL implementation for PostgreSQL. + +```sql +CREATE TABLE users ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + username VARCHAR(50) UNIQUE NOT NULL, + email VARCHAR(255) UNIQUE NOT NULL, + password_hash TEXT NOT NULL, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE memes ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + title VARCHAR(255) NOT NULL, + image_url TEXT NOT NULL, + user_id UUID REFERENCES users(id) ON DELETE SET NULL, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE tags ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name VARCHAR(50) UNIQUE NOT NULL +); + +CREATE TABLE meme_tags ( + meme_id UUID REFERENCES memes(id) ON DELETE CASCADE, + tag_id UUID REFERENCES tags(id) ON DELETE CASCADE, + PRIMARY KEY (meme_id, tag_id) +); + +CREATE TABLE comments ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + content TEXT NOT NULL, + user_id UUID REFERENCES users(id) ON DELETE SET NULL, + meme_id UUID REFERENCES memes(id) ON DELETE CASCADE, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP +); +``` diff --git a/documentation/content/docs/conception/meta.en.json b/documentation/content/docs/conception/meta.en.json new file mode 100644 index 0000000..3eb69fa --- /dev/null +++ b/documentation/content/docs/conception/meta.en.json @@ -0,0 +1,3 @@ +{ + "title": "Design" +} diff --git a/documentation/content/docs/conception/meta.json b/documentation/content/docs/conception/meta.json new file mode 100644 index 0000000..4ef1132 --- /dev/null +++ b/documentation/content/docs/conception/meta.json @@ -0,0 +1,3 @@ +{ + "title": "Conception" +} diff --git a/documentation/content/docs/index.fr.mdx b/documentation/content/docs/index.fr.mdx new file mode 100644 index 0000000..5484829 --- /dev/null +++ b/documentation/content/docs/index.fr.mdx @@ -0,0 +1,13 @@ +--- +title: Introduction +description: Bienvenue sur MemeGoat, la bibliothèque de MEME et GIF. +--- + +MemeGoat est un site bibliothèque de MEME et de GIF. +Le but est de permettre de retrouver une image adaptée à son besoin par une simple recherche. +Il est aussi possible de créer du contenu sur le site. + +## Objectifs +- Recherche rapide et intuitive. +- Partage de contenu original. +- Bibliothèque communautaire. diff --git a/documentation/content/docs/index.mdx b/documentation/content/docs/index.mdx index 1ede18e..53457a3 100644 --- a/documentation/content/docs/index.mdx +++ b/documentation/content/docs/index.mdx @@ -1,13 +1,13 @@ --- -title: Hello World -description: Your first document +title: Introduction +description: Welcome to MemeGoat, the MEME and GIF library. --- -Welcome to the docs! You can start writing documents in `/content/docs`. +MemeGoat is a MEME and GIF library website. +The goal is to allow finding an image suited to one's needs through a simple search. +It is also possible to create content on the site. -## What is Next? - - - - - +## Goals +- Fast and intuitive search. +- Sharing original content. +- Community-driven library. diff --git a/documentation/content/docs/stack/index.fr.mdx b/documentation/content/docs/stack/index.fr.mdx new file mode 100644 index 0000000..be8fc61 --- /dev/null +++ b/documentation/content/docs/stack/index.fr.mdx @@ -0,0 +1,17 @@ +--- +title: Stack Technique +description: Choix technologiques pour MemeGoat. +--- + +## Frontend +- **Framework**: Next.js 15 +- **Style**: Tailwind CSS +- **Bibliothèque UI**: Lucide React, Radix UI + +## Backend +- **Langage**: Node.js (TypeScript) / NestJS ou Go +- **Base de données**: PostgreSQL +- **Stockage d'images**: S3 ou similaire (Cloudinary, Uploadcare) + +## Documentation +- **Framework**: Fumadocs diff --git a/documentation/content/docs/stack/index.mdx b/documentation/content/docs/stack/index.mdx new file mode 100644 index 0000000..2bbeb15 --- /dev/null +++ b/documentation/content/docs/stack/index.mdx @@ -0,0 +1,17 @@ +--- +title: Tech Stack +description: Technological choices for MemeGoat. +--- + +## Frontend +- **Framework**: Next.js 15 +- **Style**: Tailwind CSS +- **UI Library**: Lucide React, Radix UI + +## Backend +- **Language**: Node.js (TypeScript) / NestJS or Go +- **Database**: PostgreSQL +- **Image Storage**: S3 or similar (Cloudinary, Uploadcare) + +## Documentation +- **Framework**: Fumadocs diff --git a/documentation/content/docs/stack/meta.en.json b/documentation/content/docs/stack/meta.en.json new file mode 100644 index 0000000..3c7c4f4 --- /dev/null +++ b/documentation/content/docs/stack/meta.en.json @@ -0,0 +1,3 @@ +{ + "title": "Stack" +} diff --git a/documentation/content/docs/stack/meta.json b/documentation/content/docs/stack/meta.json new file mode 100644 index 0000000..3c7c4f4 --- /dev/null +++ b/documentation/content/docs/stack/meta.json @@ -0,0 +1,3 @@ +{ + "title": "Stack" +} diff --git a/documentation/content/docs/test.mdx b/documentation/content/docs/test.mdx deleted file mode 100644 index f475f4a..0000000 --- a/documentation/content/docs/test.mdx +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: Components -description: Components ---- - -## Code Block - -```js -console.log('Hello World'); -``` - -## Cards - - - - - diff --git a/documentation/next.config.mjs b/documentation/next.config.mjs index 457dcf2..dc4fcb1 100644 --- a/documentation/next.config.mjs +++ b/documentation/next.config.mjs @@ -1,10 +1,10 @@ -import { createMDX } from 'fumadocs-mdx/next'; +import { createMDX } from "fumadocs-mdx/next"; const withMDX = createMDX(); /** @type {import('next').NextConfig} */ const config = { - reactStrictMode: true, + reactStrictMode: true, }; export default withMDX(config); diff --git a/documentation/package.json b/documentation/package.json index 98c412b..51813e9 100644 --- a/documentation/package.json +++ b/documentation/package.json @@ -1,34 +1,36 @@ { - "name": "@memegoat/documentation", - "version": "0.0.1", - "private": true, - "scripts": { - "build": "next build", - "dev": "next dev", - "start": "next start", - "types:check": "fumadocs-mdx && next typegen && tsc --noEmit", - "postinstall": "fumadocs-mdx", - "lint": "biome check", - "format": "biome format --write" - }, - "dependencies": { - "fumadocs-core": "16.4.3", - "fumadocs-mdx": "14.2.4", - "fumadocs-ui": "16.4.3", - "lucide-react": "^0.562.0", - "next": "16.1.1", - "react": "^19.2.3", - "react-dom": "^19.2.3" - }, - "devDependencies": { - "@tailwindcss/postcss": "^4.1.18", - "@types/mdx": "^2.0.13", - "@types/node": "^24.10.2", - "@types/react": "^19.2.7", - "@types/react-dom": "^19.2.3", - "postcss": "^8.5.6", - "tailwindcss": "^4.1.18", - "typescript": "^5.9.3", - "@biomejs/biome": "^2.3.10" - } -} \ No newline at end of file + "name": "@memegoat/documentation", + "version": "0.0.1", + "private": true, + "scripts": { + "build": "next build", + "dev": "next dev", + "start": "next start", + "types:check": "fumadocs-mdx && next typegen && tsc --noEmit", + "postinstall": "fumadocs-mdx", + "lint": "biome check", + "format": "biome format --write" + }, + "dependencies": { + "fumadocs-core": "16.4.3", + "fumadocs-mdx": "14.2.4", + "fumadocs-ui": "16.4.3", + "lucide-react": "^0.562.0", + "mermaid": "^11.12.2", + "next": "16.1.1", + "next-themes": "^0.4.6", + "react": "^19.2.3", + "react-dom": "^19.2.3" + }, + "devDependencies": { + "@biomejs/biome": "^2.3.10", + "@tailwindcss/postcss": "^4.1.18", + "@types/mdx": "^2.0.13", + "@types/node": "^24.10.2", + "@types/react": "^19.2.7", + "@types/react-dom": "^19.2.3", + "postcss": "^8.5.6", + "tailwindcss": "^4.1.18", + "typescript": "^5.9.3" + } +} diff --git a/documentation/postcss.config.mjs b/documentation/postcss.config.mjs index a34a3d5..017b34b 100644 --- a/documentation/postcss.config.mjs +++ b/documentation/postcss.config.mjs @@ -1,5 +1,5 @@ export default { - plugins: { - '@tailwindcss/postcss': {}, - }, + plugins: { + "@tailwindcss/postcss": {}, + }, }; diff --git a/documentation/source.config.ts b/documentation/source.config.ts index 63cedfa..a65e66a 100644 --- a/documentation/source.config.ts +++ b/documentation/source.config.ts @@ -1,22 +1,27 @@ -import { defineConfig, defineDocs, frontmatterSchema, metaSchema } from 'fumadocs-mdx/config'; +import { + defineConfig, + defineDocs, + frontmatterSchema, + metaSchema, +} from "fumadocs-mdx/config"; // You can customise Zod schemas for frontmatter and `meta.json` here // see https://fumadocs.dev/docs/mdx/collections export const docs = defineDocs({ - dir: 'content/docs', - docs: { - schema: frontmatterSchema, - postprocess: { - includeProcessedMarkdown: true, - }, - }, - meta: { - schema: metaSchema, - }, + dir: "content/docs", + docs: { + schema: frontmatterSchema, + postprocess: { + includeProcessedMarkdown: true, + }, + }, + meta: { + schema: metaSchema, + }, }); export default defineConfig({ - mdxOptions: { - // MDX options - }, + mdxOptions: { + // MDX options + }, }); diff --git a/documentation/src/app/(home)/layout.tsx b/documentation/src/app/(home)/layout.tsx deleted file mode 100644 index 77379fa..0000000 --- a/documentation/src/app/(home)/layout.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import { HomeLayout } from 'fumadocs-ui/layouts/home'; -import { baseOptions } from '@/lib/layout.shared'; - -export default function Layout({ children }: LayoutProps<'/'>) { - return {children}; -} diff --git a/documentation/src/app/(home)/page.tsx b/documentation/src/app/(home)/page.tsx deleted file mode 100644 index c936084..0000000 --- a/documentation/src/app/(home)/page.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import Link from 'next/link'; - -export default function HomePage() { - return ( -
-

Hello World

-

- You can open{' '} - - /docs - {' '} - and see the documentation. -

-
- ); -} diff --git a/documentation/src/app/[lang]/(home)/layout.tsx b/documentation/src/app/[lang]/(home)/layout.tsx new file mode 100644 index 0000000..ddf6cd0 --- /dev/null +++ b/documentation/src/app/[lang]/(home)/layout.tsx @@ -0,0 +1,6 @@ +import { HomeLayout } from "fumadocs-ui/layouts/home"; +import { baseOptions } from "@/lib/layout.shared"; + +export default function Layout({ children }: { children: React.ReactNode; params: Promise<{ lang: string }>}) { + return {children}; +} diff --git a/documentation/src/app/[lang]/(home)/page.tsx b/documentation/src/app/[lang]/(home)/page.tsx new file mode 100644 index 0000000..77065d7 --- /dev/null +++ b/documentation/src/app/[lang]/(home)/page.tsx @@ -0,0 +1,16 @@ +import Link from "next/link"; + +export default function HomePage() { + return ( +
+

Hello World

+

+ You can open{" "} + + /docs + {" "} + and see the documentation. +

+
+ ); +} diff --git a/documentation/src/app/[lang]/docs/[[...slug]]/page.tsx b/documentation/src/app/[lang]/docs/[[...slug]]/page.tsx new file mode 100644 index 0000000..5ce974c --- /dev/null +++ b/documentation/src/app/[lang]/docs/[[...slug]]/page.tsx @@ -0,0 +1,54 @@ +import { getPageImage, source } from "@/lib/source"; +import { + DocsBody, + DocsDescription, + DocsPage, + DocsTitle, +} from "fumadocs-ui/layouts/docs/page"; +import { notFound } from "next/navigation"; +import { getMDXComponents } from "@/mdx-components"; +import type { Metadata } from "next"; +import { createRelativeLink } from "fumadocs-ui/mdx"; + +export default async function Page(props: { params: Promise<{ lang: string; slug?: string[]; }> }) { + const params = await props.params; + const page = source.getPage(params.slug, params.lang); + if (!page) notFound(); + + const MDX = page.data.body; + + return ( + + {page.data.title} + {page.data.description} + + + + + ); +} + +export async function generateStaticParams() { + return source.generateParams(); +} + +export async function generateMetadata( + props: PageProps<"/docs/[[...slug]]"> & { params: Promise<{ lang: string; }> }, +): Promise { + const params = await props.params; + const page = source.getPage(params.slug, params.lang); + if (!page) notFound(); + + return { + title: page.data.title, + description: page.data.description, + openGraph: { + images: getPageImage(page).url, + }, + }; +} diff --git a/documentation/src/app/[lang]/docs/layout.tsx b/documentation/src/app/[lang]/docs/layout.tsx new file mode 100644 index 0000000..392fc28 --- /dev/null +++ b/documentation/src/app/[lang]/docs/layout.tsx @@ -0,0 +1,11 @@ +import { source } from "@/lib/source"; +import { DocsLayout } from "fumadocs-ui/layouts/docs"; +import { baseOptions } from "@/lib/layout.shared"; + +export default function Layout({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} diff --git a/documentation/src/app/[lang]/global.css b/documentation/src/app/[lang]/global.css new file mode 100644 index 0000000..dbcc721 --- /dev/null +++ b/documentation/src/app/[lang]/global.css @@ -0,0 +1,3 @@ +@import "tailwindcss"; +@import "fumadocs-ui/css/neutral.css"; +@import "fumadocs-ui/css/preset.css"; diff --git a/documentation/src/app/[lang]/layout.tsx b/documentation/src/app/[lang]/layout.tsx new file mode 100644 index 0000000..8167380 --- /dev/null +++ b/documentation/src/app/[lang]/layout.tsx @@ -0,0 +1,38 @@ +import { RootProvider } from "fumadocs-ui/provider/next"; +import "./global.css"; +import { Inter } from "next/font/google"; +import { defineI18nUI } from "fumadocs-ui/i18n"; +import { i18n } from "@/lib/i18n"; + +const inter = Inter({ + subsets: ["latin"], +}); + +const { provider } = defineI18nUI(i18n, { + translations: { + en: { + displayName: "English", + }, + fr: { + displayName: "French", + }, + }, +}); + +export default async function RootLayout({ + params, + children, +}: { + params: Promise<{ lang: string }>; + children: React.ReactNode; +}) { + const lang = (await params).lang; + + return ( + + + {children} + + + ); +} diff --git a/documentation/src/app/api/search/route.ts b/documentation/src/app/api/search/route.ts index 7ba7e82..e19bc5b 100644 --- a/documentation/src/app/api/search/route.ts +++ b/documentation/src/app/api/search/route.ts @@ -1,7 +1,9 @@ -import { source } from '@/lib/source'; -import { createFromSource } from 'fumadocs-core/search/server'; +import { source } from "@/lib/source"; +import { createFromSource } from "fumadocs-core/search/server"; export const { GET } = createFromSource(source, { - // https://docs.orama.com/docs/orama-js/supported-languages - language: 'english', + localeMap: { + fr: { language: 'french' }, + en: { language: 'english' }, + }, }); diff --git a/documentation/src/app/docs/[[...slug]]/page.tsx b/documentation/src/app/docs/[[...slug]]/page.tsx deleted file mode 100644 index 3d4190c..0000000 --- a/documentation/src/app/docs/[[...slug]]/page.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { getPageImage, source } from '@/lib/source'; -import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page'; -import { notFound } from 'next/navigation'; -import { getMDXComponents } from '@/mdx-components'; -import type { Metadata } from 'next'; -import { createRelativeLink } from 'fumadocs-ui/mdx'; - -export default async function Page(props: PageProps<'/docs/[[...slug]]'>) { - const params = await props.params; - const page = source.getPage(params.slug); - if (!page) notFound(); - - const MDX = page.data.body; - - return ( - - {page.data.title} - {page.data.description} - - - - - ); -} - -export async function generateStaticParams() { - return source.generateParams(); -} - -export async function generateMetadata(props: PageProps<'/docs/[[...slug]]'>): Promise { - const params = await props.params; - const page = source.getPage(params.slug); - if (!page) notFound(); - - return { - title: page.data.title, - description: page.data.description, - openGraph: { - images: getPageImage(page).url, - }, - }; -} diff --git a/documentation/src/app/docs/layout.tsx b/documentation/src/app/docs/layout.tsx deleted file mode 100644 index a373143..0000000 --- a/documentation/src/app/docs/layout.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { source } from '@/lib/source'; -import { DocsLayout } from 'fumadocs-ui/layouts/docs'; -import { baseOptions } from '@/lib/layout.shared'; - -export default function Layout({ children }: LayoutProps<'/docs'>) { - return ( - - {children} - - ); -} diff --git a/documentation/src/app/global.css b/documentation/src/app/global.css deleted file mode 100644 index 50b3bc2..0000000 --- a/documentation/src/app/global.css +++ /dev/null @@ -1,3 +0,0 @@ -@import 'tailwindcss'; -@import 'fumadocs-ui/css/neutral.css'; -@import 'fumadocs-ui/css/preset.css'; diff --git a/documentation/src/app/layout.tsx b/documentation/src/app/layout.tsx deleted file mode 100644 index 22fdca3..0000000 --- a/documentation/src/app/layout.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { RootProvider } from 'fumadocs-ui/provider/next'; -import './global.css'; -import { Inter } from 'next/font/google'; - -const inter = Inter({ - subsets: ['latin'], -}); - -export default function Layout({ children }: LayoutProps<'/'>) { - return ( - - - {children} - - - ); -} diff --git a/documentation/src/app/llms-full.txt/route.ts b/documentation/src/app/llms-full.txt/route.ts index d494d2c..b5b8fe6 100644 --- a/documentation/src/app/llms-full.txt/route.ts +++ b/documentation/src/app/llms-full.txt/route.ts @@ -1,10 +1,10 @@ -import { getLLMText, source } from '@/lib/source'; +import { getLLMText, source } from "@/lib/source"; export const revalidate = false; export async function GET() { - const scan = source.getPages().map(getLLMText); - const scanned = await Promise.all(scan); + const scan = source.getPages().map(getLLMText); + const scanned = await Promise.all(scan); - return new Response(scanned.join('\n\n')); + return new Response(scanned.join("\n\n")); } diff --git a/documentation/src/app/og/docs/[...slug]/route.tsx b/documentation/src/app/og/docs/[...slug]/route.tsx index 2d741be..fdfc67e 100644 --- a/documentation/src/app/og/docs/[...slug]/route.tsx +++ b/documentation/src/app/og/docs/[...slug]/route.tsx @@ -1,27 +1,34 @@ -import { getPageImage, source } from '@/lib/source'; -import { notFound } from 'next/navigation'; -import { ImageResponse } from 'next/og'; -import { generate as DefaultImage } from 'fumadocs-ui/og'; +import { getPageImage, source } from "@/lib/source"; +import { notFound } from "next/navigation"; +import { ImageResponse } from "next/og"; +import { generate as DefaultImage } from "fumadocs-ui/og"; export const revalidate = false; -export async function GET(_req: Request, { params }: RouteContext<'/og/docs/[...slug]'>) { - const { slug } = await params; - const page = source.getPage(slug.slice(0, -1)); - if (!page) notFound(); +export async function GET( + _req: Request, + { params }: RouteContext<"/og/docs/[...slug]">, +) { + const { slug } = await params; + const page = source.getPage(slug.slice(0, -1)); + if (!page) notFound(); - return new ImageResponse( - , - { - width: 1200, - height: 630, - }, - ); + return new ImageResponse( + , + { + width: 1200, + height: 630, + }, + ); } export function generateStaticParams() { - return source.getPages().map((page) => ({ - lang: page.locale, - slug: getPageImage(page).segments, - })); + return source.getPages().map((page) => ({ + lang: page.locale, + slug: getPageImage(page).segments, + })); } diff --git a/documentation/src/components/mdx/mermaid.tsx b/documentation/src/components/mdx/mermaid.tsx new file mode 100644 index 0000000..beb5fee --- /dev/null +++ b/documentation/src/components/mdx/mermaid.tsx @@ -0,0 +1,56 @@ +'use client'; + +import { use, useEffect, useId, useState } from 'react'; +import { useTheme } from 'next-themes'; + +export function Mermaid({ chart }: { chart: string }) { + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + }, []); + + if (!mounted) return; + return ; +} + +const cache = new Map>(); + +function cachePromise(key: string, setPromise: () => Promise): Promise { + const cached = cache.get(key); + if (cached) return cached as Promise; + + const promise = setPromise(); + cache.set(key, promise); + return promise; +} + +function MermaidContent({ chart }: { chart: string }) { + const id = useId(); + const { resolvedTheme } = useTheme(); + const { default: mermaid } = use(cachePromise('mermaid', () => import('mermaid'))); + + mermaid.initialize({ + startOnLoad: false, + securityLevel: 'loose', + fontFamily: 'inherit', + themeCSS: 'margin: 1.5rem auto 0;', + theme: resolvedTheme === 'dark' ? 'dark' : 'default', + }); + + const { svg, bindFunctions } = use( + cachePromise(`${chart}-${resolvedTheme}`, () => { + return mermaid.render(id, chart.replaceAll('\\n', '\n')); + }), + ); + + return ( +
{ + if (container) bindFunctions?.(container); + }} + // biome-ignore lint/security/noDangerouslySetInnerHtml: correct usage. + dangerouslySetInnerHTML={{ __html: svg }} + /> + ); +} \ No newline at end of file diff --git a/documentation/src/lib/i18n.ts b/documentation/src/lib/i18n.ts new file mode 100644 index 0000000..6906259 --- /dev/null +++ b/documentation/src/lib/i18n.ts @@ -0,0 +1,6 @@ +import { defineI18n } from "fumadocs-core/i18n"; + +export const i18n = defineI18n({ + defaultLanguage: "en", + languages: ["en", "fr"], +}); diff --git a/documentation/src/lib/layout.shared.tsx b/documentation/src/lib/layout.shared.tsx index 7e961b6..f963462 100644 --- a/documentation/src/lib/layout.shared.tsx +++ b/documentation/src/lib/layout.shared.tsx @@ -1,9 +1,11 @@ -import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared'; +import type { BaseLayoutProps } from "fumadocs-ui/layouts/shared"; +import {i18n} from "@/lib/i18n"; export function baseOptions(): BaseLayoutProps { - return { - nav: { - title: 'My App', - }, - }; + return { + i18n, + nav: { + title: "MemeGoat", + }, + }; } diff --git a/documentation/src/lib/source.ts b/documentation/src/lib/source.ts index 2b2d52f..f38beed 100644 --- a/documentation/src/lib/source.ts +++ b/documentation/src/lib/source.ts @@ -1,27 +1,29 @@ -import { docs } from 'fumadocs-mdx:collections/server'; -import { type InferPageType, loader } from 'fumadocs-core/source'; -import { lucideIconsPlugin } from 'fumadocs-core/source/lucide-icons'; +import { docs } from "fumadocs-mdx:collections/server"; +import { type InferPageType, loader } from "fumadocs-core/source"; +import { lucideIconsPlugin } from "fumadocs-core/source/lucide-icons"; +import {i18n} from "@/lib/i18n"; // See https://fumadocs.dev/docs/headless/source-api for more info export const source = loader({ - baseUrl: '/docs', - source: docs.toFumadocsSource(), - plugins: [lucideIconsPlugin()], + i18n, + baseUrl: "/docs", + source: docs.toFumadocsSource(), + plugins: [lucideIconsPlugin()], }); export function getPageImage(page: InferPageType) { - const segments = [...page.slugs, 'image.png']; + const segments = [...page.slugs, "image.png"]; - return { - segments, - url: `/og/docs/${segments.join('/')}`, - }; + return { + segments, + url: `/og/docs/${segments.join("/")}`, + }; } export async function getLLMText(page: InferPageType) { - const processed = await page.data.getText('processed'); + const processed = await page.data.getText("processed"); - return `# ${page.data.title} + return `# ${page.data.title} ${processed}`; } diff --git a/documentation/src/mdx-components.tsx b/documentation/src/mdx-components.tsx index 20beb4c..357a053 100644 --- a/documentation/src/mdx-components.tsx +++ b/documentation/src/mdx-components.tsx @@ -1,9 +1,22 @@ -import defaultMdxComponents from 'fumadocs-ui/mdx'; -import type { MDXComponents } from 'mdx/types'; +import defaultMdxComponents from "fumadocs-ui/mdx"; +import type { MDXComponents } from "mdx/types"; +import { Mermaid } from "@/components/mdx/mermaid"; export function getMDXComponents(components?: MDXComponents): MDXComponents { - return { - ...defaultMdxComponents, - ...components, - }; + return { + ...defaultMdxComponents, + ...components, + pre: ({ children, ...props }: any) => { + if ( + children && + typeof children === "object" && + "type" in children && + (children as any).type === "code" && + (children as any).props.className === "language-mermaid" + ) { + return ; + } + return {children}; + }, + }; } diff --git a/documentation/src/proxy.ts b/documentation/src/proxy.ts new file mode 100644 index 0000000..2dbd7b7 --- /dev/null +++ b/documentation/src/proxy.ts @@ -0,0 +1,10 @@ +import { createI18nMiddleware } from "fumadocs-core/i18n/middleware"; +import { i18n } from "@/lib/i18n"; + +export default createI18nMiddleware(i18n); + +export const config = { + // Matcher ignoring `/_next/` and `/api/` + //TODO Adjust it to ignore static assets in `/public` folder + matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"], +}; diff --git a/documentation/tsconfig.json b/documentation/tsconfig.json index 77775fb..2c49434 100644 --- a/documentation/tsconfig.json +++ b/documentation/tsconfig.json @@ -1,46 +1,36 @@ { - "compilerOptions": { - "baseUrl": ".", - "target": "ESNext", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "react-jsx", - "incremental": true, - "paths": { - "@/*": [ - "./src/*" - ], - "fumadocs-mdx:collections/*": [ - ".source/*" - ] - }, - "plugins": [ - { - "name": "next" - } - ] - }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx", - ".next/types/**/*.ts", - ".next/dev/types/**/*.ts" - ], - "exclude": [ - "node_modules" - ] -} \ No newline at end of file + "compilerOptions": { + "baseUrl": ".", + "target": "ESNext", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "paths": { + "@/*": ["./src/*"], + "fumadocs-mdx:collections/*": [".source/*"] + }, + "plugins": [ + { + "name": "next" + } + ] + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts" + ], + "exclude": ["node_modules"] +}