@zendir/ui 0.5.0 → 0.6.0

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 (391) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +640 -631
  3. package/dist/_virtual/_rolldown/runtime.js +13 -0
  4. package/dist/index.js +17 -221
  5. package/dist/react/3d/CesiumCaptureSource.d.ts +0 -1
  6. package/dist/react/3d/CesiumCaptureSource.js +364 -283
  7. package/dist/react/3d/CesiumCaptureSource.js.map +1 -1
  8. package/dist/react/3d/ZenSpace3D.d.ts +2 -3
  9. package/dist/react/3d/ZenSpace3D.js +1681 -1237
  10. package/dist/react/3d/ZenSpace3D.js.map +1 -1
  11. package/dist/react/3d/ZenSpace3DCesium.d.ts +0 -1
  12. package/dist/react/3d/ZenSpace3DCesium.js +513 -560
  13. package/dist/react/3d/ZenSpace3DCesium.js.map +1 -1
  14. package/dist/react/3d/ZenSpace3DShaders.js +61 -66
  15. package/dist/react/3d/ZenSpace3DShaders.js.map +1 -1
  16. package/dist/react/3d/ZenSpace3DTypes.d.ts +19 -20
  17. package/dist/react/3d/ZenSpace3DUtils.d.ts +0 -1
  18. package/dist/react/3d/ZenSpace3DUtils.js +37 -24
  19. package/dist/react/3d/ZenSpace3DUtils.js.map +1 -1
  20. package/dist/react/3d/capturePngAnalysis.js +42 -36
  21. package/dist/react/3d/capturePngAnalysis.js.map +1 -1
  22. package/dist/react/3d/index.d.ts +3 -3
  23. package/dist/react/3d/index.js +5 -53
  24. package/dist/react/3d/threeLoader.d.ts +1 -1
  25. package/dist/react/3d/threeLoader.js +23 -18
  26. package/dist/react/3d/threeLoader.js.map +1 -1
  27. package/dist/react/astro/ClassificationBanner.d.ts +2 -3
  28. package/dist/react/astro/ClassificationBanner.js +95 -79
  29. package/dist/react/astro/ClassificationBanner.js.map +1 -1
  30. package/dist/react/astro/GlobalStatusBar.d.ts +0 -1
  31. package/dist/react/astro/GlobalStatusBar.js +157 -163
  32. package/dist/react/astro/GlobalStatusBar.js.map +1 -1
  33. package/dist/react/astro/MissionClock.d.ts +7 -8
  34. package/dist/react/astro/MissionClock.js +377 -400
  35. package/dist/react/astro/MissionClock.js.map +1 -1
  36. package/dist/react/astro/MonitoringIcon.d.ts +1 -2
  37. package/dist/react/astro/MonitoringIcon.js +422 -358
  38. package/dist/react/astro/MonitoringIcon.js.map +1 -1
  39. package/dist/react/astro/Notification.d.ts +1 -2
  40. package/dist/react/astro/Notification.js +229 -126
  41. package/dist/react/astro/Notification.js.map +1 -1
  42. package/dist/react/astro/Progress.d.ts +0 -1
  43. package/dist/react/astro/Progress.js +199 -141
  44. package/dist/react/astro/Progress.js.map +1 -1
  45. package/dist/react/astro/SimulationControls.d.ts +3 -4
  46. package/dist/react/astro/SimulationControls.js +596 -650
  47. package/dist/react/astro/SimulationControls.js.map +1 -1
  48. package/dist/react/astro/StatusIndicator.d.ts +0 -1
  49. package/dist/react/astro/StatusIndicator.js +236 -170
  50. package/dist/react/astro/StatusIndicator.js.map +1 -1
  51. package/dist/react/astro/UnifiedTimeline.d.ts +9 -10
  52. package/dist/react/astro/UnifiedTimeline.js +2345 -2392
  53. package/dist/react/astro/UnifiedTimeline.js.map +1 -1
  54. package/dist/react/astro/index.d.ts +5 -5
  55. package/dist/react/astro/index.js +1 -25
  56. package/dist/react/cards/AccessCard.d.ts +0 -1
  57. package/dist/react/cards/AccessCard.js +471 -405
  58. package/dist/react/cards/AccessCard.js.map +1 -1
  59. package/dist/react/cards/OrbitCard.d.ts +0 -1
  60. package/dist/react/cards/OrbitCard.js +487 -364
  61. package/dist/react/cards/OrbitCard.js.map +1 -1
  62. package/dist/react/cards/SpacecraftCard.d.ts +0 -1
  63. package/dist/react/cards/SpacecraftCard.js +813 -925
  64. package/dist/react/cards/SpacecraftCard.js.map +1 -1
  65. package/dist/react/cards/TelemetryCard.d.ts +0 -1
  66. package/dist/react/cards/TelemetryCard.js +1055 -732
  67. package/dist/react/cards/TelemetryCard.js.map +1 -1
  68. package/dist/react/cards/TelemetryStreamCard.d.ts +0 -1
  69. package/dist/react/cards/TelemetryStreamCard.js +323 -297
  70. package/dist/react/cards/TelemetryStreamCard.js.map +1 -1
  71. package/dist/react/cards/index.d.ts +1 -1
  72. package/dist/react/cards/index.js +1 -8
  73. package/dist/react/charts/GroundTrackMap.d.ts +6 -7
  74. package/dist/react/charts/GroundTrackMap.js +1377 -1256
  75. package/dist/react/charts/GroundTrackMap.js.map +1 -1
  76. package/dist/react/charts/GroundTrackMapLeaflet.d.ts +1 -2
  77. package/dist/react/charts/GroundTrackMapLeaflet.js +1065 -987
  78. package/dist/react/charts/GroundTrackMapLeaflet.js.map +1 -1
  79. package/dist/react/charts/groundTrackMapLeafletTiles.js +34 -25
  80. package/dist/react/charts/groundTrackMapLeafletTiles.js.map +1 -1
  81. package/dist/react/charts/groundTrackMapLeafletUtils.js +70 -61
  82. package/dist/react/charts/groundTrackMapLeafletUtils.js.map +1 -1
  83. package/dist/react/charts/index.d.ts +1 -1
  84. package/dist/react/charts/index.js +7 -100
  85. package/dist/react/charts/unified/AstroChart.d.ts +1 -2
  86. package/dist/react/charts/unified/AstroChart.js +1331 -1411
  87. package/dist/react/charts/unified/AstroChart.js.map +1 -1
  88. package/dist/react/charts/unified/PowerOverviewChart.d.ts +3 -3
  89. package/dist/react/charts/unified/PowerOverviewChart.js +495 -478
  90. package/dist/react/charts/unified/PowerOverviewChart.js.map +1 -1
  91. package/dist/react/charts/unified/domain.d.ts +12 -13
  92. package/dist/react/charts/unified/domain.js +3999 -3145
  93. package/dist/react/charts/unified/domain.js.map +1 -1
  94. package/dist/react/charts/unified/generators.d.ts +3 -4
  95. package/dist/react/charts/unified/generators.js +561 -498
  96. package/dist/react/charts/unified/generators.js.map +1 -1
  97. package/dist/react/charts/unified/index.d.ts +1 -1
  98. package/dist/react/charts/unified/presets.d.ts +14 -15
  99. package/dist/react/charts/unified/presets.js +857 -994
  100. package/dist/react/charts/unified/presets.js.map +1 -1
  101. package/dist/react/charts/unified/sync.d.ts +2 -3
  102. package/dist/react/charts/unified/sync.js +229 -195
  103. package/dist/react/charts/unified/sync.js.map +1 -1
  104. package/dist/react/charts/unified/theme.d.ts +11 -12
  105. package/dist/react/charts/unified/theme.js +606 -642
  106. package/dist/react/charts/unified/theme.js.map +1 -1
  107. package/dist/react/charts/unified/types.d.ts +32 -33
  108. package/dist/react/charts/unified/useChartStream.d.ts +1 -2
  109. package/dist/react/charts/unified/useChartStream.js +203 -216
  110. package/dist/react/charts/unified/useChartStream.js.map +1 -1
  111. package/dist/react/chatgpt/AppCard.d.ts +1 -2
  112. package/dist/react/chatgpt/index.d.ts +7 -7
  113. package/dist/react/chatgpt/index.js +160 -139
  114. package/dist/react/chatgpt/index.js.map +1 -1
  115. package/dist/react/context/CategoryContext.d.ts +0 -1
  116. package/dist/react/context/CategoryContext.js +78 -29
  117. package/dist/react/context/CategoryContext.js.map +1 -1
  118. package/dist/react/context/DisplaySettingsContext.d.ts +1 -2
  119. package/dist/react/context/DisplaySettingsContext.js +205 -156
  120. package/dist/react/context/DisplaySettingsContext.js.map +1 -1
  121. package/dist/react/context/SpatialSelectionContext.d.ts +0 -1
  122. package/dist/react/context/SpatialSelectionContext.js +36 -7
  123. package/dist/react/context/SpatialSelectionContext.js.map +1 -1
  124. package/dist/react/core/data/DataTable.d.ts +3 -4
  125. package/dist/react/core/data/DataTable.js +473 -440
  126. package/dist/react/core/data/DataTable.js.map +1 -1
  127. package/dist/react/core/data/DataValue.d.ts +4 -5
  128. package/dist/react/core/data/DataValue.js +605 -571
  129. package/dist/react/core/data/DataValue.js.map +1 -1
  130. package/dist/react/core/data/propertyConfig.d.ts +1 -2
  131. package/dist/react/core/data/propertyConfig.js +446 -382
  132. package/dist/react/core/data/propertyConfig.js.map +1 -1
  133. package/dist/react/core/display/AstroIcon.d.ts +4 -5
  134. package/dist/react/core/display/AstroIcon.js +339 -429
  135. package/dist/react/core/display/AstroIcon.js.map +1 -1
  136. package/dist/react/core/display/Badge.d.ts +2 -3
  137. package/dist/react/core/display/Badge.js +131 -131
  138. package/dist/react/core/display/Badge.js.map +1 -1
  139. package/dist/react/core/display/CardHeader.d.ts +0 -1
  140. package/dist/react/core/display/CardHeader.js +398 -311
  141. package/dist/react/core/display/CardHeader.js.map +1 -1
  142. package/dist/react/core/display/Container.d.ts +2 -3
  143. package/dist/react/core/display/Container.js +640 -668
  144. package/dist/react/core/display/Container.js.map +1 -1
  145. package/dist/react/core/display/CopyButton.d.ts +1 -2
  146. package/dist/react/core/display/CopyButton.js +158 -101
  147. package/dist/react/core/display/CopyButton.js.map +1 -1
  148. package/dist/react/core/display/GlassCard.d.ts +3 -4
  149. package/dist/react/core/display/GlassCard.js +416 -369
  150. package/dist/react/core/display/GlassCard.js.map +1 -1
  151. package/dist/react/core/display/HeaderIconWithStatus.d.ts +0 -1
  152. package/dist/react/core/display/HeaderIconWithStatus.js +152 -152
  153. package/dist/react/core/display/HeaderIconWithStatus.js.map +1 -1
  154. package/dist/react/core/display/Icon.d.ts +2 -3
  155. package/dist/react/core/display/Icon.js +172 -143
  156. package/dist/react/core/display/Icon.js.map +1 -1
  157. package/dist/react/core/display/Typography.d.ts +24 -25
  158. package/dist/react/core/display/Typography.js +360 -178
  159. package/dist/react/core/display/Typography.js.map +1 -1
  160. package/dist/react/core/feedback/ConfirmDialog.d.ts +1 -2
  161. package/dist/react/core/feedback/ConfirmDialog.js +343 -304
  162. package/dist/react/core/feedback/ConfirmDialog.js.map +1 -1
  163. package/dist/react/core/feedback/Dialog.d.ts +2 -3
  164. package/dist/react/core/feedback/Dialog.js +189 -197
  165. package/dist/react/core/feedback/Dialog.js.map +1 -1
  166. package/dist/react/core/feedback/Toast.d.ts +2 -3
  167. package/dist/react/core/feedback/Toast.js +346 -207
  168. package/dist/react/core/feedback/Toast.js.map +1 -1
  169. package/dist/react/core/index.d.ts +26 -26
  170. package/dist/react/core/index.js +7 -119
  171. package/dist/react/core/inputs/Button.d.ts +2 -3
  172. package/dist/react/core/inputs/Button.js +281 -304
  173. package/dist/react/core/inputs/Button.js.map +1 -1
  174. package/dist/react/core/inputs/Checkbox.d.ts +2 -3
  175. package/dist/react/core/inputs/Checkbox.js +139 -127
  176. package/dist/react/core/inputs/Checkbox.js.map +1 -1
  177. package/dist/react/core/inputs/Input.d.ts +3 -4
  178. package/dist/react/core/inputs/Input.js +277 -285
  179. package/dist/react/core/inputs/Input.js.map +1 -1
  180. package/dist/react/core/inputs/LimitsBar.d.ts +1 -2
  181. package/dist/react/core/inputs/LimitsBar.js +271 -196
  182. package/dist/react/core/inputs/LimitsBar.js.map +1 -1
  183. package/dist/react/core/inputs/NumberInput.d.ts +2 -3
  184. package/dist/react/core/inputs/NumberInput.js +531 -503
  185. package/dist/react/core/inputs/NumberInput.js.map +1 -1
  186. package/dist/react/core/inputs/PinInput.d.ts +2 -3
  187. package/dist/react/core/inputs/PinInput.js +224 -207
  188. package/dist/react/core/inputs/PinInput.js.map +1 -1
  189. package/dist/react/core/inputs/Select.d.ts +1 -2
  190. package/dist/react/core/inputs/Select.js +298 -299
  191. package/dist/react/core/inputs/Select.js.map +1 -1
  192. package/dist/react/core/inputs/Toggle.d.ts +2 -3
  193. package/dist/react/core/inputs/Toggle.js +142 -148
  194. package/dist/react/core/inputs/Toggle.js.map +1 -1
  195. package/dist/react/core/layout/Box.d.ts +3 -4
  196. package/dist/react/core/layout/Box.js +118 -122
  197. package/dist/react/core/layout/Box.js.map +1 -1
  198. package/dist/react/core/layout/Center.d.ts +0 -1
  199. package/dist/react/core/layout/Center.js +45 -32
  200. package/dist/react/core/layout/Center.js.map +1 -1
  201. package/dist/react/core/layout/Divider.d.ts +1 -2
  202. package/dist/react/core/layout/Divider.js +112 -106
  203. package/dist/react/core/layout/Divider.js.map +1 -1
  204. package/dist/react/core/layout/Flex.d.ts +4 -5
  205. package/dist/react/core/layout/Flex.js +120 -124
  206. package/dist/react/core/layout/Flex.js.map +1 -1
  207. package/dist/react/core/layout/Grid.d.ts +5 -6
  208. package/dist/react/core/layout/Grid.js +131 -138
  209. package/dist/react/core/layout/Grid.js.map +1 -1
  210. package/dist/react/core/layout/Spacer.d.ts +0 -1
  211. package/dist/react/core/layout/Spacer.js +36 -29
  212. package/dist/react/core/layout/Spacer.js.map +1 -1
  213. package/dist/react/core/layout/Stack.d.ts +4 -5
  214. package/dist/react/core/layout/Stack.js +127 -70
  215. package/dist/react/core/layout/Stack.js.map +1 -1
  216. package/dist/react/core/layout/responsive.d.ts +1 -2
  217. package/dist/react/core/layout/responsive.js +25 -19
  218. package/dist/react/core/layout/responsive.js.map +1 -1
  219. package/dist/react/core/layout/useBreakpoint.d.ts +1 -1
  220. package/dist/react/core/layout/useBreakpoint.js +119 -66
  221. package/dist/react/core/layout/useBreakpoint.js.map +1 -1
  222. package/dist/react/core/navigation/AppBar.d.ts +1 -2
  223. package/dist/react/core/navigation/AppBar.js +827 -805
  224. package/dist/react/core/navigation/AppBar.js.map +1 -1
  225. package/dist/react/core/navigation/Pagination.d.ts +2 -3
  226. package/dist/react/core/navigation/Pagination.js +207 -187
  227. package/dist/react/core/navigation/Pagination.js.map +1 -1
  228. package/dist/react/core/navigation/SideNav.d.ts +5 -6
  229. package/dist/react/core/navigation/SideNav.js +855 -629
  230. package/dist/react/core/navigation/SideNav.js.map +1 -1
  231. package/dist/react/core/navigation/Tabs.d.ts +0 -1
  232. package/dist/react/core/navigation/Tabs.js +113 -119
  233. package/dist/react/core/navigation/Tabs.js.map +1 -1
  234. package/dist/react/core/overlays/Popover.d.ts +2 -3
  235. package/dist/react/core/overlays/Popover.js +303 -282
  236. package/dist/react/core/overlays/Popover.js.map +1 -1
  237. package/dist/react/core/overlays/SidePanel.d.ts +1 -2
  238. package/dist/react/core/overlays/SidePanel.js +217 -212
  239. package/dist/react/core/overlays/SidePanel.js.map +1 -1
  240. package/dist/react/core/overlays/Tooltip.d.ts +1 -2
  241. package/dist/react/core/overlays/Tooltip.js +170 -176
  242. package/dist/react/core/overlays/Tooltip.js.map +1 -1
  243. package/dist/react/core/widgets/ActivityPlanner.d.ts +0 -1
  244. package/dist/react/core/widgets/ActivityPlanner.js +855 -517
  245. package/dist/react/core/widgets/ActivityPlanner.js.map +1 -1
  246. package/dist/react/core/widgets/Capture.d.ts +2 -3
  247. package/dist/react/core/widgets/Capture.js +965 -779
  248. package/dist/react/core/widgets/Capture.js.map +1 -1
  249. package/dist/react/core/widgets/ChatPanel.d.ts +16 -17
  250. package/dist/react/core/widgets/ChatPanel.js +1734 -1034
  251. package/dist/react/core/widgets/ChatPanel.js.map +1 -1
  252. package/dist/react/core/widgets/ColorPickerPanel.d.ts +0 -1
  253. package/dist/react/core/widgets/ColorPickerPanel.js +298 -287
  254. package/dist/react/core/widgets/ColorPickerPanel.js.map +1 -1
  255. package/dist/react/core/widgets/CommandBuilder.d.ts +2 -3
  256. package/dist/react/core/widgets/CommandBuilder.js +624 -516
  257. package/dist/react/core/widgets/CommandBuilder.js.map +1 -1
  258. package/dist/react/core/widgets/ConnectionForm.d.ts +2 -3
  259. package/dist/react/core/widgets/ConnectionForm.js +528 -492
  260. package/dist/react/core/widgets/ConnectionForm.js.map +1 -1
  261. package/dist/react/core/widgets/FileExplorer.d.ts +3 -4
  262. package/dist/react/core/widgets/FileExplorer.js +617 -505
  263. package/dist/react/core/widgets/FileExplorer.js.map +1 -1
  264. package/dist/react/core/widgets/HexViewer.d.ts +2 -3
  265. package/dist/react/core/widgets/HexViewer.js +1353 -1091
  266. package/dist/react/core/widgets/HexViewer.js.map +1 -1
  267. package/dist/react/core/widgets/ImageFrame.d.ts +1 -2
  268. package/dist/react/core/widgets/ImageFrame.js +230 -193
  269. package/dist/react/core/widgets/ImageFrame.js.map +1 -1
  270. package/dist/react/core/widgets/ImageGallery.d.ts +2 -1
  271. package/dist/react/core/widgets/ImageGallery.js +380 -314
  272. package/dist/react/core/widgets/ImageGallery.js.map +1 -1
  273. package/dist/react/core/widgets/ImagePanel.d.ts +0 -1
  274. package/dist/react/core/widgets/ImagePanel.js +110 -101
  275. package/dist/react/core/widgets/ImagePanel.js.map +1 -1
  276. package/dist/react/core/widgets/LogViewer.d.ts +2 -3
  277. package/dist/react/core/widgets/LogViewer.js +711 -607
  278. package/dist/react/core/widgets/LogViewer.js.map +1 -1
  279. package/dist/react/core/widgets/MessageStream.d.ts +3 -4
  280. package/dist/react/core/widgets/MessageStream.js +514 -444
  281. package/dist/react/core/widgets/MessageStream.js.map +1 -1
  282. package/dist/react/core/widgets/MissionCalendar.d.ts +3 -4
  283. package/dist/react/core/widgets/MissionCalendar.js +1488 -1020
  284. package/dist/react/core/widgets/MissionCalendar.js.map +1 -1
  285. package/dist/react/core/widgets/PacketViewer.d.ts +2 -3
  286. package/dist/react/core/widgets/PacketViewer.js +550 -421
  287. package/dist/react/core/widgets/PacketViewer.js.map +1 -1
  288. package/dist/react/core/widgets/capture-placeholder.png.js +6 -5
  289. package/dist/react/core/widgets/capture-placeholder.png.js.map +1 -1
  290. package/dist/react/hooks/index.d.ts +5 -5
  291. package/dist/react/hooks/useAccessWindows.d.ts +0 -1
  292. package/dist/react/hooks/useCompactMode.d.ts +1 -1
  293. package/dist/react/hooks/useCompactMode.js +104 -58
  294. package/dist/react/hooks/useCompactMode.js.map +1 -1
  295. package/dist/react/hooks/useGroundTrackHistory.d.ts +0 -1
  296. package/dist/react/hooks/useSimulationScene.d.ts +1 -2
  297. package/dist/react/hooks/useSimulationScene.js +481 -374
  298. package/dist/react/hooks/useSimulationScene.js.map +1 -1
  299. package/dist/react/index.d.ts +3 -3
  300. package/dist/react/panels/LayerControlPanel.d.ts +1 -2
  301. package/dist/react/panels/LayerControlPanel.js +223 -180
  302. package/dist/react/panels/LayerControlPanel.js.map +1 -1
  303. package/dist/react/panels/ObjectInventoryPanel.d.ts +2 -3
  304. package/dist/react/panels/ObjectInventoryPanel.js +315 -250
  305. package/dist/react/panels/ObjectInventoryPanel.js.map +1 -1
  306. package/dist/react/panels/index.d.ts +1 -1
  307. package/dist/react/panels/index.js +1 -6
  308. package/dist/react/shared/ErrorBoundary.d.ts +1 -2
  309. package/dist/react/shared/ErrorBoundary.js +170 -139
  310. package/dist/react/shared/ErrorBoundary.js.map +1 -1
  311. package/dist/react/shared/Skeleton.d.ts +1 -2
  312. package/dist/react/shared/Skeleton.js +300 -301
  313. package/dist/react/shared/Skeleton.js.map +1 -1
  314. package/dist/react/theme/ThemeProvider.d.ts +2 -321
  315. package/dist/react/theme/ThemeProvider.js +312 -939
  316. package/dist/react/theme/ThemeProvider.js.map +1 -1
  317. package/dist/react/theme/cardAccent.d.ts +1 -2
  318. package/dist/react/theme/cardAccent.js +196 -126
  319. package/dist/react/theme/cardAccent.js.map +1 -1
  320. package/dist/react/theme/config.d.ts +0 -1
  321. package/dist/react/theme/config.js +47 -25
  322. package/dist/react/theme/config.js.map +1 -1
  323. package/dist/react/theme/index.d.ts +2 -2
  324. package/dist/react/theme/index.js +1 -16
  325. package/dist/react/theme/types.d.ts +332 -0
  326. package/dist/react/theme/types.js +39 -0
  327. package/dist/react/theme/types.js.map +1 -0
  328. package/dist/react/types.d.ts +8 -8
  329. package/dist/react/types.js +147 -47
  330. package/dist/react/types.js.map +1 -1
  331. package/dist/react/utils/categoryPalette.d.ts +0 -1
  332. package/dist/react/utils/categoryPalette.js +91 -102
  333. package/dist/react/utils/categoryPalette.js.map +1 -1
  334. package/dist/react/utils/index.d.ts +5 -5
  335. package/dist/react/utils/index.js +457 -371
  336. package/dist/react/utils/index.js.map +1 -1
  337. package/dist/react/visualizations/EclipseTimerCard.d.ts +0 -1
  338. package/dist/react/visualizations/LinkBudgetCard.d.ts +0 -1
  339. package/dist/react/visualizations/NavBallCard.d.ts +0 -1
  340. package/dist/react/visualizations/PropulsionCard.d.ts +1 -2
  341. package/dist/react/visualizations/SensorFootprintCard.d.ts +1 -2
  342. package/dist/react/visualizations/ThermalHeatmapCard.d.ts +0 -1
  343. package/dist/react/visualizations/index.d.ts +3 -3
  344. package/dist/react.d.ts +2 -1
  345. package/dist/react.js +17 -221
  346. package/dist/shaders/atmosphere.frag.js +6 -5
  347. package/dist/shaders/atmosphere.frag.js.map +1 -1
  348. package/dist/shaders/atmosphere.vert.js +6 -5
  349. package/dist/shaders/atmosphere.vert.js.map +1 -1
  350. package/dist/shaders/stars.frag.js +6 -5
  351. package/dist/shaders/stars.frag.js.map +1 -1
  352. package/dist/shaders/stars.vert.js +6 -5
  353. package/dist/shaders/stars.vert.js.map +1 -1
  354. package/dist/style.css +217 -194
  355. package/dist/tokens/core.d.ts +159 -0
  356. package/dist/tokens/core.js +144 -0
  357. package/dist/tokens/core.js.map +1 -0
  358. package/dist/tokens/css-vars.d.ts +213 -2
  359. package/dist/tokens/css-vars.js +590 -227
  360. package/dist/tokens/css-vars.js.map +1 -1
  361. package/dist/tokens/index.d.ts +31 -228
  362. package/dist/tokens/index.js +281 -366
  363. package/dist/tokens/index.js.map +1 -1
  364. package/dist/tokens/palettes/astro.d.ts +129 -0
  365. package/dist/tokens/palettes/astro.js +112 -0
  366. package/dist/tokens/palettes/astro.js.map +1 -0
  367. package/dist/tokens/palettes/index.d.ts +288 -0
  368. package/dist/tokens/palettes/index.js +35 -0
  369. package/dist/tokens/palettes/index.js.map +1 -0
  370. package/dist/tokens/palettes/tailwind.d.ts +324 -0
  371. package/dist/tokens/palettes/tailwind.js +201 -0
  372. package/dist/tokens/palettes/tailwind.js.map +1 -0
  373. package/dist/tokens/palettes/zendir.d.ts +126 -0
  374. package/dist/tokens/palettes/zendir.js +92 -0
  375. package/dist/tokens/palettes/zendir.js.map +1 -0
  376. package/dist/tokens/themes.d.ts +30 -0
  377. package/dist/tokens/themes.js +704 -0
  378. package/dist/tokens/themes.js.map +1 -0
  379. package/dist/tokens/tokens.css +419 -41
  380. package/dist/types/index.d.ts +2 -2
  381. package/package.json +310 -313
  382. package/dist/index.js.map +0 -1
  383. package/dist/react/3d/index.js.map +0 -1
  384. package/dist/react/astro/index.js.map +0 -1
  385. package/dist/react/cards/index.js.map +0 -1
  386. package/dist/react/charts/index.js.map +0 -1
  387. package/dist/react/core/index.js.map +0 -1
  388. package/dist/react/panels/index.js.map +0 -1
  389. package/dist/react/theme/astro-tokens.d.ts +0 -153
  390. package/dist/react/theme/index.js.map +0 -1
  391. package/dist/react.js.map +0 -1
