diff --git a/.agents/skills/rspress-best-practices/SKILL.md b/.agents/skills/rspress-best-practices/SKILL.md new file mode 100644 index 0000000..af0370b --- /dev/null +++ b/.agents/skills/rspress-best-practices/SKILL.md @@ -0,0 +1,82 @@ +--- +name: rspress-best-practices +description: Rspress best practices for config, CLI workflow, content organization, frontmatter, MDX, themes, i18n, search, static assets, deployment, and debugging. Use when writing, reviewing, or troubleshooting Rspress documentation sites. +--- + +# Rspress Best Practices + +Apply these rules when writing or reviewing Rspress (v2) sites. + +## Configuration + +- Use `rspress.config.ts` and `defineConfig` from `@rspress/core` +- Set `root` explicitly when docs are not under the default `docs/` directory +- Keep site-wide settings such as `title`, `description`, `icon`, `logo`, `base`, and `lang` in config instead of repeating them in page files +- Prefer first-class Rspress options before custom theme code or low-level bundler overrides +- Keep custom theme code in a top-level `theme/` directory and import original theme pieces from `@rspress/core/theme-original` + +## CLI + +- Use `rspress dev` for local development +- Use `rspress build` for production output +- Use `rspress preview` only for local preview of the built site +- Use `rspress eject` only when CSS variables, class overrides, or layout wrapping cannot solve the customization + +## Docs Structure And Navigation + +- Keep docs content under one clear docs root and group pages by topic or workflow, not by team ownership +- Use `_meta.json` or `_nav.json` to control sidebar and navigation labels/order instead of encoding order in filenames +- Put reusable MDX snippets or shared components in shared files instead of duplicating them across pages +- Keep landing pages concise and link to deeper task-oriented guides from them + +## Writing And Frontmatter + +- Add clear `title` and `description` frontmatter, and set `sidebar`, `outline`, `navbar`, or `footer` only when page defaults are not enough +- Use `pageType: home`, `doc`, `doc-wide`, `custom`, or `blank` intentionally based on layout needs +- Write task-first headings and short intros; avoid marketing-heavy copy in technical docs +- Prefer one topic per page and split overly long pages by workflow or feature area +- Keep code examples minimal, runnable, and version-accurate + +## MDX And Components + +- Use MDX for interactive docs and embedded components, but keep the main narrative understandable as plain markdown +- Prefer documented Rspress theme/runtime APIs over importing from internal source paths +- For app-wide UI or providers, use `globalUIComponents` or theme overrides instead of repeating imports in each page + +## Theme And Styling + +- Prefer CSS variables for brand colors, spacing, and surface styling +- Prefer BEM class overrides or `Layout` slots before ejecting built-in components +- In `theme/` files, keep `export * from '@rspress/core/theme-original'` unless intentionally replacing a named export +- Avoid full component ejection unless config, CSS, and wrapping cannot meet the requirement + +## I18n, Search, And AI + +- For multilingual sites, organize locale content under per-language directories and keep navigation mirrored where practical +- Keep descriptions and other frontmatter text in the same language as the page content +- Configure search intentionally: use local search for small or medium sites, and hosted search when scale or cross-version indexing requires it +- Enable `llms` or `ssgMd` only when the site benefits from machine-readable outputs, and keep descriptions accurate because those outputs surface page summaries + +## Assets And Public Files + +- Import source-managed images and components from docs/theme source when they belong to the content +- Use `public/` only for assets that must keep stable URL paths, such as favicons, social images, or download files +- Reference public assets by absolute site path and make sure they still work when `base` is set + +## Plugins And Integration + +- Prefer official Rspress plugins for search, preview, and API-doc scenarios before building custom solutions +- For component or library docs, use `@rspress/plugin-preview` and `@rspress/plugin-api-docgen` when interactive demos or API tables are needed +- Keep plugin usage explicit in config and remove unused plugins to reduce maintenance cost + +## Build, Deploy, And Debugging + +- Validate both `rspress dev` and `rspress build`; a page that works in dev can still fail during static generation +- Verify broken links, missing assets, and wrong `base` handling before deployment +- Keep generated output out of source control unless the hosting workflow explicitly requires committed artifacts +- When debugging content issues, inspect the resolved docs root, frontmatter, and theme overrides before assuming a bundler problem + +## Documentation + +- For the latest Rspress docs, read https://rspress.rs/llms.txt +- Use the config and API docs when checking exact option names or current behavior diff --git a/.agents/skills/rspress-custom-theme/SKILL.md b/.agents/skills/rspress-custom-theme/SKILL.md new file mode 100644 index 0000000..2ee763c --- /dev/null +++ b/.agents/skills/rspress-custom-theme/SKILL.md @@ -0,0 +1,242 @@ +--- +name: rspress-custom-theme +description: Customize Rspress themes using CSS variables, Layout slots, component wrapping, or component ejection. Use when a user wants to change the look and feel of an Rspress site, override theme components, add custom navigation/sidebar/footer content, inject global providers, or modify the default Rspress theme in any way. Also use when a user mentions theme/index.tsx, Layout slots, BEM class overrides, or rspress eject. +--- + +# Rspress Custom Theme + +Guide for customizing Rspress (v2) themes. Rspress offers four levels of customization, from lightest to heaviest. Always prefer the lightest approach that meets the requirement — lighter approaches are more maintainable and survive Rspress upgrades. + +## Workflow + +1. **Understand the user's goal** — what do they want to change? (colors, layout, inject content, replace a component entirely?) +2. **Pick the right level** using the decision flow below +3. **Set up `theme/index.tsx`** if needed (Levels 1A, 3, 4 all need it) +4. **Implement** following the patterns in this skill and reference files +5. **Verify** the user's Rspress version is v2 (imports use `@rspress/core/*` not `rspress/*`) + +## Decision Flow + +| User wants to... | Level | Approach | +| ---------------------------------------------------------------- | ----- | --------------------------- | +| Change brand colors, fonts, spacing, shadows | 1 | CSS variables | +| Adjust a specific component's style (borders, padding, etc.) | 2 | BEM class overrides | +| Add content around existing components (banners, footers, logos) | 3 | Layout slots (wrap) | +| Override MDX rendering (custom `

