Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
ec8a5dc
Migrate documentation from VuePress 2 to Fumadocs
raspdevpy Aug 3, 2026
ea61d44
Fix dev-only image crash and unstyled sidebar folders
raspdevpy Aug 3, 2026
a4cd11c
u
zerofoil Aug 3, 2026
4233397
ignoring cache files
NervN Aug 3, 2026
713853e
Test change to see the build speed
NervN Aug 3, 2026
91c2aff
check one page modify
NervN Aug 3, 2026
5622a6c
Merge pull request #145 from zerofoil/fumadocs
NervN Aug 3, 2026
ff13f94
add shiki
NervN Aug 3, 2026
8393a28
Some changes
zerofoil Aug 3, 2026
e47ff31
Merge branch 'fumadocs-migration' into fumadocs
zerofoil Aug 3, 2026
b6fa131
Merge pull request #146 from zerofoil/fumadocs
NervN Aug 3, 2026
f719085
Update layout.shared.tsx
NervN Aug 3, 2026
3ef8d47
support for user mention/ping
NervN Aug 7, 2026
fcade61
Initial documentation of the new word trigger
NervN Aug 7, 2026
b8d1394
fix word_new page
NervN Aug 8, 2026
18a4727
add visual examples for app user/message trigger
NervN Aug 8, 2026
bcc0658
update custom bot guide to add intent
NervN Aug 8, 2026
ee7b4f5
document needed intent for custom bot for triggers
NervN Aug 8, 2026
550589b
hi
zerofoil Aug 4, 2026
066a136
Merge branch 'raspdevpy:fumadocs-migration' into fumadocs-migration
zerofoil Aug 8, 2026
5d96a08
Merge pull request #147 from zerofoil/fumadocs-migration
NervN Aug 8, 2026
5d58ed3
new utility wrapper for discord message
NervN Aug 8, 2026
d5e91b5
use cc lang
NervN Aug 8, 2026
f6ceaab
fix embed color
NervN Aug 8, 2026
4298fa2
fix when embed is empty
NervN Aug 8, 2026
a9a06e7
use new wrapper for discord messages
NervN Aug 8, 2026
1cb9e91
fix typescript check
NervN Aug 8, 2026
6930249
remove legacy function $error
NervN Aug 9, 2026
9501f5b
optimized view-related vars function
NervN Aug 9, 2026
1aece11
add query regex for $viewUserVars
NervN Aug 9, 2026
61ca544
use local bot-profile
NervN Aug 9, 2026
540a4e2
add example with separator in $viewServerVars
NervN Aug 9, 2026
fcf8783
add example to $sendMessage
NervN Aug 9, 2026
9791eb2
use cc lang for usage function
NervN Aug 9, 2026
8371e6e
fix func template and update it
NervN Aug 9, 2026
7957db1
use new discord message format
NervN Aug 9, 2026
4b9f143
adjust the spacing for discord messages
NervN Aug 9, 2026
5d0c161
Use new Tag wrapper
NervN Aug 9, 2026
999da2e
Use title style for tag
NervN Aug 9, 2026
b2fda3f
adjust missing title-style for tags
NervN Aug 9, 2026
8ad19a6
adjust the automatic tag extractor to use the new tag component
NervN Aug 9, 2026
c84addf
slash command support on the main bot for internal commands
NervN Aug 9, 2026
3fc668c
new sorting type for userleaderboard
NervN Aug 10, 2026
8744f96
new sorting type for $userVarRank
NervN Aug 10, 2026
0d01625
the wrapper accept same props and use the new format for discord mess…
NervN Aug 10, 2026
60a66dd
Fixed $memberJoinedDate broken markdown format
red88phantom Aug 10, 2026
2e6335d
Another requested adjustment
red88phantom Aug 10, 2026
9753919
Merge pull request #148 from red88phantom/fumadocs-forked
NervN Aug 10, 2026
e53a7ca
$message can be used inside app_cmd_message
NervN Aug 11, 2026
5e62413
use bold text instead of header, so the functions are clickable
NervN Aug 12, 2026
0af02cc
Restored missing syntax information for encoded character codes
red88phantom Aug 12, 2026
6c447aa
Deleted duplicate syntax page
red88phantom Aug 12, 2026
feb103b
Corrected brackets
red88phantom Aug 12, 2026
6488789
Merge pull request #149 from red88phantom/fumadocs-forked
NervN Aug 12, 2026
02d6a46
Enforce function naming convention like $funcName
NervN Aug 14, 2026
332c440
$includeLibrary respects the status
NervN Aug 14, 2026
bebdf5e
update poll trigger
NervN Aug 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
17 changes: 14 additions & 3 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
**/*
!package.json
!package-lock.json
!guide
!nginx.conf
!pnpm-lock.yaml
!pnpm-workspace.yaml
!next.config.mjs
!postcss.config.mjs
!source.config.ts
!tsconfig.json
!app
!components
!lib
!content
!data
!public
!scripts
!nginx.conf
19 changes: 17 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,23 @@ data.json
build*.sh
ignore/*
.DS_Store
guide/.vuepress/public/images/*.*
.vscode
OnTemplate.md
.env
guide/.vuepress/public/docs-pages.json

# next / fumadocs
.source
/.next/
/out/
*.tsbuildinfo
next-env.d.ts
.vercel

# remote images cached locally by lib/remark/images.ts
guide/.vuepress/public/images/*.*

# browser-automation session artifacts (snapshots, console logs)
.playwright-mcp/

.pnpm-store
docs-pages.json
1 change: 0 additions & 1 deletion .npmrc

This file was deleted.

14 changes: 8 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@
FROM node:24-alpine AS builder
WORKDIR /app

COPY package*.json ./
RUN npm ci --legacy-peer-deps
RUN npm i -g pnpm@11

COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
RUN pnpm install --frozen-lockfile

COPY . .
# adjust the build command if your project uses a different script
RUN npm run build
RUN pnpm build

# Stage 2 — serve with nginx
FROM nginx:1.25-alpine
ARG BUILD_DIR=guide/.vuepress/dist
ARG BUILD_DIR=out

# Remove default config and add a simple SPA-friendly config
COPY nginx.conf /etc/nginx/conf.d/default.conf
Expand All @@ -20,4 +21,5 @@ COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/${BUILD_DIR} /usr/share/nginx/html

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
CMD ["nginx", "-g", "daemon off;"]

11 changes: 6 additions & 5 deletions DockerfileDev
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# Stage 1 — build the static assets
FROM node:24-alpine3.21 AS builder
FROM node:24-alpine3.21
WORKDIR /app

COPY package*.json ./
RUN npm i --legacy-peer-deps
RUN npm i -g pnpm@11

COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
RUN pnpm install --frozen-lockfile

COPY . .

CMD ["npm", "run", "dev"]
CMD ["pnpm", "dev"]
24 changes: 19 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ For larger changes involving many files, we recommend using your IDE and the dev
### Requirements

[Git](https://git-scm.com/install/),
[Node.js](https://nodejs.org/en/download/current) `>=22.18.0` or [Docker Desktop](https://www.docker.com/products/docker-desktop/)
[Node.js](https://nodejs.org/en/download/current) `>=22.18.0` with [pnpm](https://pnpm.io/installation), or [Docker Desktop](https://www.docker.com/products/docker-desktop/)

### Steps

Expand All @@ -43,13 +43,13 @@ git clone git@github.com:YOUR_USERNAME/ccdoc.git
3\. Install dependencies:

```bash
npm i
pnpm install
```

4\. Start the dev server and go to [localhost:8080](http://localhost:8080):

```bash
npm run dev
pnpm dev
```

### Docker Compose
Expand All @@ -60,6 +60,16 @@ npm run dev
docker compose up
```

### Termux

The default Turbopack does not natively run on Android. You need to download their fixed package:

```bash
pkg i turbopack
```

Restart your app and then continue using the [Node.js](#nodejs) method.

## Saving Changes

After your changes are done, you need to update your fork.
Expand All @@ -79,7 +89,11 @@ git commit -m "Updated category Member"
3\. Push changes to your fork:

```bash
git push
git push origin
```

To send these changes for review, open your cloned fork on GitHub and click the `Open Pull Request` button.
To send these changes for review, open your cloned fork on GitHub, and click the `Open Pull Request` button.

## Naviagation

All documentation files are stored at `/content/docs`.
83 changes: 83 additions & 0 deletions app/(docs)/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { getPageMarkdownUrl, source } from "@/lib/source";
import {
DocsBody,
DocsDescription,
DocsPage,
DocsTitle,
MarkdownCopyButton,
ViewOptionsPopover,
} from "fumadocs-ui/layouts/docs/page";
import { notFound } from "next/navigation";
import { getMDXComponents } from "@/components/mdx";
import type { Metadata } from "next";
import { createRelativeLink } from "fumadocs-ui/mdx";
import { appName, gitConfig, socialImage, appDescription } from "@/lib/shared";
import { Button } from "@/components/ui/button";
import { GitHubLogoIcon } from "@radix-ui/react-icons";

export default async function Page(props: PageProps<"/[[...slug]]">) {
const params = await props.params;
const page = source.getPage(params.slug);
if (!page) notFound();

const MDX = page.data.body;
const markdownUrl = getPageMarkdownUrl(page).url;

return (
<DocsPage toc={page.data.toc} full={page.data.full}>
<DocsTitle>{page.data.title}</DocsTitle>
<DocsDescription className="mb-0">
{page.data.description}
</DocsDescription>
<div className="flex flex-row gap-2 items-center border-b pb-6">
<MarkdownCopyButton markdownUrl={markdownUrl} />
<Button
color="secondary"
icon={<GitHubLogoIcon />}
link={`https://github.com/${gitConfig.user}/${gitConfig.repo}/edit/${gitConfig.branch}/content/docs/${page.path}`}
>
Edit This Page
</Button>
</div>
<DocsBody>
<MDX
components={getMDXComponents({
a: createRelativeLink(source, page),
})}
/>
</DocsBody>
</DocsPage>
);
}

export async function generateStaticParams() {
return source.generateParams();
}

export async function generateMetadata(
props: PageProps<"/[[...slug]]">,
): Promise<Metadata> {
const params = await props.params;
const page = source.getPage(params.slug);
if (!page) notFound();

const social = page.data.title
? `${page.data.title} | ${appName}`
: `${appName} Documentation`;

return {
title: page.data.title,
description: appDescription,
openGraph: {
title: social,
description: appDescription,
images: socialImage,
},
twitter: {
card: "summary",
title: social,
description: appDescription,
images: socialImage,
},
};
}
11 changes: 11 additions & 0 deletions app/(docs)/layout.tsx
Original file line number Diff line number Diff line change
@@ -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 }: LayoutProps<"/">) {
return (
<DocsLayout tree={source.getPageTree()} {...baseOptions()}>
{children}
</DocsLayout>
);
}
53 changes: 53 additions & 0 deletions app/api/search/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import fs from 'node:fs';
import path from 'node:path';
import { source } from '@/lib/source';
import { createFromSource } from 'fumadocs-core/search/server';

export const revalidate = false;

/** difficulty labels were never treated as tags */
const NOT_A_TAG = /Easy|Difficult|Read Below|Medium|Bugged/i;

