{option.data.avatar &&
}
diff --git a/web/src/components/Header/index.tsx b/web/src/components/Header/index.tsx
index ac59fcc2..49988223 100644
--- a/web/src/components/Header/index.tsx
+++ b/web/src/components/Header/index.tsx
@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-02 15:07:49
* @Last Modified by: ZhaoYing
- * @Last Modified time: 2026-02-05 13:43:59
+ * @Last Modified time: 2026-04-07 12:18:58
*/
/**
* AppHeader Component
@@ -77,7 +77,7 @@ const AppHeader: FC<{source?: 'space' | 'manage';}> = ({source = 'manage'}) => {
{
key: '1',
icon:
- {/[\u4e00-\u9fa5]/.test(user.username) ? user.username.slice(0, 2) : user.username[0]}
+ {/[\u4e00-\u9fa5]/.test(user.username) ? user.username.slice(0, 2) : user.username?.[0]}
,
label: (<>
{user.username}
@@ -91,10 +91,10 @@ const AppHeader: FC<{source?: 'space' | 'manage';}> = ({source = 'manage'}) => {
},
{
key: '3',
- icon:
,
+ icon:
,
label:
{t('header.userInfo')}
-
+
,
className: 'rb:text-[#212332]!',
onClick: () => {
@@ -103,10 +103,10 @@ const AppHeader: FC<{source?: 'space' | 'manage';}> = ({source = 'manage'}) => {
},
{
key: '4',
- icon:
,
+ icon:
,
label:
{t('header.settings')}
-
+
,
className: 'rb:text-[#212332]!',
onClick: () => {
@@ -120,7 +120,7 @@ const AppHeader: FC<{source?: 'space' | 'manage';}> = ({source = 'manage'}) => {
},
{
key: '6',
- icon:
,
+ icon:
,
label: t('header.logout'),
danger: true,
className: 'rb:hover:rb:bg-transparent rb:hover:text-[#FF5D34]!',
@@ -180,7 +180,7 @@ const AppHeader: FC<{source?: 'space' | 'manage';}> = ({source = 'manage'}) => {
>
- {/[\u4e00-\u9fa5]/.test(user.username) ? user.username.slice(0, 2) : user.username[0]}
+ {/[\u4e00-\u9fa5]/.test(user.username) ? user.username.slice(user.username.length, -2) : user.username[0]}
{user.username}
= ({
value,
needCopy = true,
size = 'default',
- showLineNumbers = false
+ showLineNumbers = false,
+ background = '#F0F3F8'
}) => {
return (
@@ -43,7 +45,7 @@ const CodeBlock: FC
= ({
style={atelierHeathLight}
customStyle={{
padding: '8px 12px 8px 12px',
- backgroundColor: '#F0F3F8',
+ backgroundColor: background,
borderRadius: 8,
fontSize: size === 'small' ? 12 : 14,
wordBreak: 'break-all'
diff --git a/web/src/components/Markdown/index.tsx b/web/src/components/Markdown/index.tsx
index 6b9dc12a..bd33cf76 100644
--- a/web/src/components/Markdown/index.tsx
+++ b/web/src/components/Markdown/index.tsx
@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-02 15:17:31
* @Last Modified by: ZhaoYing
- * @Last Modified time: 2026-04-02 16:06:03
+ * @Last Modified time: 2026-04-07 21:56:00
*/
/**
* RbMarkdown Component
@@ -22,7 +22,7 @@
* @component
*/
-import { useState, useRef, useEffect, type FC, createContext, useContext, useCallback } from 'react'
+import { useState, useRef, useEffect, type FC, createContext, useContext, useCallback, useMemo } from 'react'
import { Image, Input, Select, Form, Checkbox, Radio, ColorPicker, DatePicker, TimePicker, InputNumber, Slider } from 'antd'
import ReactMarkdown from 'react-markdown'
import RemarkGfm from 'remark-gfm'
@@ -44,6 +44,11 @@ const FormContext = createContext<{
onSubmit?: (values: Record) => void;
} | null>(null)
+/** Stable form wrapper component — state lives in RbMarkdown, survives components object rebuilds */
+const RbForm: FC = ({ children, ...props }) => (
+
+)
+
/** Props interface for RbMarkdown component */
interface RbMarkdownProps {
/** Markdown content to render */
@@ -60,8 +65,8 @@ interface RbMarkdownProps {
onFormSubmit?: (values: Record) => void;
}
-/** Build components with onFormSubmit callback */
-const buildComponents = (onFormSubmit?: (values: Record) => void) => ({
+/** Build stable components map — form submission handled via FormContext */
+const buildComponents = () => ({
h1: ({ children, ...props }: any) => {children}
,
h2: ({ children, ...props }: any) => {children}
,
h3: ({ children, ...props }: any) => {children}
,
@@ -95,53 +100,50 @@ const buildComponents = (onFormSubmit?: (values: Record) => void) =
td: ({ children, ...props }: any) => {children} | ,
button: ({ children, ...props }: any) => {
const ctx = useContext(FormContext)
- return ctx?.onSubmit?.(ctx.values)}>{[children]}
+ return ctx?.onSubmit?.(ctx?.values ?? {})}>{[children]}
},
- table: ({ children, ...props }: any) => ,
- tr: ({ children, ...props }: any) => {children}
,
- th: ({ children, ...props }: any) => {children} | ,
- td: ({ children, ...props }: any) => {children} | ,
- input: ({ children, ...props }: any) => {
+ input: ({ children, value, ...props }: any) => {
const ctx = useContext(FormContext)
const handleChange = useCallback((val: any) => {
if (props.name) ctx?.setValue(props.name, val)
}, [ctx, props.name])
+ console.log('props', props)
switch (props.type) {
case 'color':
- return
+ return
case 'time':
- return
+ return
case 'date':
- return
+ return
case 'datetime':
case 'datetime-local':
- return
+ return
case 'week':
- return
+ return
case 'month':
- return
+ return
case 'number':
- return
+ return
case 'search':
- return handleChange(e.target.value)} />
+ return handleChange(e.target.value)} />
case 'range':
- return
+ return
case 'submit':
case 'button':
- return ctx?.onSubmit?.(ctx.values)}>{[props.value || children]}
+ return ctx?.onSubmit?.(ctx?.values ?? {})}>{[props.value || children]}
case 'checkbox':
- return handleChange(e.target.checked)}>{children}
+ return handleChange(e.target.checked)}>{children}
case 'password':
- return handleChange(e.target.value)} />
+ return handleChange(e.target.value)} />
case 'radio':
- return handleChange(e.target.value)}>{children}
+ return handleChange(e.target.value)}>{children}
case 'select': {
const raw = props['data-options']
const options = (typeof raw === 'string' ? JSON.parse(raw) : raw || []).map((v: string) => ({ label: v, value: v }))
- return