`, ``, etc.) | 3 | `components` slot | +| Wrap the app in a provider (state, analytics, auth) | 4 | Eject `Root` | +| Replace built-in icons (logo, GitHub, search, etc.) | — | Icon re-export | +| Completely replace a built-in component | 4 | Eject that component | +| Add a global floating component (back-to-top, chat widget) | — | `globalUIComponents` config | +| Control page layout structure (hide sidebar, blank page) | — | Frontmatter `pageType` | + +--- + +## theme/index.tsx — The Entry Point + +Levels 1A, 3, and 4 all require a `theme/index.tsx` file in the project root (sibling to `docs/`). This is the single entry point for all theme customizations: + +```text +project/ +├── docs/ +├── theme/ +│ ├── index.tsx # Theme entry — re-exports + overrides +│ ├── index.css # CSS variable / BEM overrides (optional) +│ └── components/ # Ejected components (Level 4) +└── rspress.config.ts +``` + +Minimal setup: + +```tsx +// theme/index.tsx +import './index.css'; // optional +export * from '@rspress/core/theme-original'; +``` + +**Critical import rule**: Inside `theme/` files, always import from `@rspress/core/theme-original`. The path `@rspress/core/theme` resolves to your own `theme/index.tsx`, which causes circular imports. (In `docs/` MDX files, `@rspress/core/theme` is fine — it correctly points to your custom theme.) + +--- + +## Level 1: CSS Variables + +Override CSS custom properties for brand colors, backgrounds, text, code blocks, and more. + +**Option A** — `theme/index.css` (use when you also have component overrides in `theme/index.tsx`): + +```css +/* theme/index.css */ +:root { + --rp-c-brand: #7c3aed; + --rp-c-brand-light: #8b5cf6; + --rp-c-brand-dark: #6d28d9; +} +.dark { + --rp-c-brand: #a78bfa; +} +``` + +**Option B** — `globalStyles` (use when you only need CSS changes, no component overrides): + +```ts +// rspress.config.ts +export default defineConfig({ + globalStyles: path.join(__dirname, 'styles/custom.css'), +}); +``` + +> **Full variable list**: Read `references/css-variables.md` for all available CSS variables with light/dark defaults. + +--- + +## Level 2: BEM Class Overrides + +All built-in components follow BEM naming: `.rp-[component]__[element]--[modifier]`. + +Common targets: `.rp-nav`, `.rp-link`, `.rp-tabs`, `.rp-codeblock`, `.rp-codeblock__title`, `.rp-nav-menu__item--active`. + +Use these in your CSS file for targeted style changes when CSS variables aren't granular enough. + +--- + +## Level 3: Wrap (Layout Slots) + +Inject content at specific positions in the layout without replacing built-in components. Override `Layout` in `theme/index.tsx`: + +```tsx +// theme/index.tsx +import { Layout as OriginalLayout } from '@rspress/core/theme-original'; +export * from '@rspress/core/theme-original'; + +export function Layout() { + return ( + } bottom={} /> + ); +} +``` + +Use runtime hooks inside slot components — import from `@rspress/core/runtime`: `useDark()`, `useLang()`, `useVersion()`, `usePage()`, `useSite()`, `useFrontmatter()`, `useI18n()`. + +> **All slots & examples**: Read `references/layout-slots.md` for the complete slot list and usage patterns including i18n and MDX component overrides. + +--- + +## Level 4: Eject + +Copy a built-in component's source for full replacement. Only use when wrap/slots cannot achieve the customization. + +```bash +rspress eject # list available components +rspress eject DocFooter # eject to theme/components/DocFooter/ +``` + +Then re-export in `theme/index.tsx` (named export takes precedence over the wildcard): + +```tsx +export * from '@rspress/core/theme-original'; +export { DocFooter } from './components/DocFooter'; +``` + +> **Component list & patterns**: Read `references/eject-components.md` for available components, workflow, and common patterns. + +--- + +## Custom Icons + +Rspress has 27 built-in icons used across the UI. You can replace any of them by re-exporting your own icon component with the same name — no ejection needed. This uses the same `theme/index.tsx` mechanism: your named export takes precedence over the wildcard re-export. + +**Icon type**: Each icon is a React component or a URL string: + +```ts +import type { FC, SVGProps } from 'react'; +type Icon = FC> | string; +``` + +**Example 1** — Replace an icon with a custom SVG component: + +```tsx +// theme/index.tsx +export * from '@rspress/core/theme-original'; + +// Named export overrides the wildcard — replaces the GitHub icon site-wide +export const IconGithub = (props: React.SVGProps) => ( + + + +); +``` + +**Example 2** — Use an SVGR import: + +```tsx +// theme/index.tsx +export * from '@rspress/core/theme-original'; + +import CustomGithubIcon from './icons/github.svg?react'; +export const IconGithub = CustomGithubIcon; +``` + +**Using `SvgWrapper` in MDX or custom components**: + +```mdx +import { SvgWrapper, IconGithub } from '@rspress/core/theme'; + + +``` + +**Available icons**: `IconArrowDown`, `IconArrowRight`, `IconClose`, `IconCopy`, `IconDeprecated`, `IconDown`, `IconEdit`, `IconEmpty`, `IconExperimental`, `IconExternalLink`, `IconFile`, `IconGithub`, `IconGitlab`, `IconHeader`, `IconJump`, `IconLink`, `IconLoading`, `IconMenu`, `IconMoon`, `IconScrollToTop`, `IconSearch`, `IconSmallMenu`, `IconSuccess`, `IconSun`, `IconTitle`, `IconWrap`, `IconWrapped`. + +> **Source**: See the [icons source](https://github.com/web-infra-dev/rspress/blob/main/packages/core/src/theme/icons.ts) for default implementations. + +--- + +## Global UI Components + +For components that should render on every page without theme overrides: + +```ts +// rspress.config.ts +export default defineConfig({ + globalUIComponents: [ + path.join(__dirname, 'components', 'BackToTop.tsx'), + [ + path.join(__dirname, 'components', 'Analytics.tsx'), + { trackingId: '...' }, + ], + ], +}); +``` + +--- + +## Page Types + +Control layout per page via frontmatter `pageType`: + +| Value | Description | +| ---------- | ------------------------------------- | +| `home` | Home page with navbar | +| `doc` | Standard doc with sidebar and outline | +| `doc-wide` | Doc without sidebar/outline | +| `custom` | Custom content with navbar only | +| `blank` | Custom content without navbar | +| `404` | 404 error page | + +Fine-grained: set `navbar: false`, `sidebar: false`, `outline: false`, `footer: false` individually. + +--- + +## Common Pitfalls + +- **Circular import**: Using `@rspress/core/theme` instead of `@rspress/core/theme-original` in `theme/` files — causes infinite loop. +- **Eject over-use**: Ejecting when a Layout slot or CSS variable would suffice — creates upgrade burden. +- **Missing re-export**: Forgetting `export * from '@rspress/core/theme-original'` in `theme/index.tsx` — breaks all un-overridden components. +- **v1 imports**: Using `rspress/theme` or `@rspress/theme-default` — these are v1 paths. v2 uses `@rspress/core/theme-original`. + +## Reference + +- Custom theme guide: +- CSS variables: +- Layout component: +- Built-in icons: +- Built-in hooks: +- CLI commands (eject): diff --git a/.agents/skills/rspress-custom-theme/references/css-variables.md b/.agents/skills/rspress-custom-theme/references/css-variables.md new file mode 100644 index 0000000..3fca55f --- /dev/null +++ b/.agents/skills/rspress-custom-theme/references/css-variables.md @@ -0,0 +1,143 @@ +# CSS Variables Reference + +Complete list of CSS variables exposed by Rspress for theme customization. Override these in `theme/index.css` or via `globalStyles` in `rspress.config.ts`. + +For dark mode overrides, wrap variables in `.dark { ... }`. + +Official reference: + +--- + +## Brand Colors + +| Variable | Light Default | Dark Default | +| ---------------------- | --------------------------- | ------------ | +| `--rp-c-brand` | `#0095ff` | (same) | +| `--rp-c-brand-light` | `#33adff` | (same) | +| `--rp-c-brand-lighter` | `#c6e0fd` | (same) | +| `--rp-c-brand-dark` | `#0077ff` | (same) | +| `--rp-c-brand-darker` | `#005fcc` | (same) | +| `--rp-c-brand-tint` | `rgba(127, 163, 255, 0.16)` | (same) | + +## Background + +| Variable | Light Default | Dark Default | +| ---------------- | ------------- | ------------ | +| `--rp-c-bg` | `#ffffff` | `#121212` | +| `--rp-c-bg-soft` | `#f8f8f9` | `#292e37` | +| `--rp-c-bg-mute` | `#f1f1f1` | `#343a46` | +| `--rp-c-bg-alt` | `#fff` | `#000` | + +## Text + +| Variable | Light Default | Dark Default | +| ------------------------- | --------------------------- | --------------------------- | +| `--rp-c-text-0` | `#000000` | `#ffffff` | +| `--rp-c-text-1` | `#242424` | `rgba(255, 255, 245, 0.93)` | +| `--rp-c-text-2` | `rgba(0, 0, 0, 0.7)` | `rgba(255, 255, 245, 0.65)` | +| `--rp-c-text-3` | `rgba(60, 60, 60, 0.33)` | `rgba(235, 235, 235, 0.38)` | +| `--rp-c-text-4` | `rgba(60, 60, 60, 0.18)` | `rgba(235, 235, 235, 0.18)` | +| `--rp-c-text-code` | `#476582` | `#c9def1` | +| `--rp-c-text-code-bg` | `rgba(153, 161, 179, 0.08)` | `rgba(255, 255, 255, 0.08)` | +| `--rp-c-text-code-border` | `rgba(0, 0, 0, 0.05)` | `rgba(255, 255, 255, 0.05)` | +| `--rp-c-link` | `var(--rp-c-brand-dark)` | `var(--rp-c-brand-light)` | + +## Dividers + +| Variable | Light Default | Dark Default | +| ---------------------- | --------------------- | ------------------------ | +| `--rp-c-divider` | `rgba(0, 0, 0, 0.25)` | `rgba(84, 84, 84, 0.65)` | +| `--rp-c-divider-light` | `rgba(0, 0, 0, 0.12)` | `rgba(84, 84, 84, 0.48)` | + +## Gray Scale + +| Variable | Default | +| --------------------- | --------- | +| `--rp-c-gray` | `#8e8e8e` | +| `--rp-c-gray-light-1` | `#aeaeae` | +| `--rp-c-gray-light-2` | `#c7c7c7` | +| `--rp-c-gray-light-3` | `#d1d1d1` | +| `--rp-c-gray-light-4` | `#e5e5e5` | +| `--rp-c-gray-light-5` | `#f2f2f2` | + +## Layout (Radius & Shadows) + +| Variable | Default | +| --------------------------------------- | ---------------------- | +| `--rp-radius` | `1rem` | +| `--rp-radius-small` | `0.5rem` | +| `--rp-radius-large` | `1.5rem` | +| `--rp-shadow-1` through `--rp-shadow-5` | 5 levels of box-shadow | + +## Code Block + +| Variable | Light Default | Dark Default | +| ------------------------ | ------------------------------------- | -------------------- | +| `--rp-code-font-size` | `0.875rem` | (same) | +| `--rp-code-title-bg` | `#f8f8f9` | `#191919` | +| `--rp-code-block-color` | `rgb(46, 52, 64)` | `rgb(229, 231, 235)` | +| `--rp-code-block-bg` | `var(--rp-c-bg)` | (same) | +| `--rp-code-block-border` | `1px solid var(--rp-c-divider-light)` | (same) | +| `--rp-code-block-shadow` | `none` | (same) | + +## Shiki Syntax Highlighting + +### Light Mode + +| Variable | Default | +| --------------------------------- | -------------------- | +| `--shiki-foreground` | `inherit` | +| `--shiki-background` | `transparent` | +| `--shiki-token-constant` | `#1976d2` | +| `--shiki-token-string` | `#31a94d` | +| `--shiki-token-comment` | `rgb(182, 180, 180)` | +| `--shiki-token-keyword` | `#cf2727` | +| `--shiki-token-parameter` | `#f59403` | +| `--shiki-token-function` | `#7041c8` | +| `--shiki-token-string-expression` | `#218438` | +| `--shiki-token-punctuation` | `#242323` | +| `--shiki-token-link` | `#22863a` | +| `--shiki-token-deleted` | `#d32828` | +| `--shiki-token-inserted` | `#22863a` | + +### Dark Mode + +| Variable | Default | +| --------------------------------- | --------- | +| `--shiki-token-constant` | `#6fb0fa` | +| `--shiki-token-string` | `#f9a86e` | +| `--shiki-token-comment` | `#6a727b` | +| `--shiki-token-keyword` | `#f47481` | +| `--shiki-token-parameter` | `#ff9800` | +| `--shiki-token-function` | `#ae8eeb` | +| `--shiki-token-string-expression` | `#4fb74d` | +| `--shiki-token-punctuation` | `#bbbbbb` | +| `--shiki-token-link` | `#f9a76d` | +| `--shiki-token-deleted` | `#ee6d7a` | +| `--shiki-token-inserted` | `#36c47f` | + +## Home Page + +| Variable | Light Default | Dark Default | +| -------------------------------- | ------------------------------------------ | ----------------------------------------------- | +| `--rp-home-hero-secondary-color` | `#a673ff` | (same) | +| `--rp-home-hero-title-color` | `transparent` | (same) | +| `--rp-home-hero-title-bg` | gradient (90deg) | (same) | +| `--rp-home-background-bg` | radial gradients | dark radial gradients | +| `--rp-home-feature-bg` | `linear-gradient(135deg, #fff, #f9f9f980)` | `linear-gradient(135deg, #ffffff00, #ffffff08)` | + +## Quick Start Example + +```css +/* theme/index.css */ +:root { + --rp-c-brand: #7c3aed; + --rp-c-brand-light: #8b5cf6; + --rp-c-brand-dark: #6d28d9; +} +.dark { + --rp-c-brand: #a78bfa; + --rp-c-brand-light: #c4b5fd; + --rp-c-brand-dark: #8b5cf6; +} +``` diff --git a/.agents/skills/rspress-custom-theme/references/eject-components.md b/.agents/skills/rspress-custom-theme/references/eject-components.md new file mode 100644 index 0000000..235800f --- /dev/null +++ b/.agents/skills/rspress-custom-theme/references/eject-components.md @@ -0,0 +1,154 @@ +# Eject Components Reference + +Eject copies a built-in component's source code into your project for full customization. This is the heaviest approach — ejected components do not receive automatic updates when Rspress upgrades. Prefer CSS variables, BEM overrides, or Layout slots whenever possible. + +Official reference: + +--- + +## Eject Command + +```bash +# List all available components +rspress eject + +# Eject a specific component +rspress eject +``` + +Ejected source is placed in `theme/components//`. + +## Available Components + +| Component | Description | Consider wrapping first? | +| ---------------- | ----------------------------------------- | ------------------------------------------------ | +| `Layout` | Main layout container with all slot props | Yes — use Layout slots instead | +| `Root` | Application root wrapper | Only eject for global providers | +| `Banner` | Notification banner at top of page | Check `top` slot first | +| `NavTitle` | Navigation logo and title | Check `navTitle` / `beforeNavTitle` slots | +| `HomeLayout` | Complete home page layout | Check home page slots first | +| `HomeHero` | Hero section on home page | Check `beforeHero` / `afterHero` slots | +| `HomeFeature` | Feature grid cards | Check `beforeFeatures` / `afterFeatures` slots | +| `HomeBackground` | Home page background effects | Try CSS variables first | +| `HomeFooter` | Home page footer | Check `bottom` slot first | +| `DocFooter` | Documentation page footer | Check `beforeDocFooter` / `afterDocFooter` slots | +| `EditLink` | "Edit this page" link | Configure via `themeConfig.editLink` | +| `LastUpdated` | Last updated timestamp | Usually config is enough | +| `PrevNextPage` | Previous/next page navigation | Check `beforeDocFooter` slot | +| `OverviewGroup` | Overview page group cards | — | +| `Tag` | Tag/label component | — | + +## Step-by-Step Eject Workflow + +1. **Eject the component:** + + ```bash + rspress eject DocFooter + ``` + +2. **Re-export in theme/index.tsx:** + + ```tsx + // theme/index.tsx + export * from '@rspress/core/theme-original'; + export { DocFooter } from './components/DocFooter'; + ``` + + The named export takes precedence over the wildcard re-export, so Rspress uses your custom version. + +3. **Modify the ejected source** in `theme/components/DocFooter/`. + +## Common Pattern: Root for Global Providers + +The most common eject use case is wrapping the entire app in a context provider (state management, analytics, auth, etc.): + +```tsx +// theme/components/Root/index.tsx +import type { RootProps } from '@rspress/core/theme'; + +export function Root({ children }: RootProps) { + return ( + + {children} + + ); +} +``` + +```tsx +// theme/index.tsx +export * from '@rspress/core/theme-original'; +export { Root } from './components/Root'; +``` + +## Common Pattern: Custom Home Page (HomeLayout) + +When the default home page structure (Hero + Features) doesn't meet the design requirements — for example, you need a completely different landing page with custom sections, animations, or a non-standard layout — write a custom `HomeLayout` component and re-export it directly: + +```tsx +// theme/components/HomeLayout/index.tsx +import { useSite, useLang } from '@rspress/core/runtime'; + +export function HomeLayout() { + const site = useSite(); + const lang = useLang(); + const { title, description } = site.siteData; + + return ( +
+
+

