@hkyhy/marsun-components-core 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -0
- package/dist/components/AgentHub/AgentHubAccessGuard.js +12 -0
- package/dist/components/AgentHub/AgentHubAccessGuard.js.map +1 -0
- package/dist/components/AgentHub/AgentHubIndexRedirect.js +11 -0
- package/dist/components/AgentHub/AgentHubIndexRedirect.js.map +1 -0
- package/dist/components/AgentHub/ChatSessionAccessGuard.js +11 -0
- package/dist/components/AgentHub/ChatSessionAccessGuard.js.map +1 -0
- package/dist/components/Auth/PermissionGuard.js +18 -0
- package/dist/components/Auth/PermissionGuard.js.map +1 -0
- package/dist/components/Auth/ProtectedRoute.js +21 -0
- package/dist/components/Auth/ProtectedRoute.js.map +1 -0
- package/dist/components/Auth/hasPermission.js +7 -0
- package/dist/components/Auth/hasPermission.js.map +1 -0
- package/dist/components/Descriptions/CommonDescriptions.js +14 -0
- package/dist/components/Descriptions/CommonDescriptions.js.map +1 -0
- package/dist/components/File/FileItem/index.js +82 -0
- package/dist/components/File/FileItem/index.js.map +1 -0
- package/dist/components/File/FileItem/style.module.scss.js +18 -0
- package/dist/components/File/FileItem/style.module.scss.js.map +1 -0
- package/dist/components/File/FileLink/index.js +27 -0
- package/dist/components/File/FileLink/index.js.map +1 -0
- package/dist/components/File/FileLink/style.module.scss.js +10 -0
- package/dist/components/File/FileLink/style.module.scss.js.map +1 -0
- package/dist/components/File/FilePreview/index.js +49 -0
- package/dist/components/File/FilePreview/index.js.map +1 -0
- package/dist/components/File/FilePreview/style.module.scss.js +5 -0
- package/dist/components/File/FilePreview/style.module.scss.js.map +1 -0
- package/dist/components/File/FilePreviewModal/index.js +12 -0
- package/dist/components/File/FilePreviewModal/index.js.map +1 -0
- package/dist/components/File/fileDisplay.js +67 -0
- package/dist/components/File/fileDisplay.js.map +1 -0
- package/dist/components/Filter/CommonFilter/index.js +81 -0
- package/dist/components/Filter/CommonFilter/index.js.map +1 -0
- package/dist/components/Filter/CommonFilter/style.module.scss.js +20 -0
- package/dist/components/Filter/CommonFilter/style.module.scss.js.map +1 -0
- package/dist/components/Filter/FilterDateRange/index.js +97 -0
- package/dist/components/Filter/FilterDateRange/index.js.map +1 -0
- package/dist/components/Filter/FilterDateRange/style.module.scss.js +10 -0
- package/dist/components/Filter/FilterDateRange/style.module.scss.js.map +1 -0
- package/dist/components/Filter/FilterInput/index.js +56 -0
- package/dist/components/Filter/FilterInput/index.js.map +1 -0
- package/dist/components/Filter/FilterNumberRange/index.js +81 -0
- package/dist/components/Filter/FilterNumberRange/index.js.map +1 -0
- package/dist/components/Filter/FilterNumberRange/style.module.scss.js +9 -0
- package/dist/components/Filter/FilterNumberRange/style.module.scss.js.map +1 -0
- package/dist/components/Filter/FilterPanel/index.js +21 -0
- package/dist/components/Filter/FilterPanel/index.js.map +1 -0
- package/dist/components/Filter/FilterPanel/style.module.scss.js +8 -0
- package/dist/components/Filter/FilterPanel/style.module.scss.js.map +1 -0
- package/dist/components/Filter/FilterPopover/index.js +52 -0
- package/dist/components/Filter/FilterPopover/index.js.map +1 -0
- package/dist/components/Filter/FilterSelect/index.js +160 -0
- package/dist/components/Filter/FilterSelect/index.js.map +1 -0
- package/dist/components/Filter/FilterSelect/style.module.scss.js +16 -0
- package/dist/components/Filter/FilterSelect/style.module.scss.js.map +1 -0
- package/dist/components/Filter/FilterTreeSelect/index.js +249 -0
- package/dist/components/Filter/FilterTreeSelect/index.js.map +1 -0
- package/dist/components/Filter/FilterTreeSelect/style.module.scss.js +19 -0
- package/dist/components/Filter/FilterTreeSelect/style.module.scss.js.map +1 -0
- package/dist/components/Filter/FilterTrigger/index.js +31 -0
- package/dist/components/Filter/FilterTrigger/index.js.map +1 -0
- package/dist/components/Filter/FilterTrigger/style.module.scss.js +10 -0
- package/dist/components/Filter/FilterTrigger/style.module.scss.js.map +1 -0
- package/dist/components/Filter/types.js +12 -0
- package/dist/components/Filter/types.js.map +1 -0
- package/dist/components/Filter/useFilterState.js +35 -0
- package/dist/components/Filter/useFilterState.js.map +1 -0
- package/dist/components/Form/FetchSelect.js +37 -0
- package/dist/components/Form/FetchSelect.js.map +1 -0
- package/dist/components/Form/FetchTreeSelect.js +28 -0
- package/dist/components/Form/FetchTreeSelect.js.map +1 -0
- package/dist/components/Form/PersonOptionRow/index.js +37 -0
- package/dist/components/Form/PersonOptionRow/index.js.map +1 -0
- package/dist/components/Form/PersonOptionRow/style.module.scss.js +11 -0
- package/dist/components/Form/PersonOptionRow/style.module.scss.js.map +1 -0
- package/dist/components/Form/StepForm.js +34 -0
- package/dist/components/Form/StepForm.js.map +1 -0
- package/dist/components/Icons/index.js +245 -0
- package/dist/components/Icons/index.js.map +1 -0
- package/dist/components/Layout/PageHeaderLayout/index.js +41 -0
- package/dist/components/Layout/PageHeaderLayout/index.js.map +1 -0
- package/dist/components/Layout/PageHeaderLayout/style.module.scss.js +10 -0
- package/dist/components/Layout/PageHeaderLayout/style.module.scss.js.map +1 -0
- package/dist/components/Modal/StepModal/index.js +64 -0
- package/dist/components/Modal/StepModal/index.js.map +1 -0
- package/dist/components/Modal/StepModal/style.module.scss.js +9 -0
- package/dist/components/Modal/StepModal/style.module.scss.js.map +1 -0
- package/dist/components/Stat/StatCard/index.js +34 -0
- package/dist/components/Stat/StatCard/index.js.map +1 -0
- package/dist/components/Stat/StatCard/style.module.scss.js +7 -0
- package/dist/components/Stat/StatCard/style.module.scss.js.map +1 -0
- package/dist/components/Stat/StatCardList.js +20 -0
- package/dist/components/Stat/StatCardList.js.map +1 -0
- package/dist/components/Stat/StatPendingBreakdown/index.js +38 -0
- package/dist/components/Stat/StatPendingBreakdown/index.js.map +1 -0
- package/dist/components/Stat/StatPendingBreakdown/style.module.scss.js +9 -0
- package/dist/components/Stat/StatPendingBreakdown/style.module.scss.js.map +1 -0
- package/dist/components/Tag/FileTags.js +8 -0
- package/dist/components/Tag/FileTags.js.map +1 -0
- package/dist/components/Tag/SemanticTag.js +92 -0
- package/dist/components/Tag/SemanticTag.js.map +1 -0
- package/dist/components/Tag/Tags/index.js +32 -0
- package/dist/components/Tag/Tags/index.js.map +1 -0
- package/dist/components/Tag/Tags/style.module.scss.js +9 -0
- package/dist/components/Tag/Tags/style.module.scss.js.map +1 -0
- package/dist/components/TooltipInfo/TooltipInfo.js +31 -0
- package/dist/components/TooltipInfo/TooltipInfo.js.map +1 -0
- package/dist/components/Tour/AppTour/index.js +40 -0
- package/dist/components/Tour/AppTour/index.js.map +1 -0
- package/dist/components/Tour/AppTour/style.module.scss.js +7 -0
- package/dist/components/Tour/AppTour/style.module.scss.js.map +1 -0
- package/dist/components/VirtualScrollbar/VirtualScrollbar/index.js +97 -0
- package/dist/components/VirtualScrollbar/VirtualScrollbar/index.js.map +1 -0
- package/dist/components/VirtualScrollbar/VirtualScrollbar/style.module.scss.js +12 -0
- package/dist/components/VirtualScrollbar/VirtualScrollbar/style.module.scss.js.map +1 -0
- package/dist/components/VirtualScrollbar/useVirtualScrollbar.js +97 -0
- package/dist/components/VirtualScrollbar/useVirtualScrollbar.js.map +1 -0
- package/dist/hooks/useFetchData.js +69 -0
- package/dist/hooks/useFetchData.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +182 -0
- package/dist/index.js.map +1 -0
- package/dist/marsun-components-core.css +1 -0
- package/dist/provider/MarsunCoreProvider.js +51 -0
- package/dist/provider/MarsunCoreProvider.js.map +1 -0
- package/dist/provider/context.js +27 -0
- package/dist/provider/context.js.map +1 -0
- package/dist/theme/constants.js +15 -0
- package/dist/theme/constants.js.map +1 -0
- package/dist/theme/index.d.ts +2 -0
- package/dist/theme/index.js +9 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/theme/theme.js +286 -0
- package/dist/theme/theme.js.map +1 -0
- package/dist/utils/format.js +9 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/resolveMaybeFn.js +11 -0
- package/dist/utils/resolveMaybeFn.js.map +1 -0
- package/package.json +83 -0
package/README.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# @hkyhy/marsun-components-core
|
|
2
|
+
|
|
3
|
+
Marsun 纯 UI 组件库(React 19 + antd 6)。从 `maoyang_data-asset-system` 的 Common / AgentHub 拆分,**不含业务数据**。
|
|
4
|
+
|
|
5
|
+
[](https://github.com/hkyhy/MARSUN_components-core/actions/workflows/ci.yml)
|
|
6
|
+
[](https://hkyhy.github.io/MARSUN_components-core/)
|
|
7
|
+
|
|
8
|
+
**远程仓库**:`git@github.com:hkyhy/MARSUN_components-core.git`
|
|
9
|
+
|
|
10
|
+
**组件 Showcase**:https://hkyhy.github.io/MARSUN_components-core/
|
|
11
|
+
|
|
12
|
+
## 安装
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @hkyhy/marsun-components-core antd react react-dom
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
> 发布至 [npm](https://www.npmjs.com/package/@hkyhy/marsun-components-core)(GitHub Secret `HKYHY_PACKAGE_PUBLISH` + tag `v*` 触发,见「发布版本」)。
|
|
19
|
+
|
|
20
|
+
## 快速开始
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import { MarsunCoreProvider, SemanticTag, FetchTreeSelect } from '@hkyhy/marsun-components-core';
|
|
24
|
+
|
|
25
|
+
<MarsunCoreProvider
|
|
26
|
+
auth={{
|
|
27
|
+
isAuthenticated: true,
|
|
28
|
+
hasPermission: (p) => permissions.includes(p),
|
|
29
|
+
hasAnyRole: (roles) => roles.some((r) => userRoles.includes(r)),
|
|
30
|
+
}}
|
|
31
|
+
fetch={{ baseUrl: '/api', headers: { Authorization: `Bearer ${token}` } }}
|
|
32
|
+
>
|
|
33
|
+
<SemanticTag color="primary">标签</SemanticTag>
|
|
34
|
+
<FetchTreeSelect
|
|
35
|
+
treeData={treeData}
|
|
36
|
+
// 或 fetch 模式:
|
|
37
|
+
// fetchUrl="/departments/tree"
|
|
38
|
+
// transformData={(raw) => raw.data}
|
|
39
|
+
/>
|
|
40
|
+
</MarsunCoreProvider>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## 设计原则
|
|
44
|
+
|
|
45
|
+
- **零业务依赖**:无 `departmentPath`、`personOption` 等领域工具;`transformData` 由消费方实现
|
|
46
|
+
- **双模式数据**:props 传 `data`/`treeData`/`options` 优先;或 `fetchUrl` + `transformData`
|
|
47
|
+
- **MaybeFn 参数**:`display` / `hidden` / `disabled` 等支持 `boolean | (ctx) => boolean`
|
|
48
|
+
- **Mock 数据**:各组件 `doc/*.mock.json`,仅 dev showcase 使用,不打入 npm 产物
|
|
49
|
+
|
|
50
|
+
## 目录
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
src/components/
|
|
54
|
+
Auth/ Filter/ Form/ File/ Tag/ Icons/ ... # Common 拍平
|
|
55
|
+
AgentHub/ # Chat + KnowledgeBase
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Dev
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm install
|
|
62
|
+
npm run dev # 本地 showcase :5175
|
|
63
|
+
npm run build # 库产物 dist/
|
|
64
|
+
npm run build:showcase # 静态 showcase → dist-showcase/(GitHub Pages)
|
|
65
|
+
npm run preview:showcase # 预览 showcase 构建结果
|
|
66
|
+
npm run typecheck
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### GitHub Pages
|
|
70
|
+
|
|
71
|
+
- 推送 `main` 后由 `.github/workflows/pages.yml` 自动部署
|
|
72
|
+
- 项目页 base path:`/MARSUN_components-core/`
|
|
73
|
+
- 本地模拟 Pages 构建:`VITE_BASE_PATH=/MARSUN_components-core/ npm run build:showcase && npm run preview:showcase`
|
|
74
|
+
|
|
75
|
+
### 发布版本(npm)
|
|
76
|
+
|
|
77
|
+
包名为 **`@hkyhy/marsun-components-core`**(npm scope 与 GitHub 发布账号 `hkyhy` 对齐;若需 `@marsun` 须先在 npm 创建该组织)。
|
|
78
|
+
|
|
79
|
+
1. 在 GitHub 仓库 **Settings → Secrets → Actions** 配置 `HKYHY_PACKAGE_PUBLISH`(npm Automation Token,对 `@hkyhy` 有 publish 权限)
|
|
80
|
+
2. 更新 `package.json` 的 `version`,提交后打 tag 并推送:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npm version patch # 或 minor / major
|
|
84
|
+
git push origin main --tags
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
推送 `v*` tag 后 `.github/workflows/publish.yml` 自动执行 `npm publish`(仅发布 `dist/`,不含 dev showcase)。
|
|
88
|
+
|
|
89
|
+
也可在 Actions 中手动运行 **Publish npm**,填写已有 tag(如 `v0.1.2`)。
|
|
90
|
+
|
|
91
|
+
## 后续接入 maoyang
|
|
92
|
+
|
|
93
|
+
发布 npm 后,在 `maoyang_data-asset-system` 批量替换:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import { SemanticTag, FetchTreeSelect } from '@hkyhy/marsun-components-core';
|
|
97
|
+
// 业务 wrapper 留在 maoyang
|
|
98
|
+
import { DepartmentSelect } from '@/components/Common/Form/DepartmentSelect';
|
|
99
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as r, Fragment as e } from "react/jsx-runtime";
|
|
2
|
+
import { Navigate as u } from "react-router-dom";
|
|
3
|
+
const s = ({
|
|
4
|
+
mode: t,
|
|
5
|
+
isAdmin: n = !1,
|
|
6
|
+
redirectTo: o = "/",
|
|
7
|
+
children: a
|
|
8
|
+
}) => n ? /* @__PURE__ */ r(e, { children: a }) : t === "admin-only" || t === "chat-manage" ? /* @__PURE__ */ r(u, { to: o, replace: !0 }) : /* @__PURE__ */ r(e, { children: a });
|
|
9
|
+
export {
|
|
10
|
+
s as default
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=AgentHubAccessGuard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentHubAccessGuard.js","sources":["../../../src/components/AgentHub/AgentHubAccessGuard.tsx"],"sourcesContent":["import React from 'react';\nimport { Navigate } from 'react-router-dom';\n\nexport interface AgentHubAccessGuardProps {\n mode: 'admin-only' | 'chat-manage';\n /** 是否管理员 */\n isAdmin?: boolean;\n /** 无权限时重定向路径 */\n redirectTo?: string;\n children: React.ReactNode;\n}\n\nconst AgentHubAccessGuard: React.FC<AgentHubAccessGuardProps> = ({\n mode,\n isAdmin = false,\n redirectTo = '/',\n children,\n}) => {\n if (isAdmin) return <>{children}</>;\n if (mode === 'admin-only' || mode === 'chat-manage') {\n return <Navigate to={redirectTo} replace />;\n }\n return <>{children}</>;\n};\n\nexport default AgentHubAccessGuard;\n"],"names":["AgentHubAccessGuard","mode","isAdmin","redirectTo","children","jsx","Fragment","Navigate"],"mappings":";;AAYA,MAAMA,IAA0D,CAAC;AAAA,EAC/D,MAAAC;AAAA,EACA,SAAAC,IAAU;AAAA,EACV,YAAAC,IAAa;AAAA,EACb,UAAAC;AACF,MACMF,IAAgB,gBAAAG,EAAAC,GAAA,EAAG,UAAAF,EAAA,CAAS,IAC5BH,MAAS,gBAAgBA,MAAS,gBAC7B,gBAAAI,EAACE,GAAA,EAAS,IAAIJ,GAAY,SAAO,IAAC,2BAEjC,UAAAC,GAAS;"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as r } from "react/jsx-runtime";
|
|
2
|
+
import { Navigate as o } from "react-router-dom";
|
|
3
|
+
const u = ({
|
|
4
|
+
isAdmin: t = !1,
|
|
5
|
+
adminPath: e = "/agent-hub/chat",
|
|
6
|
+
userPath: a = "/agent-hub/chat"
|
|
7
|
+
}) => /* @__PURE__ */ r(o, { to: t ? e : a, replace: !0 });
|
|
8
|
+
export {
|
|
9
|
+
u as default
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=AgentHubIndexRedirect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentHubIndexRedirect.js","sources":["../../../src/components/AgentHub/AgentHubIndexRedirect.tsx"],"sourcesContent":["import React from 'react';\nimport { Navigate } from 'react-router-dom';\n\nexport interface AgentHubIndexRedirectProps {\n isAdmin?: boolean;\n adminPath?: string;\n userPath?: string;\n}\n\nconst AgentHubIndexRedirect: React.FC<AgentHubIndexRedirectProps> = ({\n isAdmin = false,\n adminPath = '/agent-hub/chat',\n userPath = '/agent-hub/chat',\n}) => <Navigate to={isAdmin ? adminPath : userPath} replace />;\n\nexport default AgentHubIndexRedirect;\n"],"names":["AgentHubIndexRedirect","isAdmin","adminPath","userPath","Navigate"],"mappings":";;AASA,MAAMA,IAA8D,CAAC;AAAA,EACnE,SAAAC,IAAU;AAAA,EACV,WAAAC,IAAY;AAAA,EACZ,UAAAC,IAAW;AACb,wBAAOC,GAAA,EAAS,IAAIH,IAAUC,IAAYC,GAAU,SAAO,GAAA,CAAC;"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as t, Fragment as o } from "react/jsx-runtime";
|
|
2
|
+
import { Navigate as u } from "react-router-dom";
|
|
3
|
+
const c = ({
|
|
4
|
+
hasAccess: e = !0,
|
|
5
|
+
redirectTo: r = "/agent-hub/chat",
|
|
6
|
+
children: a
|
|
7
|
+
}) => e ? /* @__PURE__ */ t(o, { children: a }) : /* @__PURE__ */ t(u, { to: r, replace: !0 });
|
|
8
|
+
export {
|
|
9
|
+
c as default
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=ChatSessionAccessGuard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatSessionAccessGuard.js","sources":["../../../src/components/AgentHub/ChatSessionAccessGuard.tsx"],"sourcesContent":["import React from 'react';\nimport { Navigate } from 'react-router-dom';\n\nexport interface AgentHubSessionAccessGuardProps {\n hasAccess?: boolean;\n redirectTo?: string;\n children: React.ReactNode;\n}\n\nconst AgentHubSessionAccessGuard: React.FC<AgentHubSessionAccessGuardProps> = ({\n hasAccess = true,\n redirectTo = '/agent-hub/chat',\n children,\n}) => {\n if (!hasAccess) return <Navigate to={redirectTo} replace />;\n return <>{children}</>;\n};\n\nexport default AgentHubSessionAccessGuard;\n"],"names":["AgentHubSessionAccessGuard","hasAccess","redirectTo","children","jsx","Navigate"],"mappings":";;AASA,MAAMA,IAAwE,CAAC;AAAA,EAC7E,WAAAC,IAAY;AAAA,EACZ,YAAAC,IAAa;AAAA,EACb,UAAAC;AACF,MACOF,2BACK,UAAAE,GAAS,IADI,gBAAAC,EAACC,KAAS,IAAIH,GAAY,SAAO,IAAC;"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as r, Fragment as n } from "react/jsx-runtime";
|
|
2
|
+
import { resolveVisible as h } from "../../utils/resolveMaybeFn.js";
|
|
3
|
+
import { useMarsunAuth as x } from "../../provider/context.js";
|
|
4
|
+
const s = ({
|
|
5
|
+
roles: t,
|
|
6
|
+
permission: u,
|
|
7
|
+
display: d,
|
|
8
|
+
hidden: f,
|
|
9
|
+
fallback: e = null,
|
|
10
|
+
children: m
|
|
11
|
+
}) => {
|
|
12
|
+
const { hasAnyRole: i, isAuthenticated: o, hasPermission: c } = x();
|
|
13
|
+
return h(d, f, { roles: t, permission: u }) ? o ? u && !(c != null && c(u)) ? /* @__PURE__ */ r(n, { children: e }) : t && t.length > 0 && !(i != null && i(t)) ? /* @__PURE__ */ r(n, { children: e }) : /* @__PURE__ */ r(n, { children: m }) : /* @__PURE__ */ r(n, { children: e }) : null;
|
|
14
|
+
};
|
|
15
|
+
export {
|
|
16
|
+
s as default
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=PermissionGuard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PermissionGuard.js","sources":["../../../src/components/Auth/PermissionGuard.tsx"],"sourcesContent":["import { useMarsunAuth } from '@/provider';\nimport type { MaybeFn } from '@/utils/resolveMaybeFn';\nimport { resolveVisible } from '@/utils/resolveMaybeFn';\nimport React from 'react';\n\nexport type PermissionGuardContext = {\n roles?: string[];\n permission?: string;\n};\n\nexport interface PermissionGuardProps {\n /** 允许访问的角色列表 */\n roles?: string[];\n /** 允许访问的权限 key */\n permission?: string;\n /** 展示控制 */\n display?: MaybeFn<boolean, PermissionGuardContext>;\n hidden?: MaybeFn<boolean, PermissionGuardContext>;\n fallback?: React.ReactNode;\n children: React.ReactNode;\n}\n\nconst PermissionGuard: React.FC<PermissionGuardProps> = ({\n roles,\n permission,\n display,\n hidden,\n fallback = null,\n children,\n}) => {\n const { hasAnyRole, isAuthenticated, hasPermission } = useMarsunAuth();\n const ctx: PermissionGuardContext = { roles, permission };\n\n if (!resolveVisible(display, hidden, ctx)) return null;\n if (!isAuthenticated) return <>{fallback}</>;\n if (permission && !hasPermission?.(permission)) return <>{fallback}</>;\n if (roles && roles.length > 0 && !hasAnyRole?.(roles)) return <>{fallback}</>;\n\n return <>{children}</>;\n};\n\nexport default PermissionGuard;\n"],"names":["PermissionGuard","roles","permission","display","hidden","fallback","children","hasAnyRole","isAuthenticated","hasPermission","useMarsunAuth","resolveVisible","jsx","Fragment"],"mappings":";;;AAsBA,MAAMA,IAAkD,CAAC;AAAA,EACvD,OAAAC;AAAA,EACA,YAAAC;AAAA,EACA,SAAAC;AAAA,EACA,QAAAC;AAAA,EACA,UAAAC,IAAW;AAAA,EACX,UAAAC;AACF,MAAM;AACJ,QAAM,EAAE,YAAAC,GAAY,iBAAAC,GAAiB,eAAAC,EAAA,IAAkBC,EAAA;AAGvD,SAAKC,EAAeR,GAASC,GAFO,EAAE,OAAAH,GAAO,YAAAC,EAAA,CAEL,IACnCM,IACDN,KAAc,EAACO,KAAA,QAAAA,EAAgBP,6BAAuB,UAAAG,GAAS,IAC/DJ,KAASA,EAAM,SAAS,KAAK,EAACM,KAAA,QAAAA,EAAaN,MAAe,gBAAAW,EAAAC,GAAA,EAAG,UAAAR,EAAA,CAAS,2BAEhE,UAAAC,GAAS,IAJU,gBAAAM,EAAAC,GAAA,EAAG,UAAAR,GAAS,IADS;AAMpD;"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as t, Fragment as f } from "react/jsx-runtime";
|
|
2
|
+
import { useLocation as $, Navigate as c } from "react-router-dom";
|
|
3
|
+
import { useMarsunAuth as g } from "../../provider/context.js";
|
|
4
|
+
const x = ({
|
|
5
|
+
roles: e,
|
|
6
|
+
permission: u,
|
|
7
|
+
loginPath: i = "/login",
|
|
8
|
+
fallbackPath: a = "/",
|
|
9
|
+
children: p
|
|
10
|
+
}) => {
|
|
11
|
+
const { isAuthenticated: m, hasAnyRole: r, hasPermission: o } = g(), n = $();
|
|
12
|
+
if (!m) {
|
|
13
|
+
const d = encodeURIComponent(`${n.pathname}${n.search}${n.hash}`);
|
|
14
|
+
return /* @__PURE__ */ t(c, { to: `${i}?redirect=${d}`, replace: !0 });
|
|
15
|
+
}
|
|
16
|
+
return e && e.length > 0 && !(r != null && r(e)) ? /* @__PURE__ */ t(c, { to: a, replace: !0 }) : u && !(o != null && o(u)) ? /* @__PURE__ */ t(c, { to: a, replace: !0 }) : /* @__PURE__ */ t(f, { children: p });
|
|
17
|
+
};
|
|
18
|
+
export {
|
|
19
|
+
x as default
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=ProtectedRoute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProtectedRoute.js","sources":["../../../src/components/Auth/ProtectedRoute.tsx"],"sourcesContent":["import { useMarsunAuth } from '@/provider';\nimport React from 'react';\nimport { Navigate, useLocation } from 'react-router-dom';\n\nexport interface ProtectedRouteProps {\n roles?: string[];\n permission?: string;\n loginPath?: string;\n fallbackPath?: string;\n children: React.ReactNode;\n}\n\nconst ProtectedRoute: React.FC<ProtectedRouteProps> = ({\n roles,\n permission,\n loginPath = '/login',\n fallbackPath = '/',\n children,\n}) => {\n const { isAuthenticated, hasAnyRole, hasPermission } = useMarsunAuth();\n const location = useLocation();\n\n if (!isAuthenticated) {\n const redirect = encodeURIComponent(`${location.pathname}${location.search}${location.hash}`);\n return <Navigate to={`${loginPath}?redirect=${redirect}`} replace />;\n }\n\n if (roles && roles.length > 0 && !hasAnyRole?.(roles)) {\n return <Navigate to={fallbackPath} replace />;\n }\n\n if (permission && !hasPermission?.(permission)) {\n return <Navigate to={fallbackPath} replace />;\n }\n\n return <>{children}</>;\n};\n\nexport default ProtectedRoute;\n"],"names":["ProtectedRoute","roles","permission","loginPath","fallbackPath","children","isAuthenticated","hasAnyRole","hasPermission","useMarsunAuth","location","useLocation","redirect","jsx","Navigate"],"mappings":";;;AAYA,MAAMA,IAAgD,CAAC;AAAA,EACrD,OAAAC;AAAA,EACA,YAAAC;AAAA,EACA,WAAAC,IAAY;AAAA,EACZ,cAAAC,IAAe;AAAA,EACf,UAAAC;AACF,MAAM;AACJ,QAAM,EAAE,iBAAAC,GAAiB,YAAAC,GAAY,eAAAC,EAAA,IAAkBC,EAAA,GACjDC,IAAWC,EAAA;AAEjB,MAAI,CAACL,GAAiB;AACpB,UAAMM,IAAW,mBAAmB,GAAGF,EAAS,QAAQ,GAAGA,EAAS,MAAM,GAAGA,EAAS,IAAI,EAAE;AAC5F,WAAO,gBAAAG,EAACC,KAAS,IAAI,GAAGX,CAAS,aAAaS,CAAQ,IAAI,SAAO,GAAA,CAAC;AAAA,EACpE;AAEA,SAAIX,KAASA,EAAM,SAAS,KAAK,EAACM,KAAA,QAAAA,EAAaN,MACtC,gBAAAY,EAACC,GAAA,EAAS,IAAIV,GAAc,SAAO,IAAC,IAGzCF,KAAc,EAACM,KAAA,QAAAA,EAAgBN,MAC1B,gBAAAW,EAACC,GAAA,EAAS,IAAIV,GAAc,SAAO,IAAC,2BAGnC,UAAAC,GAAS;AACrB;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hasPermission.js","sources":["../../../src/components/Auth/hasPermission.ts"],"sourcesContent":["/** 通过 Provider 注入的 hasPermission 回调检查权限 */\nexport function hasPermission(\n check: ((permission: string) => boolean) | undefined,\n perm: string,\n): boolean {\n if (!check) return false;\n return check(perm);\n}\n"],"names":["hasPermission","check","perm"],"mappings":"AACO,SAASA,EACdC,GACAC,GACS;AACT,SAAKD,IACEA,EAAMC,CAAI,IADE;AAErB;"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as o } from "react/jsx-runtime";
|
|
2
|
+
import { Descriptions as r } from "antd";
|
|
3
|
+
const d = ({
|
|
4
|
+
content: s,
|
|
5
|
+
column: a = 2,
|
|
6
|
+
bordered: e = !0,
|
|
7
|
+
size: n = "small",
|
|
8
|
+
title: p,
|
|
9
|
+
extra: m
|
|
10
|
+
}) => /* @__PURE__ */ o(r, { column: a, bordered: e, size: n, title: p, extra: m, children: s.map((l, t) => /* @__PURE__ */ o(r.Item, { label: l.label, span: l.span, children: l.value }, t)) });
|
|
11
|
+
export {
|
|
12
|
+
d as default
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=CommonDescriptions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CommonDescriptions.js","sources":["../../../src/components/Descriptions/CommonDescriptions.tsx"],"sourcesContent":["import { Descriptions } from 'antd';\nimport React from 'react';\n\nexport interface DescriptionItem {\n label: string;\n value: React.ReactNode;\n span?: number;\n}\n\nexport interface CommonDescriptionsProps {\n content: DescriptionItem[];\n column?:\n | number\n | { xs?: number; sm?: number; md?: number; lg?: number; xl?: number; xxl?: number };\n bordered?: boolean;\n size?: 'small' | 'default' | 'middle';\n title?: React.ReactNode;\n extra?: React.ReactNode;\n}\n\nconst CommonDescriptions: React.FC<CommonDescriptionsProps> = ({\n content,\n column = 2,\n bordered = true,\n size = 'small',\n title,\n extra,\n}) => (\n <Descriptions column={column} bordered={bordered} size={size} title={title} extra={extra}>\n {content.map((item, index) => (\n <Descriptions.Item key={index} label={item.label} span={item.span}>\n {item.value}\n </Descriptions.Item>\n ))}\n </Descriptions>\n);\n\nexport default CommonDescriptions;\n"],"names":["CommonDescriptions","content","column","bordered","size","title","extra","jsx","Descriptions","item","index"],"mappings":";;AAoBA,MAAMA,IAAwD,CAAC;AAAA,EAC7D,SAAAC;AAAA,EACA,QAAAC,IAAS;AAAA,EACT,UAAAC,IAAW;AAAA,EACX,MAAAC,IAAO;AAAA,EACP,OAAAC;AAAA,EACA,OAAAC;AACF,MACE,gBAAAC,EAACC,GAAA,EAAa,QAAAN,GAAgB,UAAAC,GAAoB,MAAAC,GAAY,OAAAC,GAAc,OAAAC,GACzE,UAAAL,EAAQ,IAAI,CAACQ,GAAMC,MAClB,gBAAAH,EAACC,EAAa,MAAb,EAA8B,OAAOC,EAAK,OAAO,MAAMA,EAAK,MAC1D,UAAAA,EAAK,MAAA,GADgBC,CAExB,CACD,EAAA,CACH;"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { jsxs as o, Fragment as C, jsx as i } from "react/jsx-runtime";
|
|
2
|
+
import { Eye as T, Download as z, Trash2 as x } from "../../Icons/index.js";
|
|
3
|
+
import { formatFileSize as b } from "../../../utils/format.js";
|
|
4
|
+
import { Tooltip as I, Button as P } from "antd";
|
|
5
|
+
import { useState as j } from "react";
|
|
6
|
+
import A from "../FilePreviewModal/index.js";
|
|
7
|
+
import { normalizeFileDisplayItem as O, getFileTypeName as S, getFileIcon as B } from "../fileDisplay.js";
|
|
8
|
+
import l from "./style.module.scss.js";
|
|
9
|
+
import t from "classnames";
|
|
10
|
+
import D from "../../Tag/FileTags.js";
|
|
11
|
+
const R = ({
|
|
12
|
+
file: a,
|
|
13
|
+
status: s,
|
|
14
|
+
showDownload: d = !0,
|
|
15
|
+
showDelete: h = !1,
|
|
16
|
+
showPreview: w = !0,
|
|
17
|
+
actions: N,
|
|
18
|
+
onDownload: n,
|
|
19
|
+
onDelete: c,
|
|
20
|
+
onPreview: f
|
|
21
|
+
}) => {
|
|
22
|
+
const [u, p] = j(!1), e = O(a), y = () => {
|
|
23
|
+
if (n) {
|
|
24
|
+
n(e);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
e.url && window.open(e.url, "_blank");
|
|
28
|
+
}, g = () => {
|
|
29
|
+
f ? f(e) : p(!0);
|
|
30
|
+
}, m = [];
|
|
31
|
+
w && m.push({
|
|
32
|
+
key: "preview",
|
|
33
|
+
icon: /* @__PURE__ */ i(T, {}),
|
|
34
|
+
tooltip: "预览",
|
|
35
|
+
onClick: () => g()
|
|
36
|
+
}), d && m.push({
|
|
37
|
+
key: "download",
|
|
38
|
+
icon: /* @__PURE__ */ i(z, {}),
|
|
39
|
+
tooltip: "下载",
|
|
40
|
+
onClick: () => y()
|
|
41
|
+
}), h && c && m.push({
|
|
42
|
+
key: "delete",
|
|
43
|
+
icon: /* @__PURE__ */ i(x, {}),
|
|
44
|
+
tooltip: "删除",
|
|
45
|
+
onClick: () => c(e)
|
|
46
|
+
});
|
|
47
|
+
const v = [...m, ...N ?? []], k = S(e.name, e.mimeType);
|
|
48
|
+
return /* @__PURE__ */ o(C, { children: [
|
|
49
|
+
/* @__PURE__ */ i("div", { className: t("file-item-root", l["file-item-root"]), children: /* @__PURE__ */ o("div", { className: t("file-item-container", l["file-item-container"]), children: [
|
|
50
|
+
/* @__PURE__ */ o("div", { className: t("file-item-wrapper", l["file-item-wrapper"]), children: [
|
|
51
|
+
/* @__PURE__ */ i("span", { className: t("file-item-inner", l["file-item-inner"]), children: B(e.name, e.mimeType) }),
|
|
52
|
+
/* @__PURE__ */ o("div", { className: t("file-item-header", l["file-item-header"]), children: [
|
|
53
|
+
/* @__PURE__ */ o("div", { className: t("file-item-body", l["file-item-body"]), children: [
|
|
54
|
+
/* @__PURE__ */ i("span", { className: t("file-item-footer", l["file-item-footer"]), title: e.name, children: e.name }),
|
|
55
|
+
/* @__PURE__ */ i("span", { className: t("file-item-row", l["file-item-row"]), children: k }),
|
|
56
|
+
e.size != null && /* @__PURE__ */ i("span", { className: t("file-item-row", l["file-item-row"]), children: b(e.size) })
|
|
57
|
+
] }),
|
|
58
|
+
e.tags && e.tags.length > 0 && /* @__PURE__ */ i(D, { tags: e.tags, className: t("file-item-col", l["file-item-col"]) })
|
|
59
|
+
] })
|
|
60
|
+
] }),
|
|
61
|
+
/* @__PURE__ */ o("div", { className: t("file-item-wrap", l["file-item-wrap"]), children: [
|
|
62
|
+
s && /* @__PURE__ */ i("span", { className: t("file-item-panel", l["file-item-panel"]), children: s }),
|
|
63
|
+
/* @__PURE__ */ i("div", { className: t("file-item-action-group", l["file-item-action-group"]), children: v.map((r) => /* @__PURE__ */ i(I, { title: r.tooltip, children: /* @__PURE__ */ i(
|
|
64
|
+
P,
|
|
65
|
+
{
|
|
66
|
+
type: "text",
|
|
67
|
+
size: "small",
|
|
68
|
+
icon: r.icon,
|
|
69
|
+
onClick: (F) => {
|
|
70
|
+
F.stopPropagation(), r.onClick(a);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
) }, r.key)) })
|
|
74
|
+
] })
|
|
75
|
+
] }) }),
|
|
76
|
+
/* @__PURE__ */ i(A, { open: u, file: e, onClose: () => p(!1) })
|
|
77
|
+
] });
|
|
78
|
+
};
|
|
79
|
+
export {
|
|
80
|
+
R as FileItem
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/components/File/FileItem/index.tsx"],"sourcesContent":["import { FileTags } from '@/components/Tag';\nimport { Trash2, Download, Eye } from '@/components/Icons';\nimport { formatFileSize } from '@/utils/format';\nimport { Button, Tooltip } from 'antd';\nimport React, { useState } from 'react';\nimport FilePreviewModal from '../FilePreviewModal';\nimport { getFileIcon, getFileTypeName, normalizeFileDisplayItem } from '../fileDisplay';\nimport type { FileDisplayItem } from '../types';\nimport styles from './style.module.scss';\nimport classNames from 'classnames';\n\nexport interface FileItemAction {\n key: string;\n icon: React.ReactNode;\n tooltip: string;\n onClick: (file: FileDisplayItem) => void;\n}\n\nexport interface FileItemProps {\n file: FileDisplayItem;\n status?: React.ReactNode;\n showDownload?: boolean;\n showDelete?: boolean;\n showPreview?: boolean;\n actions?: FileItemAction[];\n onDownload?: (file: FileDisplayItem) => void;\n onDelete?: (file: FileDisplayItem) => void;\n onPreview?: (file: FileDisplayItem) => void;\n}\n\nconst FileItem: React.FC<FileItemProps> = ({\n file,\n status,\n showDownload = true,\n showDelete = false,\n showPreview = true,\n actions,\n onDownload,\n onDelete,\n onPreview,\n}) => {\n const [previewOpen, setPreviewOpen] = useState(false);\n const resolvedFile = normalizeFileDisplayItem(file);\n\n const handleDownload = () => {\n if (onDownload) {\n onDownload(resolvedFile);\n return;\n }\n if (resolvedFile.url) window.open(resolvedFile.url, '_blank');\n };\n\n const handlePreview = () => {\n if (onPreview) onPreview(resolvedFile);\n else setPreviewOpen(true);\n };\n\n const defaultActions: FileItemAction[] = [];\n if (showPreview) {\n defaultActions.push({\n key: 'preview',\n icon: <Eye />,\n tooltip: '预览',\n onClick: () => handlePreview(),\n });\n }\n if (showDownload) {\n defaultActions.push({\n key: 'download',\n icon: <Download />,\n tooltip: '下载',\n onClick: () => handleDownload(),\n });\n }\n if (showDelete && onDelete) {\n defaultActions.push({\n key: 'delete',\n icon: <Trash2 />,\n tooltip: '删除',\n onClick: () => onDelete(resolvedFile),\n });\n }\n\n const allActions = [...defaultActions, ...(actions ?? [])];\n const typeName = getFileTypeName(resolvedFile.name, resolvedFile.mimeType);\n\n return (\n <>\n <div className={classNames('file-item-root', styles['file-item-root'])}>\n <div className={classNames('file-item-container', styles['file-item-container'])}>\n <div className={classNames('file-item-wrapper', styles['file-item-wrapper'])}>\n <span className={classNames('file-item-inner', styles['file-item-inner'])}>\n {getFileIcon(resolvedFile.name, resolvedFile.mimeType)}\n </span>\n <div className={classNames('file-item-header', styles['file-item-header'])}>\n <div className={classNames('file-item-body', styles['file-item-body'])}>\n <span className={classNames('file-item-footer', styles['file-item-footer'])} title={resolvedFile.name}>\n {resolvedFile.name}\n </span>\n <span className={classNames('file-item-row', styles['file-item-row'])}>{typeName}</span>\n {resolvedFile.size != null && (\n <span className={classNames('file-item-row', styles['file-item-row'])}>\n {formatFileSize(resolvedFile.size)}\n </span>\n )}\n </div>\n {resolvedFile.tags && resolvedFile.tags.length > 0 && (\n <FileTags tags={resolvedFile.tags} className={classNames('file-item-col', styles['file-item-col'])} />\n )}\n </div>\n </div>\n\n <div className={classNames('file-item-wrap', styles['file-item-wrap'])}>\n {status && <span className={classNames('file-item-panel', styles['file-item-panel'])}>{status}</span>}\n <div className={classNames('file-item-action-group', styles['file-item-action-group'])}>\n {allActions.map((action) => (\n <Tooltip key={action.key} title={action.tooltip}>\n <Button\n type=\"text\"\n size=\"small\"\n icon={action.icon}\n onClick={(e) => {\n e.stopPropagation();\n action.onClick(file);\n }}\n />\n </Tooltip>\n ))}\n </div>\n </div>\n </div>\n </div>\n <FilePreviewModal open={previewOpen} file={resolvedFile} onClose={() => setPreviewOpen(false)} />\n </>\n );\n};\n\nexport { FileItem };\nexport default FileItem;\n"],"names":["FileItem","file","status","showDownload","showDelete","showPreview","actions","onDownload","onDelete","onPreview","previewOpen","setPreviewOpen","useState","resolvedFile","normalizeFileDisplayItem","handleDownload","handlePreview","defaultActions","Eye","Download","Trash2","allActions","typeName","getFileTypeName","jsxs","Fragment","jsx","classNames","styles","getFileIcon","formatFileSize","FileTags","action","Tooltip","Button","e","FilePreviewModal"],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const i = {
|
|
2
|
+
"file-item-root": "_file-item-root_lmij6_1",
|
|
3
|
+
"file-item-container": "_file-item-container_lmij6_8",
|
|
4
|
+
"file-item-wrapper": "_file-item-wrapper_lmij6_18",
|
|
5
|
+
"file-item-inner": "_file-item-inner_lmij6_25",
|
|
6
|
+
"file-item-header": "_file-item-header_lmij6_29",
|
|
7
|
+
"file-item-body": "_file-item-body_lmij6_34",
|
|
8
|
+
"file-item-footer": "_file-item-footer_lmij6_40",
|
|
9
|
+
"file-item-row": "_file-item-row_lmij6_47",
|
|
10
|
+
"file-item-col": "_file-item-col_lmij6_53",
|
|
11
|
+
"file-item-wrap": "_file-item-wrap_lmij6_18",
|
|
12
|
+
"file-item-panel": "_file-item-panel_lmij6_66",
|
|
13
|
+
"file-item-action-group": "_file-item-action-group_lmij6_71"
|
|
14
|
+
};
|
|
15
|
+
export {
|
|
16
|
+
i as default
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=style.module.scss.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style.module.scss.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsxs as n, jsx as a } from "react/jsx-runtime";
|
|
2
|
+
import { normalizeFileDisplayItem as r, getFileIcon as t, getFileTypeName as o } from "../fileDisplay.js";
|
|
3
|
+
import l from "./style.module.scss.js";
|
|
4
|
+
import p from "classnames";
|
|
5
|
+
const h = ({ file: s, onClick: i }) => {
|
|
6
|
+
const e = r(s);
|
|
7
|
+
return /* @__PURE__ */ n(
|
|
8
|
+
"a",
|
|
9
|
+
{
|
|
10
|
+
className: p("file-link-actions", l["file-link-actions"]),
|
|
11
|
+
onClick: (m) => {
|
|
12
|
+
m.preventDefault(), i == null || i(e);
|
|
13
|
+
},
|
|
14
|
+
href: e.url ?? "#",
|
|
15
|
+
title: e.name,
|
|
16
|
+
children: [
|
|
17
|
+
/* @__PURE__ */ a("span", { className: l["file-link-inner"], children: t(e.name, e.mimeType) }),
|
|
18
|
+
/* @__PURE__ */ a("span", { className: l["file-link-toolbar"], children: e.name }),
|
|
19
|
+
/* @__PURE__ */ a("span", { className: l["file-link-row"], children: o(e.name, e.mimeType) })
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
};
|
|
24
|
+
export {
|
|
25
|
+
h as default
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/components/File/FileLink/index.tsx"],"sourcesContent":["import type { FileDisplayItem } from '../types';\nimport { getFileIcon, getFileTypeName, normalizeFileDisplayItem } from '../fileDisplay';\nimport React from 'react';\nimport styles from './style.module.scss';\nimport classNames from 'classnames';\n\nexport interface FileLinkProps {\n file: FileDisplayItem;\n onClick?: (file: FileDisplayItem) => void;\n}\n\nconst FileLink: React.FC<FileLinkProps> = ({ file, onClick }) => {\n const resolvedFile = normalizeFileDisplayItem(file);\n\n return (\n <a\n className={classNames('file-link-actions', styles['file-link-actions'])}\n onClick={(e) => { e.preventDefault(); onClick?.(resolvedFile); }}\n href={resolvedFile.url ?? '#'}\n title={resolvedFile.name}\n >\n <span className={styles['file-link-inner']}>{getFileIcon(resolvedFile.name, resolvedFile.mimeType)}</span>\n <span className={styles['file-link-toolbar']}>{resolvedFile.name}</span>\n <span className={styles['file-link-row']}>{getFileTypeName(resolvedFile.name, resolvedFile.mimeType)}</span>\n </a>\n );\n};\n\nexport default FileLink;\n"],"names":["FileLink","file","onClick","resolvedFile","normalizeFileDisplayItem","jsxs","classNames","styles","e","jsx","getFileTypeName"],"mappings":";;;;AAWA,MAAMA,IAAoC,CAAC,EAAE,MAAAC,GAAM,SAAAC,QAAc;AAC/D,QAAMC,IAAeC,EAAyBH,CAAI;AAElD,SACA,gBAAAI;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWC,EAAW,qBAAqBC,EAAO,mBAAmB,CAAC;AAAA,MACtE,SAAS,CAACC,MAAM;AAAE,QAAAA,EAAE,eAAA,GAAkBN,KAAA,QAAAA,EAAUC;AAAA,MAAe;AAAA,MAC/D,MAAMA,EAAa,OAAO;AAAA,MAC1B,OAAOA,EAAa;AAAA,MAEpB,UAAA;AAAA,QAAA,gBAAAM,EAAC,QAAA,EAAK,WAAWF,EAAO,iBAAiB,GAAI,YAAYJ,EAAa,MAAMA,EAAa,QAAQ,EAAA,CAAE;AAAA,0BAClG,QAAA,EAAK,WAAWI,EAAO,mBAAmB,GAAI,YAAa,MAAK;AAAA,QACjE,gBAAAE,EAAC,QAAA,EAAK,WAAWF,EAAO,eAAe,GAAI,UAAAG,EAAgBP,EAAa,MAAMA,EAAa,QAAQ,EAAA,CAAE;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGzG;"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const i = {
|
|
2
|
+
"file-link-inner": "_file-link-inner_uetzp_1",
|
|
3
|
+
"file-link-row": "_file-link-row_uetzp_5",
|
|
4
|
+
"file-link-actions": "_file-link-actions_uetzp_11",
|
|
5
|
+
"file-link-toolbar": "_file-link-toolbar_uetzp_22"
|
|
6
|
+
};
|
|
7
|
+
export {
|
|
8
|
+
i as default
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=style.module.scss.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style.module.scss.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { jsxs as a, jsx as i, Fragment as f } from "react/jsx-runtime";
|
|
2
|
+
import { formatFileSize as d } from "../../../utils/format.js";
|
|
3
|
+
import { CloudDownload as v } from "../../Icons/index.js";
|
|
4
|
+
import { Button as w, Empty as h, Image as u } from "antd";
|
|
5
|
+
import { normalizeFileDisplayItem as g, getFileIcon as N, getFileTypeName as y } from "../fileDisplay.js";
|
|
6
|
+
import r from "./style.module.scss.js";
|
|
7
|
+
import p from "classnames";
|
|
8
|
+
function F(l, t) {
|
|
9
|
+
return t ?? l.url ?? l.thumbnailUrl;
|
|
10
|
+
}
|
|
11
|
+
function o(l) {
|
|
12
|
+
var n;
|
|
13
|
+
if ((l.mimeType ?? "").startsWith("image/")) return !0;
|
|
14
|
+
const s = ((n = (l.name ?? "").split(".").pop()) == null ? void 0 : n.toLowerCase()) ?? "";
|
|
15
|
+
return ["png", "jpg", "jpeg", "gif", "webp", "svg"].includes(s);
|
|
16
|
+
}
|
|
17
|
+
const k = ({
|
|
18
|
+
file: l,
|
|
19
|
+
url: t,
|
|
20
|
+
unsupportedMessage: s = "暂不支持预览此文件类型",
|
|
21
|
+
title: n,
|
|
22
|
+
extra: c
|
|
23
|
+
}) => {
|
|
24
|
+
const e = g(l), m = F(e, t);
|
|
25
|
+
return /* @__PURE__ */ a("div", { className: p("file-preview", r["file-preview"]), children: [
|
|
26
|
+
/* @__PURE__ */ a("div", { className: p("file-preview-header", r["file-preview-header"]), children: [
|
|
27
|
+
/* @__PURE__ */ i("div", { className: p("file-preview-title", r["file-preview-title"]), children: n ?? /* @__PURE__ */ a(f, { children: [
|
|
28
|
+
/* @__PURE__ */ i("span", { className: r["file-preview-icon"], children: N(e.name, e.mimeType) }),
|
|
29
|
+
/* @__PURE__ */ i("span", { children: e.name }),
|
|
30
|
+
/* @__PURE__ */ a("span", { className: r["file-preview-meta"], children: [
|
|
31
|
+
y(e.name, e.mimeType),
|
|
32
|
+
e.size != null && ` · ${d(e.size)}`
|
|
33
|
+
] })
|
|
34
|
+
] }) }),
|
|
35
|
+
c,
|
|
36
|
+
m && /* @__PURE__ */ i(w, { type: "link", icon: /* @__PURE__ */ i(v, {}), href: m, target: "_blank", rel: "noreferrer", children: "下载" })
|
|
37
|
+
] }),
|
|
38
|
+
/* @__PURE__ */ a("div", { className: p("file-preview-body", r["file-preview-body"]), children: [
|
|
39
|
+
!m && /* @__PURE__ */ i(h, { description: "无可预览地址" }),
|
|
40
|
+
m && o(e) && /* @__PURE__ */ i(u, { src: m, alt: e.name, className: r["file-preview-image"] }),
|
|
41
|
+
m && !o(e) && /* @__PURE__ */ i("iframe", { src: m, title: e.name, className: r["file-preview-iframe"] }),
|
|
42
|
+
m && !o(l) && s && /* @__PURE__ */ i("p", { className: r["file-preview-unsupported"], children: s })
|
|
43
|
+
] })
|
|
44
|
+
] });
|
|
45
|
+
};
|
|
46
|
+
export {
|
|
47
|
+
k as default
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/components/File/FilePreview/index.tsx"],"sourcesContent":["import { formatFileSize } from '@/utils/format';\nimport { CloudDownload } from '@/components/Icons';\nimport { Button, Empty, Image } from 'antd';\nimport React from 'react';\nimport { getFileIcon, getFileTypeName, normalizeFileDisplayItem } from '../fileDisplay';\nimport type { FileDisplayItem } from '../types';\nimport styles from './style.module.scss';\nimport classNames from 'classnames';\n\nexport interface FilePreviewProps {\n file: FileDisplayItem;\n url?: string;\n unsupportedMessage?: string;\n title?: React.ReactNode;\n extra?: React.ReactNode;\n}\n\nfunction resolvePreviewUrl(file: FileDisplayItem, url?: string): string | undefined {\n return url ?? file.url ?? file.thumbnailUrl;\n}\n\nfunction isImage(file: FileDisplayItem): boolean {\n const mime = file.mimeType ?? '';\n if (mime.startsWith('image/')) return true;\n const ext = (file.name ?? '').split('.').pop()?.toLowerCase() ?? '';\n return ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg'].includes(ext);\n}\n\nconst FilePreview: React.FC<FilePreviewProps> = ({\n file,\n url,\n unsupportedMessage = '暂不支持预览此文件类型',\n title,\n extra,\n}) => {\n const resolvedFile = normalizeFileDisplayItem(file);\n const previewUrl = resolvePreviewUrl(resolvedFile, url);\n\n return (\n <div className={classNames('file-preview', styles['file-preview'])}>\n <div className={classNames('file-preview-header', styles['file-preview-header'])}>\n <div className={classNames('file-preview-title', styles['file-preview-title'])}>\n {title ?? (\n <>\n <span className={styles['file-preview-icon']}>{getFileIcon(resolvedFile.name, resolvedFile.mimeType)}</span>\n <span>{resolvedFile.name}</span>\n <span className={styles['file-preview-meta']}>\n {getFileTypeName(resolvedFile.name, resolvedFile.mimeType)}\n {resolvedFile.size != null && ` · ${formatFileSize(resolvedFile.size)}`}\n </span>\n </>\n )}\n </div>\n {extra}\n {previewUrl && (\n <Button type=\"link\" icon={<CloudDownload />} href={previewUrl} target=\"_blank\" rel=\"noreferrer\">\n 下载\n </Button>\n )}\n </div>\n <div className={classNames('file-preview-body', styles['file-preview-body'])}>\n {!previewUrl && <Empty description=\"无可预览地址\" />}\n {previewUrl && isImage(resolvedFile) && (\n <Image src={previewUrl} alt={resolvedFile.name} className={styles['file-preview-image']} />\n )}\n {previewUrl && !isImage(resolvedFile) && (\n <iframe src={previewUrl} title={resolvedFile.name} className={styles['file-preview-iframe']} />\n )}\n {previewUrl && !isImage(file) && unsupportedMessage && (\n <p className={styles['file-preview-unsupported']}>{unsupportedMessage}</p>\n )}\n </div>\n </div>\n );\n};\n\nexport default FilePreview;\n"],"names":["resolvePreviewUrl","file","url","isImage","ext","_a","FilePreview","unsupportedMessage","title","extra","resolvedFile","normalizeFileDisplayItem","previewUrl","jsxs","classNames","styles","jsx","Fragment","getFileTypeName","formatFileSize","Button","CloudDownload","Empty","Image"],"mappings":";;;;;;;AAiBA,SAASA,EAAkBC,GAAuBC,GAAkC;AAClF,SAAOA,KAAOD,EAAK,OAAOA,EAAK;AACjC;AAEA,SAASE,EAAQF,GAAgC;;AAE/C,OADaA,EAAK,YAAY,IACrB,WAAW,QAAQ,EAAG,QAAO;AACtC,QAAMG,MAAOC,KAAAJ,EAAK,QAAQ,IAAI,MAAM,GAAG,EAAE,UAA5B,gBAAAI,EAAmC,kBAAiB;AACjE,SAAO,CAAC,OAAO,OAAO,QAAQ,OAAO,QAAQ,KAAK,EAAE,SAASD,CAAG;AAClE;AAEA,MAAME,IAA0C,CAAC;AAAA,EAC/C,MAAAL;AAAA,EACA,KAAAC;AAAA,EACA,oBAAAK,IAAqB;AAAA,EACrB,OAAAC;AAAA,EACA,OAAAC;AACF,MAAM;AACJ,QAAMC,IAAeC,EAAyBV,CAAI,GAC5CW,IAAaZ,EAAkBU,GAAcR,CAAG;AAEtD,SACE,gBAAAW,EAAC,SAAI,WAAWC,EAAW,gBAAgBC,EAAO,cAAc,CAAC,GAC/D,UAAA;AAAA,IAAA,gBAAAF,EAAC,SAAI,WAAWC,EAAW,uBAAuBC,EAAO,qBAAqB,CAAC,GAC7E,UAAA;AAAA,MAAA,gBAAAC,EAAC,OAAA,EAAI,WAAWF,EAAW,sBAAsBC,EAAO,oBAAoB,CAAC,GAC1E,UAAAP,KACC,gBAAAK,EAAAI,GAAA,EACE,UAAA;AAAA,QAAA,gBAAAD,EAAC,QAAA,EAAK,WAAWD,EAAO,mBAAmB,GAAI,YAAYL,EAAa,MAAMA,EAAa,QAAQ,EAAA,CAAE;AAAA,QACrG,gBAAAM,EAAC,QAAA,EAAM,UAAAN,EAAa,KAAA,CAAK;AAAA,QACzB,gBAAAG,EAAC,QAAA,EAAK,WAAWE,EAAO,mBAAmB,GACxC,UAAA;AAAA,UAAAG,EAAgBR,EAAa,MAAMA,EAAa,QAAQ;AAAA,UACxDA,EAAa,QAAQ,QAAQ,MAAMS,EAAeT,EAAa,IAAI,CAAC;AAAA,QAAA,EAAA,CACvE;AAAA,MAAA,EAAA,CACF,EAAA,CAEJ;AAAA,MACCD;AAAA,MACAG,KACC,gBAAAI,EAACI,GAAA,EAAO,MAAK,QAAO,MAAM,gBAAAJ,EAACK,GAAA,CAAA,CAAc,GAAI,MAAMT,GAAY,QAAO,UAAS,KAAI,cAAa,UAAA,KAAA,CAEhG;AAAA,IAAA,GAEJ;AAAA,IACA,gBAAAC,EAAC,SAAI,WAAWC,EAAW,qBAAqBC,EAAO,mBAAmB,CAAC,GACxE,UAAA;AAAA,MAAA,CAACH,KAAc,gBAAAI,EAACM,GAAA,EAAM,aAAY,SAAA,CAAS;AAAA,MAC3CV,KAAcT,EAAQO,CAAY,uBAChCa,GAAA,EAAM,KAAKX,GAAY,KAAKF,EAAa,MAAM,WAAWK,EAAO,oBAAoB,GAAG;AAAA,MAE1FH,KAAc,CAACT,EAAQO,CAAY,KAClC,gBAAAM,EAAC,UAAA,EAAO,KAAKJ,GAAY,OAAOF,EAAa,MAAM,WAAWK,EAAO,qBAAqB,GAAG;AAAA,MAE9FH,KAAc,CAACT,EAAQF,CAAI,KAAKM,KAC/B,gBAAAS,EAAC,KAAA,EAAE,WAAWD,EAAO,0BAA0B,GAAI,UAAAR,EAAA,CAAmB;AAAA,IAAA,EAAA,CAE1E;AAAA,EAAA,GACF;AAEJ;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style.module.scss.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as o } from "react/jsx-runtime";
|
|
2
|
+
import { Modal as m } from "antd";
|
|
3
|
+
import n from "../FilePreview/index.js";
|
|
4
|
+
import { normalizeFileDisplayItem as d } from "../fileDisplay.js";
|
|
5
|
+
const c = ({ open: r, file: i, url: l, onClose: t }) => {
|
|
6
|
+
const e = d(i);
|
|
7
|
+
return /* @__PURE__ */ o(m, { open: r, onCancel: t, footer: null, width: 900, destroyOnHidden: !0, title: e.name, children: /* @__PURE__ */ o(n, { file: e, url: l }) });
|
|
8
|
+
};
|
|
9
|
+
export {
|
|
10
|
+
c as default
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/components/File/FilePreviewModal/index.tsx"],"sourcesContent":["import { Modal } from 'antd';\nimport React from 'react';\nimport FilePreview from '../FilePreview';\nimport { normalizeFileDisplayItem } from '../fileDisplay';\nimport type { FileDisplayItem } from '../types';\n\nexport interface FilePreviewModalProps {\n open: boolean;\n file: FileDisplayItem;\n url?: string;\n onClose: () => void;\n}\n\nconst FilePreviewModal: React.FC<FilePreviewModalProps> = ({ open, file, url, onClose }) => {\n const resolvedFile = normalizeFileDisplayItem(file);\n\n return (\n <Modal open={open} onCancel={onClose} footer={null} width={900} destroyOnHidden title={resolvedFile.name}>\n <FilePreview file={resolvedFile} url={url} />\n </Modal>\n );\n};\n\nexport default FilePreviewModal;\n"],"names":["FilePreviewModal","open","file","url","onClose","resolvedFile","normalizeFileDisplayItem","Modal","jsx","FilePreview"],"mappings":";;;;AAaA,MAAMA,IAAoD,CAAC,EAAE,MAAAC,GAAM,MAAAC,GAAM,KAAAC,GAAK,SAAAC,QAAc;AAC1F,QAAMC,IAAeC,EAAyBJ,CAAI;AAElD,2BACCK,GAAA,EAAM,MAAAN,GAAY,UAAUG,GAAS,QAAQ,MAAM,OAAO,KAAK,iBAAe,IAAC,OAAOC,EAAa,MAClG,UAAA,gBAAAG,EAACC,KAAY,MAAMJ,GAAc,KAAAF,GAAU,EAAA,CAC7C;AAEF;"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { jsx as m } from "react/jsx-runtime";
|
|
2
|
+
import { FileArchive as p, FileImage as r, Presentation as l, FileSpreadsheet as i, FileText as c, File as u } from "../Icons/index.js";
|
|
3
|
+
const x = {
|
|
4
|
+
pdf: c,
|
|
5
|
+
doc: c,
|
|
6
|
+
docx: c,
|
|
7
|
+
txt: c,
|
|
8
|
+
md: c,
|
|
9
|
+
xls: i,
|
|
10
|
+
xlsx: i,
|
|
11
|
+
csv: i,
|
|
12
|
+
ppt: l,
|
|
13
|
+
pptx: l,
|
|
14
|
+
png: r,
|
|
15
|
+
jpg: r,
|
|
16
|
+
jpeg: r,
|
|
17
|
+
gif: r,
|
|
18
|
+
webp: r,
|
|
19
|
+
zip: p,
|
|
20
|
+
rar: p,
|
|
21
|
+
"7z": p
|
|
22
|
+
};
|
|
23
|
+
function s(e) {
|
|
24
|
+
const t = e.lastIndexOf(".");
|
|
25
|
+
return t >= 0 ? e.slice(t + 1).toLowerCase() : "";
|
|
26
|
+
}
|
|
27
|
+
function F(e) {
|
|
28
|
+
const t = e.trim();
|
|
29
|
+
if (!t) return "未命名文件";
|
|
30
|
+
try {
|
|
31
|
+
const d = new URL(t, "http://placeholder.local").pathname.split("/").filter(Boolean).pop() ?? "", a = decodeURIComponent(d);
|
|
32
|
+
if (a) return a;
|
|
33
|
+
} catch {
|
|
34
|
+
}
|
|
35
|
+
const n = t.split(/[/?#]/).filter(Boolean).pop() ?? "";
|
|
36
|
+
try {
|
|
37
|
+
return decodeURIComponent(n) || "未命名文件";
|
|
38
|
+
} catch {
|
|
39
|
+
return n || "未命名文件";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function g(e) {
|
|
43
|
+
var o;
|
|
44
|
+
const t = ((o = e.name) == null ? void 0 : o.trim()) || (e.url ? F(e.url) : "未命名文件"), n = e.extension ?? s(t);
|
|
45
|
+
return {
|
|
46
|
+
...e,
|
|
47
|
+
name: t,
|
|
48
|
+
extension: n || e.extension
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function h(e, t) {
|
|
52
|
+
const n = s(e), o = x[n] ?? u;
|
|
53
|
+
return /* @__PURE__ */ m(o, {});
|
|
54
|
+
}
|
|
55
|
+
function C(e, t) {
|
|
56
|
+
var o;
|
|
57
|
+
const n = s(e);
|
|
58
|
+
return n ? n.toUpperCase() : t ? ((o = t.split("/").pop()) == null ? void 0 : o.toUpperCase()) ?? "FILE" : "FILE";
|
|
59
|
+
}
|
|
60
|
+
export {
|
|
61
|
+
s as getFileExtension,
|
|
62
|
+
h as getFileIcon,
|
|
63
|
+
C as getFileTypeName,
|
|
64
|
+
g as normalizeFileDisplayItem,
|
|
65
|
+
F as parseFileNameFromUrl
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=fileDisplay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileDisplay.js","sources":["../../../src/components/File/fileDisplay.tsx"],"sourcesContent":["import React from 'react';\nimport {\n File,\n FileArchive,\n FileImage,\n FileSpreadsheet,\n FileText,\n Presentation,\n} from '@/components/Icons';\nimport type { FileDisplayItem } from './types';\n\nconst EXT_ICON_MAP: Record<string, React.FC<{ className?: string }>> = {\n pdf: FileText,\n doc: FileText,\n docx: FileText,\n txt: FileText,\n md: FileText,\n xls: FileSpreadsheet,\n xlsx: FileSpreadsheet,\n csv: FileSpreadsheet,\n ppt: Presentation,\n pptx: Presentation,\n png: FileImage,\n jpg: FileImage,\n jpeg: FileImage,\n gif: FileImage,\n webp: FileImage,\n zip: FileArchive,\n rar: FileArchive,\n '7z': FileArchive,\n};\n\nexport function getFileExtension(name: string): string {\n const dot = name.lastIndexOf('.');\n return dot >= 0 ? name.slice(dot + 1).toLowerCase() : '';\n}\n\n/** 从 URL 路径解析文件名(decodeURIComponent,失败时回退为「未命名文件」) */\nexport function parseFileNameFromUrl(url: string): string {\n const trimmed = url.trim();\n if (!trimmed) return '未命名文件';\n\n try {\n const pathname = new URL(trimmed, 'http://placeholder.local').pathname;\n const segment = pathname.split('/').filter(Boolean).pop() ?? '';\n const decoded = decodeURIComponent(segment);\n if (decoded) return decoded;\n } catch {\n // fall through\n }\n\n const fallback = trimmed.split(/[/?#]/).filter(Boolean).pop() ?? '';\n try {\n const decoded = decodeURIComponent(fallback);\n return decoded || '未命名文件';\n } catch {\n return fallback || '未命名文件';\n }\n}\n\n/** 补全 name / extension:name 缺省时从 url 解析 */\nexport function normalizeFileDisplayItem(file: FileDisplayItem): FileDisplayItem & { name: string } {\n const name = file.name?.trim() || (file.url ? parseFileNameFromUrl(file.url) : '未命名文件');\n const extension = file.extension ?? getFileExtension(name);\n\n return {\n ...file,\n name,\n extension: extension || file.extension,\n };\n}\n\nexport function getFileIcon(name: string, _mimeType?: string): React.ReactNode {\n const ext = getFileExtension(name);\n const Icon = EXT_ICON_MAP[ext] ?? File;\n return <Icon />;\n}\n\nexport function getFileTypeName(name: string, mimeType?: string): string {\n const ext = getFileExtension(name);\n if (ext) return ext.toUpperCase();\n if (mimeType) return mimeType.split('/').pop()?.toUpperCase() ?? 'FILE';\n return 'FILE';\n}\n"],"names":["EXT_ICON_MAP","FileText","FileSpreadsheet","Presentation","FileImage","FileArchive","getFileExtension","name","dot","parseFileNameFromUrl","url","trimmed","segment","decoded","fallback","normalizeFileDisplayItem","file","_a","extension","getFileIcon","_mimeType","ext","Icon","File","getFileTypeName","mimeType"],"mappings":";;AAWA,MAAMA,IAAiE;AAAA,EACrE,KAAKC;AAAA,EACL,KAAKA;AAAA,EACL,MAAMA;AAAA,EACN,KAAKA;AAAA,EACL,IAAIA;AAAA,EACJ,KAAKC;AAAA,EACL,MAAMA;AAAA,EACN,KAAKA;AAAA,EACL,KAAKC;AAAA,EACL,MAAMA;AAAA,EACN,KAAKC;AAAA,EACL,KAAKA;AAAA,EACL,MAAMA;AAAA,EACN,KAAKA;AAAA,EACL,MAAMA;AAAA,EACN,KAAKC;AAAA,EACL,KAAKA;AAAA,EACL,MAAMA;AACR;AAEO,SAASC,EAAiBC,GAAsB;AACrD,QAAMC,IAAMD,EAAK,YAAY,GAAG;AAChC,SAAOC,KAAO,IAAID,EAAK,MAAMC,IAAM,CAAC,EAAE,gBAAgB;AACxD;AAGO,SAASC,EAAqBC,GAAqB;AACxD,QAAMC,IAAUD,EAAI,KAAA;AACpB,MAAI,CAACC,EAAS,QAAO;AAErB,MAAI;AAEF,UAAMC,IADW,IAAI,IAAID,GAAS,0BAA0B,EAAE,SACrC,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,IAAA,KAAS,IACvDE,IAAU,mBAAmBD,CAAO;AAC1C,QAAIC,EAAS,QAAOA;AAAA,EACtB,QAAQ;AAAA,EAER;AAEA,QAAMC,IAAWH,EAAQ,MAAM,OAAO,EAAE,OAAO,OAAO,EAAE,IAAA,KAAS;AACjE,MAAI;AAEF,WADgB,mBAAmBG,CAAQ,KACzB;AAAA,EACpB,QAAQ;AACN,WAAOA,KAAY;AAAA,EACrB;AACF;AAGO,SAASC,EAAyBC,GAA2D;;AAClG,QAAMT,MAAOU,IAAAD,EAAK,SAAL,gBAAAC,EAAW,YAAWD,EAAK,MAAMP,EAAqBO,EAAK,GAAG,IAAI,UACzEE,IAAYF,EAAK,aAAaV,EAAiBC,CAAI;AAEzD,SAAO;AAAA,IACL,GAAGS;AAAA,IACH,MAAAT;AAAA,IACA,WAAWW,KAAaF,EAAK;AAAA,EAAA;AAEjC;AAEO,SAASG,EAAYZ,GAAca,GAAqC;AAC7E,QAAMC,IAAMf,EAAiBC,CAAI,GAC3Be,IAAOtB,EAAaqB,CAAG,KAAKE;AAClC,2BAAQD,GAAA,EAAK;AACf;AAEO,SAASE,EAAgBjB,GAAckB,GAA2B;;AACvE,QAAMJ,IAAMf,EAAiBC,CAAI;AACjC,SAAIc,IAAYA,EAAI,YAAA,IAChBI,MAAiBR,IAAAQ,EAAS,MAAM,GAAG,EAAE,IAAA,MAApB,gBAAAR,EAA2B,kBAAiB,SAC1D;AACT;"}
|