Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
I
incorrupt_party_build
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
David Yang
incorrupt_party_build
Commits
4ecd1406
Commit
4ecd1406
authored
Aug 26, 2026
by
Andy-bubu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: align application switcher with Xinyuan baseline
parent
d04092d9
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
152 additions
and
77 deletions
+152
-77
ui-architecture.md
docs/ui-architecture.md
+1
-1
ui-migration-checklist.md
docs/ui-migration-checklist.md
+11
-1
xinyuan-design-system.md
docs/xinyuan-design-system.md
+1
-1
xinyuan-ui-audit.md
docs/xinyuan-ui-audit.md
+3
-2
AppShell.jsx
src/components/AppShell.jsx
+6
-3
XinyuanModal.jsx
src/components/XinyuanModal.jsx
+20
-13
shell.css
src/design-system/shell.css
+19
-0
ApplicationSwitcherDialog.jsx
src/pages/project_manager_xy/ApplicationSwitcherDialog.jsx
+91
-56
No files found.
docs/ui-architecture.md
View file @
4ecd1406
...
...
@@ -9,7 +9,7 @@
字段后缀图标由
`src/components/AppIcons.jsx`
的
`FIELD_SUFFIX_ICON_STYLE`
统一提供语义颜色。
`XinyuanAutocomplete`
和
`FormDatePicker`
直接把该样式绑定到 Ant 图标根节点,并在共享组件内部固定 16px 图标与 DatePicker 24px Trigger 几何;页面不得覆盖颜色、位置或内部 slot。
应用切换由
`ApplicationSwitcherDialog.jsx`
保留目标应用的
数据归一化、当前项识别和跳转逻辑,但视觉结构严格继承“问题整改”:46rem/42rem Modal、手机一列、
`sm`
起固定两列、12px gap,真实 Card 和 Loading Skeleton 使用同一网格,不设置桌面三列分支
。
应用切换由
`ApplicationSwitcherDialog.jsx`
保留目标应用的
`/application/info`
、用户应用合并、当前项识别和跳转逻辑,并从
`SiteContext`
使用
`/info -> site.group`
动态生成有权限的非空分组。结构严格继承
`model_analysis`
:46rem/42rem Modal、28px inset、24px/12px 分组节奏、手机一列、
`sm`
起固定两列、36px identity well;未归组应用进入“其他应用”,无分组配置时使用“全部应用”
。
## 直接导入规则
...
...
docs/ui-migration-checklist.md
View file @
4ecd1406
...
...
@@ -14,7 +14,7 @@
-
[
x
]
Login:迁移 HeroUI 原生控件、验证码、filled/autofill 和响应式结构
-
[
x
]
Shell:迁移品牌、offcanvas、用户菜单、主题和 base-aware 导航
-
[
x
]
应用切换:
迁移 HeroUI Modal、真实应用
和 36px identity well
-
[
x
]
应用切换:
同步
`model_analysis`
HeroUI Modal、
`site.group`
动态分组、真实数量、“其他应用”/“全部应用”回退
和 36px identity well
-
[
x
]
驾驶舱:移除 ECharts/手写 KPI,改用 HeroUI Pro KPI、PieChart、BarChart、ComposedChart、ChartTooltip
-
[
x
]
党风廉政 Tabs、结构化筛选与透明工具栏 SearchField;无刷新/查询按钮并保持自动筛选
-
[
x
]
党风廉政 DataGrid、选择、ActionBar、固定 10 条 Pagination
...
...
@@ -45,3 +45,13 @@
-
[
]
控制台无 runtime、slot、provider、重复 Context 错误
运行态验收说明:2026-08-19 本地开发服务已启动,但当前执行环境未暴露可连接的应用内浏览器或 Chrome 实例,以上三项浏览器门禁尚未执行,不能以静态检查替代。
## 2026-08-26 应用切换专项验收
-
[
x
]
与
`model_analysis`
同时打开并在 1440x900、1280x720、768x1024、390x844 测量:目标与基准均为桌面/平板 736px、390 视口 358px,24px 圆角、28px inset、24px 关闭按钮和 36px identity well。
-
[
x
]
`sm`
起严格两列、移动端一列,所有网格横纵 gap 12px;Body 独立滚动且长列表不增加第三列。
-
[
x
]
动态分组保持配置和组内顺序、过滤空组与无权限应用,显示真实数量;未归组应用进入“其他应用”,无配置时使用单个“全部应用”。
-
[
x
]
浅色和深色的 Modal/Card/Surface 均由 HeroUI 语义 Surface 提供,无白色硬编码背景;“当前”仅出现一次。
-
[
x
]
Escape、关闭按钮、焦点约束、dialog accessible name 与
`aria-current`
通过。
-
[
x
]
应用切换自身无控制台错误或告警。
-
[
]
390px 从 Mobile Sidebar 入口打开时仍会触发既有 Sidebar Dialog title 告警,与本次应用切换组件无关,未扩大范围修改。
docs/xinyuan-design-system.md
View file @
4ecd1406
...
...
@@ -34,7 +34,7 @@
-
业务列表固定每页 10 条,不提供页容量选择器。
-
Dashboard/KPI 外层圆角 24px,DataGrid 20px,字段 12px,Modal 24px。
-
例行成功反馈使用顶部居中的自动消失 Toast;需要处理的错误保留上下文 Alert。
-
应用切换
Modal 固定采用手机一列、
`sm`
起两列的应用 Card 网格,间距 12px;加载骨架使用相同网格,桌面不得切成三列,长列表
在 Modal Body 内滚动。
-
应用切换
严格继承
`model_analysis`
:从
`/info -> site.group`
动态生成分组,保持配置顺序并显示真实数量;未归组应用进入“其他应用”,无配置时使用“全部应用”。Modal 固定 46rem/42rem、28px inset、手机一列、
`sm`
起两列,间距 12px;加载骨架使用相同网格,桌面不得切成三列,长列表仅
在 Modal Body 内滚动。
## 字段后缀图标
...
...
docs/xinyuan-ui-audit.md
View file @
4ecd1406
...
...
@@ -56,7 +56,7 @@
-
已通过官方
`hpsetup`
在当前仓库独立安装
`@heroui-pro/react@1.0.0-beta.8`
;
`package.json`
、lockfile 和安装目录均不再依赖相邻项目、绝对路径或软链接。
-
HeroUI 基础样式入口已更正为
`@heroui/styles/css`
。此前包根 JavaScript 入口导致 Tabs、Input、Button、Dropdown 和 DataGrid 缺失官方结构样式,是本次截图中纵向 Tabs、裸控件和尺寸异常的共同根因。
-
Catalyst、Headless UI、旧 Select/Table 兼容层与多余 pnpm lockfile 已从活动源码移除。
-
Login、Shell、
应用切换、党风廉政筛选/DataGrid/Modal/DropZone 已完成原生 HeroUI/HeroUI Pro 结构迁移;与“问题整改”的浏览器逐项对照仍受浏览器不可用阻断
。
-
Login、Shell、
党风廉政筛选/DataGrid/Modal/DropZone 已完成原生 HeroUI/HeroUI Pro 结构迁移。应用切换进一步同步
`model_analysis`
当前基准:保留
`/application/info`
与用户权限合并,读取
`/info -> site.group`
动态分组,显示真实组数并处理“其他应用”/“全部应用”回退
。
-
党风廉政筛选对齐问题整改基线:Surface 内前三项等宽排列,溢出条件通过 Disclosure 展开;移除刷新和查询按钮,字段变化后自动请求,关键词采用约 300ms 延迟。
-
驾驶舱已移除 ECharts,KPI 使用 HeroUI Pro
`KPI`
compound API,图表使用 Pro
`PieChart`
、
`BarChart`
、
`ComposedChart`
与
`ChartTooltipContent`
。
-
`src/xinyuan-portable.css`
已删除;页面目录不存在私有 CSS/Less/SCSS。
`theme.css`
与 Skill 权威副本一致,
`tokens.css`
、
`shell.css`
、
`tailwind.css`
、
`global.less`
与确认基准逐字节一致。
...
...
@@ -64,7 +64,8 @@
-
2026-08-19 最终静态门禁:
`npm run build`
、
`git diff --check`
、鑫元审计脚本均成功;旧组件、ECharts、页面私有视觉类、跨项目依赖、本机路径和授权值均无有效源码命中。
-
HeroUI Pro 的 CSS、入口文件和 sidebar/navbar/data-grid/drop-zone/action-bar/empty-state ESM 导入均可用。
-
依赖树的应用与 Pro 主路径统一使用 HeroUI 3.2.2 / React Aria Components 1.19.0;Adobe Spectrum 的间接依赖仍包含 React Aria Components 1.20.0,不进入应用直接组件边界。
-
开发服务在 2026-08-19 启动于
`http://localhost:8003/incorrupt_party_build/`
。当前执行环境没有可连接浏览器,因此桌面/平板/移动端、深浅主题、打开态弹层和控制台检查仍待浏览器门禁执行。
-
2026-08-26 修改前开发服务以
`npm run dev`
启动于
`http://localhost:8003/incorrupt_party_build/`
,base/publicPath 为
`/incorrupt_party_build/`
;未登录状态跳转
`/login?redirect=%2F`
,控制台无错误或警告。应用切换改动后的四视口、深浅主题和打开态结果记录在迁移清单中。
-
应用切换已与
`model_analysis`
在四个规定视口逐项测量一致,深浅主题均通过;桌面入口控制台无错误或告警。移动端打开 Sidebar 时 HeroUI Mobile Sidebar 仍产生既有 Dialog title 告警,应用切换自身具备 accessible name/Heading,未产生新增告警。
## 原始业务状态记录
...
...
src/components/AppShell.jsx
View file @
4ecd1406
import
{
useLayoutEffect
,
useState
}
from
'react'
;
import
{
use
Context
,
use
LayoutEffect
,
useState
}
from
'react'
;
import
{
Sidebar
}
from
'@heroui-pro/react/sidebar'
;
import
{
Toast
}
from
'@heroui/react'
;
import
{
history
}
from
'umi'
;
import
ApplicationSwitcherDialog
from
'@/pages/project_manager_xy/ApplicationSwitcherDialog'
;
import
{
SiteContext
}
from
'@/wrapper/Site'
;
import
DashboardNavbar
from
'./DashboardNavbar'
;
import
DashboardSidebar
from
'./DashboardSidebar'
;
...
...
@@ -27,6 +28,7 @@ export default function AppShell({
title
,
...
sidebarProps
})
{
const
siteInfo
=
useContext
(
SiteContext
);
const
[
theme
,
setTheme
]
=
useState
(
getInitialTheme
);
const
[
isApplicationDialogOpen
,
setIsApplicationDialogOpen
]
=
useState
(
false
);
...
...
@@ -67,9 +69,10 @@ export default function AppShell({
</
div
>
</
Sidebar
.
Main
>
<
ApplicationSwitcherDialog
o
pen=
{
isApplicationDialogOpen
}
onClose=
{
()
=>
setIsApplicationDialogOpen
(
false
)
}
isO
pen=
{
isApplicationDialogOpen
}
siteInfo=
{
siteInfo
}
userInfo=
{
sidebarProps
.
userInfo
}
onOpenChange=
{
setIsApplicationDialogOpen
}
/>
<
Toast
.
Provider
maxVisibleToasts=
{
3
}
placement=
"top"
/>
</
Sidebar
.
Provider
>
...
...
src/components/XinyuanModal.jsx
View file @
4ecd1406
import
{
Close
}
from
'@/components/AppIcons'
;
import
{
Modal
}
from
'@heroui/react'
;
import
clsx
from
'clsx'
;
...
...
@@ -11,14 +10,16 @@ const DIALOG_WIDTH_CLASS = {
};
export
default
function
XinyuanModal
({
bodyClassName
,
children
,
dialogClassName
,
footer
,
isOpen
,
onOpenChange
,
size
=
'lg'
,
isDismissable
,
title
,
description
,
size
=
'lg'
,
dialogClassName
,
bodyClassName
,
children
,
footer
,
})
{
const
modalSize
=
[
'xs'
,
'sm'
,
'md'
,
'lg'
].
includes
(
size
)
?
size
:
'lg'
;
...
...
@@ -26,26 +27,32 @@ export default function XinyuanModal({
<
Modal
.
Root
>
<
Modal
.
Trigger
aria
-
hidden=
"true"
className=
"sr-only"
tabIndex=
{
-
1
}
/>
<
Modal
.
Backdrop
isDismissable=
{
isDismissable
}
isOpen=
{
isOpen
}
onOpenChange=
{
onOpenChange
}
variant=
"blur"
onOpenChange=
{
onOpenChange
}
>
<
Modal
.
Container
placement=
"center"
scroll=
"inside"
size=
{
modalSize
}
>
<
Modal
.
Dialog
aria
-
label=
{
title
}
className=
{
clsx
(
DIALOG_WIDTH_CLASS
[
size
]
&&
'
p-7'
,
'xy-modal-dialog
p-7'
,
DIALOG_WIDTH_CLASS
[
size
],
dialogClassName
,
)
}
>
<
Modal
.
CloseTrigger
aria
-
label=
"关闭"
>
<
Close
size=
{
16
}
/>
</
Modal
.
CloseTrigger
>
<
Modal
.
CloseTrigger
aria
-
label=
"关闭"
style=
{
{
insetInlineEnd
:
'1.75rem'
,
top
:
'1.75rem'
}
}
/>
<
Modal
.
Header
>
<
Modal
.
Heading
>
{
title
}
</
Modal
.
Heading
>
{
description
?
<
div
className=
"text-sm text-muted"
>
{
description
}
</
div
>
:
null
}
</
Modal
.
Header
>
<
Modal
.
Body
className=
{
bodyClassName
}
>
{
children
}
</
Modal
.
Body
>
{
footer
?
<
Modal
.
Footer
>
{
footer
}
</
Modal
.
Footer
>
:
null
}
<
Modal
.
Body
className=
{
bodyClassName
}
style=
{
{
marginTop
:
'0.75rem'
}
}
>
{
children
}
</
Modal
.
Body
>
{
footer
?
<
Modal
.
Footer
style=
{
{
marginTop
:
'1.5rem'
}
}
>
{
footer
}
</
Modal
.
Footer
>
:
null
}
</
Modal
.
Dialog
>
</
Modal
.
Container
>
</
Modal
.
Backdrop
>
...
...
src/design-system/shell.css
View file @
4ecd1406
...
...
@@ -650,6 +650,25 @@
align-items
:
stretch
;
}
.xy-modal-dialog
{
min-width
:
0
;
}
.xy-app-switcher-dialog
{
width
:
min
(
46rem
,
calc
(
100vw
-
2rem
));
max-width
:
min
(
46rem
,
calc
(
100vw
-
2rem
));
max-height
:
min
(
42rem
,
calc
(
100
dvh
-
2rem
));
}
.xy-app-identity-well
,
.xy-app-identity-avatar
{
border-radius
:
var
(
--rc-radius-control
);
}
.xy-app-identity-avatar
{
background
:
transparent
;
}
.rc-list-stack
,
.rc-list-data-stack
{
gap
:
var
(
--rc-list-stack-gap
);
...
...
src/pages/project_manager_xy/ApplicationSwitcherDialog.jsx
View file @
4ecd1406
import
xyLogoRed
from
'@/assets/identity/xy-logo-red.png'
;
import
XinyuanModal
from
'@/components/XinyuanModal'
;
import
{
APP_NAME
,
APP_ROUTE_NAME
}
from
'@/config/ApplicationConfig'
;
import
{
getApplications
}
from
'@/services/DataService'
;
import
{
Close
as
XMarkIcon
,
ExclamationTriangleIcon
,
}
from
'@/components/AppIcons'
;
import
{
ExclamationTriangleIcon
}
from
'@/components/AppIcons'
;
import
{
Alert
,
Avatar
,
Card
,
Chip
,
Description
,
Modal
,
Skeleton
,
Surface
,
}
from
'@heroui/react'
;
...
...
@@ -23,6 +21,7 @@ const CURRENT_APPLICATION = {
name
:
APP_ROUTE_NAME
,
title
:
APP_DISPLAY_NAME
,
description
:
APP_LOGIN_SUBTITLE
,
logo
:
xyLogoRed
,
};
function
normalizeLabelList
(
items
)
{
...
...
@@ -71,8 +70,9 @@ function normalizeApplication(application, fallback = {}) {
fallback
?.
title
||
application
?.
title
||
'进入对应应用继续处理业务'
,
logo
:
application
?.
logo
||
logo
:
isCurrentSystem
?
xyLogoRed
:
application
?.
logo
||
application
?.
logo_url
||
application
?.
icon
||
fallback
?.
logo
||
...
...
@@ -149,6 +149,57 @@ function unwrapApplications(response) {
return
candidates
.
find
(
Array
.
isArray
)
||
[];
}
function
buildApplicationSections
(
applications
,
applicationGroups
)
{
if
(
!
Array
.
isArray
(
applicationGroups
)
||
applicationGroups
.
length
===
0
)
{
return
[{
key
:
'all'
,
label
:
'全部应用'
,
applications
}];
}
const
applicationMap
=
new
Map
(
applications
.
map
((
application
)
=>
[
application
.
name
,
application
]),
);
const
groupedApplicationNames
=
new
Set
();
const
sections
=
applicationGroups
.
map
((
group
,
index
)
=>
{
const
groupApplications
=
Array
.
isArray
(
group
?.
applications
)
?
group
.
applications
.
map
((
name
)
=>
{
if
(
groupedApplicationNames
.
has
(
name
))
{
return
null
;
}
const
application
=
applicationMap
.
get
(
name
);
if
(
application
)
{
groupedApplicationNames
.
add
(
name
);
}
return
application
;
})
.
filter
(
Boolean
)
:
[];
return
{
key
:
group
?.
label
||
`group-
${
index
}
`
,
label
:
group
?.
label
||
'应用分组'
,
applications
:
groupApplications
,
};
})
.
filter
((
section
)
=>
section
.
applications
.
length
>
0
);
const
ungroupedApplications
=
applications
.
filter
(
(
application
)
=>
!
groupedApplicationNames
.
has
(
application
.
name
),
);
if
(
ungroupedApplications
.
length
>
0
)
{
sections
.
push
({
key
:
'ungrouped'
,
label
:
'其他应用'
,
applications
:
ungroupedApplications
,
});
}
return
sections
;
}
function
isCurrentApplication
(
application
)
{
if
(
typeof
window
===
'undefined'
)
{
return
false
;
...
...
@@ -202,13 +253,9 @@ function ApplicationCard({ application }) {
rel=
{
target
?
'noreferrer'
:
undefined
}
target=
{
target
}
>
<
Surface
aria
-
hidden=
"true"
className=
"grid size-9 shrink-0 place-items-center overflow-hidden rounded-[var(--rc-radius-control)]"
variant=
"tertiary"
>
<
Surface
aria
-
hidden=
"true"
className=
"xy-app-identity-well grid size-9 shrink-0 place-items-center overflow-hidden"
variant=
"tertiary"
>
<
Avatar
className=
"
size-full rounded-[var(--rc-radius-control)] bg-transparent
"
className=
"
xy-app-identity-avatar size-full
"
color=
"accent"
variant=
"soft"
>
...
...
@@ -219,12 +266,12 @@ function ApplicationCard({ application }) {
</
Avatar
>
</
Surface
>
<
span
className=
"min-w-0 flex-1"
>
<
span
className=
"block
break-words font-medium leading-5 text-foreground
"
title=
{
application
.
title
}
>
<
span
className=
"block
truncate text-sm font-medium leading-5
"
title=
{
application
.
title
}
>
{
application
.
title
}
</
span
>
<
span
className=
"block truncate text-sm text-muted
"
title=
{
application
.
description
}
>
<
Description
className=
"mt-0.5 block truncate leading-4
"
title=
{
application
.
description
}
>
{
application
.
description
||
application
.
name
||
'应用'
}
</
spa
n
>
</
Descriptio
n
>
</
span
>
{
current
?
<
Chip
color=
"accent"
size=
"sm"
>
当前
</
Chip
>
:
null
}
</
a
>
...
...
@@ -252,8 +299,9 @@ function LoadingSkeleton() {
}
export
default
function
ApplicationSwitcherDialog
({
open
,
onClose
,
isOpen
,
onOpenChange
,
siteInfo
,
userInfo
,
})
{
const
fallbackApplications
=
useMemo
(()
=>
{
...
...
@@ -279,6 +327,10 @@ export default function ApplicationSwitcherDialog({
fallbackApplications
.
length
>
0
?
'success'
:
'idle'
,
);
const
[
errorMessage
,
setErrorMessage
]
=
useState
(
''
);
const
applicationSections
=
useMemo
(
()
=>
buildApplicationSections
(
applications
,
siteInfo
?.
group
),
[
applications
,
siteInfo
?.
group
],
);
useEffect
(()
=>
{
if
(
fallbackApplications
.
length
===
0
)
{
...
...
@@ -295,7 +347,7 @@ export default function ApplicationSwitcherDialog({
},
[
fallbackApplications
]);
useEffect
(()
=>
{
if
(
!
o
pen
)
{
if
(
!
isO
pen
)
{
return
;
}
...
...
@@ -336,40 +388,17 @@ export default function ApplicationSwitcherDialog({
return
()
=>
{
cancelled
=
true
;
};
},
[
fallbackApplications
,
o
pen
]);
},
[
fallbackApplications
,
isO
pen
]);
return
(
<
Modal
.
Root
>
<
Modal
.
Trigger
aria
-
hidden=
"true"
className=
"sr-only"
tabIndex=
{
-
1
}
/>
<
Modal
.
Backdrop
isOpen=
{
open
}
onOpenChange=
{
(
isOpen
)
=>
{
if
(
!
isOpen
)
onClose
?.();
}
}
variant=
"blur"
>
<
Modal
.
Container
className=
"w-full sm:w-full"
placement=
"center"
scroll=
"inside"
size=
"lg"
<
XinyuanModal
description=
"选择你可访问的应用"
dialogClassName=
"xy-app-switcher-dialog"
isOpen=
{
isOpen
}
size=
"xl"
title=
"应用切换"
onOpenChange=
{
onOpenChange
}
>
<
Modal
.
Dialog
className=
"app-switcher-dialog max-h-[min(42rem,calc(100dvh-2rem))]"
style=
{
{
maxWidth
:
'min(46rem, calc(100vw - 2rem))'
}
}
>
<
Modal
.
CloseTrigger
aria
-
label=
"关闭应用切换"
>
<
XMarkIcon
size=
{
16
}
/>
</
Modal
.
CloseTrigger
>
<
Modal
.
Header
>
<
div
className=
"min-w-0"
>
<
Modal
.
Heading
>
应用切换
</
Modal
.
Heading
>
<
Description
>
选择你可访问的应用
</
Description
>
</
div
>
</
Modal
.
Header
>
<
Modal
.
Body
className=
"[scrollbar-gutter:stable]"
>
{
status
===
'error'
&&
errorMessage
?
(
<
Alert
status=
"warning"
>
<
Alert
.
Indicator
>
...
...
@@ -384,14 +413,24 @@ export default function ApplicationSwitcherDialog({
{
status
===
'loading'
&&
applications
.
length
===
0
?
(
<
LoadingSkeleton
/>
)
:
applications
.
length
>
0
?
(
<
div
className=
"space-y-6"
>
{
applicationSections
.
map
((
section
)
=>
(
<
section
key=
{
section
.
key
}
>
<
div
className=
"mb-3 flex items-center justify-between gap-3"
>
<
h3
className=
"text-sm font-medium leading-5"
>
{
section
.
label
}
</
h3
>
<
Description
>
{
section
.
applications
.
length
}
个应用
</
Description
>
</
div
>
<
div
className=
"grid gap-3 sm:grid-cols-2"
>
{
applications
.
map
((
application
)
=>
(
{
section
.
applications
.
map
((
application
)
=>
(
<
ApplicationCard
key=
{
application
.
name
}
application=
{
application
}
/>
))
}
</
div
>
</
section
>
))
}
</
div
>
)
:
(
<
EmptyState
size=
"md"
>
<
EmptyState
.
Header
>
...
...
@@ -402,10 +441,6 @@ export default function ApplicationSwitcherDialog({
</
EmptyState
.
Header
>
</
EmptyState
>
)
}
</
Modal
.
Body
>
</
Modal
.
Dialog
>
</
Modal
.
Container
>
</
Modal
.
Backdrop
>
</
Modal
.
Root
>
</
XinyuanModal
>
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment