@voplus/morpho-workspace 11.2.4 → 11.2.6

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.
Files changed (80) hide show
  1. package/es/modules/{calendar/CalendarRoutes.d.ts → calendar-board/CalendarBoardRoutes.d.ts} +2 -1
  2. package/es/modules/{calendar/CalendarRoutes.js → calendar-board/CalendarBoardRoutes.js} +10 -9
  3. package/es/modules/calendar-board/CalendarBoardRoutes.js.map +1 -0
  4. package/es/modules/calendar-board/components/CalendarActionProperties/index.d.ts +20 -0
  5. package/es/modules/calendar-board/components/CalendarActionProperties/index.js +36 -0
  6. package/es/modules/calendar-board/components/CalendarActionProperties/index.js.map +1 -0
  7. package/es/modules/calendar-board/components/CalendarBoardGrid/index.d.ts +45 -0
  8. package/es/modules/calendar-board/components/CalendarBoardGrid/index.js +89 -0
  9. package/es/modules/calendar-board/components/CalendarBoardGrid/index.js.map +1 -0
  10. package/es/modules/calendar-board/components/CalendarEventChip/index.d.ts +22 -0
  11. package/es/modules/calendar-board/components/CalendarEventChip/index.js +20 -0
  12. package/es/modules/calendar-board/components/CalendarEventChip/index.js.map +1 -0
  13. package/es/modules/calendar-board/components/CalendarLegend/index.d.ts +42 -0
  14. package/es/modules/calendar-board/components/CalendarLegend/index.js +94 -0
  15. package/es/modules/calendar-board/components/CalendarLegend/index.js.map +1 -0
  16. package/es/modules/calendar-board/components/CalendarMoreLink/index.d.ts +11 -0
  17. package/es/modules/calendar-board/components/CalendarMoreLink/index.js +12 -0
  18. package/es/modules/calendar-board/components/CalendarMoreLink/index.js.map +1 -0
  19. package/es/modules/calendar-board/components/CalendarSidebar/index.d.ts +34 -0
  20. package/es/modules/calendar-board/components/CalendarSidebar/index.js +45 -0
  21. package/es/modules/calendar-board/components/CalendarSidebar/index.js.map +1 -0
  22. package/es/modules/calendar-board/components/CalendarToolbar/index.d.ts +30 -0
  23. package/es/modules/calendar-board/components/CalendarToolbar/index.js +30 -0
  24. package/es/modules/calendar-board/components/CalendarToolbar/index.js.map +1 -0
  25. package/es/modules/calendar-board/components/CalendarUpcomingBar/index.d.ts +30 -0
  26. package/es/modules/calendar-board/components/CalendarUpcomingBar/index.js +35 -0
  27. package/es/modules/calendar-board/components/CalendarUpcomingBar/index.js.map +1 -0
  28. package/es/modules/calendar-board/components/CalendarUpcomingEntry/index.d.ts +25 -0
  29. package/es/modules/calendar-board/components/CalendarUpcomingEntry/index.js +35 -0
  30. package/es/modules/calendar-board/components/CalendarUpcomingEntry/index.js.map +1 -0
  31. package/es/modules/calendar-board/components/CalendarViewFilter/index.d.ts +19 -0
  32. package/es/modules/calendar-board/components/CalendarViewFilter/index.js +29 -0
  33. package/es/modules/calendar-board/components/CalendarViewFilter/index.js.map +1 -0
  34. package/es/modules/calendar-board/components/CalendarViewSwitcher/index.d.ts +14 -0
  35. package/es/modules/calendar-board/components/CalendarViewSwitcher/index.js +15 -0
  36. package/es/modules/calendar-board/components/CalendarViewSwitcher/index.js.map +1 -0
  37. package/es/modules/calendar-board/event-meta.d.ts +262 -0
  38. package/es/modules/calendar-board/event-meta.js +329 -0
  39. package/es/modules/calendar-board/event-meta.js.map +1 -0
  40. package/es/modules/calendar-board/layout.d.ts +27 -0
  41. package/es/modules/calendar-board/layout.js +20 -0
  42. package/es/modules/calendar-board/layout.js.map +1 -0
  43. package/es/modules/calendar-board/pages/CalendarBoard/index.css +262 -0
  44. package/es/modules/calendar-board/pages/CalendarBoard/index.d.ts +4 -0
  45. package/es/modules/calendar-board/pages/CalendarBoard/index.js +323 -0
  46. package/es/modules/calendar-board/pages/CalendarBoard/index.js.map +1 -0
  47. package/es/modules/calendar-board/pages/CalendarBoard/state.d.ts +112 -0
  48. package/es/modules/calendar-board/pages/CalendarBoard/state.js +206 -0
  49. package/es/modules/calendar-board/pages/CalendarBoard/state.js.map +1 -0
  50. package/es/modules/calendar-board/sidebar-data.d.ts +35 -0
  51. package/es/modules/calendar-board/sidebar-data.js +28 -0
  52. package/es/modules/calendar-board/sidebar-data.js.map +1 -0
  53. package/es/modules/meeting/components/NewMeetingForm/index.js +1 -1
  54. package/es/modules/meeting/components/NewMeetingForm/index.js.map +1 -1
  55. package/es/modules/project/ProjectDefaultView/index.js +2 -2
  56. package/es/modules/project/ProjectDefaultView/index.js.map +1 -1
  57. package/es/routes.js +2 -2
  58. package/es/routes.js.map +1 -1
  59. package/package.json +1 -1
  60. package/es/modules/calendar/CalendarRoutes.js.map +0 -1
  61. package/es/modules/calendar/components/ActionCard/index.d.ts +0 -7
  62. package/es/modules/calendar/components/ActionCard/index.js +0 -12
  63. package/es/modules/calendar/components/ActionCard/index.js.map +0 -1
  64. package/es/modules/calendar/components/CalendarEventContent/index.d.ts +0 -11
  65. package/es/modules/calendar/components/CalendarEventContent/index.js +0 -10
  66. package/es/modules/calendar/components/CalendarEventContent/index.js.map +0 -1
  67. package/es/modules/calendar/components/CalendarMenu/index.css +0 -30
  68. package/es/modules/calendar/components/CalendarMenu/index.d.ts +0 -7
  69. package/es/modules/calendar/components/CalendarMenu/index.js +0 -52
  70. package/es/modules/calendar/components/CalendarMenu/index.js.map +0 -1
  71. package/es/modules/calendar/pages/CalendarMonth/index.css +0 -248
  72. package/es/modules/calendar/pages/CalendarMonth/index.d.ts +0 -4
  73. package/es/modules/calendar/pages/CalendarMonth/index.js +0 -190
  74. package/es/modules/calendar/pages/CalendarMonth/index.js.map +0 -1
  75. package/es/modules/calendar/pages/CalendarMonth/state.d.ts +0 -11
  76. package/es/modules/calendar/pages/CalendarMonth/state.js +0 -58
  77. package/es/modules/calendar/pages/CalendarMonth/state.js.map +0 -1
  78. package/es/modules/my-document/SectionTemplate/documentGroups.test.d.ts +0 -1
  79. package/es/modules/my-document/SectionTemplate/documentGroups.test.js +0 -63
  80. package/es/modules/my-document/SectionTemplate/documentGroups.test.js.map +0 -1
