使用场景
侧边信息栏主要用于在 AI 场景下,用于信息展示,功能配置。包括 MCP 配置、参考来源、代码预览、富文本预览及编辑等功能
代码演示
如何引入
<script setup lang="ts">
import { Annotation, MCPConfigure, Sidebar } from '@fibrous/semi-ai-vue';
const { Container, CodeContent, CodeItem, FileContent, FileItem } = Sidebar;
const { AnnotationContent } = Annotation;
</script>
基础容器
侧边信息栏的基础容器,基础容器是MCP 配置、参考来源、以及侧边消息栏的基础容器。
v-model:visible控制显示和隐藏。点击关闭按钮,或在closeOnEsc为true时按下 Esc,会先更新为false再触发canceltitle设置纯文本标题,需要自定义内容时使用#title插槽motion设置是否有展开动画resizable设置宽度是否可伸缩,为true时候可通过minWidth,maxWidth设置最小,最大宽度
代码
<script setup lang="ts">
import { shallowRef } from 'vue';
import { Sidebar } from '@fibrous/semi-ai-vue';
import { Button, Switch } from '@fibrous/semi-ui-vue';
const { Container } = Sidebar;
const containerStyle = {
display: 'flex',
height: '500px',
border: '1px solid var(--semi-color-border)',
borderRadius: '8px',
overflow: 'hidden',
boxSizing: 'border-box',
} as const;
const visible = shallowRef(true);
const motion = shallowRef(true);
const resizable = shallowRef(true);
</script>
<template>
<div :style="containerStyle">
<div :style="{ flexGrow: 1, flexShrink: 1, padding: '20px' }">
<div>
<Button :aria-pressed="visible" @click="visible = !visible">显示容器</Button>
<div :style="{ display: 'flex', alignItems: 'center', marginTop: '10px' }">
<span id="sidebar-container-motion">是否有动画</span>
<Switch v-model="motion" aria-labelledby="sidebar-container-motion" />
</div>
<div :style="{ display: 'flex', alignItems: 'center', marginTop: '10px' }">
<span id="sidebar-container-resizable">是否可伸缩</span>
<Switch v-model="resizable" aria-labelledby="sidebar-container-resizable" />
</div>
</div>
</div>
<Container v-model:visible="visible" maxWidth="60%" :minWidth="250" :motion="motion" :resizable="resizable" :style="resizable ? undefined : { width: '200px' }" title="基础容器示例" />
</div>
</template>MCP 配置
使用 MCPConfigure 进行 MCP 工具的展示、启用/关闭、配置及搜索
- 通过
v-model:options和v-model:customOptions绑定内置的 MCP 工具和自定义 MCP 工具,切换启用/关闭时先更新绑定值,再触发statusChange - 通过
v-model:visible设置组件的显示和隐藏,使用cancel监听用户的关闭行为 - 使用
statusChange自定义处理 MCP 工具的启用/关闭 - 使用
addClick处理自定义 MCP 页的点击添加按钮后的操作 - 可通过
configureClick监听内置 MCP 工具的配置,通过editClick监听自定义 MCP 工具的配置 - 工具项的图标和描述使用
#icon、#desc插槽,整行用#item替换;插槽参数为{ item, index, custom }
其他 MCPConfigure 的 API 见 MCPConfigure
传入 MCP 工具项的类型如下
interface MCPConfigureOption {
icon?: string; // 图片地址,其他内容使用 #icon 插槽
label?: string;
value: string; // 必填,标识工具项,需唯一
desc?: string; // 纯文本,其他内容使用 #desc 插槽
active?: boolean;
disabled?: boolean;
configure?: boolean; // 是否显示配置按钮
}
用例如下:
代码
<script setup lang="ts">
import { shallowRef, useTemplateRef, type Component } from 'vue';
import { MCPConfigure, type MCPConfigureOption } from '@fibrous/semi-ai-vue';
import { IconFigma, IconSemiLogo } from '@fibrous/semi-icons-vue';
import { Button, Form, FormInput, FormTextArea, Modal, type FormHandle } from '@fibrous/semi-ui-vue';
interface McpFormValues {
name: string;
src: string;
desc: string;
}
const containerStyle = {
display: 'flex',
height: '500px',
border: '1px solid var(--semi-color-border)',
borderRadius: '8px',
overflow: 'hidden',
boxSizing: 'border-box',
} as const;
// icon only takes an image URL, so the built-in options get their icons from the #icon slot
const builtinIcons: Record<string, Component> = {
'Semi mcp': IconSemiLogo,
figma: IconFigma,
};
const srcRules = [
{ required: true, message: '请输入 MCP 图标 URL' },
{
validator: (_rule: unknown, value: string) => /^(?:https?:\/\/)?(?:www\.)?[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+(?::\d+)?(?:\/[^\s]*)?$/i.test(value),
message: '请输入有效的 MCP 图标 URL',
},
];
let index = 1;
const visible = shallowRef(true);
const options = shallowRef<MCPConfigureOption[]>([
{
value: 'Semi mcp',
label: 'Semi',
configure: true,
desc: '支持 Semi 的文档、源码搜索,辅助开发',
},
{
value: 'figma',
label: 'Figma',
desc: 'Figma MCP Server 连接Figma与AI开发工具的功能。它通过标准化的模型上下文协MCP),将组件、变量等设计数据和上下文暴露给AI,从而实现从设计稿到代码的智能生成,显著提升开发效率。',
},
]);
const customOptions = shallowRef<MCPConfigureOption[]>([]);
const modalVisible = shallowRef(false);
const form = useTemplateRef<FormHandle<McpFormValues>>('form');
const handleOk = () => {
form.value?.formApi
.validate()
.then((values) => {
customOptions.value = [
...customOptions.value,
{
label: values.name,
icon: values.src,
value: `mcp-${index++}`,
desc: values.desc,
},
];
modalVisible.value = false;
})
.catch((errors) => {
console.log('errors', errors);
});
};
const onConfigureClick = (_event: MouseEvent, option: MCPConfigureOption) => {
console.log('configure click', option);
};
const onEditClick = (_event: MouseEvent, option: MCPConfigureOption) => {
console.log('edit click', option);
};
</script>
<template>
<div :style="containerStyle">
<div :style="{ flexGrow: 1, flexShrink: 1, padding: '20px' }">
<Button :aria-pressed="visible" @click="visible = !visible">MCP 配置</Button>
</div>
<MCPConfigure v-model:customOptions="customOptions" v-model:options="options" v-model:visible="visible" :resizable="false" :style="{ width: '500px' }" @addClick="modalVisible = true" @configureClick="onConfigureClick" @editClick="onEditClick">
<template #icon="{ item }">
<img v-if="item.icon" alt="" :src="item.icon" :style="{ width: '100%', height: '100%' }" />
<component :is="builtinIcons[item.value]" v-else />
</template>
</MCPConfigure>
<Modal v-model:visible="modalVisible" closeOnEsc title="自定义 MCP" @ok="handleOk">
<Form ref="form" layout="vertical" @valueChange="(values) => console.log(values)">
<FormInput field="name" label="MCP 名称" :rules="[{ required: true, message: '请输入 MCP 名称' }]" :style="{ width: '100%' }" />
<FormInput field="src" initValue="/assets/placeholder/avatar-a.svg" label="MCP 图标 URL" :rules="srcRules" :style="{ width: '100%' }" />
<FormTextArea field="desc" label="MCP 介绍" :rules="[{ required: true, message: '请输入 MCP 介绍' }]" :style="{ width: '100%' }" />
</Form>
</Modal>
</div>
</template>参考来源
使用 Annotation 组件可以管理参考来源的展示
v-model:activeKey管理当前展开的项info设置参考来源的具体内容click在点击某条参考来源时触发,参数为事件和该条目- 分组标题使用
#infoHeader插槽,条目使用#item插槽替换;#header是整个容器头部
代码
<script setup lang="ts">
import { shallowRef } from 'vue';
import { Annotation, type AnnotationInfo, type AnnotationItem } from '@fibrous/semi-ai-vue';
import { Button } from '@fibrous/semi-ui-vue';
const containerStyle = {
display: 'flex',
height: '500px',
border: '1px solid var(--semi-color-border)',
borderRadius: '8px',
overflow: 'hidden',
boxSizing: 'border-box',
} as const;
const logo = '/assets/placeholder/avatar-a.svg';
const img = '/assets/root-web-sites/abstract.jpg';
const defaultInfoList: AnnotationInfo[] = [
{
header: 'Semi design introduction',
key: '1',
annotations: [
{
order: 1,
type: 'video',
duration: 4432,
title: 'Semi Design is a design system designed',
url: 'https://semi.design/',
logo,
siteName: 'Semi Design',
detail: ' As a comprehensive, easy-to-use, and high-quality modern enterprise-level application UI solution',
img,
},
{
order: 2,
title: 'Quick start',
type: 'video',
duration: 56,
url: 'https://semi.design/',
detail: ' As a comprehensive, easy-to-use, and high-quality modern enterprise-level application UI solution',
logo,
siteName: 'Semi Design',
img,
},
{
order: 3,
title: 'Use components in a modular way',
url: 'https://semi.design/',
detail: `Semi provides esm format dist, and the css of the component is only imported by the corresponding js.
When used in Webpack, Rspack, create-react-app or Vite projects, there is no need to configure any compilation items.`,
logo,
siteName: 'Semi Design',
img,
},
],
},
{
header: 'Design resource',
key: '2',
annotations: [
{
order: 2,
title: 'Semi Design resource',
url: 'https://semi.design/',
detail: 'Semi Design provides a wealth of design resources to help designers and developers collaborate efficiently. Whether you are a community user or a ByteDance internal designer, you can find UI Kit resource and Figma plug-ins that suit you here.',
logo,
siteName: 'Semi Design resource',
img,
},
],
},
];
const defaultSize = { width: 420 };
const visible = shallowRef(true);
const activeKey = shallowRef<string | string[]>('1');
const onChange = (key: string | string[]) => {
console.log('change', key);
};
const onClick = (event: MouseEvent, item: AnnotationItem) => {
console.log('click', event, item);
};
</script>
<template>
<div :style="containerStyle">
<div :style="{ flexGrow: 1, flexShrink: 1, padding: '20px' }">
<Button :aria-pressed="visible" @click="visible = !visible">参考来源</Button>
</div>
<Annotation v-model:activeKey="activeKey" v-model:visible="visible" :defaultSize="defaultSize" :info="defaultInfoList" @change="onChange" @click="onClick" />
</div>
</template>代码展示
可通过 Sidebar 中的 CodeItem 展示代码,CodeItem 基于 JsonViewer 以及 CodeHighlight 实现。
content: 内容字符串isJson: 是否为 jsonlanguage: 编程语言名称,同CodeHighlight的 language,需先通过CodeHighlight.register注册jsonViewerProps: 配置其他 JsonViewer 参数codeHighlightProps: 配置其他 CodeHighlight 参数
jsonViewerProps 中 JsonViewer 的 value 在 Vue 中叫 modelValue,jsonViewerProps 与 codeHighlightProps 还可以带 class、style。JsonViewer 的自定义渲染与搜索按钮通过 CodeItem 的 #customRender、#searchButton 插槽使用。
代码
<script setup lang="ts">
import { computed, shallowRef } from 'vue';
import { Sidebar } from '@fibrous/semi-ai-vue';
import { Radio, RadioGroup, type RadioValue } from '@fibrous/semi-ui-vue';
const { CodeItem } = Sidebar;
const code = `.semi-animation-react-demo-auto {
button {
height: 50px;
border: 0;
cursor: pointer !important;
background: #777;
color: white;
outline: none;
-webkit-appearance: none;
}
button:hover {
background: #878787;
}
.auto-main {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto 1fr;
background: #575757;
}
.content {
grid-column: span 3;
}
.item {
background: indianred;
width: 100%;
overflow: hidden;
color: white;
}
.item p {
margin: 0;
padding: 10px;
}
}
`;
const json = `{
"axisX": {
"title": {
"visible": false,
"position": "center"
},
"label": {
"visible": true,
"style": {
"fontSize": 12,
"fontWeight": 400,
"lineHeight": 16,
"fontFamily": [
"Inter"
],
"fill": "rgba(0, 0, 0, 0.47843137254901963)"
},
"space": 12
}
}
}`;
const codeProps = {
content: code,
language: 'css',
};
const jsonProps = {
isJson: true,
content: json,
};
const type = shallowRef<RadioValue | undefined>('json');
const itemProps = computed(() => (type.value === 'json' ? jsonProps : codeProps));
</script>
<template>
<RadioGroup v-model="type" buttonSize="middle" :style="{ marginBottom: '10px' }" type="button">
<Radio value="json">JSON</Radio>
<Radio value="css">CSS</Radio>
</RadioGroup>
<div :style="{ height: '200px', overflow: 'auto' }">
<CodeItem v-bind="itemProps" />
</div>
</template>代码列表
用户可通过 Sidebar 中的 CodeContent 组件展示代码列表信息。
v-model:activeKey管理当前展开的面板expand监听面板头部的展开按钮#customRender、#searchButton转发给每个 JSON 面板中的 JsonViewer
代码
<script setup lang="ts">
import { shallowRef } from 'vue';
import { Sidebar } from '@fibrous/semi-ai-vue';
const { CodeContent } = Sidebar;
const defaultCodes = [
{
name: 'Component.js',
key: 'code1',
language: 'javascript',
content: `import React from 'react';
import { AutoComplete } from '@fibrous/semi-ui-react';
import { IconSearch } from '@fibrous/semi-icons-react';
() => {
const [stringData, setStringData] = useState([]);
const [value, setValue] = useState('');
const handleStringSearch = (value) => {
let result;
if (value) {
result = ['gmail.com', '163.com', 'qq.com'].map(domain => value+domain);
} else {
result = [];
}
setStringData(result);
};
const handleChange = (value) => {
console.log('onChange', value);
setValue(value);
};
return (
<AutoComplete
data={stringData}
value={value}
showClear
prefix={<IconSearch />}
placeholder="搜索... "
onSearch={handleStringSearch}
onChange={handleChange}
style={{ width: 200 }}
/>
);
};
`,
},
{
name: 'Style.css',
key: 'code2',
language: 'css',
content: `.semi-animation-react-demo-auto {
button {
height: 50px;
border: 0;
cursor: pointer !important;
background: #777;
color: white;
outline: none;
-webkit-appearance: none;
}
button:hover {
background: #878787;
}
.auto-main {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto 1fr;
background: #575757;
}
.content {
grid-column: span 3;
}
.item {
background: indianred;
width: 100%;
overflow: hidden;
color: white;
}
.item p {
margin: 0;
padding: 10px;
}
}
`,
},
{
name: 'Chart.json',
key: 'code3',
isJson: true,
language: 'html',
content: `{
"axisX": {
"title": {
"visible": false,
"position": "center"
},
"label": {
"visible": true,
"style": {
"fontSize": 12,
"fontWeight": 400,
"lineHeight": 16,
"fontFamily": [
"Inter"
],
"fill": "rgba(0, 0, 0, 0.47843137254901963)"
},
"space": 12
},
"domainLine": {
"visible": true,
"style": {
"lineWidth": 1,
"stroke": "rgba(0, 0, 0, 0.12156862745098039)",
"lineDash": []
}
},
"tick": {
"visible": false,
"style": {
"lineWidth": 1,
"stroke": "rgba(255, 255, 255, 0)"
}
},
"subTick": {
"visible": false
},
"grid": {
"visible": false
},
"subGrid": {
"visible": false
}
}
}`,
},
];
const activeKey = shallowRef<string | string[]>('code1');
</script>
<template>
<div class="semi-sidebar-main">
<CodeContent v-model:activeKey="activeKey" :codes="defaultCodes" :style="{ width: '600px' }" />
</div>
</template>富文本编辑器
可通过 Sidebar 中的 FileItem 查看、编辑富文本内容, FileItem 基于 tiptap 实现。
content:富文本 HTML。挂载后变化会同步到编辑器,与编辑器当前内容相同时不会重置,不会打断输入也不会丢失光标,同步不触发contentChangeeditable: 设置是否可编辑,挂载后变化会同步到编辑器imgUploadProps: 设置图片上传路径以及图片上传后 src 的设置,通过action设置上传地址,通过getUploadImageSrc(response)函数根据上传响应返回图片上传后地址(未提供时,响应是字符串则直接作为地址,否则取response.src),用于富文本中 img 节点的 src;Upload 的on开头监听(如onSuccess)也可在这里传入。只有设置了action或customRequest,工具栏才显示图片按钮extensions与imgUploadProps只在创建编辑器时读取,要换用新值时更换key重新挂载contentChange在编辑后触发,参数为 HTML 字符串
代码
<script setup lang="ts">
import { shallowRef } from 'vue';
import { Sidebar, type ImageUploadNodeOptions } from '@fibrous/semi-ai-vue';
import { Button } from '@fibrous/semi-ui-vue';
const { FileItem } = Sidebar;
const content = `<h2>
Semi Design 介绍
</h2>
<p>
Semi Design 是由 <strong>抖音前端团队</strong>和MED产品设计团队设计、开发并维护的<em>设计系统</em>。作为一个全面、易用、优质的现代应用UI解决方案,Semi Design从字节跳动各业务线的复杂场景中提炼而来,目前已经支撑了近千个平台产品,服务了内外部超过10万用户,详情见https://semi.design/zh-CN/start/introduction。Semi Design的特点包括:
</p>
<ul>
<li>
设计简洁、现代化。
</li>
<li>
提供主题方案,可深度样式定制。
</li>
</ul>
<p>
国际化,覆盖了简/繁体中文、英语、日语、韩语、葡萄牙语等20+种语言,日期时间组件提供全球时区支持,全部组件可自动适配阿拉伯文RTL布局。
</p>
<pre><code class="language-css">body {
display: none;
}</code></pre>
<p>
采用 Foundation 和 Adapter 跨框架技术方案,方便扩展。
</p>
<blockquote>
Semi Design 是由抖音前端团队和MED产品设计团队设计、开发并维护的设计系统
<br />
— Semi Design
</blockquote>`;
const imgUploadProps: ImageUploadNodeOptions = {
action: 'https://api.semi.design/upload',
// response is the action's result; real code reads the uploaded image URL from it
getUploadImageSrc: () => '/assets/placeholder/avatar-a.svg',
};
const editable = shallowRef(true);
</script>
<template>
<Button :aria-pressed="editable" @click="editable = !editable">可编辑</Button>
<br />
<br />
<FileItem :content="content" :editable="editable" :imgUploadProps="imgUploadProps" name="Semi Design 介绍" :style="{ border: '1px solid var(--semi-color-border)', padding: '12px' }" />
</template>富文本列表
用户可通过 Sidebar 中的 FileContent 组件展示富文本列表信息。
v-model:activeKey管理当前展开的面板expand监听面板头部的展开按钮
代码
<script setup lang="ts">
import { shallowRef } from 'vue';
import { Sidebar } from '@fibrous/semi-ai-vue';
const { FileContent } = Sidebar;
const defaultFiles = [
{
key: 'file1',
name: 'Semi Design 介绍',
content: `
<h2>
Semi Design 介绍
</h2>
<p>
Semi Design 是由 <strong>抖音前端团队</strong>和MED产品设计团队设计、开发并维护的<em>设计系统</em>。作为一个全面、易用、优质的现代应用UI解决方案,Semi Design从字节跳动各业务线的复杂场景中提炼而来,目前已经支撑了近千个平台产品,服务了内外部超过10万用户,详情见https://semi.design/zh-CN/start/introduction。Semi Design的特点包括:
</p>
<ul>
<li>
设计简洁、现代化。
</li>
<li>
提供主题方案,可深度样式定制。
</li>
</ul>
<p>
国际化,覆盖了简/繁体中文、英语、日语、韩语、葡萄牙语等20+种语言,日期时间组件提供全球时区支持,全部组件可自动适配阿拉伯文RTL布局。
</p>
<pre><code class="language-css">body {
display: none;
}</code></pre>
<p>
采用 Foundation 和 Adapter 跨框架技术方案,方便扩展。
</p>
<blockquote>
Semi Design 是由抖音前端团队和MED产品设计团队设计、开发并维护的设计系统
<br />
— Semi Design
</blockquote>
<p>
Semi Design 是由 <strong>抖音前端团队</strong>和MED产品设计团队设计、开发并维护的<em>设计系统</em>。作为一个全面、易用、优质的现代应用UI解决方案,Semi Design从字节跳动各业务线的复杂场景中提炼而来,目前已经支撑了近千个平台产品,服务了内外部超过10万用户,详情见https://semi.design/zh-CN/start/introduction。Semi Design的特点包括:
</p>
<ul>
<li>
设计简洁、现代化。
</li>
<li>
提供主题方案,可深度样式定制。
</li>
</ul>
<p>
国际化,覆盖了简/繁体中文、英语、日语、韩语、葡萄牙语等20+种语言,日期时间组件提供全球时区支持,全部组件可自动适配阿拉伯文RTL布局。
</p>
<pre><code class="language-css">body {
display: none;
}</code></pre>
<p>
采用 Foundation 和 Adapter 跨框架技术方案,方便扩展。
</p>
<blockquote>
Semi Design 是由抖音前端团队和MED产品设计团队设计、开发并维护的设计系统
<br />
— Semi Design
</blockquote>
<p>
Semi Design 是由 <strong>抖音前端团队</strong>和MED产品设计团队设计、开发并维护的<em>设计系统</em>。作为一个全面、易用、优质的现代应用UI解决方案,Semi Design从字节跳动各业务线的复杂场景中提炼而来,目前已经支撑了近千个平台产品,服务了内外部超过10万用户,详情见https://semi.design/zh-CN/start/introduction。Semi Design的特点包括:
</p>
<ul>
<li>
设计简洁、现代化。
</li>
<li>
提供主题方案,可深度样式定制。
</li>
</ul>
<p>
国际化,覆盖了简/繁体中文、英语、日语、韩语、葡萄牙语等20+种语言,日期时间组件提供全球时区支持,全部组件可自动适配阿拉伯文RTL布局。
</p>
<pre><code class="language-css">body {
display: none;
}</code></pre>
<p>
采用 Foundation 和 Adapter 跨框架技术方案,方便扩展。
</p>
<blockquote>
Semi Design 是由抖音前端团队和MED产品设计团队设计、开发并维护的设计系统
<br />
— Semi Design
</blockquote>
`,
},
{
key: 'file2',
name: 'Semi Design DSM',
content: `<h2>
Semi Design DSM
</h2>
<p>Semi DSM is a design system management tool provided by Semi Design. It supports global and component-level style customization and keeps synchronization between Figma and front-end code. Suitable for teams of all sizes. Whether you need to simplify workflow, improve team collaboration, or increase productivity, we have features suitable for you.</p>
`,
},
{
key: 'file3',
name: 'React v19 Adaptation',
content: `<h2>
React v19 Adaptation
</h2>
<p>Since the release of React v19, React has introduced numerous underlying mechanism and API changes, including upgrades and adjustments to the render mechanism, ref, context, TypeScript types, and related deprecated APIs. To ensure that the Semi Design component library is smoothly compatible with both React v19 and lower versions, we provide the original component package @fibrous/semi-ui-react for React versions below v19, as well as a new package @fibrous/semi-ui-19 specifically adapted for React v19, so users can choose as needed. This guide will help you understand how to install, use, and the precautions to take.
Installation & Usage
If your project is using React v19, please use @fibrous/semi-ui-19. For React versions below v19, continue using @fibrous/semi-ui-react as before.</p>
`,
},
];
const activeKey = shallowRef<string | string[]>('file1');
</script>
<template>
<div class="semi-sidebar-main">
<FileContent v-model:activeKey="activeKey" :files="defaultFiles" :style="{ width: '600px' }" />
</div>
</template>侧边信息栏
侧边信息栏 Sidebar 有主视图(mode 为 main)和详情视图(mode 为 code、file 及其他)。
主视图可以通过 title 或 #title 插槽配置标题,通过 showClose 决定是否展示关闭按钮,通过 options 设置顶部的按钮组(每项为 { name, key }),v-model:activeKey 绑定当前选中的项。按钮图标使用 #optionIcon="{ item, index }" 插槽,需要替换整个按钮时使用 #optionItem,其参数 onClick 用于选中该项。
对于主视图的内容渲染,可通过 #mainContent="{ activeKey }" 插槽,根据当前选中项渲染。可使用 Annotation 中的 AnnotationContent 渲染参考来源,使用 Sidebar 中内置的 FileContent 渲染富文本, CodeContent 渲染代码。
对于详情视图,如果是富文本或者代码,分别设置 mode 为 code、file,通过 detailContent 设置显示内容,即可通过内置的代码显示组件, 富文本编辑器进行显示;detailContent 的 key 变化时会重新挂载。如果想要自定义详情视图的展示,则通过 #detailContent="{ mode }" 插槽自行渲染,详情头部通过 #detailHeader="{ mode, detailContent }" 自定义,两者内容为空时回退到内置内容。点击详情头部的返回按钮触发 backWard。
代码
<script setup lang="ts">
import { shallowRef, type Component } from 'vue';
import { Annotation, Sidebar, type AnnotationInfo, type ImageUploadNodeOptions, type SideBarDetailContent } from '@fibrous/semi-ai-vue';
import { IconBriefStroked, IconCodeStroked, IconModalStroked, IconSearch } from '@fibrous/semi-icons-vue';
const { FileContent, CodeContent } = Sidebar;
const { AnnotationContent } = Annotation;
const containerStyle = {
display: 'flex',
height: '800px',
border: '1px solid var(--semi-color-border)',
borderRadius: '8px',
overflow: 'hidden',
boxSizing: 'border-box',
} as const;
const optionList = [
{
name: '查看搜索',
key: 'searchResult',
},
{
name: '文件预览',
key: 'filePreview',
},
{
name: '代码预览',
key: 'codePreview',
},
{
name: '浏览器',
key: 'network',
},
];
const optionIcons: Record<string, Component> = {
searchResult: IconSearch,
filePreview: IconBriefStroked,
codePreview: IconCodeStroked,
network: IconModalStroked,
};
const defaultCodes = [
{
name: 'Component.js',
key: 'code1',
language: 'javascript',
content: `import React from 'react';
import { AutoComplete } from '@fibrous/semi-ui-react';
import { IconSearch } from '@fibrous/semi-icons-react';
() => {
const [stringData, setStringData] = useState([]);
const [value, setValue] = useState('');
const handleStringSearch = (value) => {
let result;
if (value) {
result = ['gmail.com', '163.com', 'qq.com'].map(domain => value+domain);
} else {
result = [];
}
setStringData(result);
};
const handleChange = (value) => {
console.log('onChange', value);
setValue(value);
};
return (
<AutoComplete
data={stringData}
value={value}
showClear
prefix={<IconSearch />}
placeholder="搜索... "
onSearch={handleStringSearch}
onChange={handleChange}
style={{ width: 200 }}
/>
);
};
`,
},
{
name: 'Style.css',
key: 'code2',
language: 'css',
content: `.semi-animation-react-demo-auto {
button {
height: 50px;
border: 0;
cursor: pointer !important;
background: #777;
color: white;
outline: none;
-webkit-appearance: none;
}
button:hover {
background: #878787;
}
.auto-main {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto 1fr;
background: #575757;
}
.content {
grid-column: span 3;
}
.item {
background: indianred;
width: 100%;
overflow: hidden;
color: white;
}
.item p {
margin: 0;
padding: 10px;
}
}
`,
},
{
name: 'Chart.json',
key: 'code3',
isJson: true,
language: 'html',
content: `{
"axisX": {
"title": {
"visible": false,
"position": "center"
},
"label": {
"visible": true,
"style": {
"fontSize": 12,
"fontWeight": 400,
"lineHeight": 16,
"fontFamily": [
"Inter"
],
"fill": "rgba(0, 0, 0, 0.47843137254901963)"
},
"space": 12
},
"domainLine": {
"visible": true,
"style": {
"lineWidth": 1,
"stroke": "rgba(0, 0, 0, 0.12156862745098039)",
"lineDash": []
}
},
"tick": {
"visible": false,
"style": {
"lineWidth": 1,
"stroke": "rgba(255, 255, 255, 0)"
}
},
"subTick": {
"visible": false
},
"grid": {
"visible": false
},
"subGrid": {
"visible": false
}
}
}`,
},
];
const defaultFiles = [
{
key: 'file1',
name: 'Semi Design 介绍',
content: `
<h2>
Semi Design 介绍
</h2>
<p>
Semi Design 是由 <strong>抖音前端团队</strong>和MED产品设计团队设计、开发并维护的<em>设计系统</em>。作为一个全面、易用、优质的现代应用UI解决方案,Semi Design从字节跳动各业务线的复杂场景中提炼而来,目前已经支撑了近千个平台产品,服务了内外部超过10万用户,详情见https://semi.design/zh-CN/start/introduction。Semi Design的特点包括:
</p>
<ul>
<li>
设计简洁、现代化。
</li>
<li>
提供主题方案,可深度样式定制。
</li>
</ul>
<p>
国际化,覆盖了简/繁体中文、英语、日语、韩语、葡萄牙语等20+种语言,日期时间组件提供全球时区支持,全部组件可自动适配阿拉伯文RTL布局。
</p>
<pre><code class="language-css">body {
display: none;
}</code></pre>
<p>
采用 Foundation 和 Adapter 跨框架技术方案,方便扩展。
</p>
<blockquote>
Semi Design 是由抖音前端团队和MED产品设计团队设计、开发并维护的设计系统
<br />
— Semi Design
</blockquote>
<p>
Semi Design 是由 <strong>抖音前端团队</strong>和MED产品设计团队设计、开发并维护的<em>设计系统</em>。作为一个全面、易用、优质的现代应用UI解决方案,Semi Design从字节跳动各业务线的复杂场景中提炼而来,目前已经支撑了近千个平台产品,服务了内外部超过10万用户,详情见https://semi.design/zh-CN/start/introduction。Semi Design的特点包括:
</p>
<ul>
<li>
设计简洁、现代化。
</li>
<li>
提供主题方案,可深度样式定制。
</li>
</ul>
<p>
国际化,覆盖了简/繁体中文、英语、日语、韩语、葡萄牙语等20+种语言,日期时间组件提供全球时区支持,全部组件可自动适配阿拉伯文RTL布局。
</p>
<pre><code class="language-css">body {
display: none;
}</code></pre>
<p>
采用 Foundation 和 Adapter 跨框架技术方案,方便扩展。
</p>
<blockquote>
Semi Design 是由抖音前端团队和MED产品设计团队设计、开发并维护的设计系统
<br />
— Semi Design
</blockquote>
<p>
Semi Design 是由 <strong>抖音前端团队</strong>和MED产品设计团队设计、开发并维护的<em>设计系统</em>。作为一个全面、易用、优质的现代应用UI解决方案,Semi Design从字节跳动各业务线的复杂场景中提炼而来,目前已经支撑了近千个平台产品,服务了内外部超过10万用户,详情见https://semi.design/zh-CN/start/introduction。Semi Design的特点包括:
</p>
<ul>
<li>
设计简洁、现代化。
</li>
<li>
提供主题方案,可深度样式定制。
</li>
</ul>
<p>
国际化,覆盖了简/繁体中文、英语、日语、韩语、葡萄牙语等20+种语言,日期时间组件提供全球时区支持,全部组件可自动适配阿拉伯文RTL布局。
</p>
<pre><code class="language-css">body {
display: none;
}</code></pre>
<p>
采用 Foundation 和 Adapter 跨框架技术方案,方便扩展。
</p>
<blockquote>
Semi Design 是由抖音前端团队和MED产品设计团队设计、开发并维护的设计系统
<br />
— Semi Design
</blockquote>
`,
},
{
key: 'file2',
name: 'Semi Design DSM',
content: `<h2>
Semi Design DSM
</h2>
<p>Semi DSM is a design system management tool provided by Semi Design. It supports global and component-level style customization and keeps synchronization between Figma and front-end code. Suitable for teams of all sizes. Whether you need to simplify workflow, improve team collaboration, or increase productivity, we have features suitable for you.</p>
`,
},
{
key: 'file3',
name: 'React v19 Adaptation',
content: `<h2>
React v19 Adaptation
</h2>
<p>Since the release of React v19, React has introduced numerous underlying mechanism and API changes, including upgrades and adjustments to the render mechanism, ref, context, TypeScript types, and related deprecated APIs. To ensure that the Semi Design component library is smoothly compatible with both React v19 and lower versions, we provide the original component package @fibrous/semi-ui-react for React versions below v19, as well as a new package @fibrous/semi-ui-19 specifically adapted for React v19, so users can choose as needed. This guide will help you understand how to install, use, and the precautions to take.
Installation & Usage
If your project is using React v19, please use @fibrous/semi-ui-19. For React versions below v19, continue using @fibrous/semi-ui-react as before.</p>
`,
},
];
const logo = '/assets/placeholder/avatar-a.svg';
const img = '/assets/root-web-sites/abstract.jpg';
const defaultInfoList: AnnotationInfo[] = [
{
header: 'Semi design introduction',
key: '1',
annotations: [
{
order: 1,
type: 'video',
duration: 4432,
title: 'Semi Design is a design system designed',
url: 'https://semi.design/',
logo,
siteName: 'Semi Design',
detail: ' As a comprehensive, easy-to-use, and high-quality modern enterprise-level application UI solution',
img,
},
{
order: 2,
title: 'Quick start',
type: 'video',
duration: 56,
url: 'https://semi.design/',
detail: ' As a comprehensive, easy-to-use, and high-quality modern enterprise-level application UI solution',
logo,
siteName: 'Semi Design',
img,
},
{
order: 3,
title: 'Use components in a modular way',
url: 'https://semi.design/',
detail: `Semi provides esm format dist, and the css of the component is only imported by the corresponding js.
When used in Webpack, Rspack, create-react-app or Vite projects, there is no need to configure any compilation items.`,
logo,
siteName: 'Semi Design',
img,
},
],
},
{
header: 'Design resource',
key: '2',
annotations: [
{
order: 2,
title: 'Semi Design resource',
url: 'https://semi.design/',
detail: 'Semi Design provides a wealth of design resources to help designers and developers collaborate efficiently. Whether you are a community user or a ByteDance internal designer, you can find UI Kit resource and Figma plug-ins that suit you here.',
logo,
siteName: 'Semi Design resource',
img,
},
],
},
];
const imgUploadProps: ImageUploadNodeOptions = {
action: 'https://api.semi.design/upload',
// response is the action's result; real code reads the uploaded image URL from it
getUploadImageSrc: () => logo,
};
const defaultSize = { width: '60%' };
const mode = shallowRef('main');
const activeKey = shallowRef('codePreview');
const activeCodeKey = shallowRef<string | string[]>('code1');
const activeFileKey = shallowRef<string | string[]>('file1');
const activeReferKey = shallowRef<string | string[]>('1');
const currentDetail = shallowRef<SideBarDetailContent>();
const onExpand = (_event: MouseEvent, content: SideBarDetailContent, expandMode: string) => {
mode.value = expandMode;
currentDetail.value = content;
};
</script>
<template>
<div :style="containerStyle">
<div :style="{ flexGrow: 1, flexShrink: 1, padding: '20px' }">工作区占位</div>
<Sidebar v-model:activeKey="activeKey" :defaultSize="defaultSize" :detailContent="currentDetail" :imgUploadProps="imgUploadProps" :mode="mode" :motion="false" :options="optionList" :showClose="false" title="Agent 的工作空间" visible @backWard="(_event, backMode) => (mode = backMode)">
<template #optionIcon="{ item }">
<component :is="optionIcons[item.key]" />
</template>
<template #mainContent="{ activeKey: currentKey }">
<AnnotationContent v-if="currentKey === 'searchResult'" v-model:activeKey="activeReferKey" :info="defaultInfoList" />
<FileContent v-else-if="currentKey === 'filePreview'" v-model:activeKey="activeFileKey" :files="defaultFiles" @expand="onExpand" />
<CodeContent v-else-if="currentKey === 'codePreview'" v-model:activeKey="activeCodeKey" :codes="defaultCodes" @expand="onExpand" />
<img v-else-if="currentKey === 'network'" alt="network" src="/assets/root-web-sites/test.jpg" :style="{ width: '100%' }" />
</template>
</Sidebar>
</div>
</template>API 参考
Sidebar、Annotation、MCPConfigure 与 Container 的 class、style 和其他未声明的属性(如 aria-label)落在 .semi-sidebar-container 元素上;根元素被命名(aria-label 或 aria-labelledby)且没有指定 role 时,role 为 group。CodeContent、CodeItem、FileContent、FileItem、AnnotationContent 的未声明属性落在各自的根元素上。
Sidebar、Annotation、MCPConfigure 与 Sidebar.Container 的模板 ref 类型为 SidebarContainerHandle(从 @fibrous/semi-ai-vue 导出),成员 root 为 HTMLDivElement | null,容器隐藏时为 null。
Container
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| visible | 是否显示容器,配合 v-model:visible 使用。 | boolean | false |
| title | 纯文本标题;传入 title 插槽时以插槽为准。 | string | undefined |
| motion | 显示与隐藏时是否使用展开动画。 | boolean | true |
| resizable | 宽度是否可拖拽调整;为 true 时 minWidth、maxWidth 与 defaultSize 生效。 | boolean | true |
| minWidth | 可调整的最小宽度,仅在 resizable 为 true 时生效。 | string | number | 150 |
| maxWidth | 可调整的最大宽度,仅在 resizable 为 true 时生效。 | string | number | undefined |
| defaultSize | 初始宽高,仅在 resizable 为 true 时生效。 | Type{ width?: string | number | undefined; height?: string | number | undefined; } | undefined |
| showClose | 是否显示头部的关闭按钮。 | boolean | true |
| closeOnEsc | 按下 Esc 键时是否触发 cancel。 | boolean | false |
Events
| 事件 | 说明 | 回调参数 |
|---|---|---|
| update:visible | 关闭按钮或 Esc 触发取消时先于 cancel 触发,值为 false,供 v-model:visible 回写。 | [visible: false] |
| cancel | 点击关闭按钮,或在 closeOnEsc 为 true 时按下 Esc 触发。 | [event: MouseEvent | KeyboardEvent] |
| afterVisibleChange | 显示或隐藏动画结束后触发,参数为当前是否可见。 | [visible: boolean] |
Slots
| 插槽 | 说明 | 作用域参数 |
|---|---|---|
| default | 容器的内容区域。 | any |
| title | 头部标题,优先于 title 属性。 | any |
| header | 替换整个头部;内容为空时回退到内置头部。 | any |
Exposes
| 名称 | 说明 | 类型 |
|---|---|---|
| root | 容器根元素 .semi-sidebar-container;隐藏时为 null。 | HTMLDivElement | null |
MCPConfigure
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| visible | 是否显示,配合 v-model:visible 使用。 | boolean | semiGlobalDefault("MCPConfigure", "visible") |
| title | 纯文本标题,默认使用语言包中的 MCP 配置;传入 title 插槽时以插槽为准。 | string | semiGlobalDefault("MCPConfigure", "title") |
| motion | 显示与隐藏时是否使用展开动画。 | boolean | semiGlobalDefault("MCPConfigure", "motion") |
| resizable | 宽度是否可拖拽调整;为 true 时 minWidth、maxWidth 与 defaultSize 生效。 | boolean | semiGlobalDefault("MCPConfigure", "resizable") |
| minWidth | 可调整的最小宽度,仅在 resizable 为 true 时生效。 | string | number | semiGlobalDefault("MCPConfigure", "minWidth") |
| maxWidth | 可调整的最大宽度,仅在 resizable 为 true 时生效。 | string | number | semiGlobalDefault("MCPConfigure", "maxWidth") |
| defaultSize | 初始宽高,仅在 resizable 为 true 时生效。 | Type{ width?: string | number | undefined; height?: string | number | undefined; } | semiGlobalDefault("MCPConfigure", "defaultSize") |
| showClose | 是否显示头部的关闭按钮。 | boolean | semiGlobalDefault("MCPConfigure", "showClose") |
| closeOnEsc | 按下 Esc 键时是否触发 cancel。 | boolean | semiGlobalDefault("MCPConfigure", "closeOnEsc") |
| options | 内置 MCP 工具列表,配合 v-model:options 使用;每项的 value 必填且唯一。 | MCPConfigureOption[] | semiGlobalDefault("MCPConfigure", "options") |
| customOptions | 自定义 MCP 工具列表,配合 v-model:customOptions 使用。 | MCPConfigureOption[] | semiGlobalDefault("MCPConfigure", "customOptions") |
| filter | 自定义搜索过滤,参数为转为小写的输入值和选项;默认按 label 与 desc 匹配。 | Type((inputValue: string, option: MCPConfigureOption) => boolean) | undefined |
| placeholder | 搜索框的占位文字,默认使用语言包文案。 | string | semiGlobalDefault("MCPConfigure", "placeholder") |
Events
| 事件 | 说明 | 回调参数 |
|---|---|---|
| update:visible | 关闭按钮或 Esc 触发取消时先于 cancel 触发,值为 false,供 v-model:visible 回写。 | [visible: false] |
| cancel | 点击关闭按钮,或在 closeOnEsc 为 true 时按下 Esc 触发。 | [event: MouseEvent | KeyboardEvent] |
| afterVisibleChange | 显示或隐藏动画结束后触发,参数为当前是否可见。 | [visible: boolean] |
| update:options | 切换内置工具的启用状态时先于 statusChange 触发,供 v-model:options 回写。 | [options: MCPConfigureOption[]] |
| update:customOptions | 切换自定义工具的启用状态时先于 statusChange 触发,供 v-model:customOptions 回写。 | [options: MCPConfigureOption[]] |
| statusChange | 切换启用状态后触发,参数为 active 已更新的列表,以及它是否为自定义列表。 | [options: MCPConfigureOption[], custom: boolean] |
| search | 搜索输入变化时触发,参数为输入值,以及当前是否为自定义列表。 | [inputValue: string, custom: boolean] |
| addClick | 点击自定义页的新增按钮时触发。 | [event: MouseEvent] |
| configureClick | 点击内置工具的配置按钮时触发,参数为点击事件和对应选项。 | [event: MouseEvent, option: MCPConfigureOption] |
| editClick | 点击自定义工具的编辑按钮时触发,参数为点击事件和对应选项。 | [event: MouseEvent, option: MCPConfigureOption] |
Slots
| 插槽 | 说明 | 作用域参数 |
|---|---|---|
| title | 头部标题,优先于 title 属性。 | any |
| header | 替换整个头部;内容为空时回退到内置头部。 | any |
| icon | 选项的图标,作用域参数为 item、index 和 custom;提供后所有选项都使用它,icon 字段只在未提供时作为图片地址。 | MCPConfigureItemSlotProps |
| desc | 选项的描述,作用域参数为 item、index 和 custom;未提供时显示 desc 字段。 | MCPConfigureItemSlotProps |
| item | 替换整行内置选项,作用域参数为 item、index 和 custom。 | MCPConfigureItemSlotProps |
Exposes
| 名称 | 说明 | 类型 |
|---|---|---|
| root | 容器根元素 .semi-sidebar-container;隐藏时为 null。 | HTMLDivElement | null |
MCPConfigureOption
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| active | 是否处于激活状态 | boolean | false |
| configure | 是否显示配置按钮 | boolean | false |
| desc | 描述文本,内置过滤会匹配它;其他内容使用 #desc 插槽 | string | - |
| disabled | 是否禁用,为 true 时用户无法更改激活状态 | boolean | false |
| icon | 图标的图片地址;其他内容使用 #icon 插槽 | string | - |
| label | 标签文本 | string | - |
| value | 对应的值,必填。在 statusChange 中标识选项,也作为列表项的 key,同一列表内需唯一 | string | - |
Annotation
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| visible | 是否显示,配合 v-model:visible 使用。 | boolean | semiGlobalDefault("Annotation", "visible") |
| title | 纯文本标题,默认使用语言包中的参考来源;传入 title 插槽时以插槽为准。 | string | semiGlobalDefault("Annotation", "title") |
| motion | 显示与隐藏时是否使用展开动画。 | boolean | semiGlobalDefault("Annotation", "motion") |
| resizable | 宽度是否可拖拽调整;为 true 时 minWidth、maxWidth 与 defaultSize 生效。 | boolean | semiGlobalDefault("Annotation", "resizable") |
| minWidth | 可调整的最小宽度,仅在 resizable 为 true 时生效。 | string | number | semiGlobalDefault("Annotation", "minWidth") |
| maxWidth | 可调整的最大宽度,仅在 resizable 为 true 时生效。 | string | number | semiGlobalDefault("Annotation", "maxWidth") |
| defaultSize | 初始宽高,仅在 resizable 为 true 时生效。 | Type{ width?: string | number | undefined; height?: string | number | undefined; } | semiGlobalDefault("Annotation", "defaultSize") |
| showClose | 是否显示头部的关闭按钮。 | boolean | semiGlobalDefault("Annotation", "showClose") |
| closeOnEsc | 按下 Esc 键时是否触发 cancel。 | boolean | semiGlobalDefault("Annotation", "closeOnEsc") |
| activeKey | 当前展开的分组 key,配合 v-model:activeKey 使用。 | string | string[] | semiGlobalDefault("Annotation", "activeKey") |
| info | 参考来源分组列表,每组包含 header、key 与 annotations。 | AnnotationInfo[] | semiGlobalDefault("Annotation", "info") |
Events
| 事件 | 说明 | 回调参数 |
|---|---|---|
| update:visible | 关闭按钮或 Esc 触发取消时先于 cancel 触发,值为 false,供 v-model:visible 回写。 | [visible: false] |
| cancel | 点击关闭按钮,或在 closeOnEsc 为 true 时按下 Esc 触发。 | [event: MouseEvent | KeyboardEvent] |
| afterVisibleChange | 显示或隐藏动画结束后触发,参数为当前是否可见。 | [visible: boolean] |
| update:activeKey | 展开或收起分组时先于 change 触发,供 v-model:activeKey 回写。 | [activeKey: string[]] |
| change | 展开或收起分组时触发,参数为当前展开的 key。 | [activeKey: string | string[]] |
| click | 点击某条参考来源时触发,参数为点击事件和对应条目;根元素的原生 click 不单独上报。 | [event: MouseEvent, item: AnnotationItem] |
Slots
| 插槽 | 说明 | 作用域参数 |
|---|---|---|
| title | 头部标题,优先于 title 属性。 | any |
| header | 替换整个容器头部;内容为空时回退到内置头部。 | any |
| infoHeader | 分组头部图标之后的内容,作用域参数为 item 与 index;未提供时显示 header 字段。 | AnnotationHeaderSlotProps |
| item | 替换内置的参考来源条目,作用域参数为 item 与 index(在分组内的位置)。 | AnnotationItemSlotProps |
Exposes
| 名称 | 说明 | 类型 |
|---|---|---|
| root | 容器根元素 .semi-sidebar-container;隐藏时为 null。 | HTMLDivElement | null |
AnnotationContent
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| activeKey | 当前展开的分组 key,配合 v-model:activeKey 使用。 | string | string[] | undefined |
| info | 参考来源分组列表,每组包含 header、key 与 annotations。 | AnnotationInfo[] | [] |
Events
| 事件 | 说明 | 回调参数 |
|---|---|---|
| update:activeKey | 展开或收起分组时先于 change 触发,供 v-model:activeKey 回写。 | [activeKey: string[]] |
| change | 展开或收起分组时触发,参数为当前展开的 key。 | [activeKey: string | string[]] |
| click | 点击某条参考来源时触发,参数为点击事件和对应条目;根元素的原生 click 不单独上报。 | [event: MouseEvent, item: AnnotationItem] |
Slots
| 插槽 | 说明 | 作用域参数 |
|---|---|---|
| header | 分组头部图标之后的内容,作用域参数为 item 与 index;未提供时显示 header 字段。 | AnnotationHeaderSlotProps |
| item | 替换内置的参考来源条目,作用域参数为 item 与 index(在分组内的位置)。 | AnnotationItemSlotProps |
Exposes
| 名称 | 说明 | 类型 |
|---|---|---|
| 无 |
AnnotationInfo
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| annotations | 该分组下的参考来源条目 | AnnotationItem[] | - |
| header | 分组标题的纯文本,也可用 #infoHeader(Annotation)或 #header(AnnotationContent)插槽自定义 | string | - |
| key | 分组的唯一标识 | string | - |
AnnotationItem
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| detail | 内容详情/补充说明(如视频简介、文本备注等) | string | - |
| duration | 时长(通常为视频时长,单位:秒) | number | - |
| img | 图片地址(如视频封面图、文本配图地址) | string | - |
| logo | 站点/内容所属平台的 logo 图片地址 | string | - |
| order | 引用序号(用于内容排序/标注序号展示) | number | - |
| siteName | 内容所属的站点/平台名称 | string | - |
| title | 内容标题 | string | - |
| type | 内容类型 | 'video' | 'text' | - |
| url | 资源链接,在新标签页打开;没有 url 的条目渲染为无 href 的链接,只能用指针点击 | string | - |
Sidebar
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| mode | 展示模式:main 为主视图,code 与 file 使用内置详情,其他字符串通过 detailContent 插槽自行渲染。 | string | semiDefault("Sidebar", "mode", strings.MODE.MAIN) |
| activeKey | 主视图中当前选中的选项 key,配合 v-model:activeKey 使用。 | string | semiGlobalDefault("Sidebar", "activeKey") |
| options | 主视图顶部的选项按钮,每项包含 name 与 key;图标使用 optionIcon 插槽。 | SideBarOption[] | semiGlobalDefault("Sidebar", "options") |
| detailContent | code 与 file 模式显示的条目,为 CodeItem 或 FileItem 的属性加 key;key 变化时重新挂载该条目。file 模式下其中的 editable 与 imgUploadProps 不生效,由 fileEditable 与 imgUploadProps 决定。 | SideBarDetailContent | semiGlobalDefault("Sidebar", "detailContent") |
| fileEditable | file 模式的富文本是否可编辑。 | boolean | semiDefault("Sidebar", "fileEditable", true) |
| imgUploadProps | file 模式的图片上传配置,编辑器创建时读取,之后变化不生效。 | ImageUploadNodeOptions | semiGlobalDefault("Sidebar", "imgUploadProps") |
| visible | 是否显示,配合 v-model:visible 使用。 | boolean | semiGlobalDefault("Sidebar", "visible") |
| title | 主视图的纯文本标题;传入 title 插槽时以插槽为准。详情视图使用内置的详情头部。 | string | semiGlobalDefault("Sidebar", "title") |
| motion | 显示与隐藏时是否使用展开动画。 | boolean | semiGlobalDefault("Sidebar", "motion") |
| resizable | 宽度是否可拖拽调整;为 true 时 minWidth、maxWidth 与 defaultSize 生效。 | boolean | semiGlobalDefault("Sidebar", "resizable") |
| minWidth | 可调整的最小宽度,仅在 resizable 为 true 时生效。 | string | number | semiGlobalDefault("Sidebar", "minWidth") |
| maxWidth | 可调整的最大宽度,仅在 resizable 为 true 时生效。 | string | number | semiGlobalDefault("Sidebar", "maxWidth") |
| defaultSize | 初始宽高,仅在 resizable 为 true 时生效。 | Type{ width?: string | number | undefined; height?: string | number | undefined; } | semiGlobalDefault("Sidebar", "defaultSize") |
| showClose | 是否显示头部的关闭按钮。 | boolean | semiGlobalDefault("Sidebar", "showClose") |
| closeOnEsc | 按下 Esc 键时是否触发 cancel。 | boolean | semiGlobalDefault("Sidebar", "closeOnEsc") |
Events
| 事件 | 说明 | 回调参数 |
|---|---|---|
| update:activeKey | 点击选项时先于 activeOptionChange 触发,供 v-model:activeKey 回写。 | [activeKey: string] |
| activeOptionChange | 点击选项时触发,参数为点击事件和该选项的 key。 | [event: MouseEvent, activeKey: string] |
| backWard | 点击详情头部的返回按钮时触发,参数为点击事件和 main。 | [event: MouseEvent, mode: string] |
| detailContentCopy | 复制按钮写入剪贴板后触发,参数为点击事件、复制的内容和是否成功。 | [event: MouseEvent, content: string, success: boolean] |
| fileContentChange | file 模式下编辑后触发,参数为 HTML 字符串。 | [content: string] |
| update:visible | 关闭按钮或 Esc 触发取消时先于 cancel 触发,值为 false,供 v-model:visible 回写。 | [visible: false] |
| cancel | 点击关闭按钮,或在 closeOnEsc 为 true 时按下 Esc 触发。 | [event: MouseEvent | KeyboardEvent] |
| afterVisibleChange | 显示或隐藏动画结束后触发,参数为当前是否可见。 | [visible: boolean] |
Slots
| 插槽 | 说明 | 作用域参数 |
|---|---|---|
| title | 主视图标题,优先于 title 属性。 | any |
| optionIcon | 内置选项按钮的图标,作用域参数为 item 与 index。 | SideBarOptionSlotProps |
| optionItem | 替换整个选项按钮,作用域参数为 item、index、active 与 onClick(选中该选项)。 | SideBarOptionItemSlotProps |
| mainContent | 主视图中选项下方的内容,作用域参数为 activeKey。 | SideBarMainContentSlotProps |
| detailHeader | 详情模式的头部,作用域参数为 mode 与 detailContent;内容为空时回退到内置头部。 | SideBarDetailHeaderSlotProps |
| detailContent | 详情模式的内容,作用域参数为 mode;内容为空时回退到内置的代码或富文本详情。 | SideBarDetailContentSlotProps |
| customRender | 转发给内置代码详情中 JsonViewer 的 customRender 插槽,用于渲染 customRenderRule 匹配的内容。 | JsonViewerCustomRenderSlotProps |
| searchButton | 转发给内置代码详情中 JsonViewer 的 searchButton 插槽,替换其搜索按钮。 | JsonViewerSearchButtonSlotProps |
Exposes
| 名称 | 说明 | 类型 |
|---|---|---|
| root | 容器根元素 .semi-sidebar-container;隐藏时为 null。 | HTMLDivElement | null |
SideBarOption
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| key | 选项的唯一标识 | string | - |
| name | 选项名称,图标使用 #optionIcon 插槽 | string | - |
CodeContent
codes 的每一项为 CodeItem 的属性加用于标识面板的 key。
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| codes | 代码条目列表,每项为 CodeItem 的属性加用于标识面板的 key。 | CodeItemData[] | [] |
| activeKey | 当前展开的代码面板 key,配合 v-model:activeKey 使用。 | string | string[] | undefined |
Events
| 事件 | 说明 | 回调参数 |
|---|---|---|
| update:activeKey | 展开或收起面板时先于 change 触发,供 v-model:activeKey 回写。 | [activeKey: string[]] |
| change | 通过箭头展开或收起面板时触发,参数为当前展开的 key。 | [activeKey: string | string[]] |
| expand | 点击面板头部旁的展开按钮时触发,参数为点击事件、对应条目和 code。仅在绑定了该事件时渲染展开按钮。 | [event: MouseEvent, item: CodeItemData, mode: string] |
Slots
| 插槽 | 说明 | 作用域参数 |
|---|---|---|
| customRender | 转发给每个 JSON 面板中 JsonViewer 的 customRender 插槽。 | JsonViewerCustomRenderSlotProps |
| searchButton | 转发给每个 JSON 面板中 JsonViewer 的 searchButton 插槽,替换其搜索按钮。 | JsonViewerSearchButtonSlotProps |
Exposes
| 名称 | 说明 | 类型 |
|---|---|---|
| 无 |
CodeItem
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| name | 代码项名称,由 CodeContent 的面板头部和 Sidebar 的详情头部显示,CodeItem 自身不渲染。 | string | undefined |
| language | 编程语言名称,同 CodeHighlight 的 language,需先通过 CodeHighlight.register 注册,未注册时显示纯文本。 | string | undefined |
| content | 代码或 JSON 字符串。 | string | undefined |
| isJson | 为 true 时用 JsonViewer 展示,否则用 CodeHighlight。 | boolean | false |
| jsonViewerProps | 传给 JsonViewer 的其他属性,以及追加的 class 与 style。modelValue(content)、width 与 height(100%)、options(只读、自动换行)、showSearch(false)已有默认值,同名属性整体覆盖默认值。 | Type(Partial<JsonViewerProps> & ElementLook) | undefined |
| codeHighlightProps | 传给 CodeHighlight 的其他属性,以及追加的 class 与 style。 | Type(Partial<CodeHighlightProps> & ElementLook) | undefined |
Events
| 事件 | 说明 | 回调参数 |
|---|---|---|
| 无 |
Slots
| 插槽 | 说明 | 作用域参数 |
|---|---|---|
| customRender | JsonViewer 的 customRender 插槽,用于渲染 jsonViewerProps.options.customRenderRule 匹配的内容。 | JsonViewerCustomRenderSlotProps |
| searchButton | JsonViewer 的 searchButton 插槽,替换其搜索按钮。 | JsonViewerSearchButtonSlotProps |
Exposes
| 名称 | 说明 | 类型 |
|---|---|---|
| 无 |
FileContent
files 的每一项为 FileItem 的属性加用于标识面板的 key,以只读方式渲染,extensions 与 imgUploadProps 会传给其预览。
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| files | 文件条目列表,以只读方式渲染,每项的 extensions 与 imgUploadProps 会传给其预览。 | FileItemData[] | [] |
| activeKey | 当前展开的文件面板 key,配合 v-model:activeKey 使用。 | string | string[] | undefined |
Events
| 事件 | 说明 | 回调参数 |
|---|---|---|
| update:activeKey | 展开或收起面板时先于 change 触发,供 v-model:activeKey 回写。 | [activeKey: string[]] |
| change | 通过箭头展开或收起面板时触发,参数为当前展开的 key。 | [activeKey: string | string[]] |
| expand | 点击面板头部旁的展开按钮时触发,参数为点击事件、对应条目和 file。仅在绑定了该事件时渲染展开按钮。 | [event: MouseEvent, item: FileItemData, mode: string] |
Slots
| 插槽 | 说明 | 作用域参数 |
|---|---|---|
| 无 |
Exposes
| 名称 | 说明 | 类型 |
|---|---|---|
| 无 |
FileItem
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| name | 文件名称,作为编辑区域的可访问名称,挂载后变化会同步到编辑器。 | string | undefined |
| content | 富文本 HTML。挂载后变化会同步到编辑器,与编辑器当前内容相同时不会重置,同步不触发 contentChange。 | string | undefined |
| editable | 是否可编辑,挂载后变化会同步到编辑器。 | boolean | true |
| extensions | 追加到内置扩展之后的 tiptap 扩展,编辑器创建时读取,之后变化不生效。 | Extensions | [] |
| imgUploadProps | 图片上传配置,编辑器创建时读取,之后变化不生效。 | ImageUploadNodeOptions | undefined |
Events
| 事件 | 说明 | 回调参数 |
|---|---|---|
| contentChange | 编辑后触发,参数为 HTML 字符串。 | [content: string] |
Slots
| 插槽 | 说明 | 作用域参数 |
|---|---|---|
| 无 |
Exposes
| 名称 | 说明 | 类型 |
|---|---|---|
| 无 |