@@ -1,1049 +1,1517 @@
1
- import { jsxs, jsx } from "react/jsx-runtime";
2
- import { memo, useState, useRef, useMemo, useCallback } from "react";
3
1
  import { useTheme } from "../../theme/ThemeProvider.js";
4
2
  import { AstroIcon } from "../display/AstroIcon.js";
3
+ import { memo, useCallback, useMemo, useRef, useState } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ //#region src/react/core/widgets/MissionCalendar.tsx
6
+ /**
7
+ * @zendir/ui - MissionCalendar Component
8
+ *
9
+ * Full-featured calendar for mission planning and scheduling with 5 views:
10
+ * Month, Week (time-grid), Day (time-grid), Gantt, and List.
11
+ *
12
+ * Includes a mini calendar sidebar for quick date navigation, timeline
13
+ * and event type filtering, right-click to create at time slots, week
14
+ * number display, and DOY (Day of Year) in the header.
15
+ *
16
+ * Features (matching/exceeding OpenC3 Calendar):
17
+ * - Day / Week / Month / Gantt / List views
18
+ * - Time-grid with 30-min rows for Week and Day views
19
+ * - Mini calendar sidebar with event type + timeline filters
20
+ * - Activity scheduling with command/script/reserve execution types
21
+ * - Metadata recording (key-value pairs, start time only)
22
+ * - Notes with start + end time
23
+ * - Status-colored events per Astro UX (circle, square, triangle down)
24
+ * - Activity lifecycle (created, started, completed, paused, stopped, error, etc.)
25
+ * - Multi-timeline support (overlapping prevention per timeline)
26
+ * - Right-click context menu to create events at specific time slots
27
+ * - Week number + DOY display
28
+ * - Contact window / eclipse / pass event types (beyond OpenC3)
29
+ * - weekStartsMonday option (Sunday-Saturday or Monday-Sunday)
30
+ * - Integration with Timeline component via onDayDrillDown
31
+ *
32
+ * @example
33
+ * ```tsx
34
+ * <MissionCalendar
35
+ * events={missionEvents}
36
+ * timelines={[{ id: 'ops', name: 'OPS-1', color: '#2dccff' }]}
37
+ * onEventCreate={(e) => console.log('New event:', e)}
38
+ * onEventClick={(e) => console.log('Clicked:', e)}
39
+ * />
40
+ * ```
41
+ */
5
42
  function getStatusColor(status, tokens) {
6
- if (!status) return tokens.colors.text.muted ?? tokens.colors.text.secondary;
7
- switch (status) {
8
- case "created":
9
- case "scheduled":
10
- return tokens.colors.status.standby;
11
- case "started":
12
- return tokens.colors.status.normal;
13
- case "completed":
14
- return tokens.colors.status.normal;
15
- case "paused":
16
- case "stopped":
17
- case "disabled":
18
- return tokens.colors.status.caution;
19
- case "error":
20
- case "failed":
21
- case "crashed":
22
- return tokens.colors.status.critical;
23
- }
43
+ if (!status) return tokens.colors.text.muted ?? tokens.colors.text.secondary;
44
+ switch (status) {
45
+ case "created":
46
+ case "scheduled": return tokens.colors.status.standby;
47
+ case "started": return tokens.colors.status.normal;
48
+ case "completed": return tokens.colors.status.normal;
49
+ case "paused":
50
+ case "stopped":
51
+ case "disabled": return tokens.colors.status.caution;
52
+ case "error":
53
+ case "failed":
54
+ case "crashed": return tokens.colors.status.critical;
55
+ }
24
56
  }
57
+ /**
58
+ * Return Astro UX status shape per status level.
59
+ * off → small dot, standby → ring ◯, normal → filled circle ●,
60
+ * caution → square ■, serious → diamond ◆, critical → triangle down ▼
61
+ */
25
62
  function getStatusShape(status) {
26
- if (!status) return "●";
27
- switch (status) {
28
- case "created":
29
- case "scheduled":
30
- return "";
31
- case "started":
32
- case "completed":
33
- return "";
34
- case "paused":
35
- case "stopped":
36
- case "disabled":
37
- return "";
38
- case "error":
39
- case "failed":
40
- case "crashed":
41
- return "▼";
42
- }
63
+ if (!status) return "●";
64
+ switch (status) {
65
+ case "created":
66
+ case "scheduled": return "◯";
67
+ case "started":
68
+ case "completed": return "●";
69
+ case "paused":
70
+ case "stopped":
71
+ case "disabled": return "■";
72
+ case "error":
73
+ case "failed":
74
+ case "crashed": return "";
75
+ }
43
76
  }
44
- const TYPE_ICON_ASTRO = ["contact", "eclipse", "pass"];
77
+ var TYPE_ICON_ASTRO = [
78
+ "contact",
79
+ "eclipse",
80
+ "pass"
81
+ ];
45
82
  function getTypeIcon(type) {
46
- switch (type) {
47
- case "command":
48
- return "";
49
- case "script":
50
- return "";
51
- case "reserve":
52
- return "";
53
- case "metadata":
54
- return "";
55
- case "note":
56
- return "✎";
57
- case "contact":
58
- return "antenna";
59
- case "eclipse":
60
- return "brightness-2";
61
- case "pass":
62
- return "satellite";
63
- }
83
+ switch (type) {
84
+ case "command": return "⌘";
85
+ case "script": return "";
86
+ case "reserve": return "▒";
87
+ case "metadata": return "";
88
+ case "note": return "✎";
89
+ case "contact": return "antenna";
90
+ case "eclipse": return "brightness-2";
91
+ case "pass": return "satellite";
92
+ }
64
93
  }
65
94
  function getDaysInMonth(year, month) {
66
- return new Date(year, month + 1, 0).getDate();
95
+ return new Date(year, month + 1, 0).getDate();
67
96
  }
68
97
  function getFirstDayOfMonth(year, month, mondayStart) {
69
- const day = new Date(year, month, 1).getDay();
70
- if (mondayStart) return day === 0 ? 6 : day - 1;
71
- return day;
98
+ const day = new Date(year, month, 1).getDay();
99
+ if (mondayStart) return day === 0 ? 6 : day - 1;
100
+ return day;
72
101
  }
73
102
  function isSameDay(a, b) {
74
- return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
103
+ return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
75
104
  }
76
105
  function formatTime(d) {
77
- return d.toLocaleTimeString("en-US", { hour12: false, hour: "2-digit", minute: "2-digit" });
106
+ return d.toLocaleTimeString("en-US", {
107
+ hour12: false,
108
+ hour: "2-digit",
109
+ minute: "2-digit"
110
+ });
78
111
  }
