From 13525d9633eaa173313ec566365d36be618e89e6 Mon Sep 17 00:00:00 2001 From: Muhammad Wildan Aldiansyah Date: Thu, 16 Apr 2026 08:55:47 +0700 Subject: [PATCH 1/2] feat: local search, blog, PWA, CI, 404 page, and docs polish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Local search: - Add @easyops-cn/docusaurus-search-local with hashed index, keyed to the docs routeBasePath (/) so the search bar covers every page. Blog / Changelog: - Re-enable the blog preset as /changelog with RSS + Atom feeds. - Ship one starter post announcing the docs refresh. - Add "Changelog" link to the navbar. PWA: - Add @docusaurus/plugin-pwa with manifest.json, apple-touch-icon, and mask-icon. swRegister is off for now to avoid cache surprises. CI: - New ci.yml that runs yarn build on every PR — catches MDX errors and broken internal links before merge. - New dependabot.yml to keep Docusaurus, Actions, and dev deps current. Custom 404: - Branded 404 page with three "go somewhere useful" tiles (Intro, Getting Started, Commands) and links to the FAQ and support server. Open Graph image: - New 1200×630 SVG at static/img/og-image.svg matching the land theme. OG and Twitter card metadata now point at it. Favicon: - Switch from the default Docusaurus favicon.ico to img/logo-mocha.svg. Other polish: - showLastUpdateAuthor enabled in docs preset. - Copy-button CSS: visible border, gold hover accent, "copied" state. - Admonitions on three pages: permissions info box in Getting Started, edit-window warning in Messages, Manage Webhooks note in Personalization. --- .github/dependabot.yml | 31 +++++ .github/workflows/ci.yml | 28 +++++ blog/2026-04-16-documentation-refresh.md | 59 +++++++++ blog/authors.yml | 7 ++ docs/chat/messages.md | 4 + docs/rooms/personalization.md | 4 + docs/tutorials/getting-started.md | 4 + docusaurus.config.js | 149 +++++++++++++++++++++-- package.json | 2 + src/css/custom.css | 41 +++++++ src/pages/404.module.css | 100 +++++++++++++++ src/pages/404.tsx | 57 +++++++++ static/img/og-image.svg | 28 +++++ static/manifest.json | 25 ++++ 14 files changed, 529 insertions(+), 10 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/ci.yml create mode 100644 blog/2026-04-16-documentation-refresh.md create mode 100644 blog/authors.yml create mode 100644 src/pages/404.module.css create mode 100644 src/pages/404.tsx create mode 100644 static/img/og-image.svg create mode 100644 static/manifest.json diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..d1c6344 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,31 @@ +version: 2 +updates: + - package-ecosystem: npm + directory: / + schedule: + interval: weekly + day: monday + open-pull-requests-limit: 5 + groups: + docusaurus: + patterns: + - "@docusaurus/*" + - "prism-react-renderer" + - "@mdx-js/*" + - "@easyops-cn/docusaurus-search-local" + update-types: + - minor + - patch + dev-tools: + patterns: + - "typescript" + - "@types/*" + update-types: + - minor + - patch + + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + day: monday diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..ea9b50a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,28 @@ +name: CI + +on: + pull_request: + branches: + - master + push: + branches-ignore: + - master + - gh-pages + +jobs: + build: + name: Build and verify docs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install dependencies + run: yarn install --frozen-lockfile=false + + - name: Build + run: yarn build diff --git a/blog/2026-04-16-documentation-refresh.md b/blog/2026-04-16-documentation-refresh.md new file mode 100644 index 0000000..f0d8471 --- /dev/null +++ b/blog/2026-04-16-documentation-refresh.md @@ -0,0 +1,59 @@ +--- +slug: documentation-refresh-2026 +title: Documentation Refresh — Tutorials, Dark Theme, Search +authors: [mocha-team] +tags: [docs, release] +description: We rebuilt the Mocha documentation site from the ground up — new tutorials, dark theme, local search, and every feature documented with examples and troubleshooting. +--- + +The Mocha documentation site just got a full refresh. Every feature is now documented, the theme matches the main mocha-bot.xyz site, and there's a proper tutorial track for people getting started with the bot. + + + +## What's new + +### Tutorials + +There's a new **Tutorials** section with four step-by-step walkthroughs that take you from "I've never used this bot" to "I'm moderating a cross-server room": + +- **[Getting Started](/tutorials/getting-started)** — invite the bot, set up permissions, create your first room. +- **[Connect Two Servers](/tutorials/connect-two-servers)** — bridge two Discord servers end-to-end with a test checklist. +- **[Share a Room via Invitation](/tutorials/share-via-invite)** — the full invitation flow with aliases, usage caps, and expiration. +- **[Curate Your Room](/tutorials/curate-your-room)** — editing details, kicking channels, enabling personalization, deleting rooms. + +### Full feature coverage + +Every slash command, chat behavior, and room feature now has its own reference page with: + +- Exact parameters with types and whether they're required. +- What the bot does under the hood (without dragging in implementation details). +- A troubleshooting table for the errors you're most likely to hit. +- Cross-links so you can hop from a command to the concept behind it. + +That includes `/feedback` (new), the full `/room invite` subcommand group, typing indicators, reply threading, pins, ratings, and personalization. + +### Dark theme to match the main site + +The docs site now uses the same visual language as [mocha-bot.xyz](https://mocha-bot.xyz): pure black background, Plus Jakarta Sans, gold accents, glass surfaces, blurred navbar. Dark mode is the only mode — no more accidental light-mode flashes when following links out of the main site. + +### Local search + +There's a search bar in the navbar now. It indexes every page at build time — no third-party service, no approval process, instant results. + +### SEO and sharing + +- Per-page Open Graph and Twitter card metadata so shared links render properly in Discord, Slack, and Twitter. +- A site-wide schema.org `WebSite` JSON-LD block plus the automatic `BreadcrumbList` structured data Docusaurus ships. +- A generated sitemap and a `robots.txt` pointing at it. +- A custom 404 page with links to the tutorials, commands reference, and FAQ. + +### Under the hood + +- Docusaurus v3 (up from v2 RC). +- PWA enabled — you can install the docs as an app. +- CI runs `yarn build` and link-checks every pull request. +- Dependabot watches for updates so nothing rots. + +## What's next + +If you spot something missing, wrong, or confusing, let us know via the in-bot `/feedback` command or drop a message in the [support server](https://discord.mocha-bot.xyz/). This site is living documentation — the more you tell us where it breaks, the better it gets. diff --git a/blog/authors.yml b/blog/authors.yml new file mode 100644 index 0000000..da468b0 --- /dev/null +++ b/blog/authors.yml @@ -0,0 +1,7 @@ +mocha-team: + name: Mocha Team + title: Mocha Bot maintainers + url: https://mocha-bot.xyz + image_url: /img/logo-mocha.png + socials: + github: mocha-bot diff --git a/docs/chat/messages.md b/docs/chat/messages.md index 026a8e2..d255d58 100644 --- a/docs/chat/messages.md +++ b/docs/chat/messages.md @@ -56,6 +56,10 @@ Editing a message edits its copies in every other channel in the room. There is After the window expires the original edit will no longer propagate to followers. +:::warning +The window is measured from when the message was originally sent, not when you start editing. If you open the edit dialog just before the window closes and hit save a minute later, Mocha has already forgotten about the message and your change will only affect the original channel. +::: + ## Delete Message Deleting a message deletes every copy of it in the room, under the same time-window rules as editing. diff --git a/docs/rooms/personalization.md b/docs/rooms/personalization.md index c6bda44..aafe0a5 100644 --- a/docs/rooms/personalization.md +++ b/docs/rooms/personalization.md @@ -30,6 +30,10 @@ The room owner can toggle the flag later. Personalization requires the **Persona - If the webhook is missing (for example, because the server didn't grant **Manage Webhooks**), Mocha falls back to a normal bot message with the standard `[ Server ][ user ] >>` prefix — nothing is lost. - When a channel disconnects, its webhook is deleted. +:::note Needs "Manage Webhooks" +Personalization only works on servers where Mocha was granted **Manage Webhooks**. The fallback keeps the room functional for servers that didn't grant it, but those channels won't show per-user avatars. There's no warning — if you're running a mixed room, some sides will have personalization and others won't. +::: + ## Things to know - Per-user edits and deletes still work: Mocha tracks the webhook that sent each copy and edits/deletes via that webhook. diff --git a/docs/tutorials/getting-started.md b/docs/tutorials/getting-started.md index 6f1b20f..061c82a 100644 --- a/docs/tutorials/getting-started.md +++ b/docs/tutorials/getting-started.md @@ -37,6 +37,10 @@ This tutorial walks you through everything you need to get Mocha running in a Di When you're done, the bot will show up in your server member list and be ready to receive slash commands. +:::info Why keep every permission? +Mocha's relay pipeline uses nearly every permission Discord exposes for a chat bot — cutting one usually breaks a subtle feature (personalization falls back to plain text, edits stop propagating, attachments get stripped). The safe default is to grant the full set. +::: + ### Permissions cheat sheet | Permission | Why Mocha needs it | diff --git a/docusaurus.config.js b/docusaurus.config.js index 985bb63..0f2ff01 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -20,6 +20,7 @@ const siteKeywords = [ 'discord server bridge', 'cross-server messaging', ]; +const ogImage = 'img/og-image.svg'; /** @type {import('@docusaurus/types').Config} */ const config = { @@ -29,7 +30,7 @@ const config = { baseUrl: '/', trailingSlash: false, onBrokenLinks: 'throw', - favicon: 'img/favicon.ico', + favicon: 'img/logo-mocha.svg', markdown: { hooks: { @@ -46,8 +47,8 @@ const config = { locales: ['en'], }, - // Extra head tags for SEO — canonical hint, robots, theme color, - // structured data for search engines. + // Extra head tags for SEO and PWA — canonical hint, robots, theme color, + // structured data, manifest, and Apple/mask icon links. headTags: [ { tagName: 'meta', @@ -77,6 +78,42 @@ const config = { href: siteUrl, }, }, + { + tagName: 'link', + attributes: { + rel: 'manifest', + href: '/manifest.json', + }, + }, + { + tagName: 'link', + attributes: { + rel: 'apple-touch-icon', + href: '/img/logo-mocha.svg', + }, + }, + { + tagName: 'link', + attributes: { + rel: 'mask-icon', + href: '/img/logo-mocha.svg', + color: '#ffd700', + }, + }, + { + tagName: 'meta', + attributes: { + name: 'apple-mobile-web-app-capable', + content: 'yes', + }, + }, + { + tagName: 'meta', + attributes: { + name: 'apple-mobile-web-app-status-bar-style', + content: 'black', + }, + }, { tagName: 'script', attributes: { @@ -113,8 +150,26 @@ const config = { sidebarPath: require.resolve('./sidebars.js'), editUrl: 'https://github.com/mocha-bot/docs/tree/master/docs/', showLastUpdateTime: true, + showLastUpdateAuthor: true, + }, + blog: { + routeBasePath: 'changelog', + path: 'blog', + blogTitle: 'Changelog', + blogDescription: + 'Release notes, documentation updates, and behind-the-scenes notes from the Mocha team.', + blogSidebarTitle: 'Recent updates', + blogSidebarCount: 'ALL', + postsPerPage: 10, + showReadingTime: false, + feedOptions: { + type: ['rss', 'atom'], + title: 'Mocha Bot Changelog', + description: + 'Release notes and documentation updates for the Mocha Discord bot.', + copyright: `Copyright © ${new Date().getFullYear()} Mocha Bot, Inc.`, + }, }, - blog: false, theme: { customCss: require.resolve('./src/css/custom.css'), }, @@ -122,17 +177,83 @@ const config = { lastmod: 'date', changefreq: 'weekly', priority: 0.5, - ignorePatterns: ['/tags/**'], filename: 'sitemap.xml', }, }), ], ], + plugins: [ + [ + require.resolve('@easyops-cn/docusaurus-search-local'), + /** @type {import('@easyops-cn/docusaurus-search-local').PluginOptions} */ + ({ + hashed: true, + language: ['en'], + docsRouteBasePath: '/', + indexBlog: true, + indexPages: true, + highlightSearchTermsOnTargetPage: true, + searchResultLimits: 10, + searchBarShortcutHint: false, + }), + ], + [ + '@docusaurus/plugin-pwa', + { + debug: false, + offlineModeActivationStrategies: [ + 'appInstalled', + 'standalone', + 'queryString', + ], + swRegister: false, + pwaHead: [ + { + tagName: 'link', + rel: 'icon', + href: '/img/logo-mocha.svg', + }, + { + tagName: 'link', + rel: 'manifest', + href: '/manifest.json', + }, + { + tagName: 'meta', + name: 'theme-color', + content: '#000000', + }, + { + tagName: 'meta', + name: 'apple-mobile-web-app-capable', + content: 'yes', + }, + { + tagName: 'meta', + name: 'apple-mobile-web-app-status-bar-style', + content: 'black', + }, + { + tagName: 'link', + rel: 'apple-touch-icon', + href: '/img/logo-mocha.svg', + }, + { + tagName: 'link', + rel: 'mask-icon', + href: '/img/logo-mocha.svg', + color: '#ffd700', + }, + ], + }, + ], + ], + themeConfig: /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ ({ - image: 'img/logo-mocha.png', + image: ogImage, metadata: [ {name: 'description', content: siteDescription}, {name: 'keywords', content: siteKeywords.join(', ')}, @@ -144,16 +265,18 @@ const config = { {property: 'og:title', content: siteTitle}, {property: 'og:description', content: siteDescription}, {property: 'og:url', content: siteUrl}, - {property: 'og:image', content: `${siteUrl}/img/logo-mocha.png`}, - {property: 'og:image:alt', content: 'Mocha Bot logo'}, + {property: 'og:image', content: `${siteUrl}/${ogImage}`}, + {property: 'og:image:alt', content: 'Mocha Bot Documentation'}, + {property: 'og:image:width', content: '1200'}, + {property: 'og:image:height', content: '630'}, {property: 'og:locale', content: 'en_US'}, // Twitter {name: 'twitter:card', content: 'summary_large_image'}, {name: 'twitter:title', content: siteTitle}, {name: 'twitter:description', content: siteDescription}, - {name: 'twitter:image', content: `${siteUrl}/img/logo-mocha.png`}, - {name: 'twitter:image:alt', content: 'Mocha Bot logo'}, + {name: 'twitter:image', content: `${siteUrl}/${ogImage}`}, + {name: 'twitter:image:alt', content: 'Mocha Bot Documentation'}, ], colorMode: { defaultMode: 'dark', @@ -167,6 +290,11 @@ const config = { src: 'img/logo-mocha.svg', }, items: [ + { + to: '/changelog', + label: 'Changelog', + position: 'right', + }, { href: 'https://mocha-bot.xyz', position: 'right', @@ -202,6 +330,7 @@ const config = { { title: 'More', items: [ + {label: 'Changelog', to: '/changelog'}, {label: 'GitHub', href: 'https://github.com/mocha-bot'}, { label: 'Edit on GitHub', diff --git a/package.json b/package.json index ef50a67..89278f0 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,9 @@ }, "dependencies": { "@docusaurus/core": "^3.7.0", + "@docusaurus/plugin-pwa": "^3.7.0", "@docusaurus/preset-classic": "^3.7.0", + "@easyops-cn/docusaurus-search-local": "^0.46.0", "@mdx-js/react": "^3.0.0", "clsx": "^2.0.0", "prism-react-renderer": "^2.3.0", diff --git a/src/css/custom.css b/src/css/custom.css index 1012781..a20dfe1 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -295,6 +295,47 @@ div[class*='codeBlockContainer'] { display: none !important; } +/* Code copy button — visible by default on the dark glass background. */ +.theme-code-block button[class*='copyButton'], +.theme-code-block button.clean-btn[class*='copyButton'] { + background: var(--mocha-surface) !important; + border: 1px solid var(--mocha-border-strong) !important; + color: rgba(255, 255, 255, 0.85) !important; + border-radius: 8px; + opacity: 1; + transition: border-color 0.2s ease, background-color 0.2s ease, + color 0.2s ease; +} + +.theme-code-block button[class*='copyButton']:hover { + border-color: var(--mocha-accent) !important; + background: rgba(255, 215, 0, 0.08) !important; + color: var(--mocha-accent) !important; +} + +.theme-code-block button[class*='copyButtonCopied'] { + border-color: var(--mocha-accent) !important; + color: var(--mocha-accent) !important; + background: rgba(255, 215, 0, 0.12) !important; +} + +/* "Last updated" line — muted foot of each doc page. */ +.theme-last-updated { + color: var(--mocha-text-muted); + font-size: 0.85rem; +} + +.theme-last-updated b { + color: var(--mocha-text); + font-weight: 600; +} + +/* Blog (changelog) — match the docs card surface. */ +.blogPostTitle_node_modules-\@docusaurus-theme-classic-lib-theme-BlogPostItem-Header-Title-styles-module, +article.blog-post h2 a { + color: var(--mocha-text); +} + /* Scrollbar (webkit only) */ ::-webkit-scrollbar { width: 10px; diff --git a/src/pages/404.module.css b/src/pages/404.module.css new file mode 100644 index 0000000..b0bd0f4 --- /dev/null +++ b/src/pages/404.module.css @@ -0,0 +1,100 @@ +.notFound { + min-height: calc(100vh - var(--ifm-navbar-height) - 4rem); + display: flex; + align-items: center; + justify-content: center; + padding: 4rem 1rem; +} + +.card { + max-width: 960px; + width: 100%; + background: rgba(255, 255, 255, 0.04); + border: 1px solid rgba(255, 255, 255, 0.12); + border-radius: 20px; + padding: 3rem 2.5rem; + text-align: center; +} + +.code { + font-size: 1rem; + letter-spacing: 0.2em; + text-transform: uppercase; + color: var(--mocha-accent, #ffd700); + font-weight: 700; + margin: 0 0 0.5rem; +} + +.title { + font-size: clamp(2rem, 4vw, 3rem); + font-weight: 800; + letter-spacing: -0.02em; + margin: 0 0 1rem; + color: #fff; +} + +.subtitle { + color: rgba(255, 255, 255, 0.7); + max-width: 560px; + margin: 0 auto 2.5rem; + font-size: 1.05rem; + line-height: 1.55; +} + +.grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + gap: 1rem; + margin-bottom: 2.5rem; + text-align: left; +} + +.tile { + display: flex; + flex-direction: column; + gap: 0.4rem; + padding: 1.25rem 1.5rem; + background: rgba(255, 255, 255, 0.04); + border: 1px solid rgba(255, 255, 255, 0.12); + border-radius: 14px; + text-decoration: none !important; + color: #fff; + transition: border-color 0.2s ease, background-color 0.2s ease, + transform 0.2s ease; +} + +.tile:hover { + border-color: var(--mocha-accent, #ffd700); + background: rgba(255, 255, 255, 0.08); + transform: translateY(-2px); + color: #fff; +} + +.tileLabel { + font-size: 0.72rem; + text-transform: uppercase; + letter-spacing: 0.14em; + color: var(--mocha-accent, #ffd700); + font-weight: 700; +} + +.tileTitle { + font-size: 1.2rem; + font-weight: 700; +} + +.tileDesc { + font-size: 0.9rem; + color: rgba(255, 255, 255, 0.65); + line-height: 1.4; +} + +.footerLinks { + color: rgba(255, 255, 255, 0.65); + font-size: 0.95rem; + margin: 0; +} + +.footerLinks a { + color: var(--mocha-accent, #ffd700); +} diff --git a/src/pages/404.tsx b/src/pages/404.tsx new file mode 100644 index 0000000..c973143 --- /dev/null +++ b/src/pages/404.tsx @@ -0,0 +1,57 @@ +import React from 'react'; +import Layout from '@theme/Layout'; +import Link from '@docusaurus/Link'; +import styles from './404.module.css'; + +export default function NotFound(): JSX.Element { + return ( + +
+
+

