@djangocfg/ui-tools 2.1.418 → 2.1.419

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 (304) hide show
  1. package/dist/file-icon/index.cjs +3 -3
  2. package/dist/file-icon/index.cjs.map +1 -1
  3. package/dist/file-icon/index.mjs +3 -3
  4. package/dist/file-icon/index.mjs.map +1 -1
  5. package/package.json +93 -28
  6. package/src/common/FloatingToolbar/actions/CopyAction.tsx +31 -0
  7. package/src/{components → common}/FloatingToolbar/actions/DownloadAction.tsx +15 -10
  8. package/src/common/FloatingToolbar/actions/ExpandAction.tsx +33 -0
  9. package/src/common/FloatingToolbar/actions/FullscreenAction.tsx +38 -0
  10. package/src/{components → common}/FloatingToolbar/index.tsx +39 -0
  11. package/src/lib/http.ts +64 -0
  12. package/src/tools/chat/index.ts +1 -1
  13. package/src/tools/chat/launcher/ChatFAB.tsx +66 -74
  14. package/src/tools/chat/launcher/header/ChatHeaderActionButton.tsx +2 -3
  15. package/src/tools/chat/lazy.tsx +1 -1
  16. package/src/tools/chat/messages/MessageBubble.tsx +1 -1
  17. package/src/tools/chat/messages/blocks/builtin.tsx +1 -1
  18. package/src/tools/chat/messages/blocks/renderers/CodeBlock.tsx +2 -2
  19. package/src/tools/chat/messages/blocks/renderers/JsonBlock.tsx +12 -1
  20. package/src/tools/data/DataGrid/lazy.tsx +1 -1
  21. package/src/tools/data/DataTable/lazy.tsx +1 -1
  22. package/src/tools/data/JsonTree/JsonViewer.tsx +720 -0
  23. package/src/tools/data/JsonTree/README.md +126 -73
  24. package/src/tools/data/JsonTree/index.tsx +3 -95
  25. package/src/tools/data/JsonTree/lazy.tsx +10 -50
  26. package/src/tools/data/JsonTree/types.ts +82 -63
  27. package/src/tools/data/Kanban/lazy.tsx +1 -1
  28. package/src/tools/data/Listbox/lazy.tsx +1 -1
  29. package/src/tools/data/Masonry/lazy.tsx +1 -1
  30. package/src/tools/data/Timeline/lazy.tsx +1 -1
  31. package/src/tools/data/Tree/lazy.tsx +1 -1
  32. package/src/tools/dev/Map/lazy.tsx +1 -1
  33. package/src/tools/dev/Mermaid/Mermaid.client.tsx +2 -2
  34. package/src/tools/dev/Mermaid/lazy.tsx +1 -1
  35. package/src/tools/dev/api/ApiRefTable/ApiRefTable.tsx +65 -0
  36. package/src/tools/dev/api/ApiRefTable/README.md +31 -0
  37. package/src/tools/dev/api/ApiRefTable/components/Row.tsx +96 -0
  38. package/src/tools/dev/api/ApiRefTable/components/TypeDisplay.tsx +44 -0
  39. package/src/tools/dev/api/ApiRefTable/index.ts +6 -0
  40. package/src/tools/dev/api/ApiRefTable/lazy.tsx +21 -0
  41. package/src/tools/dev/api/ApiRefTable/types.ts +82 -0
  42. package/src/tools/dev/api/ApiRefTable/utils.ts +42 -0
  43. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/ApiIntroSection.tsx +1 -1
  44. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/CodeSamples/index.tsx +1 -1
  45. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/index.tsx +1 -1
  46. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/ResponseBody.tsx +7 -21
  47. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/RequestPanel.tsx +1 -1
  48. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/PrettyView.tsx +13 -19
  49. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/types.ts +1 -1
  50. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/lazy.tsx +1 -1
  51. package/src/tools/dev/api/RequestViewer/README.md +33 -0
  52. package/src/tools/dev/api/RequestViewer/RequestViewer.tsx +121 -0
  53. package/src/tools/dev/api/RequestViewer/components/BodyTab.tsx +44 -0
  54. package/src/tools/dev/api/RequestViewer/components/EmptyState.tsx +13 -0
  55. package/src/tools/dev/api/RequestViewer/components/HeadersTab.tsx +78 -0
  56. package/src/tools/dev/api/RequestViewer/components/TimingTab.tsx +113 -0
  57. package/src/tools/dev/api/RequestViewer/components/utils.ts +31 -0
  58. package/src/tools/dev/api/RequestViewer/index.ts +16 -0
  59. package/src/tools/dev/api/RequestViewer/lazy.tsx +30 -0
  60. package/src/tools/dev/api/RequestViewer/types.ts +81 -0
  61. package/src/tools/dev/code/DiffViewer/DiffViewer.tsx +144 -0
  62. package/src/tools/dev/code/DiffViewer/README.md +33 -0
  63. package/src/tools/dev/code/DiffViewer/components/CopyButton.tsx +49 -0
  64. package/src/tools/dev/code/DiffViewer/components/DiffLineContent.tsx +48 -0
  65. package/src/tools/dev/code/DiffViewer/components/SplitView.tsx +220 -0
  66. package/src/tools/dev/code/DiffViewer/components/UnifiedView.tsx +154 -0
  67. package/src/tools/dev/code/DiffViewer/hooks/useDiff.ts +47 -0
  68. package/src/tools/dev/code/DiffViewer/hooks/useHighlighter.ts +54 -0
  69. package/src/tools/dev/code/DiffViewer/index.ts +22 -0
  70. package/src/tools/dev/code/DiffViewer/lazy.tsx +22 -0
  71. package/src/tools/dev/code/DiffViewer/types.ts +109 -0
  72. package/src/tools/dev/code/DiffViewer/utils/computeDiff.ts +159 -0
  73. package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/CollapseToggle.tsx +1 -1
  74. package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/MarkdownMessage.tsx +1 -1
  75. package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/components.tsx +2 -2
  76. package/src/tools/dev/{PrettyCode → code/PrettyCode}/PrettyCode.client.tsx +2 -2
  77. package/src/tools/dev/{PrettyCode → code/PrettyCode}/lazy.tsx +1 -1
  78. package/src/tools/dev/ops/EnvTable/EnvTable.tsx +228 -0
  79. package/src/tools/dev/ops/EnvTable/README.md +29 -0
  80. package/src/tools/dev/ops/EnvTable/hooks/useEnvMask.ts +121 -0
  81. package/src/tools/dev/ops/EnvTable/index.ts +12 -0
  82. package/src/tools/dev/ops/EnvTable/lazy.tsx +21 -0
  83. package/src/tools/dev/ops/EnvTable/types.ts +76 -0
  84. package/src/tools/dev/ops/LogViewer/LogViewer.tsx +194 -0
  85. package/src/tools/dev/ops/LogViewer/README.md +30 -0
  86. package/src/tools/dev/ops/LogViewer/components/LogRow.tsx +151 -0
  87. package/src/tools/dev/ops/LogViewer/components/Toolbar.tsx +199 -0
  88. package/src/tools/dev/ops/LogViewer/hooks/useAutoScroll.ts +68 -0
  89. package/src/tools/dev/ops/LogViewer/hooks/useLogFilter.ts +58 -0
  90. package/src/tools/dev/ops/LogViewer/index.ts +18 -0
  91. package/src/tools/dev/ops/LogViewer/lazy.tsx +25 -0
  92. package/src/tools/dev/ops/LogViewer/types.ts +142 -0
  93. package/src/tools/dev/ops/LogViewer/utils/ansi.ts +231 -0
  94. package/src/tools/forms/CodeEditor/hooks/useEditorTheme.ts +13 -73
  95. package/src/tools/forms/CodeEditor/lazy.tsx +1 -1
  96. package/src/tools/forms/FileUpload/lazy.tsx +1 -1
  97. package/src/tools/forms/JsonEditor/JsonEditor.tsx +115 -0
  98. package/src/tools/forms/JsonEditor/index.ts +1 -0
  99. package/src/tools/forms/JsonEditor/lazy.tsx +24 -0
  100. package/src/tools/forms/JsonForm/index.ts +1 -1
  101. package/src/tools/forms/JsonForm/lazy.tsx +1 -1
  102. package/src/tools/forms/MarkdownEditor/lazy.tsx +1 -1
  103. package/src/tools/forms/NotionEditor/README.md +237 -0
  104. package/src/tools/forms/NotionEditor/lazy.tsx +1 -1
  105. package/src/tools/index.ts +153 -13
  106. package/src/tools/input/Combobox/lazy.tsx +1 -1
  107. package/src/tools/input/CronScheduler/components/CronPreview.README.md +28 -0
  108. package/src/tools/input/CronScheduler/components/CronPreview.tsx +136 -0
  109. package/src/tools/input/CronScheduler/components/index.ts +3 -0
  110. package/src/tools/input/CronScheduler/index.tsx +5 -1
  111. package/src/tools/input/CronScheduler/lazy.tsx +5 -1
  112. package/src/tools/input/CronScheduler/utils/cron-next-runs.ts +122 -0
  113. package/src/tools/input/CronScheduler/utils/index.ts +1 -0
  114. package/src/tools/input/Scroller/lazy.tsx +1 -1
  115. package/src/tools/input/Sortable/lazy.tsx +1 -1
  116. package/src/tools/input/SpeechRecognition/lazy.tsx +1 -1
  117. package/src/tools/input/SpeechRecognition/widgets/VoiceComposerSlot.tsx +41 -36
  118. package/src/tools/media/ImageViewer/components/ImageToolbar.tsx +58 -47
  119. package/src/tools/media/ImageViewer/components/ImageViewer.tsx +27 -19
  120. package/src/tools/media/ImageViewer/lazy.tsx +1 -1
  121. package/src/tools/media/LottiePlayer/lazy.tsx +1 -1
  122. package/src/tools/media/VideoPlayer/VideoPlayer.tsx +28 -1
  123. package/src/tools/media/VideoPlayer/parts/fullscreen.tsx +21 -4
  124. package/src/tools/media/VideoPlayer/parts/pip.tsx +21 -4
  125. package/src/tools/media/VideoPlayer/parts/play-button.tsx +21 -4
  126. package/src/tools/media/VideoPlayer/parts/playback-rate.tsx +19 -3
  127. package/src/tools/media/VideoPlayer/parts/volume.tsx +237 -18
  128. package/src/tools/media/VideoPlayer/styles/video-player.css +87 -7
  129. package/src/tools/overlay/ResponsiveDialog/lazy.tsx +1 -1
  130. package/src/tools/overlay/ScrollSpy/lazy.tsx +1 -1
  131. package/src/tools/overlay/SelectionToolbar/lazy.tsx +1 -1
  132. package/src/tools/overlay/Tour/lazy.tsx +1 -1
  133. package/src/tools/visual/Marquee/lazy.tsx +1 -1
  134. package/src/tools/visual/QRCode/lazy.tsx +1 -1
  135. package/src/tools/visual/charts/ActivityGraph/ActivityGraph.tsx +195 -0
  136. package/src/tools/visual/charts/ActivityGraph/README.md +28 -0
  137. package/src/tools/visual/charts/ActivityGraph/index.ts +8 -0
  138. package/src/tools/visual/charts/ActivityGraph/lazy.tsx +21 -0
  139. package/src/tools/visual/charts/ActivityGraph/types.ts +59 -0
  140. package/src/tools/visual/charts/ActivityGraph/utils.ts +88 -0
  141. package/src/tools/visual/charts/CommitGraph/CommitGraph.tsx +80 -0
  142. package/src/tools/visual/charts/CommitGraph/README.md +28 -0
  143. package/src/tools/visual/charts/CommitGraph/components/CommitDetail.tsx +107 -0
  144. package/src/tools/visual/charts/CommitGraph/components/CommitRow.tsx +122 -0
  145. package/src/tools/visual/charts/CommitGraph/components/Rails.tsx +171 -0
  146. package/src/tools/visual/charts/CommitGraph/hooks/useGraphLayout.ts +169 -0
  147. package/src/tools/visual/charts/CommitGraph/hooks/useLaneColors.ts +45 -0
  148. package/src/tools/visual/charts/CommitGraph/index.ts +14 -0
  149. package/src/tools/visual/charts/CommitGraph/lazy.tsx +25 -0
  150. package/src/tools/visual/charts/CommitGraph/types.ts +85 -0
  151. package/src/tools/visual/charts/CommitGraph/utils.ts +53 -0
  152. package/src/tools/visual/{Gauge → charts/Gauge}/lazy.tsx +1 -1
  153. package/src/tools/visual/charts/Sparkline/README.md +29 -0
  154. package/src/tools/visual/charts/Sparkline/Sparkline.tsx +217 -0
  155. package/src/tools/visual/charts/Sparkline/index.ts +9 -0
  156. package/src/tools/visual/charts/Sparkline/lazy.tsx +26 -0
  157. package/src/tools/visual/charts/Sparkline/types.ts +58 -0
  158. package/src/tools/visual/design/ColorPalette/ColorPalette.tsx +129 -0
  159. package/src/tools/visual/design/ColorPalette/README.md +34 -0
  160. package/src/tools/visual/design/ColorPalette/components/Swatch.tsx +102 -0
  161. package/src/tools/visual/design/ColorPalette/hooks/useCopyToClipboard.ts +41 -0
  162. package/src/tools/visual/design/ColorPalette/index.ts +12 -0
  163. package/src/tools/visual/design/ColorPalette/lazy.tsx +21 -0
  164. package/src/tools/visual/design/ColorPalette/types.ts +63 -0
  165. package/src/tools/visual/design/ColorPalette/utils.ts +83 -0
  166. package/src/tools/visual/{ColorPicker → design/ColorPicker}/lazy.tsx +1 -1
  167. package/src/tools/visual/{FileIcon → design/FileIcon}/treeAdapter.tsx +1 -1
  168. package/src/tools/visual/{Fps → indicators/Fps}/lazy.tsx +1 -1
  169. package/src/tools/visual/{Rating → indicators/Rating}/lazy.tsx +1 -1
  170. package/src/tools/visual/indicators/StatusIndicator/README.md +28 -0
  171. package/src/tools/visual/indicators/StatusIndicator/StatusIndicator.tsx +83 -0
  172. package/src/tools/visual/indicators/StatusIndicator/index.ts +14 -0
  173. package/src/tools/visual/indicators/StatusIndicator/lazy.tsx +21 -0
  174. package/src/tools/visual/indicators/StatusIndicator/types.ts +133 -0
  175. package/src/components/FloatingToolbar/actions/CopyAction.tsx +0 -22
  176. package/src/components/FloatingToolbar/actions/ExpandAction.tsx +0 -25
  177. package/src/components/FloatingToolbar/actions/FullscreenAction.tsx +0 -30
  178. package/src/tools/data/JsonTree/components/JsonContent.tsx +0 -197
  179. package/src/tools/data/JsonTree/hooks/useJsonExpand.ts +0 -50
  180. /package/src/{components → common}/FloatingToolbar/FloatingToolbar.css +0 -0
  181. /package/src/{components → common}/FloatingToolbar/actions/index.ts +0 -0
  182. /package/src/{components → common}/FloatingToolbar/hooks/useElementCorner.ts +0 -0
  183. /package/src/{components → common}/FloatingToolbar/hooks/useScrollIsolation.ts +0 -0
  184. /package/src/{components → common}/index.ts +0 -0
  185. /package/src/{components → common}/lazy-wrapper.tsx +0 -0
  186. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/README.md +0 -0
  187. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/DocsView.tsx +0 -0
  188. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/CodeSamples/LanguageTabs.tsx +0 -0
  189. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/CodeSamples/useCodeSnippet.ts +0 -0
  190. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/MetaActions.tsx +0 -0
  191. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/MethodBadge.tsx +0 -0
  192. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/PathDisplay.tsx +0 -0
  193. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Parameters/ParamGroup.tsx +0 -0
  194. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Parameters/ParamRow.tsx +0 -0
  195. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Parameters/index.tsx +0 -0
  196. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/RequestBody/index.tsx +0 -0
  197. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/ResponseRow.tsx +0 -0
  198. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/StatusTag.tsx +0 -0
  199. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/index.tsx +0 -0
  200. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/FieldRow.tsx +0 -0
  201. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/buildTree.ts +0 -0
  202. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/index.tsx +0 -0
  203. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/types.ts +0 -0
  204. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Section/SectionHeader.tsx +0 -0
  205. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Section/defaults.ts +0 -0
  206. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Section/index.tsx +0 -0
  207. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/context.tsx +0 -0
  208. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/hooks/useSectionHash.ts +0 -0
  209. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/index.tsx +0 -0
  210. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/store/index.ts +0 -0
  211. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/store/selectors.ts +0 -0
  212. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/types.ts +0 -0
  213. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/SchemaCopyMenu.tsx +0 -0
  214. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/BrandHeader.tsx +0 -0
  215. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/CategoryBlock.tsx +0 -0
  216. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/EndpointRow.tsx +0 -0
  217. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/SchemaSection.tsx +0 -0
  218. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/SearchInput.tsx +0 -0
  219. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/SidebarBody.tsx +0 -0
  220. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/Toolbar.tsx +0 -0
  221. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/buildVM.ts +0 -0
  222. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/index.tsx +0 -0
  223. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/types.ts +0 -0
  224. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/useDebouncedValue.ts +0 -0
  225. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/SlideInPlayground.tsx +0 -0
  226. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/TryItSheet.tsx +0 -0
  227. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/anchor.ts +0 -0
  228. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/grouping.ts +0 -0
  229. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/index.tsx +0 -0
  230. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/sidebarLabel.ts +0 -0
  231. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/index.ts +0 -0
  232. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/BodyFormEditor.tsx +0 -0
  233. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/EndpointDraftSync.tsx +0 -0
  234. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/EndpointResetButton.tsx +0 -0
  235. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/PreviewView.tsx +0 -0
  236. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/RawView.tsx +0 -0
  237. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/StatusBar.tsx +0 -0
  238. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/ViewTabs.tsx +0 -0
  239. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/detectContent.ts +0 -0
  240. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/index.tsx +0 -0
  241. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/useResponseView.ts +0 -0
  242. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/SendButton.tsx +0 -0
  243. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ui.tsx +0 -0
  244. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/constants.ts +0 -0
  245. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/context/PlaygroundContext.tsx +0 -0
  246. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/index.ts +0 -0
  247. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useDocsUrlSync.ts +0 -0
  248. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useEndpointDraft.ts +0 -0
  249. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useMobile.ts +0 -0
  250. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useOpenApiSchema.ts +0 -0
  251. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/index.tsx +0 -0
  252. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/types.ts +0 -0
  253. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/apiKeyManager.ts +0 -0
  254. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/codeSamples.ts +0 -0
  255. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/formatters.ts +0 -0
  256. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/index.ts +0 -0
  257. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/operationToHar.ts +0 -0
  258. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/sampler.ts +0 -0
  259. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/schemaExport.ts +0 -0
  260. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/scrollParent.ts +0 -0
  261. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/url.ts +0 -0
  262. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/versionManager.ts +0 -0
  263. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/ActionRow.tsx +0 -0
  264. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/ChatMessageRow.tsx +0 -0
  265. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/CodeBlock.tsx +0 -0
  266. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/README.md +0 -0
  267. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/index.ts +0 -0
  268. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/linkRules.ts +0 -0
  269. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/plainText.ts +0 -0
  270. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/sanitize.ts +0 -0
  271. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/types.ts +0 -0
  272. /package/src/tools/dev/{PrettyCode → code/PrettyCode}/README.md +0 -0
  273. /package/src/tools/dev/{PrettyCode → code/PrettyCode}/index.tsx +0 -0
  274. /package/src/tools/dev/{PrettyCode → code/PrettyCode}/registerPrismLanguages.ts +0 -0
  275. /package/src/tools/visual/{Gauge → charts/Gauge}/Gauge.tsx +0 -0
  276. /package/src/tools/visual/{Gauge → charts/Gauge}/index.ts +0 -0
  277. /package/src/tools/visual/{Gauge → charts/Gauge}/types.ts +0 -0
  278. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/ColorPicker.tsx +0 -0
  279. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/context/ColorPickerContext.tsx +0 -0
  280. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/context/ColorPickerStore.tsx +0 -0
  281. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/context/index.ts +0 -0
  282. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/index.ts +0 -0
  283. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/lib/color-utils.ts +0 -0
  284. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerAlphaSlider.tsx +0 -0
  285. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerArea.tsx +0 -0
  286. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerEyeDropper.tsx +0 -0
  287. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerFormatSelect.tsx +0 -0
  288. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerHueSlider.tsx +0 -0
  289. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerInput.tsx +0 -0
  290. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerSwatch.tsx +0 -0
  291. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/index.ts +0 -0
  292. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/types.ts +0 -0
  293. /package/src/tools/visual/{FileIcon → design/FileIcon}/FileIcon.tsx +0 -0
  294. /package/src/tools/visual/{FileIcon → design/FileIcon}/get-file-icon.ts +0 -0
  295. /package/src/tools/visual/{FileIcon → design/FileIcon}/icons/icon-data.ts +0 -0
  296. /package/src/tools/visual/{FileIcon → design/FileIcon}/index.ts +0 -0
  297. /package/src/tools/visual/{FileIcon → design/FileIcon}/loader.ts +0 -0
  298. /package/src/tools/visual/{FileIcon → design/FileIcon}/specialFolders.ts +0 -0
  299. /package/src/tools/visual/{Fps → indicators/Fps}/Fps.tsx +0 -0
  300. /package/src/tools/visual/{Fps → indicators/Fps}/index.ts +0 -0
  301. /package/src/tools/visual/{Fps → indicators/Fps}/types.ts +0 -0
  302. /package/src/tools/visual/{Rating → indicators/Rating}/Rating.tsx +0 -0
  303. /package/src/tools/visual/{Rating → indicators/Rating}/index.ts +0 -0
  304. /package/src/tools/visual/{Rating → indicators/Rating}/types.ts +0 -0