@@ -1,6 +1,7 @@
1
1
  import React from "react";
2
2
  declare const RouteList: {
3
- CalendarMonth: {
3
+ CalendarBoard: {
4
+ /** 沿用原来的 /calendar 路由,由本模块接管 */
4
5
  route: string;
5
6
  tabPattern: RegExp;
6
7
  getUrl: () => string;
@@ -2,26 +2,27 @@ import React, { Suspense, lazy } from "react";
2
2
  import { Route, Routes } from "react-router-dom";
3
3
  import { BaseRoutes } from "@voplus/morpho-data";
4
4
  import { Skeleton } from "antd";
5
- const CalendarMonth = lazy(() => import("./pages/CalendarMonth"));
6
- const CalendarRoutes = () => {
5
+ const CalendarBoard = lazy(() => import("./pages/CalendarBoard"));
6
+ const CalendarBoardRoutes = () => {
7
7
  return (React.createElement(Suspense, { fallback: React.createElement(Skeleton, null) },
8
8
  React.createElement(Routes, null,
9
- React.createElement(Route, { path: RouteList.CalendarMonth.route, element: RouteList.CalendarMonth.component }))));
9
+ React.createElement(Route, { path: RouteList.CalendarBoard.route, element: RouteList.CalendarBoard.component }))));
10
10
  };
11
11
  const RouteList = {
12
- CalendarMonth: {
12
+ CalendarBoard: {
13
+ /** 沿用原来的 /calendar 路由,由本模块接管 */
13
14
  route: "/calendar",
14
15
  tabPattern: RegExp("/calendar"),
15
16
  getUrl: () => `/calendar`,
16
- component: React.createElement(CalendarMonth, null),
17
+ component: React.createElement(CalendarBoard, null),
17
18
  },
18
19
  addRoutes: () => {
19
20
  BaseRoutes.routes.push({
20
- name: "calendar-month",
21
- tabBasePattern: RouteList.CalendarMonth.tabPattern,
22
- component: React.createElement(CalendarRoutes, null),
21
+ name: "calendar-board",
22
+ tabBasePattern: RouteList.CalendarBoard.tabPattern,
23
+ component: React.createElement(CalendarBoardRoutes, null),
23
24
  });
24
25
  },
25
26
  };
26
27
  export default RouteList;
27
- //# sourceMappingURL=CalendarRoutes.js.map
28
+ //# sourceMappingURL=CalendarBoardRoutes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CalendarBoardRoutes.js","sourceRoot":"","sources":["../../../src/modules/calendar-board/CalendarBoardRoutes.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAEhC,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC,CAAC;AAElE,MAAM,mBAAmB,GAAG,GAAG,EAAE;IAChC,OAAO,CACN,oBAAC,QAAQ,IAAC,QAAQ,EAAE,oBAAC,QAAQ,OAAG;QAC/B,oBAAC,MAAM;YACN,oBAAC,KAAK,IAAC,IAAI,EAAE,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,aAAa,CAAC,SAAS,GAAI,CAClF,CACC,CACX,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,SAAS,GAAG;IACjB,aAAa,EAAE;QACd,gCAAgC;QAChC,KAAK,EAAE,WAAW;QAClB,UAAU,EAAE,MAAM,CAAC,WAAW,CAAC;QAC/B,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW;QACzB,SAAS,EAAE,oBAAC,aAAa,OAAG;KAC5B;IACD,SAAS,EAAE,GAAG,EAAE;QACf,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC;YACtB,IAAI,EAAE,gBAAgB;YACtB,cAAc,EAAE,SAAS,CAAC,aAAa,CAAC,UAAU;YAClD,SAAS,EAAE,oBAAC,mBAAmB,OAAG;SAClC,CAAC,CAAC;IACJ,CAAC;CACD,CAAC;AAEF,eAAe,SAAS,CAAC"}
@@ -0,0 +1,20 @@
1
+ import React from "react";
2
+ /**
3
+ * Action 事件在右侧属性面板里的内容。
4
+ *
5
+ * 为什么不能直接用 <NodePropertiesView>:后者按 `DocumentMetaStore.getMeta(node.type)` 派发,
6
+ * 而 DocumentMetaStore 只注册了 Board / WorkScheduleNode / Meeting / MeetingsFolder / Work /
7
+ * Task / WorkType,没有 "Action"(Action 的 meta 在另一个 store:ActionMetaStore)。
8
+ * 把 Action 的 node 递进去会落到 `DefaultDocumentTypeMeta`,拿 Action 的 id 去渲染通用文档
9
+ * 属性视图 —— 那个视图会去加载一个并不存在的文档。
10
+ *
11
+ * 所以这里自己调 action 的加载入口 `useAction`:一是让内部的 ActionHeader 拿到已加载的 action,
12
+ * 二是借它的 `onError` 接住加载失败 —— 失败时只给错误提示,不渲染半个属性视图。
13
+ *
14
+ * 换一条 Action 请由调用方给 `key`(见页面的 openSource):error 是组件内状态,
15
+ * 不重挂的话上一条的报错会留在面板上。
16
+ */
17
+ declare const CalendarActionProperties: (props: {
18
+ id: string;
19
+ }) => React.JSX.Element;
20
+ export default CalendarActionProperties;
@@ -0,0 +1,36 @@
1
+ import React, { lazy, Suspense, useState } from "react";
2
+ import { Alert } from "antd";
3
+ import { useAction } from "@voplus/morpho-collaboration-action/es/data";
4
+ /**
5
+ * Action 的属性视图按需加载。
6
+ *
7
+ * 它连同 morpho-collaboration-action 的那一整条依赖,只有真的点开 Action 事件时才需要,
8
+ * 不该跟着日历页进首屏 chunk。
9
+ */
10
+ const ActionPropertiesView = lazy(() => import("@voplus/morpho-collaboration-action/es/components/FollowupAction/PropertiesView"));
11
+ /**
12
+ * Action 事件在右侧属性面板里的内容。
13
+ *
14
+ * 为什么不能直接用 <NodePropertiesView>:后者按 `DocumentMetaStore.getMeta(node.type)` 派发,
15
+ * 而 DocumentMetaStore 只注册了 Board / WorkScheduleNode / Meeting / MeetingsFolder / Work /
16
+ * Task / WorkType,没有 "Action"(Action 的 meta 在另一个 store:ActionMetaStore)。
17
+ * 把 Action 的 node 递进去会落到 `DefaultDocumentTypeMeta`,拿 Action 的 id 去渲染通用文档
18
+ * 属性视图 —— 那个视图会去加载一个并不存在的文档。
19
+ *
20
+ * 所以这里自己调 action 的加载入口 `useAction`:一是让内部的 ActionHeader 拿到已加载的 action,
21
+ * 二是借它的 `onError` 接住加载失败 —— 失败时只给错误提示,不渲染半个属性视图。
22
+ *
23
+ * 换一条 Action 请由调用方给 `key`(见页面的 openSource):error 是组件内状态,
24
+ * 不重挂的话上一条的报错会留在面板上。
25
+ */
26
+ const CalendarActionProperties = (props) => {
27
+ const [error, setError] = useState();
28
+ useAction(props.id, { onError: setError });
29
+ if (error) {
30
+ return (React.createElement(Alert, { type: "error", showIcon: true, message: "Unable to load event", description: error.message }));
31
+ }
32
+ return (React.createElement(Suspense, { fallback: null },
33
+ React.createElement(ActionPropertiesView, { id: props.id })));
34
+ };
35
+ export default CalendarActionProperties;
36
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/modules/calendar-board/components/CalendarActionProperties/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,6CAA6C,CAAC;AAExE;;;;;GAKG;AACH,MAAM,oBAAoB,GAAG,IAAI,CAChC,GAAG,EAAE,CAAC,MAAM,CAAC,iFAAiF,CAAC,CAC/F,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,MAAM,wBAAwB,GAAG,CAAC,KAAqB,EAAE,EAAE;IAC1D,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,EAAS,CAAC;IAC5C,SAAS,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;IAE3C,IAAI,KAAK,EAAE,CAAC;QACX,OAAO,CACN,oBAAC,KAAK,IAAC,IAAI,EAAC,OAAO,EAAC,QAAQ,QAAC,OAAO,EAAC,sBAAsB,EAAC,WAAW,EAAE,KAAK,CAAC,OAAO,GAAI,CAC1F,CAAC;IACH,CAAC;IAED,OAAO,CACN,oBAAC,QAAQ,IAAC,QAAQ,EAAE,IAAI;QACvB,oBAAC,oBAAoB,IAAC,EAAE,EAAE,KAAK,CAAC,EAAE,GAAI,CAC5B,CACX,CAAC;AACH,CAAC,CAAC;AAEF,eAAe,wBAAwB,CAAC"}
@@ -0,0 +1,45 @@
1
+ import React from "react";
2
+ import { type CalendarBoardEvent, type CalendarBoardSource, type CategoryColor } from "../../event-meta";
3
+ import { type CalendarViewType } from "../../pages/CalendarBoard/state";
4
+ /**
5
+ * 一个日期格最多显示几条事件,其余收进 +N 徽标。
6
+ *
7
+ * 用 dayMaxEvents(事件数)而不是 dayMaxEventRows(行数):
8
+ * 后者会把 +N 自己算进预算,传 2 实际只显示 1 张卡 —— 实测
9
+ * rows:2 → 1 卡 +4;rows:3 → 2 卡 +3;events:2 → 2 卡 +3;events:3 → 3 卡 +2。
10
+ * 需求是「每格最多两条内容」,所以用事件数语义,改卡片高度也不会让条数漂移。
11
+ */
12
+ export declare const DAY_MAX_EVENTS = 2;
13
+ /**
14
+ * 日历网格:页面的日历区块,也是 Storybook 里免后端看设计稿的入口。
15
+ *
16
+ * 数据、配色、回调全部由外部传入,组件自己不碰 store / 路由 / 侧栏,
17
+ * 因此页面传真实数据、story 传静态数据即可,两边共用同一份皮肤与视图配置。
18
+ *
19
+ * `calendar-board` 类提供 --fc-* 皮肤变量(见 pages/CalendarBoard/index.css),
20
+ * 单独渲染时同样拿得到。
21
+ */
22
+ declare const CalendarBoardGrid: (props: {
23
+ events: CalendarBoardEvent[];
24
+ /**
25
+ * 打开时用哪个视图。
26
+ *
27
+ * 只作用于挂载:之后的切换由调用方通过 calendarRef 调 changeView
28
+ * (页面就是这么做的)。卡片是否多渲染时间行不依赖它,
29
+ * 而是看 FullCalendar 实际给出的 info.view.type —— 那样永远和当前视图一致。
30
+ */
31
+ initialView: CalendarViewType;
32
+ /** 事件分类 → 颜色的稳定映射(来自 summarizeEvents) */
33
+ colorMap: Map<string, CategoryColor>;
34
+ /** 打开时定位到哪一天,默认今天(页面用默认值;固定日期的 story / 测试显式传入) */
35
+ initialDate?: string | Date;
36
+ /** FullCalendar 实例 ref:页面用它调用 today / prev / next / changeView */
37
+ calendarRef?: React.Ref<any>;
38
+ /** 点击事件卡(页面用它打开右侧属性面板) */
39
+ onSelectEvent?: (source?: CalendarBoardSource) => void;
40
+ /** 拖动结束后触发(页面用它调用 CalendarStore.edit) */
41
+ onEventDrop?: (info: any) => void;
42
+ /** 呈现一组新日期时触发(页面用它同步标题) */
43
+ onDatesSet?: (info: any) => void;
44
+ }) => React.JSX.Element;
45
+ export default CalendarBoardGrid;
@@ -0,0 +1,89 @@
1
+ import React, { useEffect, useMemo, useRef } from "react";
2
+ import FullCalendar from "@fullcalendar/react";
3
+ import dayGridPlugin from "@fullcalendar/daygrid";
4
+ import timeGridPlugin from "@fullcalendar/timegrid";
5
+ import interactionPlugin from "@fullcalendar/interaction";
6
+ import CalendarEventChip from "../CalendarEventChip";
7
+ import CalendarMoreLink from "../CalendarMoreLink";
8
+ import { DEFAULT_CATEGORY_TYPE, resolveEventColor, } from "../../event-meta";
9
+ import { FULL_CALENDAR_VIEW, FULL_CALENDAR_VIEW_OPTIONS, } from "../../pages/CalendarBoard/state";
10
+ /**
11
+ * 一个日期格最多显示几条事件,其余收进 +N 徽标。
12
+ *
13
+ * 用 dayMaxEvents(事件数)而不是 dayMaxEventRows(行数):
14
+ * 后者会把 +N 自己算进预算,传 2 实际只显示 1 张卡 —— 实测
15
+ * rows:2 → 1 卡 +4;rows:3 → 2 卡 +3;events:2 → 2 卡 +3;events:3 → 3 卡 +2。
16
+ * 需求是「每格最多两条内容」,所以用事件数语义,改卡片高度也不会让条数漂移。
17
+ */
18
+ export const DAY_MAX_EVENTS = 2;
19
+ /**
20
+ * 日历网格:页面的日历区块,也是 Storybook 里免后端看设计稿的入口。
21
+ *
22
+ * 数据、配色、回调全部由外部传入,组件自己不碰 store / 路由 / 侧栏,
23
+ * 因此页面传真实数据、story 传静态数据即可,两边共用同一份皮肤与视图配置。
24
+ *
25
+ * `calendar-board` 类提供 --fc-* 皮肤变量(见 pages/CalendarBoard/index.css),
26
+ * 单独渲染时同样拿得到。
27
+ */
28
+ const CalendarBoardGrid = (props) => {
29
+ /**
30
+ * 渲染事件:设计稿的描边大写卡片;日视图额外带上时间范围。
31
+ *
32
+ * 取色走 resolveEventColor:固定分类(Task / Case / Work)用分类原色,
33
+ * 其余一切都用中性灰 —— 与图例的 Others 圆点同一个色。
34
+ */
35
+ const renderEventContent = (info) => {
36
+ const source = info.event.extendedProps?.source;
37
+ return (React.createElement(CalendarEventChip, { title: info.event.title, color: resolveEventColor(props.colorMap, source?.type || DEFAULT_CATEGORY_TYPE), timeText: info.view.type === FULL_CALENDAR_VIEW.day ? info.timeText : undefined, onClick: () => props.onSelectEvent?.(source) }));
38
+ };
39
+ /**
40
+ * eventSources:外层数组一并 memo 掉。
41
+ *
42
+ * 实测决定会不会重置事件源的是**内层 events 数组的引用**(引用变了就用内容覆盖内部状态,
43
+ * 刚拖出去的事件会被打回原位;引用没变则不动),这一条由页面的 state.sidebarData
44
+ * 这个 computed 保证。外层这里顺手 memo,免得依赖 FullCalendar 内部的比较细节。
45
+ */
46
+ const eventSources = useMemo(() => [props.events], [props.events]);
47
+ /** 日历本体元素:既拿来观察尺寸,也是 updateSize 要重算的那个盒子 */
48
+ const containerRef = useRef(null);
49
+ /**
50
+ * 容器尺寸变化 → 让 FullCalendar 重算尺寸。
51
+ *
52
+ * 必须有这一步:FullCalendar 只在 **window resize** 与组件 props 变化时重算
53
+ * (@fullcalendar/core 的 handleWindowResize、@fullcalendar/react 的 componentDidUpdate),
54
+ * 它自己不观察容器。打开右侧属性面板时,AsideContent 会把这块压缩
55
+ * (.asideContent > div 是 flex:1),而 window 尺寸没变 —— 表格宽度停在打开前的像素值,
56
+ * 右侧的列与卡片就被本层与 AsideContent 的 overflow:hidden 裁掉了。
57
+ *
58
+ * 只认宽度:面板滑出只改宽度,高度变化(窗口纵向缩放)FullCalendar 自己会处理,
59
+ * 免得每次高度抖动都白算一遍。
60
+ */
61
+ useEffect(() => {
62
+ const element = containerRef.current;
63
+ // 只依赖 jsdom 里可能缺席的 API:没有 ResizeObserver 时保持旧行为(挂载时算一次)
64
+ if (!element || typeof ResizeObserver === "undefined")
65
+ return;
66
+ // calendarRef 声明成 Ref<any>(页面的 createRef、story/测试也这么传),
67
+ // 可能是回调 ref —— 只处理对象 ref,回调 ref 拿不到实例
68
+ const calendarRef = props.calendarRef;
69
+ if (!calendarRef || typeof calendarRef === "function")
70
+ return;
71
+ // 初值要与浏览器给的 contentRect.width 同口径(jsdom 不做布局,测试里显式给定)
72
+ let width = element.getBoundingClientRect().width;
73
+ const observer = new ResizeObserver((entries) => {
74
+ const next = entries[entries.length - 1]?.contentRect?.width;
75
+ if (next === undefined || next === width)
76
+ return;
77
+ width = next;
78
+ calendarRef.current?.getApi()?.updateSize();
79
+ });
80
+ observer.observe(element);
81
+ return () => observer.disconnect();
82
+ }, [props.calendarRef]);
83
+ return (React.createElement("div", { ref: containerRef, className: "calendar-board flex-1 min-w-0 overflow-hidden" },
84
+ React.createElement(FullCalendar, { ref: props.calendarRef, plugins: [interactionPlugin, dayGridPlugin, timeGridPlugin], editable: true, dayMaxEvents: DAY_MAX_EVENTS, headerToolbar: false, height: "100%", nowIndicator: true, initialView: FULL_CALENDAR_VIEW[props.initialView], initialDate: props.initialDate,
85
+ /** 月视图 / 周视图 / 日视图均由已装的 daygrid、timegrid 插件提供 */
86
+ views: FULL_CALENDAR_VIEW_OPTIONS, eventSources: eventSources, eventDrop: props.onEventDrop, eventContent: renderEventContent, moreLinkContent: (info) => React.createElement(CalendarMoreLink, { count: info.num }), datesSet: props.onDatesSet })));
87
+ };
88
+ export default CalendarBoardGrid;
89
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/modules/calendar-board/components/CalendarBoardGrid/index.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import React from "react";
2
+ import { type CategoryColor } from "../../event-meta";
3
+ /**
4
+ * 事件卡:设计稿里描边 + 浅底 + 大写标题的小卡片。
5
+ *
6
+ * 月 / 周视图只显示标题;日视图由 FullCalendar 额外给出 timeText,
7
+ * 于是多渲染一行时间文案(对应日历稿里的 `10AM-10:30AM`)。
8
+ *
9
+ * `calendar-event-chip` 是给 index.css 用的稳定钩子:日视图要把卡片撑满
10
+ * FullCalendar 按事件时长算出的定位盒子(见 index.css)。
11
+ *
12
+ * 只负责「长什么样」——点击后打开属性面板的逻辑留在页面里
13
+ * (页面把节点的 source 交给 morpho-document-core 的 NodePropertiesView)。
14
+ */
15
+ declare const CalendarEventChip: (props: {
16
+ title: string;
17
+ color: CategoryColor;
18
+ /** 日视图的时间范围文案;月 / 周视图不传 */
19
+ timeText?: string;
20
+ onClick?: () => void;
21
+ }) => React.JSX.Element;
22
+ export default CalendarEventChip;
@@ -0,0 +1,20 @@
1
+ import React from "react";
2
+ import classnames from "classnames";
3
+ import { CHIP_BASE_CLASS, CHIP_COLOR_CLASS, CHIP_TIME_CLASS, } from "../../event-meta";
4
+ /**
5
+ * 事件卡:设计稿里描边 + 浅底 + 大写标题的小卡片。
6
+ *
7
+ * 月 / 周视图只显示标题;日视图由 FullCalendar 额外给出 timeText,
8
+ * 于是多渲染一行时间文案(对应日历稿里的 `10AM-10:30AM`)。
9
+ *
10
+ * `calendar-event-chip` 是给 index.css 用的稳定钩子:日视图要把卡片撑满
11
+ * FullCalendar 按事件时长算出的定位盒子(见 index.css)。
12
+ *
13
+ * 只负责「长什么样」——点击后打开属性面板的逻辑留在页面里
14
+ * (页面把节点的 source 交给 morpho-document-core 的 NodePropertiesView)。
15
+ */
16
+ const CalendarEventChip = (props) => (React.createElement("div", { className: classnames("calendar-event-chip", CHIP_BASE_CLASS, CHIP_COLOR_CLASS[props.color]), title: props.title, onClick: props.onClick },
17
+ React.createElement("div", { className: "truncate" }, props.title),
18
+ props.timeText ? (React.createElement("div", { className: classnames("truncate font-normal normal-case", CHIP_TIME_CLASS[props.color]) }, props.timeText)) : null));
19
+ export default CalendarEventChip;
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/modules/calendar-board/components/CalendarEventChip/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,EACN,eAAe,EACf,gBAAgB,EAChB,eAAe,GAEf,MAAM,kBAAkB,CAAC;AAE1B;;;;;;;;;;;GAWG;AACH,MAAM,iBAAiB,GAAG,CAAC,KAM1B,EAAE,EAAE,CAAC,CACL,6BACC,SAAS,EAAE,UAAU,CAAC,qBAAqB,EAAE,eAAe,EAAE,gBAAgB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAC5F,KAAK,EAAE,KAAK,CAAC,KAAK,EAClB,OAAO,EAAE,KAAK,CAAC,OAAO;IAEtB,6BAAK,SAAS,EAAC,UAAU,IAAE,KAAK,CAAC,KAAK,CAAO;IAC5C,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CACjB,6BAAK,SAAS,EAAE,UAAU,CAAC,kCAAkC,EAAE,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAC1F,KAAK,CAAC,QAAQ,CACV,CACN,CAAC,CAAC,CAAC,IAAI,CACH,CACN,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
@@ -0,0 +1,42 @@
1
+ import React from "react";
2
+ import { type CalendarBoardSource, type ICategorySummary } from "../../event-meta";
3
+ /** 设计稿里浮层的总高上限:max-h-72 = 288px */
4
+ export declare const POPOVER_MAX_HEIGHT = 288;
5
+ /** 标题行固定高度(h-11 = 44px)+ 1px 分隔线,列表的可滚动高度由它反推 */
6
+ export declare const POPOVER_HEADER_HEIGHT = 45;
7
+ /**
8
+ * 列表的滚动高度上限。
9
+ *
10
+ * 浮层整体对齐设计稿的 max-h-72:标题行钉死高度,剩下的才给列表。
11
+ * 钉死标题行是必要的 —— 否则列表的封顶值没有确定依据(内容驱动的高度里,
12
+ * Scrollbars 的 autoHeightMax 必须是一个确定的像素值)。
13
+ */
14
+ export declare const POPOVER_LIST_MAX_HEIGHT: number;
15
+ /**
16
+ * 事件分类图例行。
17
+ *
18
+ * 对应设计稿的 `5 Meetings / 3 Deadlines / ...`:圆点用分类原色,
19
+ * 文案与底色走 morpho-theme token(bg-table / border / font-primary)。
20
+ * 数据来自 summarizeEvents(全部事件),因此不会随搜索或隐藏分类跳动。
21
+ *
22
+ * 展示的项**不**跟着数据长:固定 3 项 Task / Case / Work(没有事件也占位,计数 0)
23
+ * 加一项 Others,其余分类的事件全部收进 Others —— 折叠规则见 buildLegendCategories。
24
+ * 因此图例的行数、顺序恒定,只有数字和浮层内容随数据变化。
25
+ *
26
+ * 每一项 hover 出该项的事件列表(见 CategoryPopover),列表与图例上的数字同源,
27
+ * 所以「数字」和「浮层里的条数」永远一致。0 计数的固定项不挂浮层:没有内容可看,
28
+ * 挂上去只会弹一个空浮层。
29
+ *
30
+ * 点击浮层里的条目把事件的 source 交回调用方(onSelectEvent),组件本身只是转交 ——
31
+ * 页面拿它去打开属性面板,与事件卡 / 侧栏 UPCOMING 走同一个 openSource。
32
+ * 点完顺手把浮层收起来:点击时鼠标正停在浮层上,不关的话它会一直挂在属性面板前面。
33
+ *
34
+ * 为此 open 改成受控(state 里放当前展开的分类 type):
35
+ * hover 的开关仍然由 antd 触发,onOpenChange 原样写回 state,鼠标移入移出的行为不变;
36
+ * 一个 state 管所有分类,hover 到另一项时前一个自然收起。
37
+ */
38
+ declare const CalendarLegend: (props: {
39
+ categories: ICategorySummary[];
40
+ onSelectEvent?: (source?: CalendarBoardSource) => void;
41
+ }) => React.JSX.Element;
42
+ export default CalendarLegend;
@@ -0,0 +1,94 @@
1
+ import React, { useState } from "react";
2
+ import classnames from "classnames";
3
+ import { Popover } from "antd";
4
+ import { Scrollbars } from "react-custom-scrollbars-2";
5
+ import { buildLegendCategories, formatEventDate, getEventTitle, } from "../../event-meta";
6
+ /**
7
+ * 去掉 antd Popover 自带的内边距,让浮层内容自己贴边(设计稿的浮层是「通栏标题 + 列表」,
8
+ * 没有外层内边距)。antd 6 的内边距落在 .ant-popover-container / .ant-popover-content 上,
9
+ * 用尾置 `!` 提高优先级,避免依赖它们的样式注入顺序。
10
+ */
11
+ const POPOVER_CLASS = "[&_.ant-popover-container]:p-0! [&_.ant-popover-container]:overflow-hidden [&_.ant-popover-container]:border [&_.ant-popover-container]:border-border [&_.ant-popover-content]:p-0!";
12
+ /** 设计稿里浮层的总高上限:max-h-72 = 288px */
13
+ export const POPOVER_MAX_HEIGHT = 288;
14
+ /** 标题行固定高度(h-11 = 44px)+ 1px 分隔线,列表的可滚动高度由它反推 */
15
+ export const POPOVER_HEADER_HEIGHT = 45;
16
+ /**
17
+ * 列表的滚动高度上限。
18
+ *
19
+ * 浮层整体对齐设计稿的 max-h-72:标题行钉死高度,剩下的才给列表。
20
+ * 钉死标题行是必要的 —— 否则列表的封顶值没有确定依据(内容驱动的高度里,
21
+ * Scrollbars 的 autoHeightMax 必须是一个确定的像素值)。
22
+ */
23
+ export const POPOVER_LIST_MAX_HEIGHT = POPOVER_MAX_HEIGHT - POPOVER_HEADER_HEIGHT;
24
+ /**
25
+ * 图例 hover 出来的分类浮层。
26
+ *
27
+ * 照 calendar-recreation.html 里那个 popover 来:
28
+ * 通栏标题(分类圆点 + 大写分类名,浅底、贴顶)+ 可滚动的条目列表,
29
+ * 每条左侧标题、右侧日期(弱化色)。
30
+ *
31
+ * 圆点直接用 item.dotClass(在 buildLegendCategories 里定好):Others 是聚合项,
32
+ * 没有分类原色可给,颜色不该由这里再猜一次。
33
+ *
34
+ * 列表用 Scrollbars 而不是 overflow-y-auto:浮层是「内容撑高、超过上限才滚」,
35
+ * 所以走 autoHeight + autoHeightMax —— 这种模式下容器与滚动视图都带 max-height,
36
+ * 内容短时按内容高、超长时内部滚动,正好对应设计稿的 max-h-72。
37
+ *
38
+ * 条目可点击:点击把该条事件自己的 source 交回调用方(onSelectEvent),
39
+ * 与事件卡 / 侧栏 UPCOMING 条目同一个入口 —— 三个地方都由页面打开右侧属性面板。
40
+ */
41
+ const CategoryPopover = (props) => {
42
+ const { category, onSelectEvent } = props;
43
+ return (React.createElement("div", { className: "flex w-64 flex-col bg-bg-white" },
44
+ React.createElement("div", { className: "flex items-center gap-2 px-4 h-11 shrink-0 border-b border-border bg-bg-table" },
45
+ React.createElement("span", { className: classnames("w-2 h-2 rounded-full inline-block shrink-0", category.dotClass) }),
46
+ React.createElement("span", { className: "text-xs font-bold uppercase tracking-wide text-font-primary truncate" }, category.type)),
47
+ React.createElement(Scrollbars, { autoHide: true, autoHeight: true, autoHeightMin: 0, autoHeightMax: POPOVER_LIST_MAX_HEIGHT, className: "calendar-legend-popover-list" },
48
+ React.createElement("ul", { className: "text-sm text-font-primary" }, category.events.map((event) => (React.createElement("li", { key: event.id, className: "flex items-center justify-between gap-3 px-4 py-2.5 cursor-pointer", onClick: () => onSelectEvent?.(event.source) },
49
+ React.createElement("span", { className: "truncate" }, getEventTitle(event)),
50
+ React.createElement("span", { className: "text-font-grey shrink-0" }, formatEventDate(event)))))))));
51
+ };
52
+ /**
53
+ * 事件分类图例行。
54
+ *
55
+ * 对应设计稿的 `5 Meetings / 3 Deadlines / ...`:圆点用分类原色,
56
+ * 文案与底色走 morpho-theme token(bg-table / border / font-primary)。
57
+ * 数据来自 summarizeEvents(全部事件),因此不会随搜索或隐藏分类跳动。
58
+ *
59
+ * 展示的项**不**跟着数据长:固定 3 项 Task / Case / Work(没有事件也占位,计数 0)
60
+ * 加一项 Others,其余分类的事件全部收进 Others —— 折叠规则见 buildLegendCategories。
61
+ * 因此图例的行数、顺序恒定,只有数字和浮层内容随数据变化。
62
+ *
63
+ * 每一项 hover 出该项的事件列表(见 CategoryPopover),列表与图例上的数字同源,
64
+ * 所以「数字」和「浮层里的条数」永远一致。0 计数的固定项不挂浮层:没有内容可看,
65
+ * 挂上去只会弹一个空浮层。
66
+ *
67
+ * 点击浮层里的条目把事件的 source 交回调用方(onSelectEvent),组件本身只是转交 ——
68
+ * 页面拿它去打开属性面板,与事件卡 / 侧栏 UPCOMING 走同一个 openSource。
69
+ * 点完顺手把浮层收起来:点击时鼠标正停在浮层上,不关的话它会一直挂在属性面板前面。
70
+ *
71
+ * 为此 open 改成受控(state 里放当前展开的分类 type):
72
+ * hover 的开关仍然由 antd 触发,onOpenChange 原样写回 state,鼠标移入移出的行为不变;
73
+ * 一个 state 管所有分类,hover 到另一项时前一个自然收起。
74
+ */
75
+ const CalendarLegend = (props) => {
76
+ const [openType, setOpenType] = useState();
77
+ /** 条目点击:先关浮层,再把 source 原样交给调用方(关闭不能把这次点击吞掉) */
78
+ const handleSelectEvent = (source) => {
79
+ setOpenType(undefined);
80
+ props.onSelectEvent?.(source);
81
+ };
82
+ return (React.createElement("div", { className: "flex items-center gap-6 px-6 h-[60px] text-sm text-font-primary font-medium flex-wrap border-t border-b border-border bg-bg-table" }, buildLegendCategories(props.categories).map((item) => {
83
+ const label = (React.createElement("span", { key: item.type, className: classnames("flex items-center gap-1", item.count > 0 ? "cursor-pointer" : "cursor-default") },
84
+ React.createElement("span", { className: classnames("w-2 h-2 rounded-full inline-block mr-0.5", item.dotClass) }),
85
+ React.createElement("span", { className: "font-bold" }, item.count),
86
+ item.type));
87
+ // 0 计数没有内容可看,只作占位
88
+ if (item.count === 0)
89
+ return label;
90
+ return (React.createElement(Popover, { key: item.type, placement: "bottomLeft", arrow: false, classNames: { root: POPOVER_CLASS }, open: openType === item.type, onOpenChange: (open) => setOpenType(open ? item.type : undefined), content: React.createElement(CategoryPopover, { category: item, onSelectEvent: handleSelectEvent }) }, label));
91
+ })));
92
+ };
93
+ export default CalendarLegend;
94
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/modules/calendar-board/components/CalendarLegend/index.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import React from "react";
2
+ /**
3
+ * 月 / 周视图里「放不下的还有 N 条」徽标。
4
+ *
5
+ * 通过 FullCalendar 的 moreLinkContent 渲染,结构色走 morpho-theme token,
6
+ * 对应设计稿的 `bg-slate-100 text-slate-500 text-[10px] font-bold rounded-md`。
7
+ */
8
+ declare const CalendarMoreLink: (props: {
9
+ count: number;
10
+ }) => React.JSX.Element;
11
+ export default CalendarMoreLink;
@@ -0,0 +1,12 @@
1
+ import React from "react";
2
+ /**
3
+ * 月 / 周视图里「放不下的还有 N 条」徽标。
4
+ *
5
+ * 通过 FullCalendar 的 moreLinkContent 渲染,结构色走 morpho-theme token,
6
+ * 对应设计稿的 `bg-slate-100 text-slate-500 text-[10px] font-bold rounded-md`。
7
+ */
8
+ const CalendarMoreLink = (props) => (React.createElement("div", { className: "border border-border bg-bg-grey text-font-grey text-2xs font-bold rounded-base px-2 py-0.5 mr-0.5 cursor-pointer" },
9
+ "+",
10
+ props.count));
11
+ export default CalendarMoreLink;
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/modules/calendar-board/components/CalendarMoreLink/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;;;GAKG;AACH,MAAM,gBAAgB,GAAG,CAAC,KAAwB,EAAE,EAAE,CAAC,CACtD,6BAAK,SAAS,EAAC,kHAAkH;;IAC9H,KAAK,CAAC,KAAK,CACR,CACN,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
@@ -0,0 +1,34 @@
1
+ import React from "react";
2
+ import { type CalendarBoardSource, type IUpcomingEvent } from "../../event-meta";
3
+ import type { CalendarSidebarTab } from "../../pages/CalendarBoard/state";
4
+ /**
5
+ * 右侧栏:Search / UPCOMING·ACTIVITY / UPCOMING DEADLINES。
6
+ *
7
+ * - 搜索是纯前端过滤(见 sidebar-data.ts),不触发重新请求
8
+ * - ACTIVITY 暂无数据源,先渲染空态并留 TODO
9
+ * - 分类列表(原来的 CATEGORIES 段与它的显示 / 隐藏开关)已从侧栏移除,
10
+ * 因此这里不再接收 categories / hiddenTypes / onToggleType
11
+ *
12
+ * 注:设计稿的 `hidden md:flex` 是整页 demo 的响应式写法;这里日历是嵌在工作区
13
+ * 面板里的,视口宽度不代表面板宽度,因此侧栏常驻显示。
14
+ *
15
+ * 布局用 flex 分两段,整栏本身不滚:
16
+ * 搜索 / 页签 —— shrink-0,固定在顶部
17
+ * UPCOMING·ACTIVITY —— flex-1 min-h-0,占满剩余高度,内部交给 Scrollbars 自己滚
18
+ */
19
+ declare const CalendarSidebar: (props: {
20
+ upcoming: IUpcomingEvent[];
21
+ search: string;
22
+ tab: CalendarSidebarTab;
23
+ onSearch: (value: string) => void;
24
+ onChangeTab: (tab: CalendarSidebarTab) => void;
25
+ onSelectEvent: (source?: CalendarBoardSource) => void;
26
+ /**
27
+ * 追加到 <aside> 的类名。
28
+ *
29
+ * 小屏把它放进 Modal 时用 `w-full! border-l-0!` 覆盖掉侧栏的固定宽度与左侧分隔线 ——
30
+ * 那些是「贴在日历右边」这个位置带来的样式,通栏展示时不成立。
31
+ */
32
+ className?: string;
33
+ }) => React.JSX.Element;
34
+ export default CalendarSidebar;
@@ -0,0 +1,45 @@
1
+ import React from "react";
2
+ import classnames from "classnames";
3
+ import { Empty } from "antd";
4
+ import { FontAwesomeIcon as FAIcon, faSearchRegular } from "@voplus/morpho-ui/es/faIcons";
5
+ import { Scrollbars } from "react-custom-scrollbars-2";
6
+ import { DOT_COLOR_CLASS } from "../../event-meta";
7
+ /**
8
+ * 右侧栏:Search / UPCOMING·ACTIVITY / UPCOMING DEADLINES。
9
+ *
10
+ * - 搜索是纯前端过滤(见 sidebar-data.ts),不触发重新请求
11
+ * - ACTIVITY 暂无数据源,先渲染空态并留 TODO
12
+ * - 分类列表(原来的 CATEGORIES 段与它的显示 / 隐藏开关)已从侧栏移除,
13
+ * 因此这里不再接收 categories / hiddenTypes / onToggleType
14
+ *
15
+ * 注:设计稿的 `hidden md:flex` 是整页 demo 的响应式写法;这里日历是嵌在工作区
16
+ * 面板里的,视口宽度不代表面板宽度,因此侧栏常驻显示。
17
+ *
18
+ * 布局用 flex 分两段,整栏本身不滚:
19
+ * 搜索 / 页签 —— shrink-0,固定在顶部
20
+ * UPCOMING·ACTIVITY —— flex-1 min-h-0,占满剩余高度,内部交给 Scrollbars 自己滚
21
+ */
22
+ const CalendarSidebar = (props) => (React.createElement("aside", { className: classnames("flex w-[280px] lg:w-[340px] shrink-0 flex-col border-l border-border overflow-hidden bg-bg-white", props.className) },
23
+ React.createElement("div", { className: "p-4 shrink-0" },
24
+ React.createElement("div", { className: "relative" },
25
+ React.createElement(FAIcon, { icon: faSearchRegular, className: "absolute left-3 top-1/2 -translate-y-1/2 text-font-grey" }),
26
+ React.createElement("input", { type: "text", value: props.search, placeholder: "Search in event ...", className: "w-full pl-9 pr-3 py-2 text-sm border border-border rounded-base text-font-primary placeholder:text-font-grey focus:outline-none", onChange: (ev) => props.onSearch(ev.target.value) }))),
27
+ React.createElement("div", { className: "flex items-center bg-bg-grey rounded-base px-[5px] py-[7px] mx-4 shrink-0 text-sm font-bold uppercase tracking-wide" }, [
28
+ { value: "upcoming", label: "UPCOMING" },
29
+ { value: "activity", label: "ACTIVITY" },
30
+ ].map((tab) => (React.createElement("button", { key: tab.value, className: classnames("flex-1 px-4 py-2 rounded-base cursor-pointer", tab.value === props.tab ? "bg-bg-white text-font-secondary shadow-sm" : "text-font-grey"), onClick: () => props.onChangeTab(tab.value) }, tab.label)))),
31
+ React.createElement("div", { className: "flex-1 min-h-0" },
32
+ React.createElement(Scrollbars, { autoHide: true, className: "calendar-sidebar-scroll" }, props.tab === "upcoming" ? (React.createElement("div", { className: "px-4 pt-4" },
33
+ React.createElement("div", { className: classnames("field-label mb-2") }, "UPCOMING DEADLINES"),
34
+ React.createElement("ul", { className: "flex flex-col gap-2.5 pb-4" },
35
+ props.upcoming.map((item) => (React.createElement("li", { key: item.id, className: "flex items-start justify-between gap-2 cursor-pointer border border-border rounded-base p-3.5", onClick: () => props.onSelectEvent(item.source) },
36
+ React.createElement("div", { className: "flex items-start gap-2 min-w-0" },
37
+ React.createElement("span", { className: classnames("w-2 h-2 rounded-full mt-1.5 inline-block shrink-0", DOT_COLOR_CLASS[item.color]) }),
38
+ React.createElement("div", { className: "min-w-0" },
39
+ React.createElement("div", { className: "text-sm font-bold text-font-primary truncate" }, item.title),
40
+ React.createElement("div", { className: "text-sm font-semibold text-font-grey" }, item.timeLabel))),
41
+ React.createElement("span", { className: "text-sm font-semibold text-font-secondary shrink-0" }, item.remainingLabel)))),
42
+ props.upcoming.length === 0 && React.createElement(Empty, { image: Empty.PRESENTED_IMAGE_SIMPLE })))) : (React.createElement("div", { className: "px-4 pt-4 text-xs text-font-grey" },
43
+ React.createElement(Empty, { image: Empty.PRESENTED_IMAGE_SIMPLE })))))));
44
+ export default CalendarSidebar;
45
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/modules/calendar-board/components/CalendarSidebar/index.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import React from "react";
2
+ import type { CalendarViewType } from "../../pages/CalendarBoard/state";
3
+ /**
4
+ * 顶部工具栏:TODAY / ← 日期 → / 右侧控件区。
5
+ *
6
+ * FullCalendar 自带工具栏已由 headerToolbar={false} 关闭,这里完全自绘。
7
+ * 日期标题上盖一个透明的 DatePicker,沿用 CalendarMonth 的做法
8
+ * (点标题即可跳到某月 / 某周 / 某天)。
9
+ *
10
+ * 控件区(OwnerType 过滤器、视图切换)由页面通过 children 装配:桌面把 MONTH·WEEK·DAY
11
+ * 一起放进来,小屏则把视图切换收进 Filter 浮层、只留过滤器 —— 工具栏自己不认识视图切换,
12
+ * 因此也不接 onChangeType。
13
+ *
14
+ * 高度用 min-h 而不是固定 90px:小屏上 TODAY / 导航 / 控件区会换行,固定高度会把
15
+ * 换行出来的那一行裁掉。
16
+ */
17
+ declare const CalendarToolbar: (props: {
18
+ /** 只用于标题上那个 DatePicker 的粒度(month / week / date) */
19
+ type: CalendarViewType;
20
+ title?: string;
21
+ /** DatePicker 的受控值 */
22
+ currentTime?: any;
23
+ onToday: () => void;
24
+ onPrev: () => void;
25
+ onNext: () => void;
26
+ onChangeDate: (date: any, dateString: string | string[] | null) => void;
27
+ /** 右侧控件区(页面装配:过滤器 + 桌面的视图切换) */
28
+ children?: React.ReactNode;
29
+ }) => React.JSX.Element;
30
+ export default CalendarToolbar;