@voplus/morpho-workspace 11.2.3 → 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 (94) hide show
  1. package/es/Modules.js +2 -0
  2. package/es/Modules.js.map +1 -1
  3. package/es/data/worktype/metas.d.ts +12 -0
  4. package/es/data/worktype/metas.js +23 -0
  5. package/es/data/worktype/metas.js.map +1 -0
  6. package/es/modules/{calendar/CalendarRoutes.d.ts → calendar-board/CalendarBoardRoutes.d.ts} +2 -1
  7. package/es/modules/{calendar/CalendarRoutes.js → calendar-board/CalendarBoardRoutes.js} +10 -9
  8. package/es/modules/calendar-board/CalendarBoardRoutes.js.map +1 -0
  9. package/es/modules/calendar-board/components/CalendarActionProperties/index.d.ts +20 -0
  10. package/es/modules/calendar-board/components/CalendarActionProperties/index.js +36 -0
  11. package/es/modules/calendar-board/components/CalendarActionProperties/index.js.map +1 -0
  12. package/es/modules/calendar-board/components/CalendarBoardGrid/index.d.ts +45 -0
  13. package/es/modules/calendar-board/components/CalendarBoardGrid/index.js +89 -0
  14. package/es/modules/calendar-board/components/CalendarBoardGrid/index.js.map +1 -0
  15. package/es/modules/calendar-board/components/CalendarEventChip/index.d.ts +22 -0
  16. package/es/modules/calendar-board/components/CalendarEventChip/index.js +20 -0
  17. package/es/modules/calendar-board/components/CalendarEventChip/index.js.map +1 -0
  18. package/es/modules/calendar-board/components/CalendarLegend/index.d.ts +42 -0
  19. package/es/modules/calendar-board/components/CalendarLegend/index.js +94 -0
  20. package/es/modules/calendar-board/components/CalendarLegend/index.js.map +1 -0
  21. package/es/modules/calendar-board/components/CalendarMoreLink/index.d.ts +11 -0
  22. package/es/modules/calendar-board/components/CalendarMoreLink/index.js +12 -0
  23. package/es/modules/calendar-board/components/CalendarMoreLink/index.js.map +1 -0
  24. package/es/modules/calendar-board/components/CalendarSidebar/index.d.ts +34 -0
  25. package/es/modules/calendar-board/components/CalendarSidebar/index.js +45 -0
  26. package/es/modules/calendar-board/components/CalendarSidebar/index.js.map +1 -0
  27. package/es/modules/calendar-board/components/CalendarToolbar/index.d.ts +30 -0
  28. package/es/modules/calendar-board/components/CalendarToolbar/index.js +30 -0
  29. package/es/modules/calendar-board/components/CalendarToolbar/index.js.map +1 -0
  30. package/es/modules/calendar-board/components/CalendarUpcomingBar/index.d.ts +30 -0
  31. package/es/modules/calendar-board/components/CalendarUpcomingBar/index.js +35 -0
  32. package/es/modules/calendar-board/components/CalendarUpcomingBar/index.js.map +1 -0
  33. package/es/modules/calendar-board/components/CalendarUpcomingEntry/index.d.ts +25 -0
  34. package/es/modules/calendar-board/components/CalendarUpcomingEntry/index.js +35 -0
  35. package/es/modules/calendar-board/components/CalendarUpcomingEntry/index.js.map +1 -0
  36. package/es/modules/calendar-board/components/CalendarViewFilter/index.d.ts +19 -0
  37. package/es/modules/calendar-board/components/CalendarViewFilter/index.js +29 -0
  38. package/es/modules/calendar-board/components/CalendarViewFilter/index.js.map +1 -0
  39. package/es/modules/calendar-board/components/CalendarViewSwitcher/index.d.ts +14 -0
  40. package/es/modules/calendar-board/components/CalendarViewSwitcher/index.js +15 -0
  41. package/es/modules/calendar-board/components/CalendarViewSwitcher/index.js.map +1 -0
  42. package/es/modules/calendar-board/event-meta.d.ts +262 -0
  43. package/es/modules/calendar-board/event-meta.js +329 -0
  44. package/es/modules/calendar-board/event-meta.js.map +1 -0
  45. package/es/modules/calendar-board/layout.d.ts +27 -0
  46. package/es/modules/calendar-board/layout.js +20 -0
  47. package/es/modules/calendar-board/layout.js.map +1 -0
  48. package/es/modules/calendar-board/pages/CalendarBoard/index.css +262 -0
  49. package/es/modules/calendar-board/pages/CalendarBoard/index.d.ts +4 -0
  50. package/es/modules/calendar-board/pages/CalendarBoard/index.js +323 -0
  51. package/es/modules/calendar-board/pages/CalendarBoard/index.js.map +1 -0
  52. package/es/modules/calendar-board/pages/CalendarBoard/state.d.ts +112 -0
  53. package/es/modules/calendar-board/pages/CalendarBoard/state.js +206 -0
  54. package/es/modules/calendar-board/pages/CalendarBoard/state.js.map +1 -0
  55. package/es/modules/calendar-board/sidebar-data.d.ts +35 -0
  56. package/es/modules/calendar-board/sidebar-data.js +28 -0
  57. package/es/modules/calendar-board/sidebar-data.js.map +1 -0
  58. package/es/modules/meeting/components/NewMeetingForm/index.js +1 -1
  59. package/es/modules/meeting/components/NewMeetingForm/index.js.map +1 -1
  60. package/es/modules/project/ProjectDefaultView/index.js +2 -2
  61. package/es/modules/project/ProjectDefaultView/index.js.map +1 -1
  62. package/es/modules/work/work-schedule/components/WorkScheduleProperties/index.js +2 -3
  63. package/es/modules/work/work-schedule/components/WorkScheduleProperties/index.js.map +1 -1
  64. package/es/modules/work/work-type/components/WorkTypeLink/index.d.ts +7 -0
  65. package/es/modules/work/work-type/components/WorkTypeLink/index.js +16 -0
  66. package/es/modules/work/work-type/components/WorkTypeLink/index.js.map +1 -0
  67. package/es/modules/work/work-type/components/WorkTypeList/index.d.ts +5 -2
  68. package/es/modules/work/work-type/components/WorkTypeList/index.js +8 -6
  69. package/es/modules/work/work-type/components/WorkTypeList/index.js.map +1 -1
  70. package/es/routes.js +2 -2
  71. package/es/routes.js.map +1 -1
  72. package/package.json +1 -1
  73. package/es/modules/calendar/CalendarRoutes.js.map +0 -1
  74. package/es/modules/calendar/components/ActionCard/index.d.ts +0 -7
  75. package/es/modules/calendar/components/ActionCard/index.js +0 -12
  76. package/es/modules/calendar/components/ActionCard/index.js.map +0 -1
  77. package/es/modules/calendar/components/CalendarEventContent/index.d.ts +0 -11
  78. package/es/modules/calendar/components/CalendarEventContent/index.js +0 -10
  79. package/es/modules/calendar/components/CalendarEventContent/index.js.map +0 -1
  80. package/es/modules/calendar/components/CalendarMenu/index.css +0 -30
  81. package/es/modules/calendar/components/CalendarMenu/index.d.ts +0 -7
  82. package/es/modules/calendar/components/CalendarMenu/index.js +0 -52
  83. package/es/modules/calendar/components/CalendarMenu/index.js.map +0 -1
  84. package/es/modules/calendar/pages/CalendarMonth/index.css +0 -248
  85. package/es/modules/calendar/pages/CalendarMonth/index.d.ts +0 -4
  86. package/es/modules/calendar/pages/CalendarMonth/index.js +0 -190
  87. package/es/modules/calendar/pages/CalendarMonth/index.js.map +0 -1
  88. package/es/modules/calendar/pages/CalendarMonth/state.d.ts +0 -11
  89. package/es/modules/calendar/pages/CalendarMonth/state.js +0 -58
  90. package/es/modules/calendar/pages/CalendarMonth/state.js.map +0 -1
  91. package/es/modules/my-document/SectionTemplate/documentGroups.test.d.ts +0 -1
  92. package/es/modules/my-document/SectionTemplate/documentGroups.test.js +0 -63
  93. package/es/modules/my-document/SectionTemplate/documentGroups.test.js.map +0 -1
  94. package/es/modules/work/work-type/components/WorkTypeList/index.css +0 -5
