Skip to content

Commit b93fade

Browse files
SoonIterCopilot
andauthored
docs: upgrade custom-theme and add wrap and eject (#2925)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent c384e1e commit b93fade

File tree

27 files changed

+759
-556
lines changed

27 files changed

+759
-556
lines changed

website/docs/en/fragments/useI18n.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Rspress provides `useI18n` this hook to get the internationalized text, the usage is as follows:
1+
Rspress provides the [`useI18n`](/ui/hooks/use-i18n) hook to get the internationalized text, the usage is as follows:
22

33
```tsx
44
import { useI18n } from '@rspress/core/runtime';
@@ -34,4 +34,4 @@ const MyComponent = () => {
3434
};
3535
```
3636

37-
This way you get type hints for all literal keys defined in `i18n.json`.
37+
This way you get type hints for all text keys defined in `i18n.json`.

website/docs/en/guide/basic/_meta.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88
"multi-version",
99
"home-page",
1010
"deploy",
11-
"wrap-and-eject"
11+
"custom-theme"
1212
]

website/docs/en/ui/custom-theme.mdx renamed to website/docs/en/guide/basic/custom-theme.mdx

Lines changed: 171 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,170 @@
11
# Custom theme
22

3-
This article will tell you how to develop custom theme.
3+
1. For CSS, Rspress provides [CSS variables](#css-variables) and [BEM classnames](#bem-classname) for customization.
44

5-
## Extensions based on the default theme
5+
2. For JS / React, Rspress implements a runtime interface based on ESM re-exports, supporting modification or replacement of built-in components to implement your own home page, sidebar, search components, etc.
66

7-
In most cases, you don't want to develop a theme from scratch, but want to extend it based on the default theme. At this time, you can refer to the following methods for theme development.
7+
On top of this, there are two modes:
8+
- [**wrap**](#wrap): **Wrap** and enhance Rspress built-in components through props / slots.
9+
- [**eject**](#eject): **Copy** source code locally through the [`rspress eject`](../../api/commands.mdx#rspress-eject) command and modify it directly to override.
810

9-
:::tip
10-
If you want to develop a custom theme from scratch, you can go to [Redevelop a custom theme](/ui/custom-theme#redevelop-a-custom-theme).
11-
:::
11+
The following will introduce them in order according to the degree of theme customization.
1212

13-
### 1. Basic structure
13+
## CSS variables \{#css-variables}
14+
15+
Rspress exposes some commonly used CSS variables. Compared to rewriting Rspress built-in React components, overriding CSS variables for customization is simpler and easier to maintain. You can view these CSS variables on the [UI - CSS Variables](../../ui/vars.mdx) page, and override them through:
16+
17+
import { Tabs, Tab } from '@theme';
18+
19+
<Tabs>
20+
<Tab label="theme/index.tsx">
21+
22+
```tsx
23+
import './index.css';
24+
export * from '@rspress/core/theme-original';
25+
```
26+
27+
</Tab>
28+
<Tab label="theme/index.css">
29+
```css
30+
/* Copy CSS variable code here for style overrides */
31+
```
32+
</Tab>
33+
</Tabs>
34+
35+
## BEM classname \{#bem-classname}
36+
37+
Rspress built-in components all use BEM naming convention. You can override these classnames in the same way as [CSS Variables](#css-variables).
38+
39+
```css
40+
.rp-[component-name]__[element-name]--[modifier-name] {
41+
/* styles */
42+
}
43+
```
44+
45+
For example:
46+
47+
```css
48+
.rp-nav {
49+
}
50+
.rp-link {
51+
}
52+
.rp-tabs {
53+
}
54+
.rp-codeblock {
55+
}
56+
.rp-codeblock__title {
57+
}
58+
.rp-codeblock__description {
59+
}
60+
.rp-nav-menu__item,
61+
.rp-nav-menu__item--active {
62+
}
63+
```
64+
65+
## `theme/index.tsx`: Override built-in components using ESM re-exports \{#reexport}
1466

1567
By default, you need to create a `theme` directory under the project root directory, and then create an `index.ts` or `index.tsx` file under the `theme` directory, which is used to export the theme content.
1668

1769
```txt
18-
└── theme
19-
└── index.tsx
70+
├── docs
71+
├── theme
72+
│ └── index.tsx
73+
└── rspress.config.ts
2074
```
2175

22-
You can write the `theme/index.tsx` file as follows:
76+
You can write the `theme/index.tsx` file using built-in components from `@rspress/core/theme-original`:
2377

2478
```tsx title="theme/index.tsx"
2579
import { Layout as BasicLayout } from '@rspress/core/theme-original';
2680

2781
const Layout = () => <BasicLayout beforeNavTitle={<div>some content</div>} />;
2882

29-
export { Layout };
83+
export { Layout }; //[!code highlight]
84+
export * from '@rspress/core/theme-original'; //[!code highlight]
85+
```
86+
87+
By **ESM re-export** to override built-in components, all Rspress internal references to built-in components will preferentially use your re-exported version.
88+
89+
:::tip Note
90+
91+
Only use `@rspress/core/theme-original` when customizing themes
92+
93+
```txt
94+
├── docs
95+
│ └── index.mdx <-- "@rspress/core/theme"
96+
├── theme
97+
│ └── index.tsx <-- "@rspress/core/theme-original"
98+
└── rspress.config.ts
99+
```
30100

101+
1. In the `docs` directory, use `@rspress/core/theme`, `@rspress/core/theme` points to your `theme/index.tsx`.
102+
103+
2. In the `theme` directory, use `@rspress/core/theme-original`, `@rspress/core/theme-original` always points to Rspress built-in theme components.
104+
105+
:::
106+
107+
## Wrap: Add props/slots on re-exported components \{#wrap}
108+
109+
Wrap means adding props to re-exported components. Here's an example of inserting some content before the nav bar title:
110+
111+
<Tabs>
112+
<Tab label="theme/index.tsx">
113+
114+
```tsx
115+
import { Layout as BasicLayout } from '@rspress/core/theme-original';
116+
import { useI18n } from '@rspress/core';
117+
118+
const Layout = () => {
119+
const t = useI18n();
120+
return <BasicLayout beforeNavTitle={<div>{t('some content')}</div>} />;
121+
};
122+
123+
export { Layout };
31124
export * from '@rspress/core/theme-original';
32125
```
33126

34-
On the one hand, you need to export a theme configuration object through `export`, on the other hand, you need to export all named exported content through `export * from '@rspress/core/theme-original'` so as to ensure your theme works fine.
127+
</Tab>
128+
129+
<Tab label="i18n.json">
35130

36-
### 2. Use slot
131+
```json
132+
{
133+
"some content": {
134+
"zh": "一些内容",
135+
"en": "some content"
136+
}
137+
}
138+
```
37139

38-
It is worth noting that the `Layout` component has designed a series of props to support slot elements. You can use these props to extend the layout of the default theme. For example, change the above `Layout` component to the following form:
140+
</Tab>
141+
142+
</Tabs>
143+
144+
It's worth noting that the `Layout` component is designed with a series of props to support slot elements. You can use these props to extend the default theme layout:
145+
146+
<details>
39147

40148
```tsx title="theme/index.tsx"
41-
import { Layout as BasicLayout } from '@rspress/core/theme-original';
149+
import {
150+
Layout as BasicLayout,
151+
getCustomMDXComponent as basicGetCustomMDXComponent,
152+
} from '@rspress/core/theme-original';
42153

43154
// Show all props below
44155
const Layout = () => (
45156
<BasicLayout
46-
/* Before home hero */
157+
/* Home page Hero section before */
47158
beforeHero={<div>beforeHero</div>}
48-
/* After home hero */
159+
/* Home page Hero section after */
49160
afterHero={<div>afterHero</div>}
50-
/* Before home features */
161+
/* Home page Features section before */
51162
beforeFeatures={<div>beforeFeatures</div>}
52-
/* After home features */
163+
/* Home page Features section after */
53164
afterFeatures={<div>afterFeatures</div>}
54-
/* Before doc footer */
165+
/* Doc page Footer section before */
55166
beforeDocFooter={<div>beforeDocFooter</div>}
56-
/* After doc footer */
167+
/* Doc page Footer section after */
57168
afterDocFooter={<div>afterDocFooter</div>}
58169
/* Doc page front */
59170
beforeDoc={<div>beforeDoc</div>}
@@ -63,30 +174,42 @@ const Layout = () => (
63174
beforeDocContent={<div>beforeDocContent</div>}
64175
/* Doc content end */
65176
afterDocContent={<div>afterDocContent</div>}
66-
/* Before the nav bar */
177+
/* Before nav bar */
67178
beforeNav={<div>beforeNav</div>}
68-
/* Before the title of the nav bar in the upper left corner */
179+
/* Before upper left nav bar title */
69180
beforeNavTitle={<span>😄</span>}
70181
/* Nav bar title */
71182
navTitle={<div>Custom Nav Title</div>}
72-
/* After the title of the nav bar in the upper left corner */
183+
/* After upper left nav bar title */
73184
afterNavTitle={<div>afterNavTitle</div>}
74-
/* The right corner of the nav menu */
185+
/* Upper right corner of nav bar */
75186
afterNavMenu={<div>afterNavMenu</div>}
76-
/* Above the left sidebar */
187+
/* Above left sidebar */
77188
beforeSidebar={<div>beforeSidebar</div>}
78-
/* Below the left sidebar */
189+
/* Below left sidebar */
79190
afterSidebar={<div>afterSidebar</div>}
80-
/* Above the right outline column */
191+
/* Above right outline column */
81192
beforeOutline={<div>beforeOutline</div>}
82-
/* Below the outline column on the right */
193+
/* Below right outline column */
83194
afterOutline={<div>afterOutline</div>}
84-
/* Top of the entire page */
195+
/* Top of entire page */
85196
top={<div>top</div>}
86-
/* Bottom of the entire page */
197+
/* Bottom of entire page */
87198
bottom={<div>bottom</div>}
88199
/* Custom MDX components */
89-
components={{ p: (props) => <p {...props} className="my-4 leading-7" /> }}
200+
components={{
201+
h1: (props) => {
202+
const { h1: OriginalH1, p: OriginalP } = basicGetCustomMDXComponent();
203+
return (
204+
<>
205+
<OriginalH1 {...props} />
206+
<OriginalP>
207+
This is a custom paragraph added after every H1 heading.
208+
</OriginalP>
209+
</>
210+
);
211+
},
212+
}}
90213
/>
91214
);
92215

@@ -95,54 +218,33 @@ export { Layout };
95218
export * from '@rspress/core/theme-original';
96219
```
97220

98-
### 3. Custom home page and 404 page
221+
</details>
99222

100-
In addition to the slot method, if you want to extend the default theme components, you can also customize the Home page components and 404 page components,
101-
as well as other Rspress [built-in components](https://github.com/web-infra-dev/rspress/tree/main/packages/theme-default/src/components)
223+
## Eject: Modify source code directly \{#eject}
102224

103-
```tsx title="theme/index.tsx"
104-
import {
105-
Search as BasicSearch,
106-
Layout as BasicLayout,
107-
} from '@rspress/core/theme-original';
225+
Eject means copying the source code of a single Rspress built-in component locally and then modifying it directly. The steps are as follows:
108226

109-
// Custom Home Page
110-
const HomeLayout = () => <div>Home</div>;
111-
// Custom 404 page
112-
const NotFoundLayout = () => <div>404</div>;
113-
// Use slot
114-
const Layout = () => (
115-
<BasicLayout
116-
beforeNavTitle={<div>some content</div>}
117-
HomeLayout={HomeLayout}
118-
NotFoundLayout={NotFoundLayout}
119-
/>
120-
);
227+
1. Execute CLI [`rspress eject [component]`](../../api/commands.mdx#rspress-eject), Rspress will eject the source code of the specified component to the local `theme/components` directory, without ejecting dependencies.
121228

122-
// Custom Search Component
123-
const Search = () => (
124-
<div className="my-search">
125-
<BasicSearch />
126-
</div>
127-
);
128-
export { Search, HomeLayout, NotFoundLayout };
129-
// re-export
229+
2. Update `theme/index.tsx` re-export:
230+
231+
```tsx title="theme/index.tsx"
232+
// Assuming you ejected the DocFooter component
233+
export { DocFooter } from './components/DocFooter';
130234
export * from '@rspress/core/theme-original';
131235
```
132236

133-
Of course, you may need to use page data during the development process, you can get it through [`Runtime API`](/ui/hooks/).
237+
3. Modify `theme/components/DocFooter.tsx` as needed to meet your requirements.
134238

135-
### 4. Custom icon
239+
Rspress components are split with fine granularity, you can see which components are suitable for eject in [Built-in Components](/ui/components/).
136240

137-
If you want to modify the icons used in the default theme component individually, just put the icons with the same name in the theme/assets directory.
241+
:::warning Do you really need eject?
138242

139-
```txt
140-
└── theme
141-
└── assets
142-
└── logo.svg
143-
```
243+
Eject will increase maintenance costs, because when Rspress is updated in the future, these ejected components will not automatically receive updates, and you need to manually compare and merge changes.
144244

145-
You can view all the icons used in the default theme [here](https://github.com/web-infra-dev/rspress/tree/main/packages/theme-default/src/assets).
245+
Please check if wrap can meet your needs first. Only consider eject when wrap cannot meet your needs.
246+
247+
:::
146248

147249
## Redevelop a custom theme
148250

0 commit comments

Comments
 (0)