/**
* The old VuePress search fed `<Badge text="…" />` values into the index via
* `parseTags.js`, which is how searching "kick" or "reactions" finds a
* function. Badge props are JSX attributes, so they never reach the structured
* content Fumadocs indexes by default — read them back off the source file.
*/
function tagsFor(filePath: string, title: string) {
const raw = fs.readFileSync(path.join(process.cwd(), 'content/docs', filePath), 'utf8');

const tags: string[] = [];
for (const [, text] of raw.matchAll(/<(?:Badge|Tag)[^>]*\btext="([^"]*)"/g)) {
if (text.length > 1 && !NOT_A_TAG.test(text)) tags.push(text);
}
// the old plugin also indexed the bare function name
if (title.startsWith('$')) tags.push(title.slice(1));

return [...new Set(tags)];
}

export const { staticGET: GET } = createFromSource(source, {
// https://docs.orama.com/docs/orama-js/supported-languages
language: 'english',
buildIndex(page) {
const structuredData = page.data.structuredData;
const tags = tagsFor(page.path, page.data.title);

return {
id: page.url,
title: page.data.title,
description: page.data.description,
url: page.url,
structuredData: tags.length
? {
...structuredData,
contents: [
...structuredData.contents,
{ heading: undefined, content: tags.join(' ') },
],
}
: structuredData,
};
},
});
24 changes: 24 additions & 0 deletions app/global.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
@import "tailwindcss";
@import "fumadocs-ui/css/neutral.css";
@import "fumadocs-ui/css/preset.css";