404

+

This page doesn't exist

+

+ The link you followed might be broken, or the page may have moved. + Try one of the starting points below. +

+ +
+ + Start here + Introduction + + What Mocha is and how to get it into your Discord server. + + + + Tutorial + Getting Started + + Invite the bot, create your first room, send a test message. + + + + Reference + Commands + + Every slash command Mocha understands, with options and + examples. + + +
+ +

+ Still stuck?{' '} + Check the FAQ or{' '} + + ask in the support server + + . +

+
+
+
+ ); +} diff --git a/static/img/og-image.svg b/static/img/og-image.svg new file mode 100644 index 0000000..866c56e --- /dev/null +++ b/static/img/og-image.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + MOCHA BOT + Documentation + Drink mocha with people across the universe. + + Tutorials · Commands · Rooms · Chat · Pricing + docs.mocha-bot.xyz + + diff --git a/static/manifest.json b/static/manifest.json new file mode 100644 index 0000000..d03d73a --- /dev/null +++ b/static/manifest.json @@ -0,0 +1,25 @@ +{ + "name": "Mocha Bot Documentation", + "short_name": "Mocha Docs", + "description": "Mocha is a Discord bot that links channels across Discord servers into shared rooms. Tutorials, reference docs, and changelog.", + "start_url": "/", + "scope": "/", + "display": "standalone", + "orientation": "portrait", + "background_color": "#000000", + "theme_color": "#000000", + "icons": [ + { + "src": "/img/logo-mocha.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "any maskable" + }, + { + "src": "/img/logo-mocha.svg", + "sizes": "any", + "type": "image/svg+xml", + "purpose": "any" + } + ] +} From d4e0340a9f603ba02dc7798d834c22ed284f099b Mon Sep 17 00:00:00 2001 From: Muhammad Wildan Aldiansyah Date: Thu, 16 Apr 2026 08:59:16 +0700 Subject: [PATCH 2/2] fix(ci): use bare yarn install for yarn v1 compatibility yarn v1 doesn't accept --frozen-lockfile=false (it's not a valid flag format). And since no lockfile is committed (.gitignore excludes *.lock), the frozen-lockfile check would fail anyway. Match the existing gh-pages.yml pattern: plain yarn. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ea9b50a..b88a98b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: node-version: '20' - name: Install dependencies - run: yarn install --frozen-lockfile=false + run: yarn - name: Build run: yarn build