79
112
  function getWeekDates(date, mondayStart) {
80
- const d = new Date(date);
81
- const day = d.getDay();
82
- const diff = mondayStart ? day === 0 ? -6 : 1 - day : -day;
83
- const start = new Date(d);
84
- start.setDate(start.getDate() + diff);
85
- return Array.from({ length: 7 }, (_, i) => {
86
- const dt = new Date(start);
87
- dt.setDate(dt.getDate() + i);
88
- return dt;
89
- });
113
+ const d = new Date(date);
114
+ const day = d.getDay();
115
+ const diff = mondayStart ? day === 0 ? -6 : 1 - day : -day;
116
+ const start = new Date(d);
117
+ start.setDate(start.getDate() + diff);
118
+ return Array.from({ length: 7 }, (_, i) => {
119
+ const dt = new Date(start);
120
+ dt.setDate(dt.getDate() + i);
121
+ return dt;
122
+ });
90
123
  }
124
+ /** ISO week number */
91
125
  function getWeekNumber(d) {
92
- const date = new Date(d.getTime());
93
- date.setHours(0, 0, 0, 0);
94
- date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7);
95
- const week1 = new Date(date.getFullYear(), 0, 4);
96
- return 1 + Math.round(((date.getTime() - week1.getTime()) / 864e5 - 3 + (week1.getDay() + 6) % 7) / 7);
126
+ const date = new Date(d.getTime());
127
+ date.setHours(0, 0, 0, 0);
128
+ date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7);
129
+ const week1 = new Date(date.getFullYear(), 0, 4);
130
+ return 1 + Math.round(((date.getTime() - week1.getTime()) / 864e5 - 3 + (week1.getDay() + 6) % 7) / 7);
97
131
  }
132
+ /** Day of year (1-366) */
98
133
  function getDayOfYear(d) {
99
- const start = new Date(d.getFullYear(), 0, 0);
100
- const diff = d.getTime() - start.getTime();
101
- return Math.floor(diff / 864e5);
134
+ const start = new Date(d.getFullYear(), 0, 0);
135
+ const diff = d.getTime() - start.getTime();
136
+ return Math.floor(diff / 864e5);
102
137
  }
103
- const TIME_SLOTS = [];
138
+ /** 30-minute time slots for the time-grid views */
139
+ var TIME_SLOTS = [];
104
140
  for (let h = 0; h < 24; h++) {
105
- TIME_SLOTS.push(`${String(h).padStart(2, "0")}:00`);
106
- TIME_SLOTS.push(`${String(h).padStart(2, "0")}:30`);
141
+ TIME_SLOTS.push(`${String(h).padStart(2, "0")}:00`);
142
+ TIME_SLOTS.push(`${String(h).padStart(2, "0")}:30`);
107
143
  }
108
- const SLOT_HEIGHT = 28;
109
- const CalendarEventChip = memo(function CalendarEventChip2({
110
- event,
111
- tokens,
112
- compact,
113
- onClick
114
- }) {
115
- const color = event.color || getStatusColor(event.status, tokens);
116
- return /* @__PURE__ */ jsxs(
117
- "div",
118
- {
119
- onClick: (e) => {
120
- e.stopPropagation();
121
- onClick == null ? void 0 : onClick();
122
- },
123
- title: `${event.title}
124
- ${formatTime(event.start)}${event.end ? " – " + formatTime(event.end) : ""}
125
- ${event.description || ""}`,
126
- style: {
127
- background: `${color}22`,
128
- color: tokens.colors.text.primary,
129
- padding: compact ? "1px 4px" : "2px 6px",
130
- borderRadius: tokens.borderRadius.sm,
131
- fontSize: compact ? tokens.typography.fontSize.micro : tokens.typography.fontSize.xxs,
132
- lineHeight: compact ? "14px" : "16px",
133
- cursor: "pointer",
134
- overflow: "hidden",
135
- textOverflow: "ellipsis",
136
- whiteSpace: "nowrap",
137
- display: "flex",
138
- alignItems: "center",
139
- gap: 3,
140
- transition: "background 150ms ease",
141
- marginBottom: 1
142
- },
143
- children: [
144
- /* @__PURE__ */ jsx("span", { style: { fontSize: tokens.typography.fontSize.micro, opacity: 0.7 }, children: TYPE_ICON_ASTRO.includes(event.type) ? /* @__PURE__ */ jsx(AstroIcon, { name: getTypeIcon(event.type), size: "extra-small", label: "" }) : getTypeIcon(event.type) }),
145
- !compact && /* @__PURE__ */ jsx("span", { style: { color, fontSize: tokens.typography.fontSize.micro }, children: getStatusShape(event.status) }),
146
- /* @__PURE__ */ jsx("span", { style: { overflow: "hidden", textOverflow: "ellipsis" }, children: event.title })
147
- ]
148
- }
149
- );
144
+ var SLOT_HEIGHT = 28;
145
+ var CalendarEventChip = memo(function CalendarEventChip({ event, tokens, compact, onClick }) {
146
+ const color = event.color || getStatusColor(event.status, tokens);
147
+ return /* @__PURE__ */ jsxs("div", {
148
+ onClick: (e) => {
149
+ e.stopPropagation();
150
+ onClick?.();
151
+ },
152
+ title: `${event.title}\n${formatTime(event.start)}${event.end ? " – " + formatTime(event.end) : ""}\n${event.description || ""}`,
153
+ style: {
154
+ background: `${color}22`,
155
+ color: tokens.colors.text.primary,
156
+ padding: compact ? "1px 4px" : "2px 6px",
157
+ borderRadius: tokens.borderRadius.sm,
158
+ fontSize: compact ? tokens.typography.fontSize.micro : tokens.typography.fontSize.xxs,
159
+ lineHeight: compact ? "14px" : "16px",
160
+ cursor: "pointer",
161
+ overflow: "hidden",
162
+ textOverflow: "ellipsis",
163
+ whiteSpace: "nowrap",
164
+ display: "flex",
165
+ alignItems: "center",
166
+ gap: 3,
167
+ transition: "background 150ms ease",
168
+ marginBottom: 1
169
+ },
170
+ children: [
171
+ /* @__PURE__ */ jsx("span", {
172
+ style: {
173
+ fontSize: tokens.typography.fontSize.micro,
174
+ opacity: .7
175
+ },
176
+ children: TYPE_ICON_ASTRO.includes(event.type) ? /* @__PURE__ */ jsx(AstroIcon, {
177
+ name: getTypeIcon(event.type),
178
+ size: "extra-small",
179
+ label: ""
180
+ }) : getTypeIcon(event.type)
181
+ }),
182
+ !compact && /* @__PURE__ */ jsx("span", {
183
+ style: {
184
+ color,
185
+ fontSize: tokens.typography.fontSize.micro
186
+ },
187
+ children: getStatusShape(event.status)
188
+ }),
189
+ /* @__PURE__ */ jsx("span", {
190
+ style: {
191
+ overflow: "hidden",
192
+ textOverflow: "ellipsis"
193
+ },
194
+ children: event.title
195
+ })
196
+ ]
197
+ });
150
198
  });
151
- const MiniCalendar = memo(function MiniCalendar2({
152
- currentDate,
153
- tokens,
154
- weekStartsMonday,
155
- onDateSelect,
156
- getEventsForDay
157
- }) {
158
- const [miniDate, setMiniDate] = useState(new Date(currentDate));
159
- const year = miniDate.getFullYear();
160
- const month = miniDate.getMonth();
161
- const today = /* @__PURE__ */ new Date();
162
- const dayLabels = weekStartsMonday ? ["M", "T", "W", "T", "F", "S", "S"] : ["S", "M", "T", "W", "T", "F", "S"];
163
- const grid = useMemo(() => {
164
- const firstDay = getFirstDayOfMonth(year, month, weekStartsMonday);
165
- const daysInMonth = getDaysInMonth(year, month);
166
- const daysInPrevMonth = getDaysInMonth(year, month === 0 ? 11 : month - 1);
167
- const cells = [];
168
- for (let i = firstDay - 1; i >= 0; i--) {
169
- cells.push({ date: new Date(year, month - 1, daysInPrevMonth - i), isCurrentMonth: false });
170
- }
171
- for (let i = 1; i <= daysInMonth; i++) {
172
- cells.push({ date: new Date(year, month, i), isCurrentMonth: true });
173
- }
174
- while (cells.length < 42) {
175
- cells.push({ date: new Date(year, month + 1, cells.length - firstDay - daysInMonth + 1), isCurrentMonth: false });
176
- }
177
- return cells;
178
- }, [year, month, weekStartsMonday]);
179
- return /* @__PURE__ */ jsxs("div", { children: [
180
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 6 }, children: [
181
- /* @__PURE__ */ jsx("button", { onClick: () => setMiniDate(new Date(year, month - 1)), style: { background: "none", border: "none", color: tokens.colors.text.muted, cursor: "pointer", fontSize: 12, padding: "2px 6px" }, children: "◀" }),
182
- /* @__PURE__ */ jsx("span", { style: { fontWeight: 500, fontSize: 11 }, children: miniDate.toLocaleDateString("en-US", { month: "short", year: "numeric" }) }),
183
- /* @__PURE__ */ jsx("button", { onClick: () => setMiniDate(new Date(year, month + 1)), style: { background: "none", border: "none", color: tokens.colors.text.muted, cursor: "pointer", fontSize: 12, padding: "2px 6px" }, children: "▶" })
184
- ] }),
185
- /* @__PURE__ */ jsxs("div", { style: { display: "grid", gridTemplateColumns: "repeat(7, 1fr)", gap: 0 }, children: [
186
- dayLabels.map((d, i) => /* @__PURE__ */ jsx("div", { style: { textAlign: "center", fontSize: 9, color: tokens.colors.text.muted, fontWeight: 500, padding: "2px 0" }, children: d }, i)),
187
- grid.map(({ date, isCurrentMonth }, idx) => {
188
- const isToday = isSameDay(date, today);
189
- const isSelected = isSameDay(date, currentDate);
190
- const hasEvents = getEventsForDay(date).length > 0;
191
- return /* @__PURE__ */ jsxs(
192
- "div",
193
- {
194
- onClick: () => onDateSelect(date),
195
- style: {
196
- textAlign: "center",
197
- fontSize: 10,
198
- padding: "3px 0",
199
- cursor: "pointer",
200
- color: isSelected ? tokens.colors.text.inverse : isCurrentMonth ? tokens.colors.text.primary : tokens.colors.text.muted + "55",
201
- fontWeight: isToday || isSelected ? 700 : 400,
202
- background: isSelected ? tokens.colors.interactive.default : isToday ? `${tokens.colors.interactive.default}20` : "transparent",
203
- borderRadius: isSelected || isToday ? tokens.borderRadius.full : 0,
204
- position: "relative"
205
- },
206
- children: [
207
- date.getDate(),
208
- hasEvents && !isSelected && /* @__PURE__ */ jsx("span", { style: {
209
- position: "absolute",
210
- bottom: 0,
211
- left: "50%",
212
- transform: "translateX(-50%)",
213
- width: 3,
214
- height: 3,
215
- borderRadius: "50%",
216
- background: tokens.colors.interactive.default
217
- } })
218
- ]
219
- },
220
- idx
221
- );
222
- })
223
- ] })
224
- ] });
199
+ /** Mini calendar for sidebar */
200
+ var MiniCalendar = memo(function MiniCalendar({ currentDate, tokens, weekStartsMonday, onDateSelect, getEventsForDay }) {
201
+ const [miniDate, setMiniDate] = useState(new Date(currentDate));
202
+ const year = miniDate.getFullYear();
203
+ const month = miniDate.getMonth();
204
+ const today = /* @__PURE__ */ new Date();
205
+ const dayLabels = weekStartsMonday ? [
206
+ "M",
207
+ "T",
208
+ "W",
209
+ "T",
210
+ "F",
211
+ "S",
212
+ "S"
213
+ ] : [
214
+ "S",
215
+ "M",
216
+ "T",
217
+ "W",
218
+ "T",
219
+ "F",
220
+ "S"
221
+ ];
222
+ const grid = useMemo(() => {
223
+ const firstDay = getFirstDayOfMonth(year, month, weekStartsMonday);
224
+ const daysInMonth = getDaysInMonth(year, month);
225
+ const daysInPrevMonth = getDaysInMonth(year, month === 0 ? 11 : month - 1);
226
+ const cells = [];
227
+ for (let i = firstDay - 1; i >= 0; i--) cells.push({
228
+ date: new Date(year, month - 1, daysInPrevMonth - i),
229
+ isCurrentMonth: false
230
+ });
231
+ for (let i = 1; i <= daysInMonth; i++) cells.push({
232
+ date: new Date(year, month, i),
233
+ isCurrentMonth: true
234
+ });
235
+ while (cells.length < 42) cells.push({
236
+ date: new Date(year, month + 1, cells.length - firstDay - daysInMonth + 1),
237
+ isCurrentMonth: false
238
+ });
239
+ return cells;
240
+ }, [
241
+ year,
242
+ month,
243
+ weekStartsMonday
244
+ ]);
245
+ return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("div", {
246
+ style: {
247
+ display: "flex",
248
+ alignItems: "center",
249
+ justifyContent: "space-between",
250
+ marginBottom: 6
251
+ },
252
+ children: [
253
+ /* @__PURE__ */ jsx("button", {
254
+ onClick: () => setMiniDate(new Date(year, month - 1)),
255
+ style: {
256
+ background: "none",
257
+ border: "none",
258
+ color: tokens.colors.text.muted,
259
+ cursor: "pointer",
260
+ fontSize: 12,
261
+ padding: "2px 6px"
262
+ },
263
+ children: ""
264
+ }),
265
+ /* @__PURE__ */ jsx("span", {
266
+ style: {
267
+ fontWeight: 500,
268
+ fontSize: 11
269
+ },
270
+ children: miniDate.toLocaleDateString("en-US", {
271
+ month: "short",
272
+ year: "numeric"
273
+ })
274
+ }),
275
+ /* @__PURE__ */ jsx("button", {
276
+ onClick: () => setMiniDate(new Date(year, month + 1)),
277
+ style: {
278
+ background: "none",
279
+ border: "none",
280
+ color: tokens.colors.text.muted,
281
+ cursor: "pointer",
282
+ fontSize: 12,
283
+ padding: "2px 6px"
284
+ },
285
+ children: "▶"
286
+ })
287
+ ]
288
+ }), /* @__PURE__ */ jsxs("div", {
289
+ style: {
290
+ display: "grid",
291
+ gridTemplateColumns: "repeat(7, 1fr)",
292
+ gap: 0
293
+ },
294
+ children: [dayLabels.map((d, i) => /* @__PURE__ */ jsx("div", {
295
+ style: {
296
+ textAlign: "center",
297
+ fontSize: 9,
298
+ color: tokens.colors.text.muted,
299
+ fontWeight: 500,
300
+ padding: "2px 0"
301
+ },
302
+ children: d
303
+ }, i)), grid.map(({ date, isCurrentMonth }, idx) => {
304
+ const isToday = isSameDay(date, today);
305
+ const isSelected = isSameDay(date, currentDate);
306
+ const hasEvents = getEventsForDay(date).length > 0;
307
+ return /* @__PURE__ */ jsxs("div", {
308
+ onClick: () => onDateSelect(date),
309
+ style: {
310
+ textAlign: "center",
311
+ fontSize: 10,
312
+ padding: "3px 0",
313
+ cursor: "pointer",
314
+ color: isSelected ? tokens.colors.text.inverse : isCurrentMonth ? tokens.colors.text.primary : tokens.colors.text.muted + "55",
315
+ fontWeight: isToday || isSelected ? 700 : 400,
316
+ background: isSelected ? tokens.colors.interactive.default : isToday ? `${tokens.colors.interactive.default}20` : "transparent",
317
+ borderRadius: isSelected || isToday ? tokens.borderRadius.full : 0,
318
+ position: "relative"
319
+ },
320
+ children: [date.getDate(), hasEvents && !isSelected && /* @__PURE__ */ jsx("span", { style: {
321
+ position: "absolute",
322
+ bottom: 0,
323
+ left: "50%",
324
+ transform: "translateX(-50%)",
325
+ width: 3,
326
+ height: 3,
327
+ borderRadius: "50%",
328
+ background: tokens.colors.interactive.default
329
+ } })]
330
+ }, idx);
331
+ })]
332
+ })] });
225
333
  });