{title}

+

{description}

+ +
+ +
+ {/* Custom content: testimonials, stats, demos, etc. */} +
+
+ ); +} +``` + +```tsx +// theme/index.tsx +export * from '@rspress/core/theme-original'; +export { HomeLayout } from './components/HomeLayout'; +``` + +The named export overrides the built-in `HomeLayout` from the wildcard re-export — no need to eject first. + +If you only need to add content before/after the Hero or Features sections (without replacing the entire home page), prefer Layout slots (`beforeHero`, `afterHero`, `beforeFeatures`, `afterFeatures`) instead — see `references/layout-slots.md`. + +## Common Pattern: Custom Doc Footer + +```tsx +// theme/components/DocFooter/index.tsx +import { useFrontmatter } from '@rspress/core/runtime'; + +export function DocFooter() { + const frontmatter = useFrontmatter(); + return ( +
+ {frontmatter.author && Author: {frontmatter.author}} + Edit this page +
+ ); +} +``` + +## Important Notes + +- Always import from `@rspress/core/theme-original` in `theme/` files, never from `@rspress/core/theme` (the latter resolves to your own `theme/index.tsx`, causing circular imports). +- After ejecting, you own that component. Track Rspress changelogs for upstream changes you might want to incorporate manually. +- Run `rspress eject` (no args) to see the up-to-date list of available components — the list above may change between Rspress versions. diff --git a/.agents/skills/rspress-custom-theme/references/layout-slots.md b/.agents/skills/rspress-custom-theme/references/layout-slots.md new file mode 100644 index 0000000..1774218 --- /dev/null +++ b/.agents/skills/rspress-custom-theme/references/layout-slots.md @@ -0,0 +1,153 @@ +# Layout Slots Reference + +The `Layout` component accepts slot props (`React.ReactNode`) for injecting content at specific positions without replacing built-in components. This is the recommended way to extend Rspress before considering eject. + +Official reference: + +--- + +## All Available Slots + +### Navigation Bar + +| Slot | Position | +| ---------------- | ------------------------------------ | +| `beforeNav` | Before the entire navigation bar | +| `afterNav` | After the entire navigation bar | +| `beforeNavTitle` | Before the nav title/logo (top-left) | +| `navTitle` | Replaces the nav title content | +| `afterNavTitle` | After the nav title/logo | +| `beforeNavMenu` | Before the nav menu items | +| `afterNavMenu` | After the nav menu items | + +### Sidebar & Outline + +| Slot | Position | +| --------------- | ----------------------------------- | +| `beforeSidebar` | Above the left sidebar | +| `afterSidebar` | Below the left sidebar | +| `beforeOutline` | Above the right outline (TOC) panel | +| `afterOutline` | Below the right outline panel | + +### Home Page + +| Slot | Position | +| ---------------- | ------------------------ | +| `beforeHero` | Before the Hero section | +| `afterHero` | After the Hero section | +| `beforeFeatures` | Before the Features grid | +| `afterFeatures` | After the Features grid | + +### Doc Page + +| Slot | Position | +| ------------------ | ------------------------------------- | +| `beforeDoc` | At the very beginning of the doc page | +| `afterDoc` | At the very end of the doc page | +| `beforeDocContent` | Before the document content area | +| `afterDocContent` | After the document content area | +| `beforeDocFooter` | Before the doc footer (prev/next nav) | +| `afterDocFooter` | After the doc footer | + +### Global + +| Slot | Position | +| ------------ | ---------------------------------------------------------------------- | +| `top` | At the very top of the entire page | +| `bottom` | At the very bottom of the entire page | +| `components` | Custom MDX component overrides (`Record`) | + +--- + +## Usage Pattern + +All examples below follow the same structure in `theme/index.tsx`. The key parts: + +- Import `Layout` from `@rspress/core/theme-original` (not `@rspress/core/theme` — that causes circular imports) +- Re-export everything: `export * from '@rspress/core/theme-original'` +- Export your custom `Layout` that wraps the original with slot props + +### Basic — Single Slot + +```tsx +// theme/index.tsx +import { Layout as OriginalLayout } from '@rspress/core/theme-original'; +export * from '@rspress/core/theme-original'; + +export function Layout() { + return } />; +} +``` + +### Multiple Slots + +```tsx +// theme/index.tsx +import { Layout as OriginalLayout } from '@rspress/core/theme-original'; +export * from '@rspress/core/theme-original'; + +export function Layout() { + return ( + New version released!} + bottom={
© 2025 My Company
} + afterOutline={
Related resources
} + /> + ); +} +``` + +### With i18n Hooks + +```tsx +// theme/index.tsx +import { Layout as OriginalLayout } from '@rspress/core/theme-original'; +import { useLang } from '@rspress/core/runtime'; +export * from '@rspress/core/theme-original'; + +function LocalizedBanner() { + const lang = useLang(); + return
{lang === 'zh' ? '欢迎' : 'Welcome'}
; +} + +export function Layout() { + return } />; +} +``` + +### Override MDX Components + +The `components` slot accepts a `Record` to override how MDX elements render: + +```tsx +// theme/index.tsx +import { Layout as OriginalLayout } from '@rspress/core/theme-original'; +export * from '@rspress/core/theme-original'; + +function CustomH1({ children }: { children: React.ReactNode }) { + return ( +