@@ -0,0 +1,195 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+ //
3
+ // GitHub-style activity heatmap that visualizes daily counts as a
4
+ // color-intensity grid. Auto-sizes blocks to fit the container by default.
5
+ //
6
+ // Port notes:
7
+ // - Cell colors resolve through `useThemeColor('primary')` + `alpha(...)`,
8
+ // not raw `bg-emerald-*` (CONTRACT §2, AUDIT §1). The five emerald
9
+ // stops in the original collapse to five opacity stops on the active
10
+ // theme's `primary` token, which means the heatmap follows the theme
11
+ // preset automatically.
12
+ // - Intensity bucketing routed through `getIntensity` from
13
+ // `@djangocfg/ui-core/lib` (CONTRACT shared util added in Phase 0).
14
+ // - Container sizing routed through `useResizeObserver` from
15
+ // `@djangocfg/ui-core/hooks` (shared RO from Phase 0), replacing the
16
+ // local `ResizeObserver` instance in the source.
17
+ // - Tooltips: the original wrapped every cell in its own Radix
18
+ // `Tooltip.Provider`. Mounting a provider per cell violates CONTRACT
19
+ // §5 ("no nested providers") and explodes to 365 portals on a default
20
+ // 52-week graph. The port uses the native `title` attribute on each
21
+ // cell instead — accessible, no provider dependency, no portal.
22
+
23
+ 'use client';
24
+
25
+ import * as React from 'react';
26
+ import { cn } from '@djangocfg/ui-core/lib';
27
+ import { getIntensity } from '@djangocfg/ui-core/lib';
28
+ import { useResizeObserver } from '@djangocfg/ui-core/hooks';
29
+ import { useThemeColor, alpha } from '@djangocfg/ui-core/styles/palette';
30
+
31
+ import {
32
+ DAY_LABEL_INDICES,
33
+ DAY_LABEL_WIDTH,
34
+ DAY_LABELS,
35
+ DEFAULT_INTENSITY_OPACITY,
36
+ DEFAULT_INTENSITY_THRESHOLDS,
37
+ GAP,
38
+ MONTH_LABEL_HEIGHT,
39
+ type ActivityGraphProps,
40
+ } from './types';
41
+ import { buildWeeks, formatDate, getMonthLabels } from './utils';
42
+
43
+ export function ActivityGraph({
44
+ data,
45
+ intensityOpacity = DEFAULT_INTENSITY_OPACITY,
46
+ blockSize: fixedBlockSize,
47
+ blockRadius = 2,
48
+ weeks: weekCount = 52,
49
+ className,
50
+ ...props
51
+ }: ActivityGraphProps) {
52
+ const containerRef = React.useRef<HTMLDivElement>(null);
53
+ const { width: containerWidth } = useResizeObserver(containerRef);
54
+
55
+ const isAutoFit = fixedBlockSize == null;
56
+
57
+ // Auto-fit cell size based on container width. Falls back to a small
58
+ // default until the first measurement lands (consistent with original).
59
+ const autoSize = React.useMemo(() => {
60
+ if (!isAutoFit || containerWidth <= 0) return null;
61
+ const available = containerWidth - DAY_LABEL_WIDTH;
62
+ const size = (available - GAP * (weekCount - 1)) / weekCount;
63
+ return Math.max(4, Math.floor(size));
64
+ }, [isAutoFit, containerWidth, weekCount]);
65
+
66
+ const blockSize = fixedBlockSize ?? autoSize ?? 10;
67
+ const showGraph = !isAutoFit || autoSize != null;
68
+
69
+ // Resolve the theme color once; map each intensity bucket to an
70
+ // opacity stop applied to that color (see CONTRACT §3 — never raw
71
+ // Tailwind class for parametric colors).
72
+ const primary = useThemeColor('primary');
73
+ const intensityColors = React.useMemo(
74
+ () => intensityOpacity.map((op) => alpha(primary, op)),
75
+ [primary, intensityOpacity],
76
+ );
77
+
78
+ const weeks = React.useMemo(() => buildWeeks(data, weekCount), [data, weekCount]);
79
+ const maxCount = React.useMemo(
80
+ () => data.reduce((m, d) => (d.count > m ? d.count : m), 0),
81
+ [data],
82
+ );
83
+ const monthLabels = React.useMemo(
84
+ () => getMonthLabels(weeks, blockSize),
85
+ [weeks, blockSize],
86
+ );
87
+
88
+ const gridWidth = weeks.length * (blockSize + GAP) - GAP;
89
+ const gridHeight = 7 * (blockSize + GAP) - GAP;
90
+ const totalWidth = DAY_LABEL_WIDTH + gridWidth;
91
+
92
+ return (
93
+ <div
94
+ ref={containerRef}
95
+ className={cn(isAutoFit ? 'w-full' : 'overflow-x-auto', className)}
96
+ role="img"
97
+ aria-label="Activity graph"
98
+ data-slot="activity-graph"
99
+ {...props}
100
+ >
101
+ {showGraph && (
102
+ <div
103
+ className="flex flex-col gap-2"
104
+ style={{ minWidth: isAutoFit ? undefined : totalWidth }}
105
+ >
106
+ <div
107
+ className="relative"
108
+ style={{
109
+ width: isAutoFit ? '100%' : totalWidth,
110
+ height: MONTH_LABEL_HEIGHT + gridHeight,
111
+ }}
112
+ >
113
+ {monthLabels.map((m, i) => (
114
+ <span
115
+ key={`${m.label}-${i}`}
116
+ className="absolute text-[10px] leading-none text-muted-foreground"
117
+ style={{ left: DAY_LABEL_WIDTH + m.offset, top: 0 }}
118
+ >
119
+ {m.label}
120
+ </span>
121
+ ))}
122
+
123
+ {DAY_LABELS.map((label, i) => (
124
+ <span
125
+ key={label}
126
+ className="absolute text-[10px] leading-none text-muted-foreground"
127
+ style={{
128
+ left: 0,
129
+ top:
130
+ MONTH_LABEL_HEIGHT +
131
+ DAY_LABEL_INDICES[i] * (blockSize + GAP) +
132
+ blockSize / 2 -
133
+ 4,
134
+ }}
135
+ >
136
+ {label}
137
+ </span>
138
+ ))}
139
+
140
+ <div
141
+ className="absolute"
142
+ style={{
143
+ left: DAY_LABEL_WIDTH,
144
+ top: MONTH_LABEL_HEIGHT,
145
+ display: 'flex',
146
+ gap: GAP,
147
+ }}
148
+ >
149
+ {weeks.map((week, wi) => (
150
+ <div key={wi} style={{ display: 'flex', flexDirection: 'column', gap: GAP }}>
151
+ {week.map((day, di) => {
152
+ const ratio = maxCount > 0 ? day.count / maxCount : 0;
153
+ const intensity = getIntensity(ratio, [...DEFAULT_INTENSITY_THRESHOLDS]);
154
+ const title = `${day.count} contribution${day.count === 1 ? '' : 's'} — ${formatDate(day.date)}`;
155
+ return (
156
+ <div
157
+ key={di}
158
+ data-slot="activity-graph-cell"
159
+ data-intensity={intensity}
160
+ className="transition-colors"
161
+ title={title}
162
+ style={{
163
+ width: blockSize,
164
+ height: blockSize,
165
+ borderRadius: blockRadius,
166
+ backgroundColor: intensityColors[intensity],
167
+ }}
168
+ />
169
+ );
170
+ })}
171
+ </div>
172
+ ))}
173
+ </div>
174
+ </div>
175
+
176
+ <div className="flex items-center gap-1.5 self-end text-[10px] text-muted-foreground">
177
+ <span>Less</span>
178
+ {intensityColors.map((color, i) => (
179
+ <div
180
+ key={i}
181
+ style={{
182
+ width: blockSize,
183
+ height: blockSize,
184
+ borderRadius: blockRadius,
185
+ backgroundColor: color,
186
+ }}
187
+ />
188
+ ))}
189
+ <span>More</span>
190
+ </div>
191
+ </div>
192
+ )}
193
+ </div>
194
+ );
195
+ }
@@ -0,0 +1,28 @@
1
+ # ActivityGraph
2
+
3
+ GitHub-style contribution heatmap. Maps daily counts to opacity stops of the active theme `primary` color via `useThemeColor` + `useResizeObserver`.
4
+
5
+ ```tsx
6
+ import { ActivityGraph } from '@djangocfg/ui-tools/activity-graph';
7
+
8
+ <ActivityGraph
9
+ data={[{ date: '2025-01-12', count: 4 }, { date: '2025-01-13', count: 0 }]}
10
+ weeks={52}
11
+ />
12
+ ```
13
+
14
+ ## Props
15
+
16
+ | Prop | Type | Default | Description |
17
+ |---|---|---|---|
18
+ | `data` | `ActivityEntry[]` | — | Daily entries `{ date, count }`. Duplicate dates are summed. |
19
+ | `weeks` | `number` | `52` | Trailing week count. |
20
+ | `blockSize` | `number` | auto | Cell size in px. When omitted, auto-fits the container. |
21
+ | `blockRadius` | `number` | `2` | Cell border-radius in px. |
22
+ | `intensityOpacity` | `[number,number,number,number,number]` | `[0.08, 0.18, 0.35, 0.6, 0.95]` | Opacity stops applied to the theme `primary` color (intensity 0–4). |
23
+
24
+ Storybook: `apps/storybook/stories/ui-tools/visual/ActivityGraph.stories.tsx`
25
+
26
+ ---
27
+
28
+ Adapted from jalcoui (MIT).
@@ -0,0 +1,8 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+
3
+ export { ActivityGraph } from './ActivityGraph';
4
+ export {
5
+ DEFAULT_INTENSITY_OPACITY,
6
+ DEFAULT_INTENSITY_THRESHOLDS,
7
+ } from './types';
8
+ export type { ActivityGraphProps, ActivityEntry } from './types';
@@ -0,0 +1,21 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+
3
+ 'use client';
4
+
5
+ import { createLazyComponent } from '../../../../common/lazy-wrapper';
6
+ import type { ActivityGraphProps } from './types';
7
+
8
+ export const LazyActivityGraph = createLazyComponent<ActivityGraphProps>(
9
+ () => import('./ActivityGraph').then((mod) => ({ default: mod.ActivityGraph })),
10
+ {
11
+ displayName: 'LazyActivityGraph',
12
+ fallback: (
13
+ <div
14
+ data-slot="activity-graph-skeleton"
15
+ className="h-[120px] w-full animate-pulse rounded-md bg-muted"
16
+ />
17
+ ),
18
+ },
19
+ );
20
+
21
+ export type { ActivityGraphProps, ActivityEntry } from './types';
@@ -0,0 +1,59 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+
3
+ import type * as React from 'react';
4
+
5
+ /**
6
+ * Single day entry in the contribution heatmap.
7
+ */
8
+ export interface ActivityEntry {
9
+ /** ISO date string (YYYY-MM-DD). */
10
+ date: string;
11
+ /** Activity count for this date. */
12
+ count: number;
13
+ }
14
+
15
+ /**
16
+ * Five opacity stops applied to the resolved theme `primary` color for
17
+ * intensity levels 0–4. Level 0 is the empty / no-activity surface and is
18
+ * intentionally low (almost equal to `bg-muted`).
19
+ *
20
+ * Audit notes (AUDIT.md §1) collapse the full emerald scale to
21
+ * `alpha(primary, …)`, so the same five stops cover light and dark themes.
22
+ */
23
+ export const DEFAULT_INTENSITY_OPACITY: readonly [number, number, number, number, number] = [
24
+ 0.08, 0.18, 0.35, 0.6, 0.95,
25
+ ] as const;
26
+
27
+ /**
28
+ * Thresholds (ratios of `value / max`) that map a normalized count into
29
+ * one of four non-zero intensity buckets. Combined with the empty bucket
30
+ * for `count === 0` they yield the 5 levels expected by the heatmap.
31
+ *
32
+ * Mirrors the original jalcoui `getIntensity` (`<=0.25 / 0.5 / 0.75`).
33
+ */
34
+ export const DEFAULT_INTENSITY_THRESHOLDS: readonly [number, number, number] = [0.25, 0.5, 0.75];
35
+
36
+ export interface ActivityGraphProps extends Omit<React.ComponentProps<'div'>, 'children'> {
37
+ /** Activity data entries. Duplicates with the same `date` are summed. */
38
+ data: ActivityEntry[];
39
+ /**
40
+ * Override the 5 opacity stops applied to the active theme `primary`
41
+ * color. Index 0 is the empty surface; index 4 is the peak.
42
+ */
43
+ intensityOpacity?: readonly [number, number, number, number, number];
44
+ /**
45
+ * Fixed cell size in pixels. When omitted the component auto-sizes
46
+ * blocks to fill the available container width via `useResizeObserver`.
47
+ */
48
+ blockSize?: number;
49
+ /** Cell border radius in pixels. @default 2 */
50
+ blockRadius?: number;
51
+ /** Number of trailing weeks to display. @default 52 */
52
+ weeks?: number;
53
+ }
54
+
55
+ export const GAP = 2;
56
+ export const DAY_LABEL_WIDTH = 28;
57
+ export const MONTH_LABEL_HEIGHT = 16;
58
+ export const DAY_LABELS = ['Mon', 'Wed', 'Fri'] as const;
59
+ export const DAY_LABEL_INDICES = [1, 3, 5] as const;
@@ -0,0 +1,88 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+
3
+ import type { ActivityEntry } from './types';
4
+ import { GAP } from './types';
5
+
6
+ export interface WeekDay {
7
+ date: Date;
8
+ count: number;
9
+ }
10
+
11
+ /**
12
+ * Bucket the supplied entries into a fixed-size grid that ends on the
13
+ * current week and spans `weekCount` weeks. Missing dates fill with 0.
14
+ */
15
+ export function buildWeeks(data: ActivityEntry[], weekCount: number): WeekDay[][] {
16
+ const countMap = new Map<string, number>();
17
+ for (const entry of data) {
18
+ countMap.set(entry.date, (countMap.get(entry.date) ?? 0) + entry.count);
19
+ }
20
+
21
+ const today = new Date();
22
+ today.setHours(0, 0, 0, 0);
23
+ const todayDay = today.getDay();
24
+
25
+ const endOfWeek = new Date(today);
26
+ endOfWeek.setDate(today.getDate() + (6 - todayDay));
27
+
28
+ const totalDays = weekCount * 7;
29
+ const startDate = new Date(endOfWeek);
30
+ startDate.setDate(endOfWeek.getDate() - totalDays + 1);
31
+
32
+ const weeks: WeekDay[][] = [];
33
+ let currentWeek: WeekDay[] = [];
34
+
35
+ for (let i = 0; i < totalDays; i++) {
36
+ const d = new Date(startDate);
37
+ d.setDate(startDate.getDate() + i);
38
+ const key = d.toISOString().slice(0, 10);
39
+ currentWeek.push({ date: d, count: countMap.get(key) ?? 0 });
40
+
41
+ if (currentWeek.length === 7) {
42
+ weeks.push(currentWeek);
43
+ currentWeek = [];
44
+ }
45
+ }
46
+
47
+ if (currentWeek.length > 0) {
48
+ weeks.push(currentWeek);
49
+ }
50
+
51
+ return weeks;
52
+ }
53
+
54
+ /**
55
+ * Find the column offset for the first week of every new month. Used to
56
+ * lay month labels along the top of the grid.
57
+ */
58
+ export function getMonthLabels(
59
+ weeks: WeekDay[][],
60
+ blockSize: number,
61
+ ): { label: string; offset: number }[] {
62
+ const months: { label: string; offset: number }[] = [];
63
+ let lastKey = '';
64
+
65
+ for (let w = 0; w < weeks.length; w++) {
66
+ const firstDay = weeks[w][0];
67
+ const key = `${firstDay.date.getFullYear()}-${firstDay.date.getMonth()}`;
68
+
69
+ if (key !== lastKey) {
70
+ months.push({
71
+ label: firstDay.date.toLocaleString('en-US', { month: 'short' }),
72
+ offset: w * (blockSize + GAP),
73
+ });
74
+ lastKey = key;
75
+ }
76
+ }
77
+
78
+ return months;
79
+ }
80
+
81
+ export function formatDate(date: Date): string {
82
+ return date.toLocaleDateString('en-US', {
83
+ weekday: 'short',
84
+ month: 'short',
85
+ day: 'numeric',
86
+ year: 'numeric',
87
+ });
88
+ }
@@ -0,0 +1,80 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+ //
3
+ // Topological git graph with rail lines showing branch forks, merges, and
4
+ // commit ancestry. Renders the same visual as GitKraken / Fork / Tower.
5
+ //
6
+ // Composer only — heavy lifting lives in:
7
+ // - hooks/useGraphLayout.ts topology pass
8
+ // - hooks/useLaneColors.ts theme-aware categorical palette
9
+ // - components/Rails.tsx SVG rails + dot
10
+ // - components/CommitRow.tsx row body (refs, message, meta)
11
+ // - components/CommitDetail.tsx popover detail
12
+ //
13
+ // Project rules exercised here: semantic tokens for chrome (no raw scales),
14
+ // theme-derived hex colors for SVG strokes (no Tailwind classes inside
15
+ // `stroke=`), no nested overlay providers, attribution header, lazy entry.
16
+
17
+ 'use client';
18
+
19
+ import * as React from 'react';
20
+ import { cn } from '@djangocfg/ui-core/lib';
21
+ import type { CommitGraphProps } from './types';
22
+ import { useGraphLayout } from './hooks/useGraphLayout';
23
+ import { useLaneColors, pickLaneColor } from './hooks/useLaneColors';
24
+ import { CommitRow } from './components/CommitRow';
25
+
26
+ function CommitGraph({
27
+ commits,
28
+ truncateHash = 7,
29
+ railWidth = 24,
30
+ className,
31
+ ...props
32
+ }: CommitGraphProps) {
33
+ const laneColors = useLaneColors();
34
+ const { rows, maxRails } = useGraphLayout(commits, laneColors);
35
+ const svgWidth = maxRails * railWidth;
36
+
37
+ if (rows.length === 0) {
38
+ return (
39
+ <div
40
+ data-slot="commit-graph"
41
+ className={cn(
42
+ 'flex items-center justify-center rounded-xl border border-border/60 bg-card py-10 text-sm text-muted-foreground shadow-sm',
43
+ className,
44
+ )}
45
+ {...props}
46
+ >
47
+ No commits.
48
+ </div>
49
+ );
50
+ }
51
+
52
+ return (
53
+ <div
54
+ data-slot="commit-graph"
55
+ className={cn(
56
+ 'overflow-hidden rounded-xl border border-border/60 bg-card shadow-sm',
57
+ className,
58
+ )}
59
+ style={{ ['--commit-graph-rail-width' as string]: `${svgWidth}px` }}
60
+ {...props}
61
+ >
62
+ <div className="overflow-x-auto">
63
+ {rows.map((row, i) => (
64
+ <CommitRow
65
+ key={`${row.commit.hash}-${i}`}
66
+ row={row}
67
+ prevRow={i > 0 ? rows[i - 1] : null}
68
+ railWidth={railWidth}
69
+ maxRails={maxRails}
70
+ truncateHash={truncateHash}
71
+ laneColors={laneColors}
72
+ railColor={pickLaneColor(laneColors, row.rail)}
73
+ />
74
+ ))}
75
+ </div>
76
+ </div>
77
+ );
78
+ }
79
+
80
+ export { CommitGraph };
@@ -0,0 +1,28 @@
1
+ # CommitGraph
2
+
3
+ Git-style commit rail visualisation. Computes rail topology from `parents` and renders SVG rails + edges. Lane colors come from `useStylePresets()` so every theme preset re-skins consistently.
4
+
5
+ ```tsx
6
+ import { CommitGraph } from '@djangocfg/ui-tools/commit-graph';
7
+
8
+ <CommitGraph
9
+ commits={[
10
+ { hash: 'a1b2c3d', message: 'init', author: { name: 'Mark' }, date: '2025-01-01', parents: [] },
11
+ { hash: 'd4e5f6g', message: 'feat: auth', author: { name: 'Mark' }, date: '2025-01-02', parents: ['a1b2c3d'] },
12
+ ]}
13
+ />
14
+ ```
15
+
16
+ ## Props
17
+
18
+ | Prop | Type | Default | Description |
19
+ |---|---|---|---|
20
+ | `commits` | `Commit[]` | — | Commits in topological order (newest first). Merge = two+ `parents`. |
21
+ | `truncateHash` | `number` | `7` | Number of hash characters to display. |
22
+ | `railWidth` | `number` | `24` | Pixel width per rail column. |
23
+
24
+ Storybook: `apps/storybook/stories/ui-tools/visual/CommitGraph.stories.tsx`
25
+
26
+ ---
27
+
28
+ Adapted from jalcoui (MIT).
@@ -0,0 +1,107 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+
3
+ 'use client';
4
+
5
+ /* eslint-disable @next/next/no-img-element */
6
+
7
+ import * as React from 'react';
8
+ import { Popover, PopoverContent, PopoverTrigger } from '@djangocfg/ui-core';
9
+ import { alpha } from '@djangocfg/ui-core/styles/palette';
10
+ import type { Commit } from '../types';
11
+ import { formatFullDate, initials } from '../utils';
12
+
13
+ interface CommitDetailProps {
14
+ commit: Commit;
15
+ hashLength: number;
16
+ railColor: string;
17
+ children: React.ReactNode;
18
+ }
19
+
20
+ /**
21
+ * Popover with the full commit message, refs, tag and parent hashes. The
22
+ * trigger is the row button — the parent component owns the row markup and
23
+ * passes it through `children`.
24
+ *
25
+ * Requires the host app to mount `<UiProviders>` at the root (we do not
26
+ * remount a Popover provider here — see CONTRACT §5).
27
+ */
28
+ export function CommitDetail({
29
+ commit,
30
+ hashLength,
31
+ railColor,
32
+ children,
33
+ }: CommitDetailProps) {
34
+ // Pre-compute style strings outside JSX (per project rule: hoist derived
35
+ // values into named consts before `return (...)`).
36
+ const tagStyle = {
37
+ backgroundColor: alpha(railColor, 0.125),
38
+ color: railColor,
39
+ };
40
+ const initialsLabel = initials(commit.author.name);
41
+
42
+ return (
43
+ <Popover>
44
+ <PopoverTrigger asChild>{children}</PopoverTrigger>
45
+ <PopoverContent side="right" sideOffset={8} className="w-80 p-3">
46
+ <div className="flex flex-col gap-2">
47
+ <p className="text-sm font-medium leading-snug">{commit.message}</p>
48
+
49
+ <div className="flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
50
+ <span className="inline-flex items-center gap-1.5">
51
+ {commit.author.avatarUrl ? (
52
+ <img
53
+ src={commit.author.avatarUrl}
54
+ alt=""
55
+ width={14}
56
+ height={14}
57
+ className="size-3.5 rounded-full border border-border/60 bg-muted"
58
+ />
59
+ ) : (
60
+ <span className="flex size-3.5 items-center justify-center rounded-full bg-muted text-[7px] font-bold">
61
+ {initialsLabel}
62
+ </span>
63
+ )}
64
+ {commit.author.name}
65
+ </span>
66
+ <span className="text-border">·</span>
67
+ <code className="rounded bg-muted px-1 py-0.5 font-mono text-[10px]">
68
+ {commit.hash.slice(0, hashLength)}
69
+ </code>
70
+ </div>
71
+
72
+ <div className="text-[11px] text-muted-foreground">
73
+ {formatFullDate(commit.date)}
74
+ </div>
75
+
76
+ {(commit.refs || commit.tag) && (
77
+ <div className="flex flex-wrap gap-1">
78
+ {commit.refs?.map((ref) => (
79
+ <span
80
+ key={ref}
81
+ className="inline-flex items-center gap-1 rounded-md border border-border/60 bg-muted/50 px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground"
82
+ >
83
+ {ref}
84
+ </span>
85
+ ))}
86
+ {commit.tag && (
87
+ <span
88
+ className="inline-flex items-center rounded-md px-1.5 py-0.5 text-[10px] font-medium"
89
+ style={tagStyle}
90
+ >
91
+ {commit.tag}
92
+ </span>
93
+ )}
94
+ </div>
95
+ )}
96
+
97
+ {commit.parents.length > 0 && (
98
+ <div className="text-[10px] text-muted-foreground/60">
99
+ {commit.parents.length === 1 ? 'Parent' : 'Parents'}:{' '}
100
+ {commit.parents.map((p) => p.slice(0, hashLength)).join(', ')}
101
+ </div>
102
+ )}
103
+ </div>
104
+ </PopoverContent>
105
+ </Popover>
106
+ );
107
+ }