html {
scrollbar-gutter: stable;
}

html > body[data-scroll-locked] {
margin-right: 0px !important;
--removed-body-scroll-bar-size: 0px !important;
}

discord-messages {
display: block;
margin: 1rem 0;
border-radius: 8px;
overflow: hidden;
}
@layer utilities {
.prose p {
margin-top: 0.25rem !important;
}
}
44 changes: 44 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Inter } from "next/font/google";
import type { Metadata, Viewport } from "next";
import { Provider } from "@/components/provider";
import { appDescription, appName, siteUrl, socialImage } from "@/lib/shared";
import "./global.css";

const inter = Inter({
subsets: ["latin"],
});

export const metadata: Metadata = {
metadataBase: new URL(siteUrl),
title: {
template: `%s | ${appName}`,
default: `${appName} Documentation`,
},
description: appDescription,
icons: {
icon: socialImage,
},
openGraph: {
description: appDescription,
images: socialImage,
},
twitter: {
card: "summary",
description: appDescription,
images: socialImage,
},
};

export const viewport: Viewport = {
themeColor: "#74b0f7",
};

export default function Layout({ children }: LayoutProps<"/">) {
return (
<html lang="en" className={inter.className} suppressHydrationWarning>
<body className="flex flex-col min-h-screen">
<Provider>{children}</Provider>
</body>
</html>
);
}
10 changes: 10 additions & 0 deletions app/llms-full.txt/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
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);

return new Response(scanned.join('\n\n'));
}
Loading