@djangocfg/ui-tools 2.1.417 → 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.
- package/dist/audio-player/index.cjs +1 -2
- package/dist/audio-player/index.cjs.map +1 -1
- package/dist/audio-player/index.d.cts +3 -11
- package/dist/audio-player/index.d.ts +3 -11
- package/dist/audio-player/index.mjs +1 -2
- package/dist/audio-player/index.mjs.map +1 -1
- package/dist/file-icon/index.cjs +3 -3
- package/dist/file-icon/index.cjs.map +1 -1
- package/dist/file-icon/index.mjs +3 -3
- package/dist/file-icon/index.mjs.map +1 -1
- package/dist/tree/index.cjs +0 -3
- package/dist/tree/index.cjs.map +1 -1
- package/dist/tree/index.mjs +0 -3
- package/dist/tree/index.mjs.map +1 -1
- package/package.json +117 -36
- package/src/common/FloatingToolbar/actions/CopyAction.tsx +31 -0
- package/src/{components → common}/FloatingToolbar/actions/DownloadAction.tsx +15 -10
- package/src/common/FloatingToolbar/actions/ExpandAction.tsx +33 -0
- package/src/common/FloatingToolbar/actions/FullscreenAction.tsx +38 -0
- package/src/{components → common}/FloatingToolbar/index.tsx +39 -0
- package/src/lib/http.ts +64 -0
- package/src/tools/chat/index.ts +1 -1
- package/src/tools/chat/launcher/ChatFAB.tsx +66 -74
- package/src/tools/chat/launcher/header/ChatHeaderActionButton.tsx +2 -3
- package/src/tools/chat/lazy.tsx +1 -1
- package/src/tools/chat/messages/MessageBubble.tsx +1 -1
- package/src/tools/chat/messages/blocks/builtin.tsx +1 -1
- package/src/tools/chat/messages/blocks/renderers/CodeBlock.tsx +2 -2
- package/src/tools/chat/messages/blocks/renderers/JsonBlock.tsx +12 -1
- package/src/tools/data/DataGrid/lazy.tsx +1 -1
- package/src/tools/data/DataTable/lazy.tsx +1 -1
- package/src/tools/data/JsonTree/JsonViewer.tsx +720 -0
- package/src/tools/data/JsonTree/README.md +126 -73
- package/src/tools/data/JsonTree/index.tsx +3 -95
- package/src/tools/data/JsonTree/lazy.tsx +10 -50
- package/src/tools/data/JsonTree/types.ts +82 -63
- package/src/tools/data/Kanban/lazy.tsx +1 -1
- package/src/tools/data/Listbox/lazy.tsx +1 -1
- package/src/tools/data/Masonry/lazy.tsx +1 -1
- package/src/tools/data/Timeline/lazy.tsx +1 -1
- package/src/tools/data/Tree/components/TreeRow.tsx +0 -11
- package/src/tools/data/Tree/lazy.tsx +1 -1
- package/src/tools/dev/Map/lazy.tsx +1 -1
- package/src/tools/dev/Mermaid/Mermaid.client.tsx +2 -2
- package/src/tools/dev/Mermaid/lazy.tsx +1 -1
- package/src/tools/dev/api/ApiRefTable/ApiRefTable.tsx +65 -0
- package/src/tools/dev/api/ApiRefTable/README.md +31 -0
- package/src/tools/dev/api/ApiRefTable/components/Row.tsx +96 -0
- package/src/tools/dev/api/ApiRefTable/components/TypeDisplay.tsx +44 -0
- package/src/tools/dev/api/ApiRefTable/index.ts +6 -0
- package/src/tools/dev/api/ApiRefTable/lazy.tsx +21 -0
- package/src/tools/dev/api/ApiRefTable/types.ts +82 -0
- package/src/tools/dev/api/ApiRefTable/utils.ts +42 -0
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/ApiIntroSection.tsx +1 -1
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/CodeSamples/index.tsx +1 -1
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/index.tsx +1 -1
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/ResponseBody.tsx +7 -21
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/RequestPanel.tsx +1 -1
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/PrettyView.tsx +13 -19
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/types.ts +1 -1
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/lazy.tsx +1 -1
- package/src/tools/dev/api/RequestViewer/README.md +33 -0
- package/src/tools/dev/api/RequestViewer/RequestViewer.tsx +121 -0
- package/src/tools/dev/api/RequestViewer/components/BodyTab.tsx +44 -0
- package/src/tools/dev/api/RequestViewer/components/EmptyState.tsx +13 -0
- package/src/tools/dev/api/RequestViewer/components/HeadersTab.tsx +78 -0
- package/src/tools/dev/api/RequestViewer/components/TimingTab.tsx +113 -0
- package/src/tools/dev/api/RequestViewer/components/utils.ts +31 -0
- package/src/tools/dev/api/RequestViewer/index.ts +16 -0
- package/src/tools/dev/api/RequestViewer/lazy.tsx +30 -0
- package/src/tools/dev/api/RequestViewer/types.ts +81 -0
- package/src/tools/dev/code/DiffViewer/DiffViewer.tsx +144 -0
- package/src/tools/dev/code/DiffViewer/README.md +33 -0
- package/src/tools/dev/code/DiffViewer/components/CopyButton.tsx +49 -0
- package/src/tools/dev/code/DiffViewer/components/DiffLineContent.tsx +48 -0
- package/src/tools/dev/code/DiffViewer/components/SplitView.tsx +220 -0
- package/src/tools/dev/code/DiffViewer/components/UnifiedView.tsx +154 -0
- package/src/tools/dev/code/DiffViewer/hooks/useDiff.ts +47 -0
- package/src/tools/dev/code/DiffViewer/hooks/useHighlighter.ts +54 -0
- package/src/tools/dev/code/DiffViewer/index.ts +22 -0
- package/src/tools/dev/code/DiffViewer/lazy.tsx +22 -0
- package/src/tools/dev/code/DiffViewer/types.ts +109 -0
- package/src/tools/dev/code/DiffViewer/utils/computeDiff.ts +159 -0
- package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/CollapseToggle.tsx +1 -1
- package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/MarkdownMessage.tsx +1 -1
- package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/components.tsx +2 -2
- package/src/tools/dev/{PrettyCode → code/PrettyCode}/PrettyCode.client.tsx +2 -2
- package/src/tools/dev/{PrettyCode → code/PrettyCode}/lazy.tsx +1 -1
- package/src/tools/dev/ops/EnvTable/EnvTable.tsx +228 -0
- package/src/tools/dev/ops/EnvTable/README.md +29 -0
- package/src/tools/dev/ops/EnvTable/hooks/useEnvMask.ts +121 -0
- package/src/tools/dev/ops/EnvTable/index.ts +12 -0
- package/src/tools/dev/ops/EnvTable/lazy.tsx +21 -0
- package/src/tools/dev/ops/EnvTable/types.ts +76 -0
- package/src/tools/dev/ops/LogViewer/LogViewer.tsx +194 -0
- package/src/tools/dev/ops/LogViewer/README.md +30 -0
- package/src/tools/dev/ops/LogViewer/components/LogRow.tsx +151 -0
- package/src/tools/dev/ops/LogViewer/components/Toolbar.tsx +199 -0
- package/src/tools/dev/ops/LogViewer/hooks/useAutoScroll.ts +68 -0
- package/src/tools/dev/ops/LogViewer/hooks/useLogFilter.ts +58 -0
- package/src/tools/dev/ops/LogViewer/index.ts +18 -0
- package/src/tools/dev/ops/LogViewer/lazy.tsx +25 -0
- package/src/tools/dev/ops/LogViewer/types.ts +142 -0
- package/src/tools/dev/ops/LogViewer/utils/ansi.ts +231 -0
- package/src/tools/forms/CodeEditor/components/Editor.tsx +19 -0
- package/src/tools/forms/CodeEditor/hooks/useEditorTheme.ts +13 -73
- package/src/tools/forms/CodeEditor/lazy.tsx +1 -1
- package/src/tools/forms/CodeEditor/types/index.ts +7 -0
- package/src/tools/forms/FileUpload/lazy.tsx +1 -1
- package/src/tools/forms/JsonEditor/JsonEditor.tsx +115 -0
- package/src/tools/forms/JsonEditor/index.ts +1 -0
- package/src/tools/forms/JsonEditor/lazy.tsx +24 -0
- package/src/tools/forms/JsonForm/index.ts +1 -1
- package/src/tools/forms/JsonForm/lazy.tsx +1 -1
- package/src/tools/forms/MarkdownEditor/MarkdownEditor.tsx +40 -0
- package/src/tools/forms/MarkdownEditor/lazy.tsx +1 -1
- package/src/tools/forms/MarkdownEditor/styles.css +174 -21
- package/src/tools/forms/NotionEditor/CustomKeymap.ts +48 -0
- package/src/tools/forms/NotionEditor/LinkDialog.tsx +133 -0
- package/src/tools/forms/NotionEditor/NotionEditor.tsx +304 -0
- package/src/tools/forms/NotionEditor/README.md +237 -0
- package/src/tools/forms/NotionEditor/SlashExtension.ts +32 -0
- package/src/tools/forms/NotionEditor/SlashList.tsx +136 -0
- package/src/tools/forms/NotionEditor/TaskItemView.tsx +41 -0
- package/src/tools/forms/NotionEditor/createSlashSuggestion.ts +121 -0
- package/src/tools/forms/NotionEditor/extensions.ts +105 -0
- package/src/tools/forms/NotionEditor/index.ts +1 -0
- package/src/tools/forms/NotionEditor/lazy.tsx +44 -0
- package/src/tools/forms/NotionEditor/slashItems.ts +159 -0
- package/src/tools/forms/NotionEditor/styles.css +478 -0
- package/src/tools/forms/NotionEditor/types.ts +28 -0
- package/src/tools/index.ts +153 -13
- package/src/tools/input/Combobox/lazy.tsx +1 -1
- package/src/tools/input/CronScheduler/components/CronPreview.README.md +28 -0
- package/src/tools/input/CronScheduler/components/CronPreview.tsx +136 -0
- package/src/tools/input/CronScheduler/components/index.ts +3 -0
- package/src/tools/input/CronScheduler/index.tsx +5 -1
- package/src/tools/input/CronScheduler/lazy.tsx +5 -1
- package/src/tools/input/CronScheduler/utils/cron-next-runs.ts +122 -0
- package/src/tools/input/CronScheduler/utils/index.ts +1 -0
- package/src/tools/input/Scroller/lazy.tsx +1 -1
- package/src/tools/input/Sortable/lazy.tsx +1 -1
- package/src/tools/input/SpeechRecognition/lazy.tsx +1 -1
- package/src/tools/input/SpeechRecognition/widgets/VoiceComposerSlot.tsx +41 -36
- package/src/tools/media/AudioPlayer/PlayerShell.tsx +3 -11
- package/src/tools/media/AudioPlayer/types.ts +4 -11
- package/src/tools/media/ImageViewer/components/ImageToolbar.tsx +58 -47
- package/src/tools/media/ImageViewer/components/ImageViewer.tsx +35 -19
- package/src/tools/media/ImageViewer/lazy.tsx +1 -1
- package/src/tools/media/ImageViewer/types.ts +4 -0
- package/src/tools/media/LottiePlayer/lazy.tsx +1 -1
- package/src/tools/media/VideoPlayer/VideoPlayer.tsx +47 -1
- package/src/tools/media/VideoPlayer/parts/fullscreen.tsx +21 -4
- package/src/tools/media/VideoPlayer/parts/pip.tsx +21 -4
- package/src/tools/media/VideoPlayer/parts/play-button.tsx +21 -4
- package/src/tools/media/VideoPlayer/parts/playback-rate.tsx +19 -3
- package/src/tools/media/VideoPlayer/parts/volume.tsx +237 -18
- package/src/tools/media/VideoPlayer/styles/video-player.css +87 -7
- package/src/tools/media/VideoPlayer/types.ts +4 -0
- package/src/tools/overlay/ResponsiveDialog/lazy.tsx +1 -1
- package/src/tools/overlay/ScrollSpy/lazy.tsx +1 -1
- package/src/tools/overlay/SelectionToolbar/lazy.tsx +1 -1
- package/src/tools/overlay/Tour/lazy.tsx +1 -1
- package/src/tools/visual/Marquee/lazy.tsx +1 -1
- package/src/tools/visual/QRCode/lazy.tsx +1 -1
- package/src/tools/visual/charts/ActivityGraph/ActivityGraph.tsx +195 -0
- package/src/tools/visual/charts/ActivityGraph/README.md +28 -0
- package/src/tools/visual/charts/ActivityGraph/index.ts +8 -0
- package/src/tools/visual/charts/ActivityGraph/lazy.tsx +21 -0
- package/src/tools/visual/charts/ActivityGraph/types.ts +59 -0
- package/src/tools/visual/charts/ActivityGraph/utils.ts +88 -0
- package/src/tools/visual/charts/CommitGraph/CommitGraph.tsx +80 -0
- package/src/tools/visual/charts/CommitGraph/README.md +28 -0
- package/src/tools/visual/charts/CommitGraph/components/CommitDetail.tsx +107 -0
- package/src/tools/visual/charts/CommitGraph/components/CommitRow.tsx +122 -0
- package/src/tools/visual/charts/CommitGraph/components/Rails.tsx +171 -0
- package/src/tools/visual/charts/CommitGraph/hooks/useGraphLayout.ts +169 -0
- package/src/tools/visual/charts/CommitGraph/hooks/useLaneColors.ts +45 -0
- package/src/tools/visual/charts/CommitGraph/index.ts +14 -0
- package/src/tools/visual/charts/CommitGraph/lazy.tsx +25 -0
- package/src/tools/visual/charts/CommitGraph/types.ts +85 -0
- package/src/tools/visual/charts/CommitGraph/utils.ts +53 -0
- package/src/tools/visual/{Gauge → charts/Gauge}/lazy.tsx +1 -1
- package/src/tools/visual/charts/Sparkline/README.md +29 -0
- package/src/tools/visual/charts/Sparkline/Sparkline.tsx +217 -0
- package/src/tools/visual/charts/Sparkline/index.ts +9 -0
- package/src/tools/visual/charts/Sparkline/lazy.tsx +26 -0
- package/src/tools/visual/charts/Sparkline/types.ts +58 -0
- package/src/tools/visual/design/ColorPalette/ColorPalette.tsx +129 -0
- package/src/tools/visual/design/ColorPalette/README.md +34 -0
- package/src/tools/visual/design/ColorPalette/components/Swatch.tsx +102 -0
- package/src/tools/visual/design/ColorPalette/hooks/useCopyToClipboard.ts +41 -0
- package/src/tools/visual/design/ColorPalette/index.ts +12 -0
- package/src/tools/visual/design/ColorPalette/lazy.tsx +21 -0
- package/src/tools/visual/design/ColorPalette/types.ts +63 -0
- package/src/tools/visual/design/ColorPalette/utils.ts +83 -0
- package/src/tools/visual/{ColorPicker → design/ColorPicker}/lazy.tsx +1 -1
- package/src/tools/visual/{FileIcon → design/FileIcon}/treeAdapter.tsx +1 -1
- package/src/tools/visual/{Fps → indicators/Fps}/lazy.tsx +1 -1
- package/src/tools/visual/{Rating → indicators/Rating}/lazy.tsx +1 -1
- package/src/tools/visual/indicators/StatusIndicator/README.md +28 -0
- package/src/tools/visual/indicators/StatusIndicator/StatusIndicator.tsx +83 -0
- package/src/tools/visual/indicators/StatusIndicator/index.ts +14 -0
- package/src/tools/visual/indicators/StatusIndicator/lazy.tsx +21 -0
- package/src/tools/visual/indicators/StatusIndicator/types.ts +133 -0
- package/src/components/FloatingToolbar/actions/CopyAction.tsx +0 -22
- package/src/components/FloatingToolbar/actions/ExpandAction.tsx +0 -25
- package/src/components/FloatingToolbar/actions/FullscreenAction.tsx +0 -30
- package/src/tools/data/JsonTree/components/JsonContent.tsx +0 -197
- package/src/tools/data/JsonTree/hooks/useJsonExpand.ts +0 -50
- /package/src/{components → common}/FloatingToolbar/FloatingToolbar.css +0 -0
- /package/src/{components → common}/FloatingToolbar/actions/index.ts +0 -0
- /package/src/{components → common}/FloatingToolbar/hooks/useElementCorner.ts +0 -0
- /package/src/{components → common}/FloatingToolbar/hooks/useScrollIsolation.ts +0 -0
- /package/src/{components → common}/index.ts +0 -0
- /package/src/{components → common}/lazy-wrapper.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/README.md +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/DocsView.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/CodeSamples/LanguageTabs.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/CodeSamples/useCodeSnippet.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/MetaActions.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/MethodBadge.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/PathDisplay.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Parameters/ParamGroup.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Parameters/ParamRow.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Parameters/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/RequestBody/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/ResponseRow.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/StatusTag.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/FieldRow.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/buildTree.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/types.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Section/SectionHeader.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Section/defaults.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Section/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/context.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/hooks/useSectionHash.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/store/index.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/store/selectors.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/types.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/SchemaCopyMenu.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/BrandHeader.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/CategoryBlock.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/EndpointRow.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/SchemaSection.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/SearchInput.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/SidebarBody.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/Toolbar.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/buildVM.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/types.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/useDebouncedValue.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/SlideInPlayground.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/TryItSheet.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/anchor.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/grouping.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/sidebarLabel.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/index.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/BodyFormEditor.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/EndpointDraftSync.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/EndpointResetButton.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/PreviewView.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/RawView.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/StatusBar.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/ViewTabs.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/detectContent.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/useResponseView.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/SendButton.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ui.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/constants.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/context/PlaygroundContext.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/index.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useDocsUrlSync.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useEndpointDraft.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useMobile.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useOpenApiSchema.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/types.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/apiKeyManager.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/codeSamples.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/formatters.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/index.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/operationToHar.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/sampler.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/schemaExport.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/scrollParent.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/url.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/versionManager.ts +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/ActionRow.tsx +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/ChatMessageRow.tsx +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/CodeBlock.tsx +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/README.md +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/index.ts +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/linkRules.ts +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/plainText.ts +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/sanitize.ts +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/types.ts +0 -0
- /package/src/tools/dev/{PrettyCode → code/PrettyCode}/README.md +0 -0
- /package/src/tools/dev/{PrettyCode → code/PrettyCode}/index.tsx +0 -0
- /package/src/tools/dev/{PrettyCode → code/PrettyCode}/registerPrismLanguages.ts +0 -0
- /package/src/tools/visual/{Gauge → charts/Gauge}/Gauge.tsx +0 -0
- /package/src/tools/visual/{Gauge → charts/Gauge}/index.ts +0 -0
- /package/src/tools/visual/{Gauge → charts/Gauge}/types.ts +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/ColorPicker.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/context/ColorPickerContext.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/context/ColorPickerStore.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/context/index.ts +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/index.ts +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/lib/color-utils.ts +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerAlphaSlider.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerArea.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerEyeDropper.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerFormatSelect.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerHueSlider.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerInput.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerSwatch.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/index.ts +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/types.ts +0 -0
- /package/src/tools/visual/{FileIcon → design/FileIcon}/FileIcon.tsx +0 -0
- /package/src/tools/visual/{FileIcon → design/FileIcon}/get-file-icon.ts +0 -0
- /package/src/tools/visual/{FileIcon → design/FileIcon}/icons/icon-data.ts +0 -0
- /package/src/tools/visual/{FileIcon → design/FileIcon}/index.ts +0 -0
- /package/src/tools/visual/{FileIcon → design/FileIcon}/loader.ts +0 -0
- /package/src/tools/visual/{FileIcon → design/FileIcon}/specialFolders.ts +0 -0
- /package/src/tools/visual/{Fps → indicators/Fps}/Fps.tsx +0 -0
- /package/src/tools/visual/{Fps → indicators/Fps}/index.ts +0 -0
- /package/src/tools/visual/{Fps → indicators/Fps}/types.ts +0 -0
- /package/src/tools/visual/{Rating → indicators/Rating}/Rating.tsx +0 -0
- /package/src/tools/visual/{Rating → indicators/Rating}/index.ts +0 -0
- /package/src/tools/visual/{Rating → indicators/Rating}/types.ts +0 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// Adapted from jalcoui (MIT) — github.com/jal-co/ui
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
import { useMemo } from 'react';
|
|
6
|
+
import type { Commit, Edge, GraphRow } from '../types';
|
|
7
|
+
import { pickLaneColor } from './useLaneColors';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Topological layout pass for the commit graph.
|
|
11
|
+
*
|
|
12
|
+
* Walks the commit list in order (newest first) and tracks active rails —
|
|
13
|
+
* each slot holds the hash of the parent the rail is "waiting for". The
|
|
14
|
+
* algorithm produces:
|
|
15
|
+
*
|
|
16
|
+
* - The rail a commit's dot occupies.
|
|
17
|
+
* - The rails state after the row (for the next iteration).
|
|
18
|
+
* - Edges to draw on this row (pass-throughs, merge curves, fork curves).
|
|
19
|
+
*
|
|
20
|
+
* Rail colors are looked up at layout time so the rendered SVG can use raw
|
|
21
|
+
* hex `stroke=` values — Canvas2D/SVG won't parse Tailwind classes.
|
|
22
|
+
*/
|
|
23
|
+
function computeLayout(commits: Commit[], laneColors: string[]): GraphRow[] {
|
|
24
|
+
const rows: GraphRow[] = [];
|
|
25
|
+
const rails: (string | null)[] = [];
|
|
26
|
+
const color = (rail: number) => pickLaneColor(laneColors, rail);
|
|
27
|
+
|
|
28
|
+
for (const commit of commits) {
|
|
29
|
+
const hash = commit.hash;
|
|
30
|
+
|
|
31
|
+
// Find which rail this commit occupies (if any rail is waiting for it).
|
|
32
|
+
let commitRail = rails.indexOf(hash);
|
|
33
|
+
|
|
34
|
+
if (commitRail === -1) {
|
|
35
|
+
// New branch — find first empty slot or append.
|
|
36
|
+
const emptySlot = rails.indexOf(null);
|
|
37
|
+
if (emptySlot !== -1) {
|
|
38
|
+
commitRail = emptySlot;
|
|
39
|
+
rails[commitRail] = hash;
|
|
40
|
+
} else {
|
|
41
|
+
commitRail = rails.length;
|
|
42
|
+
rails.push(hash);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const commitColor = color(commitRail);
|
|
47
|
+
const edges: Edge[] = [];
|
|
48
|
+
|
|
49
|
+
// Pass-through rails (everything not on the commit rail).
|
|
50
|
+
for (let r = 0; r < rails.length; r++) {
|
|
51
|
+
if (r !== commitRail && rails[r] !== null) {
|
|
52
|
+
edges.push({ fromRail: r, toRail: r, color: color(r), type: 'straight' });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Clear this rail — the commit has been rendered.
|
|
57
|
+
rails[commitRail] = null;
|
|
58
|
+
|
|
59
|
+
// First parent continues on the commit's rail unless already expected
|
|
60
|
+
// elsewhere (merge of two existing branches).
|
|
61
|
+
const parents = commit.parents;
|
|
62
|
+
if (parents.length >= 1) {
|
|
63
|
+
const firstParent = parents[0];
|
|
64
|
+
const existingRail = rails.indexOf(firstParent);
|
|
65
|
+
if (existingRail !== -1) {
|
|
66
|
+
edges.push({
|
|
67
|
+
fromRail: commitRail,
|
|
68
|
+
toRail: existingRail,
|
|
69
|
+
color: commitColor,
|
|
70
|
+
type: 'merge-in',
|
|
71
|
+
});
|
|
72
|
+
} else {
|
|
73
|
+
rails[commitRail] = firstParent;
|
|
74
|
+
edges.push({
|
|
75
|
+
fromRail: commitRail,
|
|
76
|
+
toRail: commitRail,
|
|
77
|
+
color: commitColor,
|
|
78
|
+
type: 'straight',
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Second+ parents (merge sources / forks).
|
|
84
|
+
for (let p = 1; p < parents.length; p++) {
|
|
85
|
+
const parentHash = parents[p];
|
|
86
|
+
const existingRail = rails.indexOf(parentHash);
|
|
87
|
+
if (existingRail !== -1) {
|
|
88
|
+
edges.push({
|
|
89
|
+
fromRail: existingRail,
|
|
90
|
+
toRail: commitRail,
|
|
91
|
+
color: color(existingRail),
|
|
92
|
+
type: 'merge-in',
|
|
93
|
+
});
|
|
94
|
+
} else {
|
|
95
|
+
const emptySlot = rails.indexOf(null);
|
|
96
|
+
const newRail = emptySlot !== -1 ? emptySlot : rails.length;
|
|
97
|
+
if (newRail >= rails.length) rails.push(null);
|
|
98
|
+
rails[newRail] = parentHash;
|
|
99
|
+
edges.push({
|
|
100
|
+
fromRail: commitRail,
|
|
101
|
+
toRail: newRail,
|
|
102
|
+
color: color(newRail),
|
|
103
|
+
type: 'fork-out',
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Trim trailing nulls so `maxRails` stays accurate.
|
|
109
|
+
while (rails.length > 0 && rails[rails.length - 1] === null) {
|
|
110
|
+
rails.pop();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
rows.push({
|
|
114
|
+
commit,
|
|
115
|
+
rail: commitRail,
|
|
116
|
+
rails: [...rails],
|
|
117
|
+
edges,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return rows;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Auto-infer a linear topology when no commit declares parents — the
|
|
126
|
+
* jalcoui examples ship a flat list and rely on the component to chain
|
|
127
|
+
* them.
|
|
128
|
+
*/
|
|
129
|
+
function ensureTopology(commits: Commit[]): Commit[] {
|
|
130
|
+
const hasTopology = commits.some((c) => c.parents && c.parents.length > 0);
|
|
131
|
+
if (hasTopology) return commits;
|
|
132
|
+
return commits.map((c, i) => ({
|
|
133
|
+
...c,
|
|
134
|
+
parents: i < commits.length - 1 ? [commits[i + 1].hash] : [],
|
|
135
|
+
}));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface GraphLayout {
|
|
139
|
+
rows: GraphRow[];
|
|
140
|
+
maxRails: number;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* React-friendly wrapper around {@link computeLayout}. Memoizes on
|
|
145
|
+
* `commits` + `laneColors` identity so theme switches re-color but do not
|
|
146
|
+
* reshuffle topology.
|
|
147
|
+
*/
|
|
148
|
+
export function useGraphLayout(
|
|
149
|
+
commits: Commit[],
|
|
150
|
+
laneColors: string[],
|
|
151
|
+
): GraphLayout {
|
|
152
|
+
return useMemo(() => {
|
|
153
|
+
const resolved = ensureTopology(commits);
|
|
154
|
+
if (resolved.length === 0) {
|
|
155
|
+
return { rows: [], maxRails: 0 };
|
|
156
|
+
}
|
|
157
|
+
const rows = computeLayout(resolved, laneColors);
|
|
158
|
+
const maxRails = Math.max(
|
|
159
|
+
...rows.map((r) =>
|
|
160
|
+
Math.max(
|
|
161
|
+
r.rail + 1,
|
|
162
|
+
r.rails.length,
|
|
163
|
+
...r.edges.map((e) => Math.max(e.fromRail, e.toRail) + 1),
|
|
164
|
+
),
|
|
165
|
+
),
|
|
166
|
+
);
|
|
167
|
+
return { rows, maxRails };
|
|
168
|
+
}, [commits, laneColors]);
|
|
169
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Adapted from jalcoui (MIT) — github.com/jal-co/ui
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
import { useMemo } from 'react';
|
|
6
|
+
import { useStylePresets } from '@djangocfg/ui-core/styles/palette';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Hook returning the categorical lane palette as an array of hex strings.
|
|
10
|
+
*
|
|
11
|
+
* jalcoui hard-codes 8 raw colors (`#3b82f6`, `#22c55e`, …) — that would
|
|
12
|
+
* break every non-default theme preset. We instead derive the palette from
|
|
13
|
+
* {@link useStylePresets}: 8 distinguishable categorical fills that already
|
|
14
|
+
* respect the active theme. Branches beyond index 7 cycle modulo the
|
|
15
|
+
* palette length.
|
|
16
|
+
*
|
|
17
|
+
* Order is chosen for maximum perceptual distance between adjacent rails:
|
|
18
|
+
* primary → success → warning → danger → info → chart3 → chart4 → chart5.
|
|
19
|
+
*/
|
|
20
|
+
export function useLaneColors(): string[] {
|
|
21
|
+
const presets = useStylePresets();
|
|
22
|
+
|
|
23
|
+
return useMemo(
|
|
24
|
+
() => [
|
|
25
|
+
presets.primary.fill,
|
|
26
|
+
presets.success.fill,
|
|
27
|
+
presets.warning.fill,
|
|
28
|
+
presets.danger.fill,
|
|
29
|
+
presets.info.fill,
|
|
30
|
+
presets.chart3.fill,
|
|
31
|
+
presets.chart4.fill,
|
|
32
|
+
presets.chart5.fill,
|
|
33
|
+
],
|
|
34
|
+
[presets],
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Pick the color for a rail index, cycling when there are more rails than
|
|
40
|
+
* palette entries.
|
|
41
|
+
*/
|
|
42
|
+
export function pickLaneColor(colors: string[], rail: number): string {
|
|
43
|
+
if (colors.length === 0) return '#000000';
|
|
44
|
+
return colors[((rail % colors.length) + colors.length) % colors.length];
|
|
45
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Adapted from jalcoui (MIT) — github.com/jal-co/ui
|
|
2
|
+
|
|
3
|
+
export { CommitGraph } from './CommitGraph';
|
|
4
|
+
export { useLaneColors, pickLaneColor } from './hooks/useLaneColors';
|
|
5
|
+
export { useGraphLayout } from './hooks/useGraphLayout';
|
|
6
|
+
export { ROW_HEIGHT } from './types';
|
|
7
|
+
export type {
|
|
8
|
+
Commit,
|
|
9
|
+
CommitAuthor,
|
|
10
|
+
CommitGraphProps,
|
|
11
|
+
Edge,
|
|
12
|
+
EdgeType,
|
|
13
|
+
GraphRow,
|
|
14
|
+
} from './types';
|
|
@@ -0,0 +1,25 @@
|
|
|
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 { CommitGraphProps } from './types';
|
|
7
|
+
|
|
8
|
+
export const LazyCommitGraph = createLazyComponent<CommitGraphProps>(
|
|
9
|
+
() => import('./CommitGraph').then((mod) => ({ default: mod.CommitGraph })),
|
|
10
|
+
{
|
|
11
|
+
displayName: 'LazyCommitGraph',
|
|
12
|
+
fallback: (
|
|
13
|
+
<div
|
|
14
|
+
data-slot="commit-graph-skeleton"
|
|
15
|
+
className="h-40 w-full animate-pulse rounded-xl bg-muted"
|
|
16
|
+
/>
|
|
17
|
+
),
|
|
18
|
+
},
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
export type {
|
|
22
|
+
CommitGraphProps,
|
|
23
|
+
Commit,
|
|
24
|
+
CommitAuthor,
|
|
25
|
+
} from './types';
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Adapted from jalcoui (MIT) — github.com/jal-co/ui
|
|
2
|
+
|
|
3
|
+
import type * as React from 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Author metadata rendered next to each commit row and inside the detail
|
|
7
|
+
* popover. Avatar URLs are optional — when omitted, the initials of
|
|
8
|
+
* {@link CommitAuthor.name} are shown instead.
|
|
9
|
+
*/
|
|
10
|
+
export interface CommitAuthor {
|
|
11
|
+
name: string;
|
|
12
|
+
avatarUrl?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Single commit node fed into {@link CommitGraph}. Commits must be passed in
|
|
17
|
+
* topological order (newest first). The `parents` array drives the rail
|
|
18
|
+
* topology — empty for root commits, one entry for normal commits, two or
|
|
19
|
+
* more for merges.
|
|
20
|
+
*/
|
|
21
|
+
export interface Commit {
|
|
22
|
+
/** Commit hash (full or abbreviated). */
|
|
23
|
+
hash: string;
|
|
24
|
+
/** Commit message (first line). */
|
|
25
|
+
message: string;
|
|
26
|
+
/** Commit author. */
|
|
27
|
+
author: CommitAuthor;
|
|
28
|
+
/** ISO date string or Date object. */
|
|
29
|
+
date: string | Date;
|
|
30
|
+
/** Parent commit hashes. Empty for root commits. Two parents = merge commit. */
|
|
31
|
+
parents: string[];
|
|
32
|
+
/** Branch or ref labels (e.g. `"main"`, `"feat/auth"`). */
|
|
33
|
+
refs?: string[];
|
|
34
|
+
/** Tag label (e.g. `"v1.0.0"`). */
|
|
35
|
+
tag?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Props for {@link CommitGraph}.
|
|
40
|
+
*/
|
|
41
|
+
export interface CommitGraphProps
|
|
42
|
+
extends Omit<React.ComponentProps<'div'>, 'children'> {
|
|
43
|
+
/** Commits in topological order (newest first). */
|
|
44
|
+
commits: Commit[];
|
|
45
|
+
/** Number of hash characters to display. @default 7 */
|
|
46
|
+
truncateHash?: number;
|
|
47
|
+
/** Pixel width per rail column. @default 24 */
|
|
48
|
+
railWidth?: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Type of edge a rail segment renders inside a row. The layout pass tags
|
|
53
|
+
* every drawn segment with one of these — the SVG renderer only needs to
|
|
54
|
+
* pick the geometry per type.
|
|
55
|
+
*/
|
|
56
|
+
export type EdgeType = 'straight' | 'merge-in' | 'fork-out';
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* A single edge inside a {@link GraphRow}. Indices refer to rail slots
|
|
60
|
+
* (left-to-right) and `color` is a hex string already resolved through the
|
|
61
|
+
* theme palette — never a raw scale.
|
|
62
|
+
*/
|
|
63
|
+
export interface Edge {
|
|
64
|
+
fromRail: number;
|
|
65
|
+
toRail: number;
|
|
66
|
+
color: string;
|
|
67
|
+
type: EdgeType;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Output of {@link computeLayout}. One row per commit, with the rail
|
|
72
|
+
* topology snapshot needed to draw rails + edges.
|
|
73
|
+
*/
|
|
74
|
+
export interface GraphRow {
|
|
75
|
+
commit: Commit;
|
|
76
|
+
/** Rail index this commit's dot occupies. */
|
|
77
|
+
rail: number;
|
|
78
|
+
/** Rails state after this row (`null` = empty slot). */
|
|
79
|
+
rails: (string | null)[];
|
|
80
|
+
/** Edges to draw between the previous row and this row. */
|
|
81
|
+
edges: Edge[];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Pixel height of a single commit row. */
|
|
85
|
+
export const ROW_HEIGHT = 40;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Adapted from jalcoui (MIT) — github.com/jal-co/ui
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Author initials fallback for the avatar slot. Returns up to 2 uppercase
|
|
5
|
+
* characters drawn from the first letter of each whitespace-separated word.
|
|
6
|
+
*/
|
|
7
|
+
export function initials(name: string): string {
|
|
8
|
+
return name
|
|
9
|
+
.split(/\s+/)
|
|
10
|
+
.map((w) => w[0] ?? '')
|
|
11
|
+
.join('')
|
|
12
|
+
.toUpperCase()
|
|
13
|
+
.slice(0, 2);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Relative "x ago" formatter used on each commit row. Falls back to a
|
|
18
|
+
* locale-formatted date once the gap exceeds a week.
|
|
19
|
+
*/
|
|
20
|
+
export function formatRelativeDate(date: string | Date): string {
|
|
21
|
+
const d = typeof date === 'string' ? new Date(date) : date;
|
|
22
|
+
const now = new Date();
|
|
23
|
+
const diffMs = now.getTime() - d.getTime();
|
|
24
|
+
const diffMins = Math.floor(diffMs / 60_000);
|
|
25
|
+
const diffHours = Math.floor(diffMs / 3_600_000);
|
|
26
|
+
const diffDays = Math.floor(diffMs / 86_400_000);
|
|
27
|
+
|
|
28
|
+
if (diffMins < 1) return 'just now';
|
|
29
|
+
if (diffMins < 60) return `${diffMins}m ago`;
|
|
30
|
+
if (diffHours < 24) return `${diffHours}h ago`;
|
|
31
|
+
if (diffDays < 7) return `${diffDays}d ago`;
|
|
32
|
+
|
|
33
|
+
return d.toLocaleDateString('en-US', {
|
|
34
|
+
month: 'short',
|
|
35
|
+
day: 'numeric',
|
|
36
|
+
year: d.getFullYear() !== now.getFullYear() ? 'numeric' : undefined,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Fully-qualified date shown inside the commit detail popover.
|
|
42
|
+
*/
|
|
43
|
+
export function formatFullDate(date: string | Date): string {
|
|
44
|
+
const d = typeof date === 'string' ? new Date(date) : date;
|
|
45
|
+
return d.toLocaleDateString('en-US', {
|
|
46
|
+
weekday: 'short',
|
|
47
|
+
month: 'short',
|
|
48
|
+
day: 'numeric',
|
|
49
|
+
year: 'numeric',
|
|
50
|
+
hour: 'numeric',
|
|
51
|
+
minute: '2-digit',
|
|
52
|
+
});
|
|
53
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { createLazyComponent } from '
|
|
3
|
+
import { createLazyComponent } from '../../../../common/lazy-wrapper';
|
|
4
4
|
import type { GaugeProps } from './types';
|
|
5
5
|
|
|
6
6
|
export const LazyGauge = createLazyComponent<GaugeProps>(
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Sparkline
|
|
2
|
+
|
|
3
|
+
Compact inline trend chart (line / area / bar). Resolves stroke + fill via `useThemeColor(color)` — semantic tokens only, no raw scales.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { Sparkline } from '@djangocfg/ui-tools/sparkline';
|
|
7
|
+
|
|
8
|
+
<Sparkline data={[3, 5, 4, 7, 9, 8, 12]} variant="area" color="success" />
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Description |
|
|
14
|
+
|---|---|---|---|
|
|
15
|
+
| `data` | `SparklineDatum[]` | — | `number` or `{ value, label? }`. Empty array renders nothing. |
|
|
16
|
+
| `variant` | `'line' \| 'area' \| 'bar'` | `'line'` | Visual style. |
|
|
17
|
+
| `color` | `'primary' \| 'success' \| 'warning' \| 'destructive' \| 'info'` | `'primary'` | Semantic theme color. |
|
|
18
|
+
| `width` | `number` | `120` | SVG width. |
|
|
19
|
+
| `height` | `number` | `32` | SVG height. |
|
|
20
|
+
| `strokeWidth` | `number` | `1.5` | Line stroke (ignored for `bar`). |
|
|
21
|
+
| `showEndpoint` | `boolean` | `true` | Filled dot at latest point. |
|
|
22
|
+
| `showBaseline` | `boolean` | `false` | Dashed average line. |
|
|
23
|
+
| `ariaLabel` | `string` | — | Accessible label. |
|
|
24
|
+
|
|
25
|
+
Storybook: `apps/storybook/stories/ui-tools/visual/Sparkline.stories.tsx`
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
Adapted from jalcoui (MIT).
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
// Adapted from jalcoui (MIT) — github.com/jal-co/ui
|
|
2
|
+
//
|
|
3
|
+
// Generic inline SVG sparkline. Pure SVG, no charting deps. Color resolves
|
|
4
|
+
// through the theme palette (semantic token → hex), so the stroke and area
|
|
5
|
+
// fill follow the active preset.
|
|
6
|
+
//
|
|
7
|
+
// Requires <UiProviders> mounted by the host app (no nested providers here).
|
|
8
|
+
|
|
9
|
+
'use client';
|
|
10
|
+
|
|
11
|
+
import * as React from 'react';
|
|
12
|
+
import { cn } from '@djangocfg/ui-core/lib';
|
|
13
|
+
import { useThemeColor, alpha } from '@djangocfg/ui-core/styles/palette';
|
|
14
|
+
import type { SparklineDatum, SparklineProps } from './types';
|
|
15
|
+
|
|
16
|
+
function toValue(d: SparklineDatum): number {
|
|
17
|
+
return typeof d === 'number' ? d : d.value;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface Stats {
|
|
21
|
+
values: number[];
|
|
22
|
+
min: number;
|
|
23
|
+
max: number;
|
|
24
|
+
range: number;
|
|
25
|
+
avg: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function computeStats(data: SparklineDatum[]): Stats {
|
|
29
|
+
const values = data.map(toValue);
|
|
30
|
+
const max = Math.max(...values, 1);
|
|
31
|
+
const min = Math.min(...values);
|
|
32
|
+
const range = max - min || 1;
|
|
33
|
+
const total = values.reduce((s, v) => s + v, 0);
|
|
34
|
+
const avg = values.length > 0 ? total / values.length : 0;
|
|
35
|
+
return { values, min, max, range, avg };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function buildLinePath(
|
|
39
|
+
values: number[],
|
|
40
|
+
width: number,
|
|
41
|
+
height: number,
|
|
42
|
+
padding: number,
|
|
43
|
+
min: number,
|
|
44
|
+
range: number,
|
|
45
|
+
): string {
|
|
46
|
+
if (values.length === 0) return '';
|
|
47
|
+
const drawHeight = height - padding * 2;
|
|
48
|
+
const drawWidth = width - padding * 2;
|
|
49
|
+
const denom = values.length - 1 || 1;
|
|
50
|
+
|
|
51
|
+
return values
|
|
52
|
+
.map((v, i) => {
|
|
53
|
+
const x = padding + (i / denom) * drawWidth;
|
|
54
|
+
const y = padding + drawHeight - ((v - min) / range) * drawHeight;
|
|
55
|
+
return `${i === 0 ? 'M' : 'L'} ${x.toFixed(2)} ${y.toFixed(2)}`;
|
|
56
|
+
})
|
|
57
|
+
.join(' ');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function buildAreaPath(
|
|
61
|
+
linePath: string,
|
|
62
|
+
width: number,
|
|
63
|
+
height: number,
|
|
64
|
+
padding: number,
|
|
65
|
+
): string {
|
|
66
|
+
if (!linePath) return '';
|
|
67
|
+
const lastX = width - padding;
|
|
68
|
+
const firstX = padding;
|
|
69
|
+
const bottom = height - padding;
|
|
70
|
+
return `${linePath} L ${lastX.toFixed(2)} ${bottom.toFixed(2)} L ${firstX.toFixed(2)} ${bottom.toFixed(2)} Z`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function getEndpoint(
|
|
74
|
+
values: number[],
|
|
75
|
+
width: number,
|
|
76
|
+
height: number,
|
|
77
|
+
padding: number,
|
|
78
|
+
min: number,
|
|
79
|
+
range: number,
|
|
80
|
+
): { x: number; y: number } | null {
|
|
81
|
+
if (values.length === 0) return null;
|
|
82
|
+
const drawHeight = height - padding * 2;
|
|
83
|
+
const lastV = values[values.length - 1];
|
|
84
|
+
return {
|
|
85
|
+
x: width - padding,
|
|
86
|
+
y: padding + drawHeight - ((lastV - min) / range) * drawHeight,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function getBaselineY(
|
|
91
|
+
avg: number,
|
|
92
|
+
height: number,
|
|
93
|
+
padding: number,
|
|
94
|
+
min: number,
|
|
95
|
+
range: number,
|
|
96
|
+
): number {
|
|
97
|
+
const drawHeight = height - padding * 2;
|
|
98
|
+
return padding + drawHeight - ((avg - min) / range) * drawHeight;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function Sparkline({
|
|
102
|
+
data,
|
|
103
|
+
variant = 'line',
|
|
104
|
+
color = 'primary',
|
|
105
|
+
width = 120,
|
|
106
|
+
height = 32,
|
|
107
|
+
strokeWidth = 1.5,
|
|
108
|
+
showEndpoint = true,
|
|
109
|
+
showBaseline = false,
|
|
110
|
+
ariaLabel,
|
|
111
|
+
className,
|
|
112
|
+
...rest
|
|
113
|
+
}: SparklineProps) {
|
|
114
|
+
const stroke = useThemeColor(color);
|
|
115
|
+
const fill = alpha(stroke, 0.15);
|
|
116
|
+
const baselineStroke = alpha(stroke, 0.4);
|
|
117
|
+
|
|
118
|
+
if (data.length === 0) return null;
|
|
119
|
+
|
|
120
|
+
const stats = computeStats(data);
|
|
121
|
+
const padding = variant === 'bar' ? 2 : 2 + strokeWidth;
|
|
122
|
+
const linePath =
|
|
123
|
+
variant !== 'bar'
|
|
124
|
+
? buildLinePath(stats.values, width, height, padding, stats.min, stats.range)
|
|
125
|
+
: '';
|
|
126
|
+
const areaPath = variant === 'area' ? buildAreaPath(linePath, width, height, padding) : '';
|
|
127
|
+
const endpoint =
|
|
128
|
+
showEndpoint && variant !== 'bar'
|
|
129
|
+
? getEndpoint(stats.values, width, height, padding, stats.min, stats.range)
|
|
130
|
+
: null;
|
|
131
|
+
const baselineY = showBaseline
|
|
132
|
+
? getBaselineY(stats.avg, height, padding, stats.min, stats.range)
|
|
133
|
+
: null;
|
|
134
|
+
|
|
135
|
+
return (
|
|
136
|
+
<div
|
|
137
|
+
data-slot="sparkline"
|
|
138
|
+
data-variant={variant}
|
|
139
|
+
data-color={color}
|
|
140
|
+
className={cn('inline-flex items-center', className)}
|
|
141
|
+
{...rest}
|
|
142
|
+
>
|
|
143
|
+
<svg
|
|
144
|
+
viewBox={`0 0 ${width} ${height}`}
|
|
145
|
+
width={width}
|
|
146
|
+
height={height}
|
|
147
|
+
fill="none"
|
|
148
|
+
role="img"
|
|
149
|
+
aria-label={ariaLabel}
|
|
150
|
+
aria-hidden={ariaLabel ? undefined : true}
|
|
151
|
+
className="block"
|
|
152
|
+
>
|
|
153
|
+
{baselineY != null && (
|
|
154
|
+
<line
|
|
155
|
+
x1={padding}
|
|
156
|
+
y1={baselineY}
|
|
157
|
+
x2={width - padding}
|
|
158
|
+
y2={baselineY}
|
|
159
|
+
stroke={baselineStroke}
|
|
160
|
+
strokeWidth={0.75}
|
|
161
|
+
strokeDasharray="3 3"
|
|
162
|
+
/>
|
|
163
|
+
)}
|
|
164
|
+
|
|
165
|
+
{variant === 'bar' && (() => {
|
|
166
|
+
const drawHeight = height - padding * 2;
|
|
167
|
+
const drawWidth = width - padding * 2;
|
|
168
|
+
const gap = 1;
|
|
169
|
+
const barWidth = Math.max(
|
|
170
|
+
1,
|
|
171
|
+
(drawWidth - gap * (stats.values.length - 1)) / stats.values.length,
|
|
172
|
+
);
|
|
173
|
+
const denom = stats.values.length - 1 || 1;
|
|
174
|
+
return stats.values.map((v, i) => {
|
|
175
|
+
const barHeight = Math.max(1, ((v - stats.min) / stats.range) * drawHeight);
|
|
176
|
+
const x = padding + i * (barWidth + gap);
|
|
177
|
+
const y = padding + drawHeight - barHeight;
|
|
178
|
+
return (
|
|
179
|
+
<rect
|
|
180
|
+
key={i}
|
|
181
|
+
x={x}
|
|
182
|
+
y={y}
|
|
183
|
+
width={barWidth}
|
|
184
|
+
height={barHeight}
|
|
185
|
+
rx={Math.min(barWidth / 2, 1)}
|
|
186
|
+
fill={stroke}
|
|
187
|
+
opacity={0.7 + 0.3 * (i / denom)}
|
|
188
|
+
/>
|
|
189
|
+
);
|
|
190
|
+
});
|
|
191
|
+
})()}
|
|
192
|
+
|
|
193
|
+
{variant === 'area' && areaPath && <path d={areaPath} fill={fill} />}
|
|
194
|
+
|
|
195
|
+
{variant !== 'bar' && linePath && (
|
|
196
|
+
<path
|
|
197
|
+
d={linePath}
|
|
198
|
+
stroke={stroke}
|
|
199
|
+
strokeWidth={strokeWidth}
|
|
200
|
+
strokeLinecap="round"
|
|
201
|
+
strokeLinejoin="round"
|
|
202
|
+
fill="none"
|
|
203
|
+
/>
|
|
204
|
+
)}
|
|
205
|
+
|
|
206
|
+
{endpoint && (
|
|
207
|
+
<circle
|
|
208
|
+
cx={endpoint.x}
|
|
209
|
+
cy={endpoint.y}
|
|
210
|
+
r={strokeWidth + 0.5}
|
|
211
|
+
fill={stroke}
|
|
212
|
+
/>
|
|
213
|
+
)}
|
|
214
|
+
</svg>
|
|
215
|
+
</div>
|
|
216
|
+
);
|
|
217
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
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 { SparklineProps } from './types';
|
|
7
|
+
|
|
8
|
+
export const LazySparkline = createLazyComponent<SparklineProps>(
|
|
9
|
+
() => import('./Sparkline').then((mod) => ({ default: mod.Sparkline })),
|
|
10
|
+
{
|
|
11
|
+
displayName: 'LazySparkline',
|
|
12
|
+
fallback: (
|
|
13
|
+
<span
|
|
14
|
+
data-slot="sparkline-skeleton"
|
|
15
|
+
className="inline-block h-8 w-[120px] animate-pulse rounded bg-muted"
|
|
16
|
+
/>
|
|
17
|
+
),
|
|
18
|
+
},
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
export type {
|
|
22
|
+
SparklineProps,
|
|
23
|
+
SparklineColor,
|
|
24
|
+
SparklineVariant,
|
|
25
|
+
SparklineDatum,
|
|
26
|
+
} from './types';
|