@@ -0,0 +1,329 @@
1
+ import dayjs from "dayjs";
2
+ /**
3
+ * 分类色板:沿用 calendar-recreation.html 的事件卡原色(蓝 / 红 / 绿 / 橙)。
4
+ *
5
+ * 顺序即取色顺序,见 buildColorMap —— 同一 source.type 永远落在同一颜色上,
6
+ * 与现有 CalendarMonth 用 generateLightColorFromHash(source.type) 的意图一致。
7
+ */
8
+ export const CATEGORY_COLORS = ["blue", "red", "green", "orange"];
9
+ /**
10
+ * 「其他」分类统一用的中性色。
11
+ *
12
+ * 指固定 3 项(Task / Case / Work)之外的一切分类,含没有 source.type 的 Other:
13
+ * 它们在整页只有这一种颜色 —— 图例的 Others 圆点、网格里的事件卡、侧栏 UPCOMING 的
14
+ * 圆点都取它(见 resolveEventColor),所以「不属于固定分类」这件事一眼可辨。
15
+ *
16
+ * 刻意不进 CATEGORY_COLORS:它不是分类色、不参与轮转 —— 掺进去会让现有分类的配色整体挪位。
17
+ */
18
+ export const NEUTRAL_COLOR = "grey";
19
+ /**
20
+ * 事件卡配色:逐字取自 HTML 的 `border border-{c}-400 bg-{c}-50 text-{c}-600`。
21
+ *
22
+ * grey 是后加的「其他」专用色,不在设计稿的四个分类色里,按同一公式取灰阶
23
+ * (400 描边 + 50 浅底)。
24
+ */
25
+ export const CHIP_COLOR_CLASS = {
26
+ blue: "border-blue-400 bg-blue-50",
27
+ red: "border-red-400 bg-red-50",
28
+ green: "border-green-400 bg-green-50",
29
+ orange: "border-amber-400 bg-amber-50",
30
+ grey: "border-gray-400 bg-gray-50",
31
+ };
32
+ /** 事件卡内的时间行配色,取自 calendar-day-view.html 的 `text-amber-600` / `text-red-500` */
33
+ export const CHIP_TIME_CLASS = {
34
+ blue: "text-blue-500",
35
+ red: "text-red-500",
36
+ green: "text-green-600",
37
+ orange: "text-amber-600",
38
+ grey: "text-gray-500",
39
+ };
40
+ /**
41
+ * 图例 / 侧栏分类列表的圆点配色,取自 HTML 的 `bg-blue-600 / bg-red-500 / ...`。
42
+ *
43
+ * grey 与卡片同理,是同灰阶里更深的那一档(对应分类色的 500 / 600)。
44
+ */
45
+ export const DOT_COLOR_CLASS = {
46
+ blue: "bg-blue-600",
47
+ red: "bg-red-500",
48
+ green: "bg-green-600",
49
+ orange: "bg-amber-500",
50
+ grey: "bg-gray-500",
51
+ };
52
+ /**
53
+ * 事件卡外壳:HTML 的 `text-[10px] font-bold uppercase rounded-md px-2 py-0.5 border-l-4 truncate`。
54
+ *
55
+ * 用 overflow-hidden 而不是 truncate:日视图的卡片里还有第二行时间文案,
56
+ * 文字截断交给内层每一行的 truncate。
57
+ */
58
+ export const CHIP_BASE_CLASS = "border border-l-4 text-2xs text-font-primary font-bold uppercase rounded-base px-2 py-0.5 cursor-pointer overflow-hidden";
59
+ /** 没有 source.type 时归入的分类名 */
60
+ export const DEFAULT_CATEGORY_TYPE = "Other";
61
+ /** 事件的分类名(source.type) */
62
+ export const getEventType = (event) => event.source?.type || DEFAULT_CATEGORY_TYPE;
63
+ /**
64
+ * 事件的起始时间。
65
+ *
66
+ * ICalendar 声明的是 startDate,FullCalendar 读的是 start,两者都被兼容;
67
+ * 都缺失时退回 dueDate,仍缺失则返回 undefined(该事件不参与侧栏推导)。
68
+ */
69
+ export const getEventStart = (event) => {
70
+ const source = event;
71
+ const raw = event.start ?? source.startDate ?? source.dueDate;
72
+ if (!raw)
73
+ return undefined;
74
+ const date = dayjs(raw);
75
+ return date.isValid() ? date.toDate() : undefined;
76
+ };
77
+ /** 事件标题:优先 FullCalendar 解析出的 title,退回 source.title */
78
+ export const getEventTitle = (event) => event.title || event.source?.title || "";
79
+ /**
80
+ * 事件 source → <NodePropertiesView> 需要的 node。
81
+ *
82
+ * 两处形状差异,收在这里而不是散在页面里:
83
+ * - `nodeType`:NodePropertiesView 的 props 把它声明成必填,但派发其实只看 type
84
+ * (DocumentMetaStore.getPropertiesView = getMeta(document.type)),
85
+ * source 拿不到时补空串即可;
86
+ * - `title`:node 不需要,顺手剥掉,避免带进组件。
87
+ */
88
+ export const toPropertiesTarget = (source) => ({
89
+ id: source.id,
90
+ type: source.type,
91
+ nodeType: source.nodeType ?? "",
92
+ });
93
+ /**
94
+ * Action 事件的 source.type。
95
+ *
96
+ * Action 不是文档节点:它的 meta 注册在另一个 store(morpho-collaboration-action 的
97
+ * ActionMetaStore),DocumentMetaStore 里没有 "Action"(只有 Board / WorkScheduleNode /
98
+ * Meeting / MeetingsFolder / Work / Task / WorkType)。所以 Type 为 Action 的事件不能走
99
+ * <NodePropertiesView>,要另走 action 自己的加载器,见 CalendarActionProperties。
100
+ */
101
+ export const ACTION_SOURCE_TYPE = "Action";
102
+ /**
103
+ * 事件 source 是不是 Action —— 决定点开后打开哪一个属性视图。
104
+ *
105
+ * 判定只看 type:`nodeType` 运行时不一定下发(见 CalendarBoardSource.nodeType)。
106
+ */
107
+ export const isActionSource = (source) => source?.type === ACTION_SOURCE_TYPE;
108
+ /**
109
+ * 按 source.type 去重排序后依次取色。
110
+ *
111
+ * 排序保证映射只取决于「出现了哪些 type」,与事件顺序无关,
112
+ * 因此事件卡、图例、侧栏分类三处拿到的颜色必然一致。
113
+ */
114
+ export const buildColorMap = (types) => new Map(Array.from(new Set(types))
115
+ .sort()
116
+ .map((type, index) => [type, CATEGORY_COLORS[index % CATEGORY_COLORS.length]]));
117
+ /** 一次算出 type → 颜色映射与分类明细(计数 + 成员),供事件卡、图例、侧栏共用 */
118
+ export const summarizeEvents = (events) => {
119
+ const colorMap = buildColorMap(events.map(getEventType));
120
+ const groups = new Map();
121
+ events.forEach((event) => {
122
+ const type = getEventType(event);
123
+ const group = groups.get(type);
124
+ if (group) {
125
+ group.push(event);
126
+ }
127
+ else {
128
+ groups.set(type, [event]);
129
+ }
130
+ });
131
+ const categories = Array.from(groups, ([type, group]) => ({
132
+ type,
133
+ count: group.length,
134
+ color: colorMap.get(type) ?? CATEGORY_COLORS[0],
135
+ events: sortByStart(group),
136
+ })).sort((a, b) => b.count - a.count || a.type.localeCompare(b.type));
137
+ return { colorMap, categories };
138
+ };
139
+ /** 按开始时间升序;拿不到时间的排在最后(保持稳定,不改变其余相对顺序) */
140
+ const sortByStart = (events) => events
141
+ .map((event, index) => ({ event, index, time: getEventStart(event)?.getTime() ?? Infinity }))
142
+ .sort((a, b) => a.time - b.time || a.index - b.index)
143
+ .map((item) => item.event);
144
+ /**
145
+ * 图例固定展示的三个分类。
146
+ *
147
+ * 数组顺序即图例顺序,与事件多少无关:这四项是「位置」而不是「榜单」,
148
+ * 因此某一项当期没有事件时也占位(计数 0),图例不会随数据跳动。
149
+ * 匹配的是 source.type 原文(大小写敏感)。
150
+ */
151
+ export const LEGEND_FIXED_TYPES = ["Task", "Case", "Work"];
152
+ /** 固定项之外的事件全部折叠进这一项 */
153
+ export const OTHERS_CATEGORY_TYPE = "Others";
154
+ /** type 是不是固定分类(大小写敏感,与 LEGEND_FIXED_TYPES 同口径) */
155
+ const isLegendFixedType = (type) => LEGEND_FIXED_TYPES.includes(type);
156
+ /**
157
+ * Others 的圆点颜色 = 中性色。
158
+ *
159
+ * 与网格里「其他」事件卡同一个来源(NEUTRAL_COLOR 的三张表),
160
+ * 所以图例圆点、事件卡、侧栏圆点在「不属于固定分类」这件事上是一致的。
161
+ */
162
+ export const OTHERS_DOT_CLASS = DOT_COLOR_CLASS[NEUTRAL_COLOR];
163
+ /**
164
+ * 把分类明细折叠成图例要渲染的项:固定 3 项(Task / Case / Work)+ Others。
165
+ *
166
+ * 折叠只发生在**展示层**:`summarizeEvents` 的 colorMap 仍按全量分类计算,
167
+ * 所以固定项的取色与事件卡一致 —— 有事件时沿用它的原色(三处同色)。
168
+ *
169
+ * 0 计数的固定项没有原色可用,按固定下标取兜底色(Task → blue、Case → red、
170
+ * Work → green),否则三项会一起退回首色、挤成一个颜色。
171
+ *
172
+ * Others 只在真有其他分类时出现(否则就是一个恒为 0 的多余项);它的条目是
173
+ * 其余分类的事件合并后按开始时间升序 —— 与单个分类浮层同一口径,不按原分类分块。
174
+ */
175
+ export const buildLegendCategories = (categories) => {
176
+ const byType = new Map(categories.map((category) => [category.type, category]));
177
+ const fixed = LEGEND_FIXED_TYPES.map((type, index) => {
178
+ const category = byType.get(type);
179
+ return {
180
+ type,
181
+ count: category?.count ?? 0,
182
+ events: category?.events ?? [],
183
+ dotClass: category
184
+ ? DOT_COLOR_CLASS[category.color]
185
+ : DOT_COLOR_CLASS[CATEGORY_COLORS[index % CATEGORY_COLORS.length]],
186
+ };
187
+ });
188
+ // 服务端真的下发了一个叫 Others 的分类时,它同样落在这里、被并进聚合项,
189
+ // 不会和图例自己的 Others 渲染成两项
190
+ const rest = categories.filter((category) => !isLegendFixedType(category.type));
191
+ if (rest.length === 0)
192
+ return fixed;
193
+ return [
194
+ ...fixed,
195
+ {
196
+ type: OTHERS_CATEGORY_TYPE,
197
+ count: rest.reduce((total, category) => total + category.count, 0),
198
+ events: sortByStart(rest.flatMap((category) => category.events)),
199
+ dotClass: OTHERS_DOT_CLASS,
200
+ },
201
+ ];
202
+ };
203
+ /**
204
+ * 整页事件的取色入口:固定分类(Task / Case / Work)用分类原色,其余一切用中性色。
205
+ *
206
+ * 网格里的事件卡、侧栏 UPCOMING 的圆点、小屏底部条的圆点都走这里,于是
207
+ * 「不在固定分类里」在整页是同一个灰 —— 否则同一条事件会出现「网格里是灰卡、
208
+ * 侧栏里还是蓝点」这种自相矛盾的呈现。
209
+ *
210
+ * 注意与 resolveColor 的区别:那个是纯「分类色轮转」,这里才是事件的最终颜色。
211
+ */
212
+ export const resolveEventColor = (colorMap, type) => (isLegendFixedType(type) ? resolveColor(colorMap, type) : NEUTRAL_COLOR);
213
+ /** 取某个分类色(按 type 轮转);映射缺失时退回色板首色。整页取色请走 resolveEventColor */
214
+ export const resolveColor = (colorMap, type) => colorMap.get(type) ?? CATEGORY_COLORS[0];
215
+ /**
216
+ * 本地过滤:搜索关键字 + 被隐藏的分类。
217
+ *
218
+ * 纯前端过滤,不触发重新请求;日历与侧栏 UPCOMING 列表共用同一份结果。
219
+ */
220
+ export const filterEvents = (events, options) => {
221
+ const keyword = options?.search?.trim().toLowerCase() ?? "";
222
+ const hidden = new Set(options?.hiddenTypes ?? []);
223
+ return events.filter((event) => {
224
+ if (hidden.has(getEventType(event)))
225
+ return false;
226
+ if (!keyword)
227
+ return true;
228
+ return getEventTitle(event).toLowerCase().includes(keyword);
229
+ });
230
+ };
231
+ /** 侧栏 UPCOMING DEADLINES 的默认条数,与 HTML 稿一致 */
232
+ export const UPCOMING_LIMIT = 5;
233
+ /** 相对今天还有几天(今天为 0D) */
234
+ export const formatRemaining = (start, from) => `${Math.max(0, dayjs(start).startOf("day").diff(from.startOf("day"), "day"))}D`;
235
+ /**
236
+ * UPCOMING DEADLINES:今天及以后的事件,按起始时间升序取前 N 条。
237
+ *
238
+ * @param from 以哪一天为「今天」,默认取当前时间;测试注入固定日期用。
239
+ */
240
+ export const buildUpcoming = (events, summary, options) => {
241
+ const from = options?.from ?? dayjs();
242
+ const limit = options?.limit ?? UPCOMING_LIMIT;
243
+ return events
244
+ .map((event) => ({ event, start: getEventStart(event) }))
245
+ .filter((item) => {
246
+ if (!item.start)
247
+ return false;
248
+ return !dayjs(item.start).startOf("day").isBefore(from.startOf("day"));
249
+ })
250
+ .sort((a, b) => a.start.getTime() - b.start.getTime())
251
+ .slice(0, limit)
252
+ .map(({ event, start }) => {
253
+ const type = getEventType(event);
254
+ return {
255
+ id: event.id,
256
+ title: getEventTitle(event),
257
+ type,
258
+ color: resolveEventColor(summary.colorMap, type),
259
+ timeLabel: event.allDay
260
+ ? dayjs(start).format("MMM D")
261
+ : `${dayjs(start).format("MMM D")} | ${dayjs(start).format("hA")}`,
262
+ remainingLabel: formatRemaining(start, from),
263
+ source: event.source,
264
+ };
265
+ });
266
+ };
267
+ /**
268
+ * 写回服务端时的时间格式:**本地时间**,不带时区后缀。
269
+ *
270
+ * 与仓库里其它写时间属性的地方保持一致(见 MeetingHeader 的 StartTime/EndTime)。
271
+ * 注意不要用 toISOString():它产出 UTC 时刻,UTC+8 下把事件拖到某天零点时,
272
+ * 日期部分会退回前一天,服务端按本地时间解析就落到错误的日期上。
273
+ */
274
+ export const DATE_TIME_FORMAT = "YYYY-MM-DDTHH:mm:ss.SSS";
275
+ /**
276
+ * 把 FullCalendar 给出的落点转成服务端载荷。
277
+ *
278
+ * @returns 起止时间都拿不到(或非法)时返回 undefined,调用方应当放弃这次拖拽
279
+ */
280
+ export const buildDropPayload = (options) => {
281
+ const start = options.start ? dayjs(options.start) : undefined;
282
+ if (!start || !start.isValid())
283
+ return undefined;
284
+ const payload = { Start: start.format(DATE_TIME_FORMAT) };
285
+ const end = options.end ? dayjs(options.end) : undefined;
286
+ if (end && end.isValid())
287
+ payload.End = end.format(DATE_TIME_FORMAT);
288
+ return payload;
289
+ };
290
+ /**
291
+ * 事件 id 比较。
292
+ *
293
+ * FullCalendar 会把事件 id 强转成字符串(其内部 EVENT_NON_DATE_REFINERS 里 id: String),
294
+ * 所以服务端下发的数字 id 到了这边就成了 "123" —— 用 `===` 直接比会永远不相等,
295
+ * 拖拽结果就同步不回列表。这里统一按字符串比。
296
+ */
297
+ const isSameEvent = (item, id) => item.id !== undefined && item.id !== null && String(item.id) === id;
298
+ /** 按事件 id 在列表里找对应的那条(id 比较规则见 isSameEvent) */
299
+ export const findEventById = (events, id) => id ? events.find((item) => isSameEvent(item, id)) : undefined;
300
+ /**
301
+ * 把拖拽结果写回页面自己的事件列表。
302
+ *
303
+ * 必须做这一步:`state.listOptions` 只在挂载时加载一次,而事件数据会交给 FullCalendar
304
+ * 当 eventSources —— 列表里还是旧位置的话,任何一次事件源重置都会把刚拖出去的事件打回原位。
305
+ *
306
+ * ⚠️ 没命中任何一条时必须**原样返回同一个数组**:`.map()` 那种写法即使什么都没改也会造出
307
+ * 新引用,而新引用本身就会触发 FullCalendar 重置事件源,反而把拖拽结果覆盖掉。
308
+ */
309
+ export const applyDropToEvents = (events, id, drop) => {
310
+ const index = events.findIndex((item) => isSameEvent(item, id));
311
+ if (index === -1)
312
+ return events;
313
+ const next = { ...events[index] };
314
+ if (drop.start) {
315
+ next.start = drop.start;
316
+ next.startDate = dayjs(drop.start).toDate();
317
+ }
318
+ if (drop.end)
319
+ next.end = drop.end;
320
+ const result = events.slice();
321
+ result[index] = next;
322
+ return result;
323
+ };
324
+ /** 图例浮层里的日期文案,设计稿是 `Aug 3`;拿不到时间时返回空串 */
325
+ export const formatEventDate = (event) => {
326
+ const start = getEventStart(event);
327
+ return start ? dayjs(start).format("MMM D") : "";
328
+ };
329
+ //# sourceMappingURL=event-meta.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-meta.js","sourceRoot":"","sources":["../../../src/modules/calendar-board/event-meta.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * CalendarBoard 的响应式布局分派。
3
+ *
4
+ * 三条规则的唯一落点:
5
+ * - 小屏(< 1024px):不渲染右侧栏,Upcoming 固定在底部条;Day / Month / Week 收进 Filter 浮层;
6
+ * - 桌面端(≥ 1024px):右侧属性面板展开时,Upcoming 面板不显示。
7
+ *
8
+ * 抽成纯函数而不是散在页面的 JSX 里:判定输入只有「是不是小屏」和「aside 是否打开」两个布尔量,
9
+ * 规则可以被直接测;不抽的话就只能靠挂载整个 CalendarBoard(AsideContent + FullCalendar +
10
+ * tab / store / filter 上下文)来验证这三条,代价高且脆弱。
11
+ */
12
+ export interface IBoardLayout {
13
+ /** 是否渲染右侧栏(Search + UPCOMING / ACTIVITY 面板) */
14
+ showSidebar: boolean;
15
+ /** 是否渲染底部固定条(小屏专用,内容为 UPCOMING + 圆点总数 + 首条 title) */
16
+ showUpcomingBar: boolean;
17
+ /** 视图切换放哪里:true = Filter 浮层里多一列 By View,false = 留在工具栏 */
18
+ viewSwitcherInFilter: boolean;
19
+ }
20
+ /**
21
+ * @param isSmallScreen 视口是否 < 1024px(来自 useMediaQuery(SMALL_SCREEN_QUERY))
22
+ * @param isAsideOpen 右侧属性面板是否有内容(来自 asideContext.asideContent)
23
+ */
24
+ export declare const resolveBoardLayout: (options: {
25
+ isSmallScreen: boolean;
26
+ isAsideOpen: boolean;
27
+ }) => IBoardLayout;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @param isSmallScreen 视口是否 < 1024px(来自 useMediaQuery(SMALL_SCREEN_QUERY))
3
+ * @param isAsideOpen 右侧属性面板是否有内容(来自 asideContext.asideContent)
4
+ */
5
+ export const resolveBoardLayout = (options) => {
6
+ /*
7
+ * 小屏分支不看 isAsideOpen:小屏本来就没有右侧栏,Upcoming 只能靠底部条进入,
8
+ * 属性面板打开是另一回事(Modal 与 aside 互不干扰,各自占满自己的层)。
9
+ */
10
+ if (options.isSmallScreen) {
11
+ return { showSidebar: false, showUpcomingBar: true, viewSwitcherInFilter: true };
12
+ }
13
+ return {
14
+ // 需求 3:右侧面板展开时 Upcoming 面板让位(aside 自己会占掉这块宽度)
15
+ showSidebar: !options.isAsideOpen,
16
+ showUpcomingBar: false,
17
+ viewSwitcherInFilter: false,
18
+ };
19
+ };
20
+ //# sourceMappingURL=layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.js","sourceRoot":"","sources":["../../../src/modules/calendar-board/layout.ts"],"names":[],"mappings":"AAoBA;;;GAGG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,OAGlC,EAAgB,EAAE;IAClB;;;OAGG;IACH,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;QAC3B,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAE,CAAC;IAClF,CAAC;IAED,OAAO;QACN,8CAA8C;QAC9C,WAAW,EAAE,CAAC,OAAO,CAAC,WAAW;QACjC,eAAe,EAAE,KAAK;QACtB,oBAAoB,EAAE,KAAK;KAC3B,CAAC;AACH,CAAC,CAAC"}
@@ -0,0 +1,262 @@
1
+ /*
2
+ * CalendarBoard 的 FullCalendar 皮肤。
3
+ *
4
+ * FullCalendar 的内部 DOM(表格、日期格、时间轴、+N 徽标)由它自己生成,挂不上 Tailwind 类,
5
+ * 因此这里用官方 CSS 变量(--fc-*)为主、少量选择器覆盖为辅。覆盖的选择器都取自
6
+ * FullCalendar 6.1 实际注入的默认样式(见 daygrid / timegrid 的 internal.js)。
7
+ *
8
+ * 颜色一律走 morpho-theme token(var(--color-*) / var(--font-size-*)),不写死色值;
9
+ * 事件卡的分类原色在 event-meta.ts 的 CHIP_COLOR_CLASS 里,不走这里。
10
+ */
11
+
12
+ .calendar-board {
13
+ /* ═══ FullCalendar 官方 CSS 变量:把内置皮肤换成设计稿的灰白体系 ═══ */
14
+ --fc-border-color: var(--color-border);
15
+ --fc-page-bg-color: var(--color-bg-white);
16
+ --fc-neutral-bg-color: var(--color-bg-table);
17
+ --fc-neutral-text-color: var(--color-font-grey);
18
+ --fc-today-bg-color: var(--color-bg-blue-data);
19
+ --fc-highlight-color: var(--color-bg-blue-data);
20
+ --fc-now-indicator-color: var(--color-font-secondary);
21
+ --fc-more-link-bg-color: transparent;
22
+ --fc-more-link-text-color: inherit;
23
+ /* 事件节点本身不画底色 / 边框:描边浅底由 .calendar-event-chip 负责 */
24
+ --fc-event-bg-color: transparent;
25
+ --fc-event-border-color: transparent;
26
+ --fc-event-text-color: inherit;
27
+ --fc-small-font-size: var(--font-size-2xs);
28
+
29
+ /* 最后一个事件卡要给 +N 让出的宽度 */
30
+ --board-more-gutter: 36px;
31
+
32
+ .fc {
33
+ font-size: var(--font-size-xs);
34
+ }
35
+
36
+ /* ═══ 事件节点:剥掉 FullCalendar 自带外观,只剩我们的卡片 ═══ */
37
+ .fc-h-event {
38
+ border: 0;
39
+ background: transparent;
40
+ }
41
+
42
+ .fc-event-main {
43
+ height: 100%;
44
+ padding: 0;
45
+ }
46
+
47
+ /*
48
+ * ═══ 只去掉最外圈的边框(内部网格线全部保留)═══
49
+ *
50
+ * 边缘线一共有三层,来自不同元素,必须分别处理:
51
+ *
52
+ * 1. .fc-scrollgrid 自身 —— 但 FullCalendar 只让它的上 + 左可见
53
+ * (.fc .fc-scrollgrid 把 right/bottom 清零了);
54
+ * 2. .fc-scrollgrid 自己的格子(每个 section 一行、一行一个 th/td)——
55
+ * 右 + 下都在(FullCalendar 只把它们的 left/top 清零);
56
+ * 3. 紧贴外框的内层表格(列头 / 日期网格 / 时间轴)——
57
+ * 它们的最后一列、最后一行同样各画一条边线。
58
+ *
59
+ * 选择器的安全性:每一层每行的**最后一个**格子才是右侧边缘
60
+ * (时间轴与泳道的分隔线在行内前两个格子之间,不受影响);
61
+ * 底边则只取最后一行的格子,并排除 .fc-col-header —— 它的底边是
62
+ * 「列头与日期格之间」的内部线,必须留着。
63
+ */
64
+ .fc-theme-standard .fc-scrollgrid {
65
+ border: 0;
66
+ }
67
+
68
+ /** 右边缘:所有层级的最后一个格子 */
69
+ .fc-scrollgrid tr > *:last-child {
70
+ border-right-width: 0;
71
+ }
72
+
73
+ /** 下边缘:外框自身的最后一行 */
74
+ .fc-scrollgrid > tbody > tr:last-child > * {
75
+ border-bottom-width: 0;
76
+ }
77
+
78
+ /**
79
+ * 下边缘:最底部那张内层表的最后一行。
80
+ *
81
+ * 限定在「外框最后一行格子的内部」,而不是所有内层表 ——
82
+ * 日视图里全天行在外框第 2 行、并不贴底,它的底边是全天区与时间轴之间的
83
+ * 内部分隔线(那条由 .fc-timegrid-divider 负责画),不该被清掉。
84
+ */
85
+ .fc-scrollgrid > tbody > tr:last-child > * table:not(.fc-col-header) tr:last-child > * {
86
+ border-bottom-width: 0;
87
+ }
88
+
89
+ /* ═══ 列头 SUN / MON / ... ═══ */
90
+ .fc-col-header-cell {
91
+ background-color: var(--color-bg-white);
92
+ }
93
+
94
+ .fc-col-header-cell-cushion {
95
+ padding: var(--space-sm) var(--space-md);
96
+ font-size: var(--font-size-2xs);
97
+ font-weight: 600;
98
+ letter-spacing: 0.05em;
99
+ text-transform: uppercase;
100
+ color: var(--color-font-grey);
101
+ text-decoration: none;
102
+ }
103
+
104
+ /* ═══ 月 / 周视图的日期格 ═══ */
105
+ /* FullCalendar 默认 row-reverse(日期数字靠右),设计稿是左上角 */
106
+ .fc .fc-daygrid-day-top {
107
+ flex-direction: row;
108
+ }
109
+
110
+ .fc-daygrid-day-number {
111
+ padding: var(--space-sm) var(--space-md);
112
+ font-weight: 500;
113
+ color: var(--color-font-primary);
114
+ text-decoration: none;
115
+ }
116
+
117
+ .fc-day-today .fc-daygrid-day-number {
118
+ font-weight: 600;
119
+ color: var(--color-font-secondary);
120
+ }
121
+
122
+ .fc-day-other .fc-daygrid-day-number {
123
+ color: var(--color-font-disabled);
124
+ }
125
+
126
+ .fc .fc-daygrid-day-events {
127
+ margin: 0 var(--space-sm) var(--space-sm);
128
+ }
129
+
130
+ .fc-daygrid-event {
131
+ margin-top: var(--space-xs);
132
+ border-radius: 0;
133
+ /* 旧 index.css 同样关掉 nowrap,让长标题能换行 */
134
+ white-space: normal;
135
+ }
136
+
137
+ /* ═══ +N 徽标:外观由 CalendarMoreLink 负责 ═══ */
138
+ .fc-daygrid-more-link {
139
+ margin: 0;
140
+ padding: 0;
141
+ border-radius: 0;
142
+ text-decoration: none;
143
+ }
144
+
145
+ .fc-daygrid-more-link:hover {
146
+ background-color: transparent;
147
+ }
148
+
149
+ /*
150
+ * +N 与最后一个可见事件卡同排。
151
+ *
152
+ * 设计稿就是这么排的:最后一张卡让位收窄、+N 紧跟在它右边,而不是单独占一行。
153
+ * FullCalendar 没有「内联 +N」的选项;搬运 DOM 也不行 —— Preact 重渲染时会把
154
+ * .fc-daygrid-day-bottom 重新插回 .fc-daygrid-day-events,徽标跳回原位
155
+ * (实测:setOption("eventSources") 之后节点身份不变,但父级被还原)。
156
+ * 因此只能用 CSS 叠回去,好处是天然不受重渲染影响。
157
+ *
158
+ * 两步:
159
+ * 1) 让 +N 脱离文档流,钉在最后一张卡那一行的右侧;
160
+ * 2) 让最后一张「可见」卡右侧留出 +N 的位置。
161
+ *
162
+ * 第 1 步用 position: absolute + bottom: 0,而不是「上移一行」的负 margin:
163
+ * 容器底部就是最后一张卡的底部,这样不需要写死卡片高度 —— 卡片样式随时可能调,
164
+ * 任何像素常量都会在别人改 py-/text- 的时候静默失准。容器本身有 position: relative
165
+ * (FullCalendar 的 unbalanced / balanced 两种布局都会给它定位)。
166
+ *
167
+ * 门禁用 .fc-daygrid-more-link 而不是 .fc-daygrid-day-bottom:
168
+ * 后者是**每个格子都会渲染**的空容器,拿它当条件等于恒真,会让所有格子的
169
+ * 最后一张卡都被平白缩窄(这个坑是测试先发现的)。
170
+ *
171
+ * 关于「最后一个可见卡」:被收起的事件仍然留在 DOM 里(带 inline 的
172
+ * visibility: hidden),所以要按可见性过滤。这里刻意拆成两条规则
173
+ * (先给所有可见卡留位,再把后面还有可见卡的取消),避免写 :not(:has(~ …))
174
+ * 这种嵌套形式 —— 部分 CSS 引擎不支持,那会导致 +N 叠在卡片上面而不是并排。
175
+ */
176
+ .fc-daygrid-day-events:has(.fc-daygrid-more-link)
177
+ > .fc-daygrid-event-harness:not([style*="visibility: hidden"]) {
178
+ padding-right: var(--board-more-gutter);
179
+ }
180
+
181
+ .fc-daygrid-day-events:has(.fc-daygrid-more-link)
182
+ > .fc-daygrid-event-harness:not([style*="visibility: hidden"]):has(
183
+ ~ .fc-daygrid-event-harness:not([style*="visibility: hidden"])
184
+ ) {
185
+ padding-right: 0;
186
+ }
187
+
188
+ .fc .fc-daygrid-day-events:has(.fc-daygrid-more-link) > .fc-daygrid-day-bottom {
189
+ position: absolute;
190
+ right: 0;
191
+ bottom: 0;
192
+ display: flex;
193
+ justify-content: flex-end;
194
+ /* 抵消 FullCalendar 给它的行偏移与左右外边距 */
195
+ margin: 0 !important;
196
+ }
197
+
198
+ /* ═══ 日视图:时间轴 ═══ */
199
+ .fc .fc-timegrid-axis-cushion,
200
+ .fc .fc-timegrid-slot-label-cushion {
201
+ padding: 0 var(--space-md) 0 0;
202
+ font-size: var(--font-size-xs);
203
+ color: var(--color-font-grey);
204
+ }
205
+
206
+ .fc .fc-timegrid-axis-cushion {
207
+ max-width: none;
208
+ }
209
+
210
+ .fc-timegrid-event {
211
+ border-radius: var(--radius-base);
212
+ }
213
+
214
+ /* 卡片撑满 FullCalendar 按事件时长算出的定位盒子 */
215
+ .fc-timegrid-event .calendar-event-chip {
216
+ height: 100%;
217
+ }
218
+
219
+ .fc .fc-timegrid-now-indicator-line {
220
+ border-width: 1.5px 0 0;
221
+ }
222
+
223
+ /* ═══ 溢出弹层(moreLinkClick 默认 popover)═══ */
224
+ .fc-more-popover {
225
+ border-radius: var(--radius-base);
226
+ box-shadow: var(--shadow-card);
227
+ }
228
+
229
+ .fc-popover-header {
230
+ background-color: var(--color-bg-table);
231
+ }
232
+
233
+ /* ═══ 滚动条:沿用旧 index.css 的细条写法 ═══ */
234
+ .fc-scroller {
235
+ &::-webkit-scrollbar {
236
+ width: 7px;
237
+ height: 7px;
238
+ }
239
+ &::-webkit-scrollbar-track {
240
+ background-color: transparent;
241
+ border-radius: 2em;
242
+ }
243
+ &::-webkit-scrollbar-thumb {
244
+ background-color: rgba(0, 0, 0, 0.2);
245
+ background-clip: padding-box;
246
+ border-radius: 2em;
247
+ }
248
+ }
249
+ }
250
+
251
+ /**
252
+ * 盖在标题上的透明 DatePicker。
253
+ *
254
+ * 沿用 CalendarMonth 的 .calendar-ant-picker 做法:点标题即可跳到某月 / 某周 / 某天。
255
+ */
256
+ .calendar-board-picker {
257
+ position: absolute;
258
+ inset: 0;
259
+ width: 100%;
260
+ height: 100%;
261
+ opacity: 0;
262
+ }
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ import "./index.css";
3
+ declare const CalendarBoard: () => React.JSX.Element;
4
+ export default CalendarBoard;