#代码内联图标 定制主题
这是该模板独有的附加功能,通过自定义主题样式 + 定制组件,实现代码块内图标。
#使用方法
Tip
该功能 默认开启,可根据需求自由隐藏图标
#代码块标题
一个基础的代码块:
mdx
```js title="foo.js"
console.log('Hello World');
```它将被渲染为:
foo.js
js
console.log('Hello World');最关键的一点
注册图标配置:
theme/icon.less
less
// 针对代码块 title 添加图标
.rp-codeblock__title{
// #set-icon.lang 是我包装的 less 选择器
#set-icon.lang(js; var(--icon-js));
}#添加 Tabs 图标
foo.js
bar.ts
src/foo.js
js
console.log('foo');ts
console.log('bar');注册关键配置
theme/icon.less
less
// 针对 Tabs 的 label 添加图标
.rp-tabs__label__item{
// #set-icon.inline 是我包装的 less 选择器
#set-icon.inline(js; var(--icon-js));
#set-icon.inline(ts; var(--icon-ts));
}
// 针对代码块 title 添加图标
.rp-codeblock__title{
// tab-lang 是针对 Tabs 容器下的代码块 title 进行 [ 修改 | 添加 ] 图标
#set-icon.tab-lang(js; var(--icon-js-path)); // 可以不设置
}#隐藏图标 3种方法
-
通过在父元素中添加类名
remove-title-icon和remove-label-icon来分别隐藏代码块标题和 Tabs 图标。 -
或通过在 title 中添加字符串
--remove-icon来单独隐藏标题图标。md```js title="foo.js --remove-icon" console.log('Hello World'); ```它将被渲染为:
foo.jsjsconsole.log('Hello World'); -
或通过在 Tab 的
labelprop 中添加字符串--remove-icon来单独隐藏 label 图标。mdx<Tabs> // label 添加 --remove-icon <Tab label="foo.js --remove-icon"> ```js title="src/foo.js" console.log('foo'); ``` </Tab> <Tab label="bar.ts"> ```ts console.log('bar'); ``` </Tab> </Tabs>foo.jsbar.tssrc/foo.jsjsconsole.log('foo');tsconsole.log('bar');
#隐藏语言小标签
位于代码块右上角有一个语言小标签- 同理,父元素添加
remove-code-lang类名来隐藏语言小标签。 - 或通过在 title 中添加字符串
--remove-lang来单独隐藏标题语言小标签。foo.jsjsconsole.log('Hello World');
#定制主题源码
theme/index.tsx
tsx
import {
NavHamburger as BasicNavHamburger,
Layout as BasicLayout,
Tabs as BasicTabs, type TabsProps,
CodeBlock as BasicCodeBlock, type CodeBlockProps,
} from '@rspress/core/theme-original';
import './index.less';
import './icon.less';
import { type ReactNode } from 'react';
import { CssModificationProvider } from '@docs/CssModificationContext';
import { CssStyleSync } from '@docs/CssStyleSync';
// 代码块添加自定义的小语言标签
function CodeBlock(_props: CodeBlockProps) {
const { children, ...props } = _props;
// 通过给 title 添加额外字符串参数移除图标和语言标签
const removeIconKeyword = '--remove-icon'
const removeLangKeyword = '--remove-lang'
// 基础样式
let className = 'nbc-lang rp-copy-ignore'
// 判断 title 额外字符串参数
if(props.title) {
if(props.title.includes(removeIconKeyword)) {
props.title = props.title.replace(removeIconKeyword, '')
className += ' remove-nbc-icon'
}
if(props.title.includes(removeLangKeyword)) {
props.title = props.title.replace(removeLangKeyword, '')
className += ' remove-nbc-lang'
}
}
// 默认 txt 语言不显示语言标签
return (
<BasicCodeBlock {...props} >
<span className={ className }>{ props.lang !== 'txt' && props.lang }</span>
{children}
</BasicCodeBlock>
)
}
// Tab 类型定义
type TabItem = {
label: ReactNode;
value: string;
disabled?: boolean;
};
// 支持 tab 图标自定义组件
function Tabs(_props: TabsProps){
const { children, values, ...props } = _props;
// 只针对数组, 毕竟越复杂越容易出错
if(!values && Array.isArray(children)){
const values: TabItem[] = []
children.forEach( item => {
// 判断是否移除 label 图标的后缀
const suffix = '--remove-icon';
const defaultValue: undefined | string = item?.props?.value
const label:string = item?.props?.label
// 逆天, 但没办法
const lang:string = item?.props?.children?.props?.children?.props?.lang
// label 明示移除图标参数
if(label && label.includes(suffix)){
const mainLabel = label.replace(suffix, '').trim();
values.push({
label: mainLabel,
value: defaultValue ?? mainLabel,
})
return
}
const mainLabel = lang ?
<span className={`icon-${lang}`}>{label}</span>
: label
// 正常的 Tab
values.push({
label: mainLabel,
value: defaultValue ?? label,
})
})
// 返回自定义图标组件
return (
<BasicTabs {...props} values={values}>{children}</BasicTabs>
)
}
// 兜底默认
return (
<BasicTabs {...props} values={values}>{children}</BasicTabs>
)
}
// TODO 如果用不到 CSSPickerEditor 组件的话可以删
// 基础布局添加上 css 上下文
function Layout() {
return (
<CssModificationProvider>
<CssStyleSync />
<BasicLayout />
</CssModificationProvider>
)
}
// 自己的 hamburger 按钮
function NavHamburger(){
return (
<div className="nbc-nav-container">
<BasicNavHamburger/>
<div className="nbc-button-container">
<span className="nbc-top" />
<span className="nbc-middle" />
<span className="nbc-bottom" />
</div>
</div>
);
}
export { NavHamburger, Layout, Tabs, CodeBlock }
export * from '@rspress/core/theme-original';