226
- const MissionCalendar = memo(function MissionCalendar2({
227
- events,
228
- timelines = [],
229
- defaultView = "month",
230
- initialDate,
231
- height = 600,
232
- title,
233
- showSidebar = true,
234
- showTimelines = true,
235
- showFilters = true,
236
- showCreate = true,
237
- weekStartsMonday = true,
238
- onEventClick,
239
- onEventCreate,
240
- onDayDrillDown,
241
- className = ""
242
- }) {
243
- const { tokens, theme } = useTheme();
244
- const isTransparentTheme = theme === "transparent" || theme === "transparent-bold" || theme === "transparent-minimal";
245
- const [viewMode, setViewMode] = useState(defaultView);
246
- const [currentDate, setCurrentDate] = useState(initialDate || /* @__PURE__ */ new Date());
247
- const [selectedTimelines, setSelectedTimelines] = useState(
248
- new Set(timelines.map((t) => t.id))
249
- );
250
- const [typeFilter, setTypeFilter] = useState(
251
- /* @__PURE__ */ new Set(["command", "script", "reserve", "metadata", "note", "contact", "eclipse", "pass"])
252
- );
253
- const [contextMenu, setContextMenu] = useState(null);
254
- const bodyRef = useRef(null);
255
- const year = currentDate.getFullYear();
256
- const month = currentDate.getMonth();
257
- const filteredEvents = useMemo(
258
- () => events.filter(
259
- (e) => typeFilter.has(e.type) && (selectedTimelines.size === 0 || !e.timeline || selectedTimelines.has(e.timeline))
260
- ),
261
- [events, typeFilter, selectedTimelines]
262
- );
263
- const eventsByDay = useMemo(() => {
264
- const map = /* @__PURE__ */ new Map();
265
- filteredEvents.forEach((e) => {
266
- const key = `${e.start.getFullYear()}-${e.start.getMonth()}-${e.start.getDate()}`;
267
- if (!map.has(key)) map.set(key, []);
268
- map.get(key).push(e);
269
- if (e.end) {
270
- const days = Math.ceil((e.end.getTime() - e.start.getTime()) / 864e5);
271
- for (let d = 1; d <= days && d < 30; d++) {
272
- const next = new Date(e.start);
273
- next.setDate(next.getDate() + d);
274
- const nk = `${next.getFullYear()}-${next.getMonth()}-${next.getDate()}`;
275
- if (!map.has(nk)) map.set(nk, []);
276
- map.get(nk).push(e);
277
- }
278
- }
279
- });
280
- return map;
281
- }, [filteredEvents]);
282
- const getEventsForDay = useCallback((d) => {
283
- const key = `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;
284
- return eventsByDay.get(key) || [];
285
- }, [eventsByDay]);
286
- const navigate = useCallback((dir) => {
287
- if (dir === 0) {
288
- setCurrentDate(/* @__PURE__ */ new Date());
289
- return;
290
- }
291
- const d = new Date(currentDate);
292
- if (viewMode === "month") d.setMonth(d.getMonth() + dir);
293
- else if (viewMode === "week" || viewMode === "gantt") d.setDate(d.getDate() + dir * 7);
294
- else d.setDate(d.getDate() + dir);
295
- setCurrentDate(d);
296
- }, [currentDate, viewMode]);
297
- const toggleTimeline = useCallback((id) => {
298
- setSelectedTimelines((prev) => {
299
- const next = new Set(prev);
300
- if (next.has(id)) next.delete(id);
301
- else next.add(id);
302
- return next;
303
- });
304
- }, []);
305
- const toggleType = useCallback((type) => {
306
- setTypeFilter((prev) => {
307
- const next = new Set(prev);
308
- if (next.has(type)) next.delete(type);
309
- else next.add(type);
310
- return next;
311
- });
312
- }, []);
313
- const dayNames = weekStartsMonday ? ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] : ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
314
- const monthLabel = currentDate.toLocaleDateString("en-US", { month: "long", year: "numeric" });
315
- const today = /* @__PURE__ */ new Date();
316
- const weekNum = getWeekNumber(currentDate);
317
- const doy = getDayOfYear(currentDate);
318
- const monthGrid = useMemo(() => {
319
- const firstDay = getFirstDayOfMonth(year, month, weekStartsMonday);
320
- const daysInMonth = getDaysInMonth(year, month);
321
- const daysInPrevMonth = getDaysInMonth(year, month === 0 ? 11 : month - 1);
322
- const cells = [];
323
- for (let i = firstDay - 1; i >= 0; i--) {
324
- cells.push({ date: new Date(year, month - 1, daysInPrevMonth - i), isCurrentMonth: false });
325
- }
326
- for (let i = 1; i <= daysInMonth; i++) {
327
- cells.push({ date: new Date(year, month, i), isCurrentMonth: true });
328
- }
329
- while (cells.length < 42) {
330
- cells.push({ date: new Date(year, month + 1, cells.length - firstDay - daysInMonth + 1), isCurrentMonth: false });
331
- }
332
- return cells;
333
- }, [year, month, weekStartsMonday]);
334
- const weekDates = useMemo(() => getWeekDates(currentDate, weekStartsMonday), [currentDate, weekStartsMonday]);
335
- const dayEvents = useMemo(() => {
336
- const evts = getEventsForDay(currentDate);
337
- return [...evts].sort((a, b) => a.start.getTime() - b.start.getTime());
338
- }, [currentDate, getEventsForDay]);
339
- const listEvents = useMemo(() => {
340
- const now = /* @__PURE__ */ new Date();
341
- const end = new Date(now);
342
- end.setDate(end.getDate() + 7);
343
- return filteredEvents.filter((e) => e.start >= now && e.start <= end).sort((a, b) => a.start.getTime() - b.start.getTime());
344
- }, [filteredEvents]);
345
- const ganttData = useMemo(() => {
346
- const weekStart = new Date(weekDates[0]);
347
- weekStart.setHours(0, 0, 0, 0);
348
- const weekEnd = new Date(weekDates[6]);
349
- weekEnd.setHours(23, 59, 59, 999);
350
- const weekEvents = filteredEvents.filter(
351
- (e) => e.start <= weekEnd && (e.end || e.start) >= weekStart
352
- );
353
- const tlMap = /* @__PURE__ */ new Map();
354
- const noTl = [];
355
- weekEvents.forEach((e) => {
356
- const tlId = e.timeline || "";
357
- if (!tlId) {
358
- noTl.push(e);
359
- return;
360
- }
361
- if (!tlMap.has(tlId)) tlMap.set(tlId, []);
362
- tlMap.get(tlId).push(e);
363
- });
364
- const rows = [];
365
- timelines.forEach((tl) => {
366
- if (tlMap.has(tl.id)) {
367
- rows.push({ label: tl.name, color: tl.color || tokens.colors.interactive.default, events: tlMap.get(tl.id) });
368
- }
369
- });
370
- if (noTl.length > 0) rows.push({ label: "Unassigned", color: tokens.colors.text.muted ?? tokens.colors.text.secondary, events: noTl });
371
- return { rows, weekStart, weekEnd };
372
- }, [filteredEvents, weekDates, timelines, tokens]);
373
- const handleContextMenu = useCallback((e, date, slotTime) => {
374
- e.preventDefault();
375
- if (!onEventCreate) return;
376
- const d = new Date(date);
377
- if (slotTime) {
378
- const [h, m] = slotTime.split(":").map(Number);
379
- d.setHours(h, m, 0, 0);
380
- }
381
- setContextMenu({ x: e.clientX, y: e.clientY, date: d });
382
- }, [onEventCreate]);
383
- const headerLabel = useMemo(() => {
384
- if (viewMode === "month") return monthLabel;
385
- if (viewMode === "week" || viewMode === "gantt") {
386
- return `${weekDates[0].toLocaleDateString("en-US", { month: "short", day: "numeric" })} – ${weekDates[6].toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })} Week ${weekNum}`;
387
- }
388
- return currentDate.toLocaleDateString("en-US", { weekday: "long", month: "long", day: "numeric", year: "numeric" });
389
- }, [viewMode, monthLabel, weekDates, weekNum, currentDate]);
390
- const renderSidebar = () => /* @__PURE__ */ jsxs("div", { style: {
391
- width: 190,
392
- minWidth: 190,
393
- borderRight: `1px solid ${tokens.colors.border.muted}`,
394
- background: tokens.colors.background.surface,
395
- padding: "8px 10px",
396
- display: "flex",
397
- flexDirection: "column",
398
- gap: 12,
399
- overflow: "auto"
400
- }, children: [
401
- /* @__PURE__ */ jsx(
402
- MiniCalendar,
403
- {
404
- currentDate,
405
- tokens,
406
- weekStartsMonday,
407
- onDateSelect: (d) => {
408
- setCurrentDate(d);
409
- if (viewMode === "month") setViewMode("day");
410
- },
411
- getEventsForDay
412
- }
413
- ),
414
- showFilters && /* @__PURE__ */ jsxs("div", { children: [
415
- /* @__PURE__ */ jsx("div", { style: { fontSize: 10, fontWeight: 500, color: tokens.colors.text.muted, textTransform: "uppercase", letterSpacing: 0.5, marginBottom: 4 }, children: "Event Types" }),
416
- ["command", "script", "reserve", "metadata", "note", "contact"].map((type) => /* @__PURE__ */ jsxs("label", { style: {
417
- display: "flex",
418
- alignItems: "center",
419
- gap: 6,
420
- padding: "2px 0",
421
- cursor: "pointer",
422
- fontSize: 11,
423
- color: typeFilter.has(type) ? tokens.colors.text.primary : tokens.colors.text.muted + "66"
424
- }, children: [
425
- /* @__PURE__ */ jsx(
426
- "input",
427
- {
428
- type: "checkbox",
429
- checked: typeFilter.has(type),
430
- onChange: () => toggleType(type),
431
- style: { accentColor: tokens.colors.interactive.default, width: 12, height: 12 }
432
- }
433
- ),
434
- TYPE_ICON_ASTRO.includes(type) ? /* @__PURE__ */ jsx(AstroIcon, { name: getTypeIcon(type), size: "extra-small", label: "", style: { opacity: 0.7 } }) : /* @__PURE__ */ jsx("span", { style: { opacity: 0.7, fontSize: 10 }, children: getTypeIcon(type) }),
435
- /* @__PURE__ */ jsx("span", { style: { textTransform: "capitalize" }, children: type })
436
- ] }, type))
437
- ] }),
438
- showTimelines && timelines.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
439
- /* @__PURE__ */ jsx("div", { style: { fontSize: 10, fontWeight: 500, color: tokens.colors.text.muted, textTransform: "uppercase", letterSpacing: 0.5, marginBottom: 4 }, children: "Timelines" }),
440
- timelines.map((tl) => /* @__PURE__ */ jsxs("label", { style: {
441
- display: "flex",
442
- alignItems: "center",
443
- gap: 6,
444
- padding: "3px 0",
445
- cursor: "pointer",
446
- fontSize: 11,
447
- color: selectedTimelines.has(tl.id) ? tokens.colors.text.primary : tokens.colors.text.muted + "66"
448
- }, children: [
449
- /* @__PURE__ */ jsx(
450
- "input",
451
- {
452
- type: "checkbox",
453
- checked: selectedTimelines.has(tl.id),
454
- onChange: () => toggleTimeline(tl.id),
455
- style: { accentColor: tl.color || tokens.colors.interactive.default, width: 12, height: 12 }
456
- }
457
- ),
458
- /* @__PURE__ */ jsx("span", { style: { width: 8, height: 8, borderRadius: "50%", background: tl.color || tokens.colors.interactive.default, flexShrink: 0 } }),
459
- /* @__PURE__ */ jsx("span", { children: tl.name })
460
- ] }, tl.id))
461
- ] }),
462
- /* @__PURE__ */ jsxs("div", { style: {
463
- marginTop: "auto",
464
- fontSize: 10,
465
- color: tokens.colors.text.muted,
466
- borderTop: `1px solid ${tokens.colors.border.muted}`,
467
- paddingTop: 8
468
- }, children: [
469
- /* @__PURE__ */ jsxs("div", { children: [
470
- "DOY: ",
471
- /* @__PURE__ */ jsx("span", { style: { fontFamily: tokens.typography.fontFamily.mono, color: tokens.colors.text.secondary }, children: doy })
472
- ] }),
473
- /* @__PURE__ */ jsxs("div", { children: [
474
- "Week: ",
475
- /* @__PURE__ */ jsx("span", { style: { fontFamily: tokens.typography.fontFamily.mono, color: tokens.colors.text.secondary }, children: weekNum })
476
- ] }),
477
- /* @__PURE__ */ jsxs("div", { children: [
478
- "UTC: ",
479
- /* @__PURE__ */ jsx("span", { style: { fontFamily: tokens.typography.fontFamily.mono, color: tokens.colors.text.secondary }, children: today.toISOString().slice(11, 19) })
480
- ] })
481
- ] })
482
- ] });
483
- return /* @__PURE__ */ jsxs(
484
- "div",
485
- {
486
- className: `mission-calendar ${className}`,
487
- onClick: () => setContextMenu(null),
488
- style: {
489
- height: typeof height === "number" ? height : void 0,
490
- background: tokens.colors.background.base,
491
- ...tokens.colors.border.cardStyle ?? { border: `1px solid ${tokens.colors.border.muted}` },
492
- borderRadius: tokens.borderRadius.lg,
493
- overflow: "hidden",
494
- display: "flex",
495
- flexDirection: "column",
496
- fontFamily: tokens.typography.fontFamily.primary,
497
- color: tokens.colors.text.primary,
498
- backdropFilter: isTransparentTheme ? "blur(10px)" : void 0,
499
- WebkitBackdropFilter: isTransparentTheme ? "blur(10px)" : void 0
500
- },
501
- children: [
502
- /* @__PURE__ */ jsxs("div", { style: {
503
- padding: "8px 14px",
504
- borderBottom: `1px solid ${tokens.colors.border.muted}`,
505
- background: tokens.colors.background.surface,
506
- backdropFilter: "blur(8px)",
507
- display: "flex",
508
- alignItems: "center",
509
- justifyContent: "space-between",
510
- flexWrap: "wrap",
511
- gap: 8
512
- }, children: [
513
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 10 }, children: [
514
- title && /* @__PURE__ */ jsx("span", { style: { fontWeight: 500, fontSize: tokens.typography.fontSize.sm }, children: title }),
515
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 2 }, children: [
516
- /* @__PURE__ */ jsx("button", { onClick: () => navigate(-1), style: navBtnStyle(tokens), children: "◀" }),
517
- /* @__PURE__ */ jsx("button", { onClick: () => navigate(0), style: { ...navBtnStyle(tokens), padding: "3px 10px", fontSize: tokens.typography.fontSize.xs }, children: "Today" }),
518
- /* @__PURE__ */ jsx("button", { onClick: () => navigate(1), style: navBtnStyle(tokens), children: "▶" })
519
- ] }),
520
- /* @__PURE__ */ jsx("span", { style: { fontWeight: 500, fontSize: tokens.typography.fontSize.sm }, children: headerLabel }),
521
- /* @__PURE__ */ jsxs("span", { style: {
522
- fontSize: 9,
523
- fontFamily: tokens.typography.fontFamily.mono,
524
- color: tokens.colors.text.muted,
525
- background: `${tokens.colors.text.muted}15`,
526
- padding: "1px 6px",
527
- borderRadius: tokens.borderRadius.sm
528
- }, children: [
529
- "DOY ",
530
- doy
531
- ] })
532
- ] }),
533
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
534
- showCreate && /* @__PURE__ */ jsx(
535
- "button",
536
- {
537
- onClick: () => onEventCreate == null ? void 0 : onEventCreate({ start: currentDate, type: "reserve" }),
538
- style: {
539
- background: tokens.colors.interactive.default,
540
- color: tokens.colors.text.inverse,
541
- border: "none",
542
- borderRadius: tokens.borderRadius.md,
543
- padding: "4px 12px",
544
- fontSize: tokens.typography.fontSize.xs,
545
- fontWeight: 500,
546
- cursor: "pointer"
547
- },
548
- children: "+ Activity"
549
- }
550
- ),
551
- /* @__PURE__ */ jsx("div", { style: {
552
- display: "flex",
553
- borderRadius: tokens.borderRadius.md,
554
- overflow: "hidden",
555
- border: `1px solid ${tokens.colors.border.muted}`
556
- }, children: ["month", "week", "day", "gantt", "list"].map((v) => /* @__PURE__ */ jsx(
557
- "button",
558
- {
559
- onClick: () => setViewMode(v),
560
- style: {
561
- background: viewMode === v ? tokens.colors.interactive.default : tokens.colors.background.base,
562
- color: viewMode === v ? tokens.colors.text.inverse : tokens.colors.text.secondary,
563
- border: "none",
564
- padding: "3px 10px",
565
- fontSize: tokens.typography.fontSize.xxs,
566
- fontWeight: 500,
567
- cursor: "pointer",
568
- textTransform: "capitalize"
569
- },
570
- children: v
571
- },
572
- v
573
- )) })
574
- ] })
575
- ] }),
576
- /* @__PURE__ */ jsxs("div", { style: { flex: 1, display: "flex", overflow: "hidden" }, children: [
577
- showSidebar && renderSidebar(),
578
- /* @__PURE__ */ jsxs("div", { ref: bodyRef, style: { flex: 1, overflow: "auto" }, children: [
579
- viewMode === "month" && /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", height: "100%" }, children: [
580
- /* @__PURE__ */ jsx("div", { style: {
581
- display: "grid",
582
- gridTemplateColumns: "repeat(7, 1fr)",
583
- borderBottom: `1px solid ${tokens.colors.border.muted}`,
584
- background: tokens.colors.background.surface
585
- }, children: dayNames.map((d) => /* @__PURE__ */ jsx("div", { style: {
586
- padding: "4px 6px",
587
- textAlign: "center",
588
- fontSize: tokens.typography.fontSize.xxs,
589
- fontWeight: 500,
590
- color: tokens.colors.text.muted,
591
- textTransform: "uppercase"
592
- }, children: d }, d)) }),
593
- /* @__PURE__ */ jsx("div", { style: {
594
- display: "grid",
595
- gridTemplateColumns: "repeat(7, 1fr)",
596
- gridTemplateRows: "repeat(6, 1fr)",
597
- flex: 1
598
- }, children: monthGrid.map(({ date, isCurrentMonth }, idx) => {
599
- const dayEvts = getEventsForDay(date);
600
- const isToday = isSameDay(date, today);
601
- return /* @__PURE__ */ jsxs(
602
- "div",
603
- {
604
- onClick: () => {
605
- setCurrentDate(date);
606
- if (onDayDrillDown) onDayDrillDown(date, dayEvts);
607
- else setViewMode("day");
608
- },
609
- onContextMenu: (e) => handleContextMenu(e, date),
610
- style: {
611
- borderRight: `1px solid ${tokens.colors.border.muted}11`,
612
- borderBottom: `1px solid ${tokens.colors.border.muted}11`,
613
- padding: 3,
614
- cursor: "pointer",
615
- background: isToday ? `${tokens.colors.interactive.default}08` : "transparent",
616
- opacity: isCurrentMonth ? 1 : 0.35,
617
- overflow: "hidden",
618
- minHeight: 70
619
- },
620
- children: [
621
- /* @__PURE__ */ jsx("div", { style: {
622
- fontSize: tokens.typography.fontSize.xs,
623
- fontWeight: isToday ? 700 : 400,
624
- color: isToday ? tokens.colors.interactive.default : tokens.colors.text.primary,
625
- marginBottom: 2,
626
- textAlign: "right",
627
- paddingRight: 2
628
- }, children: isToday ? /* @__PURE__ */ jsx("span", { style: {
629
- background: tokens.colors.interactive.default,
630
- color: tokens.colors.text.inverse,
631
- borderRadius: tokens.borderRadius.full,
632
- width: 20,
633
- height: 20,
634
- display: "inline-flex",
635
- alignItems: "center",
636
- justifyContent: "center",
637
- fontSize: tokens.typography.fontSize.xxs
638
- }, children: date.getDate() }) : date.getDate() }),
639
- dayEvts.slice(0, 3).map((e) => /* @__PURE__ */ jsx(CalendarEventChip, { event: e, tokens, compact: true, onClick: () => onEventClick == null ? void 0 : onEventClick(e) }, e.id)),
640
- dayEvts.length > 3 && /* @__PURE__ */ jsxs("div", { style: { fontSize: tokens.typography.fontSize.micro, color: tokens.colors.text.muted, textAlign: "center" }, children: [
641
- "+",
642
- dayEvts.length - 3,
643
- " more"
644
- ] })
645
- ]
646
- },
647
- idx
648
- );
649
- }) })
650
- ] }),
651
- viewMode === "week" && /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", height: "100%" }, children: [
652
- /* @__PURE__ */ jsxs("div", { style: {
653
- display: "grid",
654
- gridTemplateColumns: `50px repeat(7, 1fr)`,
655
- borderBottom: `1px solid ${tokens.colors.border.muted}`,
656
- background: tokens.colors.background.surface,
657
- position: "sticky",
658
- top: 0,
659
- zIndex: 2
660
- }, children: [
661
- /* @__PURE__ */ jsx("div", { style: { borderRight: `1px solid ${tokens.colors.border.muted}22` } }),
662
- weekDates.map((d, i) => {
663
- const isToday = isSameDay(d, today);
664
- return /* @__PURE__ */ jsxs("div", { style: {
665
- padding: "4px 4px",
666
- textAlign: "center",
667
- background: isToday ? `${tokens.colors.interactive.default}10` : "transparent",
668
- borderRight: `1px solid ${tokens.colors.border.muted}11`
669
- }, children: [
670
- /* @__PURE__ */ jsx("div", { style: { fontSize: 9, color: tokens.colors.text.muted, textTransform: "uppercase" }, children: dayNames[i] }),
671
- /* @__PURE__ */ jsx("div", { style: {
672
- fontSize: 16,
673
- fontWeight: isToday ? 700 : 400,
674
- color: isToday ? tokens.colors.interactive.default : tokens.colors.text.primary
675
- }, children: isToday ? /* @__PURE__ */ jsx("span", { style: {
676
- background: tokens.colors.interactive.default,
677
- color: tokens.colors.text.inverse,
678
- borderRadius: tokens.borderRadius.full,
679
- width: 24,
680
- height: 24,
681
- display: "inline-flex",
682
- alignItems: "center",
683
- justifyContent: "center",
684
- fontSize: 13
685
- }, children: d.getDate() }) : d.getDate() })
686
- ] }, i);
687
- })
688
- ] }),
689
- /* @__PURE__ */ jsx("div", { style: { flex: 1, overflow: "auto" }, children: TIME_SLOTS.map((slot, _si) => {
690
- const isHour = slot.endsWith(":00");
691
- return /* @__PURE__ */ jsxs("div", { style: {
692
- display: "grid",
693
- gridTemplateColumns: `50px repeat(7, 1fr)`,
694
- height: SLOT_HEIGHT,
695
- borderBottom: `1px solid ${tokens.colors.border.muted}${isHour ? "22" : "0A"}`
696
- }, children: [
697
- /* @__PURE__ */ jsx("div", { style: {
698
- fontSize: 9,
699
- color: tokens.colors.text.muted,
700
- textAlign: "right",
701
- paddingRight: 6,
702
- fontFamily: tokens.typography.fontFamily.mono,
703
- borderRight: `1px solid ${tokens.colors.border.muted}22`,
704
- lineHeight: `${SLOT_HEIGHT}px`,
705
- visibility: isHour ? "visible" : "hidden"
706
- }, children: slot }),
707
- weekDates.map((d, di) => {
708
- const slotStart = new Date(d);
709
- slotStart.setHours(parseInt(slot), slot.endsWith(":30") ? 30 : 0, 0, 0);
710
- const slotEvents = getEventsForDay(d).filter((e) => {
711
- const eStart = e.start.getHours() * 60 + e.start.getMinutes();
712
- const sStart = parseInt(slot) * 60 + (slot.endsWith(":30") ? 30 : 0);
713
- return eStart >= sStart && eStart < sStart + 30;
714
- });
715
- return /* @__PURE__ */ jsx(
716
- "div",
717
- {
718
- onClick: () => {
719
- setCurrentDate(d);
720
- setViewMode("day");
721
- },
722
- onContextMenu: (e) => handleContextMenu(e, d, slot),
723
- style: {
724
- borderRight: `1px solid ${tokens.colors.border.muted}0A`,
725
- padding: "0 2px",
726
- cursor: "pointer",
727
- overflow: "hidden",
728
- background: isSameDay(d, today) ? `${tokens.colors.interactive.default}04` : "transparent"
729
- },
730
- children: slotEvents.map((e) => /* @__PURE__ */ jsx(CalendarEventChip, { event: e, tokens, compact: true, onClick: () => onEventClick == null ? void 0 : onEventClick(e) }, e.id))
731
- },
732
- di
733
- );
734
- })
735
- ] }, slot);
736
- }) })
737
- ] }),
738
- viewMode === "day" && /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", height: "100%" }, children: /* @__PURE__ */ jsx("div", { style: { flex: 1, overflow: "auto" }, children: TIME_SLOTS.map((slot) => {
739
- const isHour = slot.endsWith(":00");
740
- const slotEvents = dayEvents.filter((e) => {
741
- const eStart = e.start.getHours() * 60 + e.start.getMinutes();
742
- const sStart = parseInt(slot) * 60 + (slot.endsWith(":30") ? 30 : 0);
743
- return eStart >= sStart && eStart < sStart + 30;
744
- });
745
- return /* @__PURE__ */ jsxs(
746
- "div",
747
- {
748
- onContextMenu: (e) => handleContextMenu(e, currentDate, slot),
749
- style: {
750
- display: "grid",
751
- gridTemplateColumns: "50px 1fr",
752
- minHeight: slotEvents.length > 0 ? Math.max(SLOT_HEIGHT, slotEvents.length * 24 + 4) : SLOT_HEIGHT,
753
- borderBottom: `1px solid ${tokens.colors.border.muted}${isHour ? "22" : "0A"}`
754
- },
755
- children: [
756
- /* @__PURE__ */ jsx("div", { style: {
757
- fontSize: 10,
758
- color: tokens.colors.text.muted,
759
- textAlign: "right",
760
- paddingRight: 8,
761
- fontFamily: tokens.typography.fontFamily.mono,
762
- borderRight: `1px solid ${tokens.colors.border.muted}22`,
763
- lineHeight: `${SLOT_HEIGHT}px`,
764
- visibility: isHour ? "visible" : "hidden"
765
- }, children: slot }),
766
- /* @__PURE__ */ jsx("div", { style: { padding: "1px 6px", cursor: "pointer" }, children: slotEvents.map((e) => {
767
- const color = e.color || getStatusColor(e.status, tokens);
768
- return /* @__PURE__ */ jsxs(
769
- "div",
770
- {
771
- onClick: () => onEventClick == null ? void 0 : onEventClick(e),
772
- style: {
773
- background: `${color}18`,
774
- borderRadius: tokens.borderRadius.sm,
775
- padding: "3px 8px",
776
- marginBottom: 2,
777
- cursor: "pointer",
778
- display: "flex",
779
- alignItems: "center",
780
- gap: 6,
781
- fontSize: tokens.typography.fontSize.xxs
782
- },
783
- children: [
784
- TYPE_ICON_ASTRO.includes(e.type) ? /* @__PURE__ */ jsx(AstroIcon, { name: getTypeIcon(e.type), size: "extra-small", label: "", style: { opacity: 0.7 } }) : /* @__PURE__ */ jsx("span", { style: { opacity: 0.7 }, children: getTypeIcon(e.type) }),
785
- /* @__PURE__ */ jsx("span", { style: { color, fontSize: tokens.typography.fontSize.micro }, children: getStatusShape(e.status) }),
786
- /* @__PURE__ */ jsx("span", { style: { fontWeight: 500 }, children: e.title }),
787
- /* @__PURE__ */ jsxs("span", { style: { color: tokens.colors.text.muted, fontFamily: tokens.typography.fontFamily.mono, fontSize: tokens.typography.fontSize.micro, marginLeft: "auto" }, children: [
788
- formatTime(e.start),
789
- e.end ? `–${formatTime(e.end)}` : ""
790
- ] }),
791
- e.status && /* @__PURE__ */ jsx("span", { style: { fontSize: tokens.typography.fontSize.micro, color, fontWeight: 500, textTransform: "uppercase" }, children: e.status })
792
- ]
793
- },
794
- e.id
795
- );
796
- }) })
797
- ]
798
- },
799
- slot
800
- );
801
- }) }) }),
802
- viewMode === "gantt" && /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", height: "100%" }, children: [
803
- /* @__PURE__ */ jsxs("div", { style: {
804
- display: "grid",
805
- gridTemplateColumns: `120px repeat(7, 1fr)`,
806
- borderBottom: `1px solid ${tokens.colors.border.muted}`,
807
- background: tokens.colors.background.surface,
808
- position: "sticky",
809
- top: 0,
810
- zIndex: 2
811
- }, children: [
812
- /* @__PURE__ */ jsx("div", { style: { padding: "6px 8px", fontSize: 10, fontWeight: 500, color: tokens.colors.text.muted, borderRight: `1px solid ${tokens.colors.border.muted}22` }, children: "Timeline" }),
813
- weekDates.map((d, i) => {
814
- const isToday = isSameDay(d, today);
815
- return /* @__PURE__ */ jsxs("div", { style: {
816
- padding: "4px 4px",
817
- textAlign: "center",
818
- background: isToday ? `${tokens.colors.interactive.default}10` : "transparent",
819
- borderRight: `1px solid ${tokens.colors.border.muted}11`,
820
- fontSize: 10
821
- }, children: [
822
- /* @__PURE__ */ jsxs("span", { style: { color: tokens.colors.text.muted }, children: [
823
- dayNames[i],
824
- " "
825
- ] }),
826
- /* @__PURE__ */ jsx("span", { style: { fontWeight: isToday ? 700 : 400, color: isToday ? tokens.colors.interactive.default : tokens.colors.text.primary }, children: d.getDate() })
827
- ] }, i);
828
- })
829
- ] }),
830
- /* @__PURE__ */ jsx("div", { style: { flex: 1, overflow: "auto" }, children: ganttData.rows.length === 0 ? /* @__PURE__ */ jsx("div", { style: { textAlign: "center", color: tokens.colors.text.muted, padding: 40, fontSize: 12 }, children: "No activities this week" }) : ganttData.rows.map((row, ri) => /* @__PURE__ */ jsxs("div", { style: {
831
- display: "grid",
832
- gridTemplateColumns: `120px repeat(7, 1fr)`,
833
- borderBottom: `1px solid ${tokens.colors.border.muted}15`,
834
- minHeight: 36
835
- }, children: [
836
- /* @__PURE__ */ jsxs("div", { style: {
837
- padding: "6px 8px",
838
- fontSize: 11,
839
- fontWeight: 500,
840
- borderRight: `1px solid ${tokens.colors.border.muted}22`,
841
- display: "flex",
842
- alignItems: "center",
843
- gap: 6,
844
- color: tokens.colors.text.primary
845
- }, children: [
846
- /* @__PURE__ */ jsx("span", { style: { width: 6, height: 6, borderRadius: "50%", background: row.color, flexShrink: 0 } }),
847
- row.label
848
- ] }),
849
- weekDates.map((d, di) => {
850
- const cellEvents = row.events.filter((e) => {
851
- const eDay = new Date(e.start);
852
- eDay.setHours(0, 0, 0, 0);
853
- const cellDay = new Date(d);
854
- cellDay.setHours(0, 0, 0, 0);
855
- if (e.end) {
856
- const eEnd = new Date(e.end);
857
- eEnd.setHours(23, 59, 59, 999);
858
- return cellDay >= eDay && cellDay <= eEnd;
859
- }
860
- return eDay.getTime() === cellDay.getTime();
861
- });
862
- return /* @__PURE__ */ jsx(
863
- "div",
864
- {
865
- onContextMenu: (e) => handleContextMenu(e, d),
866
- style: {
867
- borderRight: `1px solid ${tokens.colors.border.muted}0A`,
868
- padding: "2px 2px",
869
- display: "flex",
870
- flexDirection: "column",
871
- gap: 2,
872
- background: isSameDay(d, today) ? `${tokens.colors.interactive.default}04` : "transparent"
873
- },
874
- children: cellEvents.map((e) => {
875
- const color = e.color || getStatusColor(e.status, tokens);
876
- return /* @__PURE__ */ jsxs(
877
- "div",
878
- {
879
- onClick: () => onEventClick == null ? void 0 : onEventClick(e),
880
- style: {
881
- background: `${color}33`,
882
- borderRadius: 3,
883
- padding: "2px 4px",
884
- fontSize: 9,
885
- fontWeight: 500,
886
- color: tokens.colors.text.primary,
887
- cursor: "pointer",
888
- whiteSpace: "nowrap",
889
- overflow: "hidden",
890
- textOverflow: "ellipsis"
891
- },
892
- title: `${e.title}
893
- ${formatTime(e.start)}${e.end ? " " + formatTime(e.end) : ""}`,
894
- children: [
895
- /* @__PURE__ */ jsx("span", { style: { opacity: 0.7, marginRight: 3 }, children: getStatusShape(e.status) }),
896
- e.title
897
- ]
898
- },
899
- e.id
900
- );
901
- })
902
- },
903
- di
904
- );
905
- })
906
- ] }, ri)) })
907
- ] }),
908
- viewMode === "list" && /* @__PURE__ */ jsxs("div", { style: { padding: 12 }, children: [
909
- /* @__PURE__ */ jsxs("div", { style: { fontSize: tokens.typography.fontSize.xs, color: tokens.colors.text.muted, marginBottom: 8 }, children: [
910
- "Upcoming 7 days ",
911
- listEvents.length,
912
- " activities"
913
- ] }),
914
- listEvents.length === 0 ? /* @__PURE__ */ jsx("div", { style: { textAlign: "center", color: tokens.colors.text.muted, padding: 40, fontSize: tokens.typography.fontSize.sm }, children: "No upcoming activities" }) : /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: 4 }, children: listEvents.map((e) => {
915
- const color = e.color || getStatusColor(e.status, tokens);
916
- return /* @__PURE__ */ jsxs(
917
- "div",
918
- {
919
- onClick: () => onEventClick == null ? void 0 : onEventClick(e),
920
- style: {
921
- display: "grid",
922
- gridTemplateColumns: "100px 1fr auto",
923
- padding: "6px 10px",
924
- borderRadius: tokens.borderRadius.md,
925
- background: `${color}08`,
926
- cursor: "pointer",
927
- alignItems: "center",
928
- gap: 10,
929
- fontSize: tokens.typography.fontSize.xs
930
- },
931
- children: [
932
- /* @__PURE__ */ jsxs("span", { style: { fontFamily: tokens.typography.fontFamily.mono, fontSize: tokens.typography.fontSize.xxs, color: tokens.colors.text.muted }, children: [
933
- e.start.toLocaleDateString("en-US", { month: "short", day: "numeric" }),
934
- " ",
935
- formatTime(e.start)
936
- ] }),
937
- /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
938
- TYPE_ICON_ASTRO.includes(e.type) ? /* @__PURE__ */ jsx(AstroIcon, { name: getTypeIcon(e.type), size: "extra-small", label: "" }) : /* @__PURE__ */ jsx("span", { children: getTypeIcon(e.type) }),
939
- /* @__PURE__ */ jsx("span", { style: { fontWeight: 500 }, children: e.title })
940
- ] }),
941
- e.status && /* @__PURE__ */ jsxs("span", { style: { fontSize: tokens.typography.fontSize.micro, color, fontWeight: 500 }, children: [
942
- getStatusShape(e.status),
943
- " ",
944
- e.status
945
- ] })
946
- ]
947
- },
948
- e.id
949
- );
950
- }) })
951
- ] })
952
- ] })
953
- ] }),
954
- /* @__PURE__ */ jsxs("div", { style: {
955
- padding: "4px 14px",
956
- borderTop: `1px solid ${tokens.colors.border.muted}`,
957
- background: tokens.colors.background.surface,
958
- fontSize: tokens.typography.fontSize.xxs,
959
- color: tokens.colors.text.muted,
960
- display: "flex",
961
- justifyContent: "space-between"
962
- }, children: [
963
- /* @__PURE__ */ jsxs("span", { children: [
964
- filteredEvents.length,
965
- " activities | DOY ",
966
- doy,
967
- " | Week ",
968
- weekNum
969
- ] }),
970
- /* @__PURE__ */ jsx("span", { children: events.filter((e) => e.status === "error" || e.status === "failed" || e.status === "crashed").length > 0 ? `⚠ ${events.filter((e) => e.status === "error" || e.status === "failed" || e.status === "crashed").length} errors` : "✓ All nominal" })
971
- ] }),
972
- contextMenu && /* @__PURE__ */ jsxs(
973
- "div",
974
- {
975
- style: {
976
- position: "fixed",
977
- left: contextMenu.x,
978
- top: contextMenu.y,
979
- zIndex: 1e3,
980
- background: tokens.colors.background.surface,
981
- backdropFilter: "blur(8px)",
982
- border: `1px solid ${tokens.colors.border.muted}`,
983
- borderRadius: tokens.borderRadius.md,
984
- boxShadow: "0 4px 16px rgba(0,0,0,0.4)",
985
- padding: 4,
986
- minWidth: 160
987
- },
988
- children: [
989
- /* @__PURE__ */ jsxs("div", { style: { fontSize: 9, color: tokens.colors.text.muted, padding: "4px 8px", fontFamily: tokens.typography.fontFamily.mono }, children: [
990
- contextMenu.date.toLocaleDateString("en-US", { month: "short", day: "numeric" }),
991
- " ",
992
- formatTime(contextMenu.date)
993
- ] }),
994
- ["command", "script", "reserve", "metadata", "note"].map((type) => /* @__PURE__ */ jsxs(
995
- "button",
996
- {
997
- onClick: () => {
998
- onEventCreate == null ? void 0 : onEventCreate({ start: contextMenu.date, type });
999
- setContextMenu(null);
1000
- },
1001
- style: {
1002
- display: "block",
1003
- width: "100%",
1004
- textAlign: "left",
1005
- background: "none",
1006
- border: "none",
1007
- color: tokens.colors.text.primary,
1008
- padding: "5px 8px",
1009
- fontSize: 11,
1010
- cursor: "pointer",
1011
- borderRadius: tokens.borderRadius.sm
1012
- },
1013
- onMouseEnter: (e) => {
1014
- e.currentTarget.style.background = `${tokens.colors.interactive.default}22`;
1015
- },
1016
- onMouseLeave: (e) => {
1017
- e.currentTarget.style.background = "none";
1018
- },
1019
- children: [
1020
- getTypeIcon(type),
1021
- " Create ",
1022
- type.charAt(0).toUpperCase() + type.slice(1)
1023
- ]
1024
- },
1025
- type
1026
- ))
1027
- ]
1028
- }
1029
- )
1030
- ]
1031
- }
1032
- );
334
+ var MissionCalendar = memo(function MissionCalendar({ events, timelines = [], defaultView = "month", initialDate, height = 600, title, showSidebar = true, showTimelines = true, showFilters = true, showCreate = true, weekStartsMonday = true, onEventClick, onEventCreate, onDayDrillDown, className = "" }) {
335
+ const { tokens, theme } = useTheme();
336
+ const isTransparentTheme = theme === "transparent" || theme === "transparent-bold" || theme === "transparent-minimal";
337
+ const [viewMode, setViewMode] = useState(defaultView);
338
+ const [currentDate, setCurrentDate] = useState(initialDate || /* @__PURE__ */ new Date());
339
+ const [selectedTimelines, setSelectedTimelines] = useState(new Set(timelines.map((t) => t.id)));
340
+ const [typeFilter, setTypeFilter] = useState(/* @__PURE__ */ new Set([
341
+ "command",
342
+ "script",
343
+ "reserve",
344
+ "metadata",
345
+ "note",
346
+ "contact",
347
+ "eclipse",
348
+ "pass"
349
+ ]));
350
+ const [contextMenu, setContextMenu] = useState(null);
351
+ const bodyRef = useRef(null);
352
+ const year = currentDate.getFullYear();
353
+ const month = currentDate.getMonth();
354
+ const filteredEvents = useMemo(() => events.filter((e) => typeFilter.has(e.type) && (selectedTimelines.size === 0 || !e.timeline || selectedTimelines.has(e.timeline))), [
355
+ events,
356
+ typeFilter,
357
+ selectedTimelines
358
+ ]);
359
+ const eventsByDay = useMemo(() => {
360
+ const map = /* @__PURE__ */ new Map();
361
+ filteredEvents.forEach((e) => {
362
+ const key = `${e.start.getFullYear()}-${e.start.getMonth()}-${e.start.getDate()}`;
363
+ if (!map.has(key)) map.set(key, []);
364
+ map.get(key).push(e);
365
+ if (e.end) {
366
+ const days = Math.ceil((e.end.getTime() - e.start.getTime()) / 864e5);
367
+ for (let d = 1; d <= days && d < 30; d++) {
368
+ const next = new Date(e.start);
369
+ next.setDate(next.getDate() + d);
370
+ const nk = `${next.getFullYear()}-${next.getMonth()}-${next.getDate()}`;
371
+ if (!map.has(nk)) map.set(nk, []);
372
+ map.get(nk).push(e);
373
+ }
374
+ }
375
+ });
376
+ return map;
377
+ }, [filteredEvents]);
378
+ const getEventsForDay = useCallback((d) => {
379
+ const key = `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;
380
+ return eventsByDay.get(key) || [];
381
+ }, [eventsByDay]);
382
+ const navigate = useCallback((dir) => {
383
+ if (dir === 0) {
384
+ setCurrentDate(/* @__PURE__ */ new Date());
385
+ return;
386
+ }
387
+ const d = new Date(currentDate);
388
+ if (viewMode === "month") d.setMonth(d.getMonth() + dir);
389
+ else if (viewMode === "week" || viewMode === "gantt") d.setDate(d.getDate() + dir * 7);
390
+ else d.setDate(d.getDate() + dir);
391
+ setCurrentDate(d);
392
+ }, [currentDate, viewMode]);
393
+ const toggleTimeline = useCallback((id) => {
394
+ setSelectedTimelines((prev) => {
395
+ const next = new Set(prev);
396
+ if (next.has(id)) next.delete(id);
397
+ else next.add(id);
398
+ return next;
399
+ });
400
+ }, []);
401
+ const toggleType = useCallback((type) => {
402
+ setTypeFilter((prev) => {
403
+ const next = new Set(prev);
404
+ if (next.has(type)) next.delete(type);
405
+ else next.add(type);
406
+ return next;
407
+ });
408
+ }, []);
409
+ const dayNames = weekStartsMonday ? [
410
+ "Mon",
411
+ "Tue",
412
+ "Wed",
413
+ "Thu",
414
+ "Fri",
415
+ "Sat",
416
+ "Sun"
417
+ ] : [
418
+ "Sun",
419
+ "Mon",
420
+ "Tue",
421
+ "Wed",
422
+ "Thu",
423
+ "Fri",
424
+ "Sat"
425
+ ];
426
+ const monthLabel = currentDate.toLocaleDateString("en-US", {
427
+ month: "long",
428
+ year: "numeric"
429
+ });
430
+ const today = /* @__PURE__ */ new Date();
431
+ const weekNum = getWeekNumber(currentDate);
432
+ const doy = getDayOfYear(currentDate);
433
+ const monthGrid = useMemo(() => {
434
+ const firstDay = getFirstDayOfMonth(year, month, weekStartsMonday);
435
+ const daysInMonth = getDaysInMonth(year, month);
436
+ const daysInPrevMonth = getDaysInMonth(year, month === 0 ? 11 : month - 1);
437
+ const cells = [];
438
+ for (let i = firstDay - 1; i >= 0; i--) cells.push({
439
+ date: new Date(year, month - 1, daysInPrevMonth - i),
440
+ isCurrentMonth: false
441
+ });
442
+ for (let i = 1; i <= daysInMonth; i++) cells.push({
443
+ date: new Date(year, month, i),
444
+ isCurrentMonth: true
445
+ });
446
+ while (cells.length < 42) cells.push({
447
+ date: new Date(year, month + 1, cells.length - firstDay - daysInMonth + 1),
448
+ isCurrentMonth: false
449
+ });
450
+ return cells;
451
+ }, [
452
+ year,
453
+ month,
454
+ weekStartsMonday
455
+ ]);
456
+ const weekDates = useMemo(() => getWeekDates(currentDate, weekStartsMonday), [currentDate, weekStartsMonday]);
457
+ const dayEvents = useMemo(() => {
458
+ return [...getEventsForDay(currentDate)].sort((a, b) => a.start.getTime() - b.start.getTime());
459
+ }, [currentDate, getEventsForDay]);
460
+ const listEvents = useMemo(() => {
461
+ const now = /* @__PURE__ */ new Date();
462
+ const end = new Date(now);
463
+ end.setDate(end.getDate() + 7);
464
+ return filteredEvents.filter((e) => e.start >= now && e.start <= end).sort((a, b) => a.start.getTime() - b.start.getTime());
465
+ }, [filteredEvents]);
466
+ const ganttData = useMemo(() => {
467
+ const weekStart = new Date(weekDates[0]);
468
+ weekStart.setHours(0, 0, 0, 0);
469
+ const weekEnd = new Date(weekDates[6]);
470
+ weekEnd.setHours(23, 59, 59, 999);
471
+ const weekEvents = filteredEvents.filter((e) => e.start <= weekEnd && (e.end || e.start) >= weekStart);
472
+ const tlMap = /* @__PURE__ */ new Map();
473
+ const noTl = [];
474
+ weekEvents.forEach((e) => {
475
+ const tlId = e.timeline || "";
476
+ if (!tlId) {
477
+ noTl.push(e);
478
+ return;
479
+ }
480
+ if (!tlMap.has(tlId)) tlMap.set(tlId, []);
481
+ tlMap.get(tlId).push(e);
482
+ });
483
+ const rows = [];
484
+ timelines.forEach((tl) => {
485
+ if (tlMap.has(tl.id)) rows.push({
486
+ label: tl.name,
487
+ color: tl.color || tokens.colors.interactive.default,
488
+ events: tlMap.get(tl.id)
489
+ });
490
+ });
491
+ if (noTl.length > 0) rows.push({
492
+ label: "Unassigned",
493
+ color: tokens.colors.text.muted ?? tokens.colors.text.secondary,
494
+ events: noTl
495
+ });
496
+ return {
497
+ rows,
498
+ weekStart,
499
+ weekEnd
500
+ };
501
+ }, [
502
+ filteredEvents,
503
+ weekDates,
504
+ timelines,
505
+ tokens
506
+ ]);
507
+ const handleContextMenu = useCallback((e, date, slotTime) => {
508
+ e.preventDefault();
509
+ if (!onEventCreate) return;
510
+ const d = new Date(date);
511
+ if (slotTime) {
512
+ const [h, m] = slotTime.split(":").map(Number);
513
+ d.setHours(h, m, 0, 0);
514
+ }
515
+ setContextMenu({
516
+ x: e.clientX,
517
+ y: e.clientY,
518
+ date: d
519
+ });
520
+ }, [onEventCreate]);
521
+ const headerLabel = useMemo(() => {
522
+ if (viewMode === "month") return monthLabel;
523
+ if (viewMode === "week" || viewMode === "gantt") return `${weekDates[0].toLocaleDateString("en-US", {
524
+ month: "short",
525
+ day: "numeric"
526
+ })} – ${weekDates[6].toLocaleDateString("en-US", {
527
+ month: "short",
528
+ day: "numeric",
529
+ year: "numeric"
530
+ })} Week ${weekNum}`;
531
+ return currentDate.toLocaleDateString("en-US", {
532
+ weekday: "long",
533
+ month: "long",
534
+ day: "numeric",
535
+ year: "numeric"
536
+ });
537
+ }, [
538
+ viewMode,
539
+ monthLabel,
540
+ weekDates,
541
+ weekNum,
542
+ currentDate
543
+ ]);
544
+ const renderSidebar = () => /* @__PURE__ */ jsxs("div", {
545
+ style: {
546
+ width: 190,
547
+ minWidth: 190,
548
+ borderRight: `1px solid ${tokens.colors.border.muted}`,
549
+ background: tokens.colors.background.surface,
550
+ padding: "8px 10px",
551
+ display: "flex",
552
+ flexDirection: "column",
553
+ gap: 12,
554
+ overflow: "auto"
555
+ },
556
+ children: [
557
+ /* @__PURE__ */ jsx(MiniCalendar, {
558
+ currentDate,
559
+ tokens,
560
+ weekStartsMonday,
561
+ onDateSelect: (d) => {
562
+ setCurrentDate(d);
563
+ if (viewMode === "month") setViewMode("day");
564
+ },
565
+ getEventsForDay
566
+ }),
567
+ showFilters && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
568
+ style: {
569
+ fontSize: 10,
570
+ fontWeight: 500,
571
+ color: tokens.colors.text.muted,
572
+ textTransform: "uppercase",
573
+ letterSpacing: .5,
574
+ marginBottom: 4
575
+ },
576
+ children: "Event Types"
577
+ }), [
578
+ "command",
579
+ "script",
580
+ "reserve",
581
+ "metadata",
582
+ "note",
583
+ "contact"
584
+ ].map((type) => /* @__PURE__ */ jsxs("label", {
585
+ style: {
586
+ display: "flex",
587
+ alignItems: "center",
588
+ gap: 6,
589
+ padding: "2px 0",
590
+ cursor: "pointer",
591
+ fontSize: 11,
592
+ color: typeFilter.has(type) ? tokens.colors.text.primary : tokens.colors.text.muted + "66"
593
+ },
594
+ children: [
595
+ /* @__PURE__ */ jsx("input", {
596
+ type: "checkbox",
597
+ checked: typeFilter.has(type),
598
+ onChange: () => toggleType(type),
599
+ style: {
600
+ accentColor: tokens.colors.interactive.default,
601
+ width: 12,
602
+ height: 12
603
+ }
604
+ }),
605
+ TYPE_ICON_ASTRO.includes(type) ? /* @__PURE__ */ jsx(AstroIcon, {
606
+ name: getTypeIcon(type),
607
+ size: "extra-small",
608
+ label: "",
609
+ style: { opacity: .7 }
610
+ }) : /* @__PURE__ */ jsx("span", {
611
+ style: {
612
+ opacity: .7,
613
+ fontSize: 10
614
+ },
615
+ children: getTypeIcon(type)
616
+ }),
617
+ /* @__PURE__ */ jsx("span", {
618
+ style: { textTransform: "capitalize" },
619
+ children: type
620
+ })
621
+ ]
622
+ }, type))] }),
623
+ showTimelines && timelines.length > 0 && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
624
+ style: {
625
+ fontSize: 10,
626
+ fontWeight: 500,
627
+ color: tokens.colors.text.muted,
628
+ textTransform: "uppercase",
629
+ letterSpacing: .5,
630
+ marginBottom: 4
631
+ },
632
+ children: "Timelines"
633
+ }), timelines.map((tl) => /* @__PURE__ */ jsxs("label", {
634
+ style: {
635
+ display: "flex",
636
+ alignItems: "center",
637
+ gap: 6,
638
+ padding: "3px 0",
639
+ cursor: "pointer",
640
+ fontSize: 11,
641
+ color: selectedTimelines.has(tl.id) ? tokens.colors.text.primary : tokens.colors.text.muted + "66"
642
+ },
643
+ children: [
644
+ /* @__PURE__ */ jsx("input", {
645
+ type: "checkbox",
646
+ checked: selectedTimelines.has(tl.id),
647
+ onChange: () => toggleTimeline(tl.id),
648
+ style: {
649
+ accentColor: tl.color || tokens.colors.interactive.default,
650
+ width: 12,
651
+ height: 12
652
+ }
653
+ }),
654
+ /* @__PURE__ */ jsx("span", { style: {
655
+ width: 8,
656
+ height: 8,
657
+ borderRadius: "50%",
658
+ background: tl.color || tokens.colors.interactive.default,
659
+ flexShrink: 0
660
+ } }),
661
+ /* @__PURE__ */ jsx("span", { children: tl.name })
662
+ ]
663
+ }, tl.id))] }),
664
+ /* @__PURE__ */ jsxs("div", {
665
+ style: {
666
+ marginTop: "auto",
667
+ fontSize: 10,
668
+ color: tokens.colors.text.muted,
669
+ borderTop: `1px solid ${tokens.colors.border.muted}`,
670
+ paddingTop: 8
671
+ },
672
+ children: [
673
+ /* @__PURE__ */ jsxs("div", { children: [
674
+ "DOY:",
675
+ " ",
676
+ /* @__PURE__ */ jsx("span", {
677
+ style: {
678
+ fontFamily: tokens.typography.fontFamily.mono,
679
+ color: tokens.colors.text.secondary
680
+ },
681
+ children: doy
682
+ })
683
+ ] }),
684
+ /* @__PURE__ */ jsxs("div", { children: [
685
+ "Week:",
686
+ " ",
687
+ /* @__PURE__ */ jsx("span", {
688
+ style: {
689
+ fontFamily: tokens.typography.fontFamily.mono,
690
+ color: tokens.colors.text.secondary
691
+ },
692
+ children: weekNum
693
+ })
694
+ ] }),
695
+ /* @__PURE__ */ jsxs("div", { children: [
696
+ "UTC:",
697
+ " ",
698
+ /* @__PURE__ */ jsx("span", {
699
+ style: {
700
+ fontFamily: tokens.typography.fontFamily.mono,
701
+ color: tokens.colors.text.secondary
702
+ },
703
+ children: today.toISOString().slice(11, 19)
704
+ })
705
+ ] })
706
+ ]
707
+ })
708
+ ]
709
+ });
710
+ return /* @__PURE__ */ jsxs("div", {
711
+ className: `mission-calendar ${className}`,
712
+ onClick: () => setContextMenu(null),
713
+ style: {
714
+ height: typeof height === "number" ? height : void 0,
715
+ background: tokens.colors.background.base,
716
+ ...tokens.colors.border.cardStyle ?? { border: `1px solid ${tokens.colors.border.muted}` },
717
+ borderRadius: tokens.borderRadius.lg,
718
+ overflow: "hidden",
719
+ display: "flex",
720
+ flexDirection: "column",
721
+ fontFamily: tokens.typography.fontFamily.primary,
722
+ color: tokens.colors.text.primary,
723
+ backdropFilter: isTransparentTheme ? "blur(10px)" : void 0,
724
+ WebkitBackdropFilter: isTransparentTheme ? "blur(10px)" : void 0
725
+ },
726
+ children: [
727
+ /* @__PURE__ */ jsxs("div", {
728
+ style: {
729
+ padding: "8px 14px",
730
+ borderBottom: `1px solid ${tokens.colors.border.muted}`,
731
+ background: tokens.colors.background.surface,
732
+ backdropFilter: "blur(8px)",
733
+ display: "flex",
734
+ alignItems: "center",
735
+ justifyContent: "space-between",
736
+ flexWrap: "wrap",
737
+ gap: 8
738
+ },
739
+ children: [/* @__PURE__ */ jsxs("div", {
740
+ style: {
741
+ display: "flex",
742
+ alignItems: "center",
743
+ gap: 10
744
+ },
745
+ children: [
746
+ title && /* @__PURE__ */ jsx("span", {
747
+ style: {
748
+ fontWeight: 500,
749
+ fontSize: tokens.typography.fontSize.sm
750
+ },
751
+ children: title
752
+ }),
753
+ /* @__PURE__ */ jsxs("div", {
754
+ style: {
755
+ display: "flex",
756
+ gap: 2
757
+ },
758
+ children: [
759
+ /* @__PURE__ */ jsx("button", {
760
+ onClick: () => navigate(-1),
761
+ style: navBtnStyle(tokens),
762
+ children: "◀"
763
+ }),
764
+ /* @__PURE__ */ jsx("button", {
765
+ onClick: () => navigate(0),
766
+ style: {
767
+ ...navBtnStyle(tokens),
768
+ padding: "3px 10px",
769
+ fontSize: tokens.typography.fontSize.xs
770
+ },
771
+ children: "Today"
772
+ }),
773
+ /* @__PURE__ */ jsx("button", {
774
+ onClick: () => navigate(1),
775
+ style: navBtnStyle(tokens),
776
+ children: "▶"
777
+ })
778
+ ]
779
+ }),
780
+ /* @__PURE__ */ jsx("span", {
781
+ style: {
782
+ fontWeight: 500,
783
+ fontSize: tokens.typography.fontSize.sm
784
+ },
785
+ children: headerLabel
786
+ }),
787
+ /* @__PURE__ */ jsxs("span", {
788
+ style: {
789
+ fontSize: 9,
790
+ fontFamily: tokens.typography.fontFamily.mono,
791
+ color: tokens.colors.text.muted,
792
+ background: `${tokens.colors.text.muted}15`,
793
+ padding: "1px 6px",
794
+ borderRadius: tokens.borderRadius.sm
795
+ },
796
+ children: ["DOY ", doy]
797
+ })
798
+ ]
799
+ }), /* @__PURE__ */ jsxs("div", {
800
+ style: {
801
+ display: "flex",
802
+ alignItems: "center",
803
+ gap: 6
804
+ },
805
+ children: [showCreate && /* @__PURE__ */ jsx("button", {
806
+ onClick: () => onEventCreate?.({
807
+ start: currentDate,
808
+ type: "reserve"
809
+ }),
810
+ style: {
811
+ background: tokens.colors.interactive.default,
812
+ color: tokens.colors.text.inverse,
813
+ border: "none",
814
+ borderRadius: tokens.borderRadius.md,
815
+ padding: "4px 12px",
816
+ fontSize: tokens.typography.fontSize.xs,
817
+ fontWeight: 500,
818
+ cursor: "pointer"
819
+ },
820
+ children: "+ Activity"
821
+ }), /* @__PURE__ */ jsx("div", {
822
+ style: {
823
+ display: "flex",
824
+ borderRadius: tokens.borderRadius.md,
825
+ overflow: "hidden",
826
+ border: `1px solid ${tokens.colors.border.muted}`
827
+ },
828
+ children: [
829
+ "month",
830
+ "week",
831
+ "day",
832
+ "gantt",
833
+ "list"
834
+ ].map((v) => /* @__PURE__ */ jsx("button", {
835
+ onClick: () => setViewMode(v),
836
+ style: {
837
+ background: viewMode === v ? tokens.colors.interactive.default : tokens.colors.background.base,
838
+ color: viewMode === v ? tokens.colors.text.inverse : tokens.colors.text.secondary,
839
+ border: "none",
840
+ padding: "3px 10px",
841
+ fontSize: tokens.typography.fontSize.xxs,
842
+ fontWeight: 500,
843
+ cursor: "pointer",
844
+ textTransform: "capitalize"
845
+ },
846
+ children: v
847
+ }, v))
848
+ })]
849
+ })]
850
+ }),
851
+ /* @__PURE__ */ jsxs("div", {
852
+ style: {
853
+ flex: 1,
854
+ display: "flex",
855
+ overflow: "hidden"
856
+ },
857
+ children: [showSidebar && renderSidebar(), /* @__PURE__ */ jsxs("div", {
858
+ ref: bodyRef,
859
+ style: {
860
+ flex: 1,
861
+ overflow: "auto"
862
+ },
863
+ children: [
864
+ viewMode === "month" && /* @__PURE__ */ jsxs("div", {
865
+ style: {
866
+ display: "flex",
867
+ flexDirection: "column",
868
+ height: "100%"
869
+ },
870
+ children: [/* @__PURE__ */ jsx("div", {
871
+ style: {
872
+ display: "grid",
873
+ gridTemplateColumns: "repeat(7, 1fr)",
874
+ borderBottom: `1px solid ${tokens.colors.border.muted}`,
875
+ background: tokens.colors.background.surface
876
+ },
877
+ children: dayNames.map((d) => /* @__PURE__ */ jsx("div", {
878
+ style: {
879
+ padding: "4px 6px",
880
+ textAlign: "center",
881
+ fontSize: tokens.typography.fontSize.xxs,
882
+ fontWeight: 500,
883
+ color: tokens.colors.text.muted,
884
+ textTransform: "uppercase"
885
+ },
886
+ children: d
887
+ }, d))
888
+ }), /* @__PURE__ */ jsx("div", {
889
+ style: {
890
+ display: "grid",
891
+ gridTemplateColumns: "repeat(7, 1fr)",
892
+ gridTemplateRows: "repeat(6, 1fr)",
893
+ flex: 1
894
+ },
895
+ children: monthGrid.map(({ date, isCurrentMonth }, idx) => {
896
+ const dayEvts = getEventsForDay(date);
897
+ const isToday = isSameDay(date, today);
898
+ return /* @__PURE__ */ jsxs("div", {
899
+ onClick: () => {
900
+ setCurrentDate(date);
901
+ if (onDayDrillDown) onDayDrillDown(date, dayEvts);
902
+ else setViewMode("day");
903
+ },
904
+ onContextMenu: (e) => handleContextMenu(e, date),
905
+ style: {
906
+ borderRight: `1px solid ${tokens.colors.border.muted}11`,
907
+ borderBottom: `1px solid ${tokens.colors.border.muted}11`,
908
+ padding: 3,
909
+ cursor: "pointer",
910
+ background: isToday ? `${tokens.colors.interactive.default}08` : "transparent",
911
+ opacity: isCurrentMonth ? 1 : .35,
912
+ overflow: "hidden",
913
+ minHeight: 70
914
+ },
915
+ children: [
916
+ /* @__PURE__ */ jsx("div", {
917
+ style: {
918
+ fontSize: tokens.typography.fontSize.xs,
919
+ fontWeight: isToday ? 700 : 400,
920
+ color: isToday ? tokens.colors.interactive.default : tokens.colors.text.primary,
921
+ marginBottom: 2,
922
+ textAlign: "right",
923
+ paddingRight: 2
924
+ },
925
+ children: isToday ? /* @__PURE__ */ jsx("span", {
926
+ style: {
927
+ background: tokens.colors.interactive.default,
928
+ color: tokens.colors.text.inverse,
929
+ borderRadius: tokens.borderRadius.full,
930
+ width: 20,
931
+ height: 20,
932
+ display: "inline-flex",
933
+ alignItems: "center",
934
+ justifyContent: "center",
935
+ fontSize: tokens.typography.fontSize.xxs
936
+ },
937
+ children: date.getDate()
938
+ }) : date.getDate()
939
+ }),
940
+ dayEvts.slice(0, 3).map((e) => /* @__PURE__ */ jsx(CalendarEventChip, {
941
+ event: e,
942
+ tokens,
943
+ compact: true,
944
+ onClick: () => onEventClick?.(e)
945
+ }, e.id)),
946
+ dayEvts.length > 3 && /* @__PURE__ */ jsxs("div", {
947
+ style: {
948
+ fontSize: tokens.typography.fontSize.micro,
949
+ color: tokens.colors.text.muted,
950
+ textAlign: "center"
951
+ },
952
+ children: [
953
+ "+",
954
+ dayEvts.length - 3,
955
+ " more"
956
+ ]
957
+ })
958
+ ]
959
+ }, idx);
960
+ })
961
+ })]
962
+ }),
963
+ viewMode === "week" && /* @__PURE__ */ jsxs("div", {
964
+ style: {
965
+ display: "flex",
966
+ flexDirection: "column",
967
+ height: "100%"
968
+ },
969
+ children: [/* @__PURE__ */ jsxs("div", {
970
+ style: {
971
+ display: "grid",
972
+ gridTemplateColumns: `50px repeat(7, 1fr)`,
973
+ borderBottom: `1px solid ${tokens.colors.border.muted}`,
974
+ background: tokens.colors.background.surface,
975
+ position: "sticky",
976
+ top: 0,
977
+ zIndex: 2
978
+ },
979
+ children: [/* @__PURE__ */ jsx("div", { style: { borderRight: `1px solid ${tokens.colors.border.muted}22` } }), weekDates.map((d, i) => {
980
+ const isToday = isSameDay(d, today);
981
+ return /* @__PURE__ */ jsxs("div", {
982
+ style: {
983
+ padding: "4px 4px",
984
+ textAlign: "center",
985
+ background: isToday ? `${tokens.colors.interactive.default}10` : "transparent",
986
+ borderRight: `1px solid ${tokens.colors.border.muted}11`
987
+ },
988
+ children: [/* @__PURE__ */ jsx("div", {
989
+ style: {
990
+ fontSize: 9,
991
+ color: tokens.colors.text.muted,
992
+ textTransform: "uppercase"
993
+ },
994
+ children: dayNames[i]
995
+ }), /* @__PURE__ */ jsx("div", {
996
+ style: {
997
+ fontSize: 16,
998
+ fontWeight: isToday ? 700 : 400,
999
+ color: isToday ? tokens.colors.interactive.default : tokens.colors.text.primary
1000
+ },
1001
+ children: isToday ? /* @__PURE__ */ jsx("span", {
1002
+ style: {
1003
+ background: tokens.colors.interactive.default,
1004
+ color: tokens.colors.text.inverse,
1005
+ borderRadius: tokens.borderRadius.full,
1006
+ width: 24,
1007
+ height: 24,
1008
+ display: "inline-flex",
1009
+ alignItems: "center",
1010
+ justifyContent: "center",
1011
+ fontSize: 13
1012
+ },
1013
+ children: d.getDate()
1014
+ }) : d.getDate()
1015
+ })]
1016
+ }, i);
1017
+ })]
1018
+ }), /* @__PURE__ */ jsx("div", {
1019
+ style: {
1020
+ flex: 1,
1021
+ overflow: "auto"
1022
+ },
1023
+ children: TIME_SLOTS.map((slot, _si) => {
1024
+ const isHour = slot.endsWith(":00");
1025
+ return /* @__PURE__ */ jsxs("div", {
1026
+ style: {
1027
+ display: "grid",
1028
+ gridTemplateColumns: `50px repeat(7, 1fr)`,
1029
+ height: SLOT_HEIGHT,
1030
+ borderBottom: `1px solid ${tokens.colors.border.muted}${isHour ? "22" : "0A"}`
1031
+ },
1032
+ children: [/* @__PURE__ */ jsx("div", {
1033
+ style: {
1034
+ fontSize: 9,
1035
+ color: tokens.colors.text.muted,
1036
+ textAlign: "right",
1037
+ paddingRight: 6,
1038
+ fontFamily: tokens.typography.fontFamily.mono,
1039
+ borderRight: `1px solid ${tokens.colors.border.muted}22`,
1040
+ lineHeight: `${SLOT_HEIGHT}px`,
1041
+ visibility: isHour ? "visible" : "hidden"
1042
+ },
1043
+ children: slot
1044
+ }), weekDates.map((d, di) => {
1045
+ new Date(d).setHours(parseInt(slot), slot.endsWith(":30") ? 30 : 0, 0, 0);
1046
+ const slotEvents = getEventsForDay(d).filter((e) => {
1047
+ const eStart = e.start.getHours() * 60 + e.start.getMinutes();
1048
+ const sStart = parseInt(slot) * 60 + (slot.endsWith(":30") ? 30 : 0);
1049
+ return eStart >= sStart && eStart < sStart + 30;
1050
+ });
1051
+ return /* @__PURE__ */ jsx("div", {
1052
+ onClick: () => {
1053
+ setCurrentDate(d);
1054
+ setViewMode("day");
1055
+ },
1056
+ onContextMenu: (e) => handleContextMenu(e, d, slot),
1057
+ style: {
1058
+ borderRight: `1px solid ${tokens.colors.border.muted}0A`,
1059
+ padding: "0 2px",
1060
+ cursor: "pointer",
1061
+ overflow: "hidden",
1062
+ background: isSameDay(d, today) ? `${tokens.colors.interactive.default}04` : "transparent"
1063
+ },
1064
+ children: slotEvents.map((e) => /* @__PURE__ */ jsx(CalendarEventChip, {
1065
+ event: e,
1066
+ tokens,
1067
+ compact: true,
1068
+ onClick: () => onEventClick?.(e)
1069
+ }, e.id))
1070
+ }, di);
1071
+ })]
1072
+ }, slot);
1073
+ })
1074
+ })]
1075
+ }),
1076
+ viewMode === "day" && /* @__PURE__ */ jsx("div", {
1077
+ style: {
1078
+ display: "flex",
1079
+ flexDirection: "column",
1080
+ height: "100%"
1081
+ },
1082
+ children: /* @__PURE__ */ jsx("div", {
1083
+ style: {
1084
+ flex: 1,
1085
+ overflow: "auto"
1086
+ },
1087
+ children: TIME_SLOTS.map((slot) => {
1088
+ const isHour = slot.endsWith(":00");
1089
+ const slotEvents = dayEvents.filter((e) => {
1090
+ const eStart = e.start.getHours() * 60 + e.start.getMinutes();
1091
+ const sStart = parseInt(slot) * 60 + (slot.endsWith(":30") ? 30 : 0);
1092
+ return eStart >= sStart && eStart < sStart + 30;
1093
+ });
1094
+ return /* @__PURE__ */ jsxs("div", {
1095
+ onContextMenu: (e) => handleContextMenu(e, currentDate, slot),
1096
+ style: {
1097
+ display: "grid",
1098
+ gridTemplateColumns: "50px 1fr",
1099
+ minHeight: slotEvents.length > 0 ? Math.max(SLOT_HEIGHT, slotEvents.length * 24 + 4) : SLOT_HEIGHT,
1100
+ borderBottom: `1px solid ${tokens.colors.border.muted}${isHour ? "22" : "0A"}`
1101
+ },
1102
+ children: [/* @__PURE__ */ jsx("div", {
1103
+ style: {
1104
+ fontSize: 10,
1105
+ color: tokens.colors.text.muted,
1106
+ textAlign: "right",
1107
+ paddingRight: 8,
1108
+ fontFamily: tokens.typography.fontFamily.mono,
1109
+ borderRight: `1px solid ${tokens.colors.border.muted}22`,
1110
+ lineHeight: `${SLOT_HEIGHT}px`,
1111
+ visibility: isHour ? "visible" : "hidden"
1112
+ },
1113
+ children: slot
1114
+ }), /* @__PURE__ */ jsx("div", {
1115
+ style: {
1116
+ padding: "1px 6px",
1117
+ cursor: "pointer"
1118
+ },
1119
+ children: slotEvents.map((e) => {
1120
+ const color = e.color || getStatusColor(e.status, tokens);
1121
+ return /* @__PURE__ */ jsxs("div", {
1122
+ onClick: () => onEventClick?.(e),
1123
+ style: {
1124
+ background: `${color}18`,
1125
+ borderRadius: tokens.borderRadius.sm,
1126
+ padding: "3px 8px",
1127
+ marginBottom: 2,
1128
+ cursor: "pointer",
1129
+ display: "flex",
1130
+ alignItems: "center",
1131
+ gap: 6,
1132
+ fontSize: tokens.typography.fontSize.xxs
1133
+ },
1134
+ children: [
1135
+ TYPE_ICON_ASTRO.includes(e.type) ? /* @__PURE__ */ jsx(AstroIcon, {
1136
+ name: getTypeIcon(e.type),
1137
+ size: "extra-small",
1138
+ label: "",
1139
+ style: { opacity: .7 }
1140
+ }) : /* @__PURE__ */ jsx("span", {
1141
+ style: { opacity: .7 },
1142
+ children: getTypeIcon(e.type)
1143
+ }),
1144
+ /* @__PURE__ */ jsx("span", {
1145
+ style: {
1146
+ color,
1147
+ fontSize: tokens.typography.fontSize.micro
1148
+ },
1149
+ children: getStatusShape(e.status)
1150
+ }),
1151
+ /* @__PURE__ */ jsx("span", {
1152
+ style: { fontWeight: 500 },
1153
+ children: e.title
1154
+ }),
1155
+ /* @__PURE__ */ jsxs("span", {
1156
+ style: {
1157
+ color: tokens.colors.text.muted,
1158
+ fontFamily: tokens.typography.fontFamily.mono,
1159
+ fontSize: tokens.typography.fontSize.micro,
1160
+ marginLeft: "auto"
1161
+ },
1162
+ children: [formatTime(e.start), e.end ? `–${formatTime(e.end)}` : ""]
1163
+ }),
1164
+ e.status && /* @__PURE__ */ jsx("span", {
1165
+ style: {
1166
+ fontSize: tokens.typography.fontSize.micro,
1167
+ color,
1168
+ fontWeight: 500,
1169
+ textTransform: "uppercase"
1170
+ },
1171
+ children: e.status
1172
+ })
1173
+ ]
1174
+ }, e.id);
1175
+ })
1176
+ })]
1177
+ }, slot);
1178
+ })
1179
+ })
1180
+ }),
1181
+ viewMode === "gantt" && /* @__PURE__ */ jsxs("div", {
1182
+ style: {
1183
+ display: "flex",
1184
+ flexDirection: "column",
1185
+ height: "100%"
1186
+ },
1187
+ children: [/* @__PURE__ */ jsxs("div", {
1188
+ style: {
1189
+ display: "grid",
1190
+ gridTemplateColumns: `120px repeat(7, 1fr)`,
1191
+ borderBottom: `1px solid ${tokens.colors.border.muted}`,
1192
+ background: tokens.colors.background.surface,
1193
+ position: "sticky",
1194
+ top: 0,
1195
+ zIndex: 2
1196
+ },
1197
+ children: [/* @__PURE__ */ jsx("div", {
1198
+ style: {
1199
+ padding: "6px 8px",
1200
+ fontSize: 10,
1201
+ fontWeight: 500,
1202
+ color: tokens.colors.text.muted,
1203
+ borderRight: `1px solid ${tokens.colors.border.muted}22`
1204
+ },
1205
+ children: "Timeline"
1206
+ }), weekDates.map((d, i) => {
1207
+ const isToday = isSameDay(d, today);
1208
+ return /* @__PURE__ */ jsxs("div", {
1209
+ style: {
1210
+ padding: "4px 4px",
1211
+ textAlign: "center",
1212
+ background: isToday ? `${tokens.colors.interactive.default}10` : "transparent",
1213
+ borderRight: `1px solid ${tokens.colors.border.muted}11`,
1214
+ fontSize: 10
1215
+ },
1216
+ children: [/* @__PURE__ */ jsxs("span", {
1217
+ style: { color: tokens.colors.text.muted },
1218
+ children: [dayNames[i], " "]
1219
+ }), /* @__PURE__ */ jsx("span", {
1220
+ style: {
1221
+ fontWeight: isToday ? 700 : 400,
1222
+ color: isToday ? tokens.colors.interactive.default : tokens.colors.text.primary
1223
+ },
1224
+ children: d.getDate()
1225
+ })]
1226
+ }, i);
1227
+ })]
1228
+ }), /* @__PURE__ */ jsx("div", {
1229
+ style: {
1230
+ flex: 1,
1231
+ overflow: "auto"
1232
+ },
1233
+ children: ganttData.rows.length === 0 ? /* @__PURE__ */ jsx("div", {
1234
+ style: {
1235
+ textAlign: "center",
1236
+ color: tokens.colors.text.muted,
1237
+ padding: 40,
1238
+ fontSize: 12
1239
+ },
1240
+ children: "No activities this week"
1241
+ }) : ganttData.rows.map((row, ri) => /* @__PURE__ */ jsxs("div", {
1242
+ style: {
1243
+ display: "grid",
1244
+ gridTemplateColumns: `120px repeat(7, 1fr)`,
1245
+ borderBottom: `1px solid ${tokens.colors.border.muted}15`,
1246
+ minHeight: 36
1247
+ },
1248
+ children: [/* @__PURE__ */ jsxs("div", {
1249
+ style: {
1250
+ padding: "6px 8px",
1251
+ fontSize: 11,
1252
+ fontWeight: 500,
1253
+ borderRight: `1px solid ${tokens.colors.border.muted}22`,
1254
+ display: "flex",
1255
+ alignItems: "center",
1256
+ gap: 6,
1257
+ color: tokens.colors.text.primary
1258
+ },
1259
+ children: [/* @__PURE__ */ jsx("span", { style: {
1260
+ width: 6,
1261
+ height: 6,
1262
+ borderRadius: "50%",
1263
+ background: row.color,
1264
+ flexShrink: 0
1265
+ } }), row.label]
1266
+ }), weekDates.map((d, di) => {
1267
+ const cellEvents = row.events.filter((e) => {
1268
+ const eDay = new Date(e.start);
1269
+ eDay.setHours(0, 0, 0, 0);
1270
+ const cellDay = new Date(d);
1271
+ cellDay.setHours(0, 0, 0, 0);
1272
+ if (e.end) {
1273
+ const eEnd = new Date(e.end);
1274
+ eEnd.setHours(23, 59, 59, 999);
1275
+ return cellDay >= eDay && cellDay <= eEnd;
1276
+ }
1277
+ return eDay.getTime() === cellDay.getTime();
1278
+ });
1279
+ return /* @__PURE__ */ jsx("div", {
1280
+ onContextMenu: (e) => handleContextMenu(e, d),
1281
+ style: {
1282
+ borderRight: `1px solid ${tokens.colors.border.muted}0A`,
1283
+ padding: "2px 2px",
1284
+ display: "flex",
1285
+ flexDirection: "column",
1286
+ gap: 2,
1287
+ background: isSameDay(d, today) ? `${tokens.colors.interactive.default}04` : "transparent"
1288
+ },
1289
+ children: cellEvents.map((e) => {
1290
+ return /* @__PURE__ */ jsxs("div", {
1291
+ onClick: () => onEventClick?.(e),
1292
+ style: {
1293
+ background: `${e.color || getStatusColor(e.status, tokens)}33`,
1294
+ borderRadius: 3,
1295
+ padding: "2px 4px",
1296
+ fontSize: 9,
1297
+ fontWeight: 500,
1298
+ color: tokens.colors.text.primary,
1299
+ cursor: "pointer",
1300
+ whiteSpace: "nowrap",
1301
+ overflow: "hidden",
1302
+ textOverflow: "ellipsis"
1303
+ },
1304
+ title: `${e.title}\n${formatTime(e.start)}${e.end ? " – " + formatTime(e.end) : ""}`,
1305
+ children: [/* @__PURE__ */ jsx("span", {
1306
+ style: {
1307
+ opacity: .7,
1308
+ marginRight: 3
1309
+ },
1310
+ children: getStatusShape(e.status)
1311
+ }), e.title]
1312
+ }, e.id);
1313
+ })
1314
+ }, di);
1315
+ })]
1316
+ }, ri))
1317
+ })]
1318
+ }),
1319
+ viewMode === "list" && /* @__PURE__ */ jsxs("div", {
1320
+ style: { padding: 12 },
1321
+ children: [/* @__PURE__ */ jsxs("div", {
1322
+ style: {
1323
+ fontSize: tokens.typography.fontSize.xs,
1324
+ color: tokens.colors.text.muted,
1325
+ marginBottom: 8
1326
+ },
1327
+ children: [
1328
+ "Upcoming 7 days — ",
1329
+ listEvents.length,
1330
+ " activities"
1331
+ ]
1332
+ }), listEvents.length === 0 ? /* @__PURE__ */ jsx("div", {
1333
+ style: {
1334
+ textAlign: "center",
1335
+ color: tokens.colors.text.muted,
1336
+ padding: 40,
1337
+ fontSize: tokens.typography.fontSize.sm
1338
+ },
1339
+ children: "No upcoming activities"
1340
+ }) : /* @__PURE__ */ jsx("div", {
1341
+ style: {
1342
+ display: "flex",
1343
+ flexDirection: "column",
1344
+ gap: 4
1345
+ },
1346
+ children: listEvents.map((e) => {
1347
+ const color = e.color || getStatusColor(e.status, tokens);
1348
+ return /* @__PURE__ */ jsxs("div", {
1349
+ onClick: () => onEventClick?.(e),
1350
+ style: {
1351
+ display: "grid",
1352
+ gridTemplateColumns: "100px 1fr auto",
1353
+ padding: "6px 10px",
1354
+ borderRadius: tokens.borderRadius.md,
1355
+ background: `${color}08`,
1356
+ cursor: "pointer",
1357
+ alignItems: "center",
1358
+ gap: 10,
1359
+ fontSize: tokens.typography.fontSize.xs
1360
+ },
1361
+ children: [
1362
+ /* @__PURE__ */ jsxs("span", {
1363
+ style: {
1364
+ fontFamily: tokens.typography.fontFamily.mono,
1365
+ fontSize: tokens.typography.fontSize.xxs,
1366
+ color: tokens.colors.text.muted
1367
+ },
1368
+ children: [
1369
+ e.start.toLocaleDateString("en-US", {
1370
+ month: "short",
1371
+ day: "numeric"
1372
+ }),
1373
+ " ",
1374
+ formatTime(e.start)
1375
+ ]
1376
+ }),
1377
+ /* @__PURE__ */ jsxs("span", {
1378
+ style: {
1379
+ display: "flex",
1380
+ alignItems: "center",
1381
+ gap: 6
1382
+ },
1383
+ children: [TYPE_ICON_ASTRO.includes(e.type) ? /* @__PURE__ */ jsx(AstroIcon, {
1384
+ name: getTypeIcon(e.type),
1385
+ size: "extra-small",
1386
+ label: ""
1387
+ }) : /* @__PURE__ */ jsx("span", { children: getTypeIcon(e.type) }), /* @__PURE__ */ jsx("span", {
1388
+ style: { fontWeight: 500 },
1389
+ children: e.title
1390
+ })]
1391
+ }),
1392
+ e.status && /* @__PURE__ */ jsxs("span", {
1393
+ style: {
1394
+ fontSize: tokens.typography.fontSize.micro,
1395
+ color,
1396
+ fontWeight: 500
1397
+ },
1398
+ children: [
1399
+ getStatusShape(e.status),
1400
+ " ",
1401
+ e.status
1402
+ ]
1403
+ })
1404
+ ]
1405
+ }, e.id);
1406
+ })
1407
+ })]
1408
+ })
1409
+ ]
1410
+ })]
1411
+ }),
1412
+ /* @__PURE__ */ jsxs("div", {
1413
+ style: {
1414
+ padding: "4px 14px",
1415
+ borderTop: `1px solid ${tokens.colors.border.muted}`,
1416
+ background: tokens.colors.background.surface,
1417
+ fontSize: tokens.typography.fontSize.xxs,
1418
+ color: tokens.colors.text.muted,
1419
+ display: "flex",
1420
+ justifyContent: "space-between"
1421
+ },
1422
+ children: [/* @__PURE__ */ jsxs("span", { children: [
1423
+ filteredEvents.length,
1424
+ " activities | DOY ",
1425
+ doy,
1426
+ " | Week ",
1427
+ weekNum
1428
+ ] }), /* @__PURE__ */ jsx("span", { children: events.filter((e) => e.status === "error" || e.status === "failed" || e.status === "crashed").length > 0 ? `⚠ ${events.filter((e) => e.status === "error" || e.status === "failed" || e.status === "crashed").length} errors` : "✓ All nominal" })]
1429
+ }),
1430
+ contextMenu && /* @__PURE__ */ jsxs("div", {
1431
+ style: {
1432
+ position: "fixed",
1433
+ left: contextMenu.x,
1434
+ top: contextMenu.y,
1435
+ zIndex: 1e3,
1436
+ background: tokens.colors.background.surface,
1437
+ backdropFilter: "blur(8px)",
1438
+ border: `1px solid ${tokens.colors.border.muted}`,
1439
+ borderRadius: tokens.borderRadius.md,
1440
+ boxShadow: "0 4px 16px rgba(0,0,0,0.4)",
1441
+ padding: 4,
1442
+ minWidth: 160
1443
+ },
1444
+ children: [/* @__PURE__ */ jsxs("div", {
1445
+ style: {
1446
+ fontSize: 9,
1447
+ color: tokens.colors.text.muted,
1448
+ padding: "4px 8px",
1449
+ fontFamily: tokens.typography.fontFamily.mono
1450
+ },
1451
+ children: [
1452
+ contextMenu.date.toLocaleDateString("en-US", {
1453
+ month: "short",
1454
+ day: "numeric"
1455
+ }),
1456
+ " ",
1457
+ formatTime(contextMenu.date)
1458
+ ]
1459
+ }), [
1460
+ "command",
1461
+ "script",
1462
+ "reserve",
1463
+ "metadata",
1464
+ "note"
1465
+ ].map((type) => /* @__PURE__ */ jsxs("button", {
1466
+ onClick: () => {
1467
+ onEventCreate?.({
1468
+ start: contextMenu.date,
1469
+ type
1470
+ });
1471
+ setContextMenu(null);
1472
+ },
1473
+ style: {
1474
+ display: "block",
1475
+ width: "100%",
1476
+ textAlign: "left",
1477
+ background: "none",
1478
+ border: "none",
1479
+ color: tokens.colors.text.primary,
1480
+ padding: "5px 8px",
1481
+ fontSize: 11,
1482
+ cursor: "pointer",
1483
+ borderRadius: tokens.borderRadius.sm
1484
+ },
1485
+ onMouseEnter: (e) => {
1486
+ e.currentTarget.style.background = `${tokens.colors.interactive.default}22`;
1487
+ },
1488
+ onMouseLeave: (e) => {
1489
+ e.currentTarget.style.background = "none";
1490
+ },
1491
+ children: [
1492
+ getTypeIcon(type),
1493
+ " Create",
1494
+ " ",
1495
+ type.charAt(0).toUpperCase() + type.slice(1)
1496
+ ]
1497
+ }, type))]
1498
+ })
1499
+ ]
1500
+ });
1033
1501
  });
1034
1502
  function navBtnStyle(tokens) {
1035
- return {
1036
- background: tokens.colors.background.base,
1037
- color: tokens.colors.text.secondary,
1038
- border: `1px solid ${tokens.colors.border.muted}`,
1039
- borderRadius: tokens.borderRadius.sm,
1040
- padding: "3px 8px",
1041
- fontSize: tokens.typography.fontSize.xs,
1042
- cursor: "pointer",
1043
- lineHeight: 1
1044
- };
1503
+ return {
1504
+ background: tokens.colors.background.base,
1505
+ color: tokens.colors.text.secondary,
1506
+ border: `1px solid ${tokens.colors.border.muted}`,
1507
+ borderRadius: tokens.borderRadius.sm,
1508
+ padding: "3px 8px",
1509
+ fontSize: tokens.typography.fontSize.xs,
1510
+ cursor: "pointer",
1511
+ lineHeight: 1
1512
+ };
1045
1513
  }
1046
- export {
1047
- MissionCalendar
1048
- };
1049
- //# sourceMappingURL=MissionCalendar.js.map
1514
+ //#endregion
1515
+ export { MissionCalendar, MissionCalendar as default };
1516
+
1517
+ //# sourceMappingURL=MissionCalendar.js.map