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"]
+}