{children}

+ ); +} + +export function Layout() { + return ; +} +``` + +--- + +## Available Hooks + +Use these hooks inside slot components. Import from `@rspress/core/runtime`. + +| Hook | Purpose | +| ------------------ | ----------------------------------- | +| `useDark()` | Returns whether dark mode is active | +| `useLang()` | Returns current language code | +| `useVersion()` | Returns current doc version | +| `usePage()` | Returns current page metadata | +| `usePages()` | Returns all pages metadata | +| `useSite()` | Returns site-level configuration | +| `useFrontmatter()` | Returns current page frontmatter | +| `useI18n()` | Returns i18n translation function | diff --git a/.claude/skills/rspress-best-practices b/.claude/skills/rspress-best-practices new file mode 120000 index 0000000..0785fd5 --- /dev/null +++ b/.claude/skills/rspress-best-practices @@ -0,0 +1 @@ +../../.agents/skills/rspress-best-practices \ No newline at end of file diff --git a/.claude/skills/rspress-custom-theme b/.claude/skills/rspress-custom-theme new file mode 120000 index 0000000..5e83813 --- /dev/null +++ b/.claude/skills/rspress-custom-theme @@ -0,0 +1 @@ +../../.agents/skills/rspress-custom-theme \ No newline at end of file diff --git a/skills-lock.json b/skills-lock.json new file mode 100644 index 0000000..912e464 --- /dev/null +++ b/skills-lock.json @@ -0,0 +1,17 @@ +{ + "version": 1, + "skills": { + "rspress-best-practices": { + "source": "rstackjs/agent-skills", + "sourceType": "github", + "skillPath": "skills/rspress-best-practices/SKILL.md", + "computedHash": "4e7ae99820cbe318bbaee92aa8b5ba115c41ea6727d4d109e1133e45a2b43368" + }, + "rspress-custom-theme": { + "source": "rstackjs/agent-skills", + "sourceType": "github", + "skillPath": "skills/rspress-custom-theme/SKILL.md", + "computedHash": "7fe2fa67caabd3336adc635fbe97716d14ff22780d0046237d3b5086e8565277" + } + } +}