@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.
- 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/package.json +93 -28
- 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/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/hooks/useEditorTheme.ts +13 -73
- package/src/tools/forms/CodeEditor/lazy.tsx +1 -1
- 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/lazy.tsx +1 -1
- package/src/tools/forms/NotionEditor/README.md +237 -0
- package/src/tools/forms/NotionEditor/lazy.tsx +1 -1
- 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/ImageViewer/components/ImageToolbar.tsx +58 -47
- package/src/tools/media/ImageViewer/components/ImageViewer.tsx +27 -19
- package/src/tools/media/ImageViewer/lazy.tsx +1 -1
- package/src/tools/media/LottiePlayer/lazy.tsx +1 -1
- package/src/tools/media/VideoPlayer/VideoPlayer.tsx +28 -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/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,109 @@
|
|
|
1
|
+
// Adapted from jalcoui (MIT) — github.com/jal-co/ui
|
|
2
|
+
|
|
3
|
+
import type * as React from 'react';
|
|
4
|
+
import type { Language } from 'prism-react-renderer';
|
|
5
|
+
|
|
6
|
+
/** Layout of the diff: single-column unified vs. side-by-side split. */
|
|
7
|
+
export type DiffLayout = 'unified' | 'split';
|
|
8
|
+
|
|
9
|
+
/** Per-line kind in a computed diff. */
|
|
10
|
+
export type DiffLineType = 'added' | 'removed' | 'context';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* One rendered line in the diff. Old / new line numbers are independent:
|
|
14
|
+
* an added line has no `oldNumber`, a removed line has no `newNumber`.
|
|
15
|
+
*/
|
|
16
|
+
export interface DiffLine {
|
|
17
|
+
type: DiffLineType;
|
|
18
|
+
content: string;
|
|
19
|
+
oldNumber: number | null;
|
|
20
|
+
newNumber: number | null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Diff stats — rendered in the header pill. */
|
|
24
|
+
export interface DiffStats {
|
|
25
|
+
added: number;
|
|
26
|
+
removed: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface WithStrings {
|
|
30
|
+
/** Original code (LHS). */
|
|
31
|
+
oldCode: string;
|
|
32
|
+
/** Updated code (RHS). */
|
|
33
|
+
newCode: string;
|
|
34
|
+
patch?: never;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface WithPatch {
|
|
38
|
+
/** Pre-computed unified diff string (alternative to oldCode / newCode). */
|
|
39
|
+
patch: string;
|
|
40
|
+
oldCode?: never;
|
|
41
|
+
newCode?: never;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type DiffInput = WithStrings | WithPatch;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Tone classes for a single diff line. Tailwind class strings backed by
|
|
48
|
+
* semantic tokens — the diff viewer adapts to the host theme (light or
|
|
49
|
+
* dark) unlike `PrettyCode`, which is intentionally always-dark. Diffs
|
|
50
|
+
* are commonly embedded in documentation pages, where forcing a dark
|
|
51
|
+
* surface on a light page looks like a bug.
|
|
52
|
+
*/
|
|
53
|
+
export interface DiffToneClasses {
|
|
54
|
+
/** Row background tint. */
|
|
55
|
+
row: string;
|
|
56
|
+
/** Gutter / line-number column foreground. */
|
|
57
|
+
num: string;
|
|
58
|
+
/** Body text color. */
|
|
59
|
+
text: string;
|
|
60
|
+
/** Header stat pill color (e.g. `+12`). */
|
|
61
|
+
stat: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Mapping from line type to tone class bundle. Semantic tokens —
|
|
66
|
+
* resolved by the host theme (light surfaces in light mode, dark in
|
|
67
|
+
* dark mode).
|
|
68
|
+
*/
|
|
69
|
+
export const DIFF_TONE_CLASSES: Record<DiffLineType, DiffToneClasses> = {
|
|
70
|
+
added: {
|
|
71
|
+
row: 'bg-success/10',
|
|
72
|
+
num: 'text-success/80',
|
|
73
|
+
text: 'text-success',
|
|
74
|
+
stat: 'text-success',
|
|
75
|
+
},
|
|
76
|
+
removed: {
|
|
77
|
+
row: 'bg-destructive/15',
|
|
78
|
+
num: 'text-destructive/80',
|
|
79
|
+
text: 'text-destructive',
|
|
80
|
+
stat: 'text-destructive',
|
|
81
|
+
},
|
|
82
|
+
context: {
|
|
83
|
+
row: '',
|
|
84
|
+
num: 'text-muted-foreground/60',
|
|
85
|
+
text: 'text-foreground',
|
|
86
|
+
stat: 'text-muted-foreground',
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export type DiffViewerProps = DiffInput &
|
|
91
|
+
Omit<React.ComponentProps<'div'>, 'children'> & {
|
|
92
|
+
/** Layout. @default `'unified'` */
|
|
93
|
+
layout?: DiffLayout;
|
|
94
|
+
/**
|
|
95
|
+
* Prism language key for optional syntax highlighting. When omitted,
|
|
96
|
+
* lines render as plain monospace. Highlighting reuses the same
|
|
97
|
+
* `prism-react-renderer` instance as the `PrettyCode` tool — no
|
|
98
|
+
* second highlighter is loaded.
|
|
99
|
+
*/
|
|
100
|
+
language?: Language | string;
|
|
101
|
+
/** Label for the LHS file header. */
|
|
102
|
+
oldTitle?: string;
|
|
103
|
+
/** Label for the RHS file header. */
|
|
104
|
+
newTitle?: string;
|
|
105
|
+
/** Show the copy-to-clipboard button. @default `true` */
|
|
106
|
+
copyable?: boolean;
|
|
107
|
+
/** Number of context lines around each hunk when diffing strings. @default `3` */
|
|
108
|
+
context?: number;
|
|
109
|
+
};
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// Adapted from jalcoui (MIT) — github.com/jal-co/ui
|
|
2
|
+
//
|
|
3
|
+
// Line-level diff via Longest Common Subsequence. The jalcoui original
|
|
4
|
+
// uses the `diff` npm package (Myers diff + unified patches). We don't
|
|
5
|
+
// pull that dependency: a 60-line LCS in TS handles up to ~5k lines
|
|
6
|
+
// fast enough for the viewer's use case (small/medium code reviews) and
|
|
7
|
+
// keeps the bundle lean. For pre-computed patches the caller can pass
|
|
8
|
+
// `patch` and we parse the unified-diff text directly — no algorithm
|
|
9
|
+
// runs at all.
|
|
10
|
+
|
|
11
|
+
import type { DiffLine } from '../types';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Compute line-level diff between two strings. Returns a flat sequence
|
|
15
|
+
* of `DiffLine`s in display order. `context` controls how many unchanged
|
|
16
|
+
* lines are emitted around each change-hunk; pass `Infinity` to keep the
|
|
17
|
+
* full file.
|
|
18
|
+
*/
|
|
19
|
+
export function diffLines(
|
|
20
|
+
oldCode: string,
|
|
21
|
+
newCode: string,
|
|
22
|
+
context = 3,
|
|
23
|
+
): DiffLine[] {
|
|
24
|
+
const oldLines = oldCode.split('\n');
|
|
25
|
+
const newLines = newCode.split('\n');
|
|
26
|
+
|
|
27
|
+
// Build LCS table (rows = oldLines + 1, cols = newLines + 1).
|
|
28
|
+
// For each cell, store the length of the longest common subsequence
|
|
29
|
+
// of `oldLines[0..i]` and `newLines[0..j]`.
|
|
30
|
+
const m = oldLines.length;
|
|
31
|
+
const n = newLines.length;
|
|
32
|
+
// Use a single flat Int32Array for cache friendliness.
|
|
33
|
+
const lcs = new Int32Array((m + 1) * (n + 1));
|
|
34
|
+
const cols = n + 1;
|
|
35
|
+
for (let i = 1; i <= m; i++) {
|
|
36
|
+
for (let j = 1; j <= n; j++) {
|
|
37
|
+
const idx = i * cols + j;
|
|
38
|
+
if (oldLines[i - 1] === newLines[j - 1]) {
|
|
39
|
+
lcs[idx] = lcs[(i - 1) * cols + (j - 1)] + 1;
|
|
40
|
+
} else {
|
|
41
|
+
const up = lcs[(i - 1) * cols + j];
|
|
42
|
+
const left = lcs[i * cols + (j - 1)];
|
|
43
|
+
lcs[idx] = up >= left ? up : left;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Walk back from (m, n) to (0, 0) emitting tagged lines.
|
|
49
|
+
type Tagged = { type: DiffLine['type']; oldNum: number | null; newNum: number | null; content: string };
|
|
50
|
+
const tagged: Tagged[] = [];
|
|
51
|
+
let i = m;
|
|
52
|
+
let j = n;
|
|
53
|
+
while (i > 0 || j > 0) {
|
|
54
|
+
if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
|
|
55
|
+
tagged.push({ type: 'context', oldNum: i, newNum: j, content: oldLines[i - 1] });
|
|
56
|
+
i--;
|
|
57
|
+
j--;
|
|
58
|
+
} else if (j > 0 && (i === 0 || lcs[i * cols + (j - 1)] >= lcs[(i - 1) * cols + j])) {
|
|
59
|
+
tagged.push({ type: 'added', oldNum: null, newNum: j, content: newLines[j - 1] });
|
|
60
|
+
j--;
|
|
61
|
+
} else if (i > 0) {
|
|
62
|
+
tagged.push({ type: 'removed', oldNum: i, newNum: null, content: oldLines[i - 1] });
|
|
63
|
+
i--;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
tagged.reverse();
|
|
67
|
+
|
|
68
|
+
// Apply context window — drop runs of `context`-only lines that are
|
|
69
|
+
// farther than `context` from any change. `Infinity` keeps every line.
|
|
70
|
+
if (!Number.isFinite(context)) {
|
|
71
|
+
return tagged.map((t) => ({
|
|
72
|
+
type: t.type,
|
|
73
|
+
content: t.content,
|
|
74
|
+
oldNumber: t.oldNum,
|
|
75
|
+
newNumber: t.newNum,
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Mark indices that are within `context` of a change.
|
|
80
|
+
const keep = new Array<boolean>(tagged.length).fill(false);
|
|
81
|
+
for (let k = 0; k < tagged.length; k++) {
|
|
82
|
+
if (tagged[k].type !== 'context') {
|
|
83
|
+
const from = Math.max(0, k - context);
|
|
84
|
+
const to = Math.min(tagged.length - 1, k + context);
|
|
85
|
+
for (let s = from; s <= to; s++) keep[s] = true;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Drop unkept context lines. We don't render hunk separators (`@@`) —
|
|
90
|
+
// the viewer is meant for compact diffs, not full-file patches.
|
|
91
|
+
const out: DiffLine[] = [];
|
|
92
|
+
for (let k = 0; k < tagged.length; k++) {
|
|
93
|
+
if (!keep[k]) continue;
|
|
94
|
+
out.push({
|
|
95
|
+
type: tagged[k].type,
|
|
96
|
+
content: tagged[k].content,
|
|
97
|
+
oldNumber: tagged[k].oldNum,
|
|
98
|
+
newNumber: tagged[k].newNum,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return out;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Parse a unified diff patch (`@@ -a,b +c,d @@` hunks) into the same
|
|
106
|
+
* `DiffLine[]` shape `diffLines()` produces. Only the line tags and
|
|
107
|
+
* numbers from the hunk headers are honored — file headers
|
|
108
|
+
* (`--- a/file`, `+++ b/file`) are skipped.
|
|
109
|
+
*/
|
|
110
|
+
export function parseUnifiedPatch(patch: string): DiffLine[] {
|
|
111
|
+
const lines: DiffLine[] = [];
|
|
112
|
+
const HUNK = /^@@\s+-(\d+)(?:,\d+)?\s+\+(\d+)(?:,\d+)?\s+@@/;
|
|
113
|
+
let oldNum = 0;
|
|
114
|
+
let newNum = 0;
|
|
115
|
+
let inHunk = false;
|
|
116
|
+
|
|
117
|
+
for (const raw of patch.split('\n')) {
|
|
118
|
+
const hunk = HUNK.exec(raw);
|
|
119
|
+
if (hunk) {
|
|
120
|
+
oldNum = parseInt(hunk[1], 10);
|
|
121
|
+
newNum = parseInt(hunk[2], 10);
|
|
122
|
+
inHunk = true;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (!inHunk) continue;
|
|
126
|
+
if (raw.startsWith('--- ') || raw.startsWith('+++ ') || raw.startsWith('\\')) continue;
|
|
127
|
+
|
|
128
|
+
if (raw.startsWith('+')) {
|
|
129
|
+
lines.push({ type: 'added', content: raw.slice(1), oldNumber: null, newNumber: newNum++ });
|
|
130
|
+
} else if (raw.startsWith('-')) {
|
|
131
|
+
lines.push({ type: 'removed', content: raw.slice(1), oldNumber: oldNum++, newNumber: null });
|
|
132
|
+
} else {
|
|
133
|
+
const content = raw.startsWith(' ') ? raw.slice(1) : raw;
|
|
134
|
+
lines.push({ type: 'context', content, oldNumber: oldNum++, newNumber: newNum++ });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return lines;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Widest gutter required for the line numbers, in characters. */
|
|
141
|
+
export function lineNumberWidth(lines: DiffLine[]): number {
|
|
142
|
+
let max = 0;
|
|
143
|
+
for (const line of lines) {
|
|
144
|
+
if (line.oldNumber && line.oldNumber > max) max = line.oldNumber;
|
|
145
|
+
if (line.newNumber && line.newNumber > max) max = line.newNumber;
|
|
146
|
+
}
|
|
147
|
+
return Math.max(String(max).length, 2);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Count `+` and `-` lines for the header stat pill. */
|
|
151
|
+
export function computeStats(lines: DiffLine[]): { added: number; removed: number } {
|
|
152
|
+
let added = 0;
|
|
153
|
+
let removed = 0;
|
|
154
|
+
for (const line of lines) {
|
|
155
|
+
if (line.type === 'added') added++;
|
|
156
|
+
else if (line.type === 'removed') removed++;
|
|
157
|
+
}
|
|
158
|
+
return { added, removed };
|
|
159
|
+
}
|
|
@@ -11,7 +11,7 @@ import remarkGfm from 'remark-gfm';
|
|
|
11
11
|
import remarkSmartypants from 'remark-smartypants';
|
|
12
12
|
import type { Components } from 'react-markdown';
|
|
13
13
|
|
|
14
|
-
import { useCollapsibleContent } from '
|
|
14
|
+
import { useCollapsibleContent } from '../../../../hooks/useCollapsibleContent';
|
|
15
15
|
import type { MarkdownMessageProps } from './types';
|
|
16
16
|
import { buildSchema, buildUrlTransform } from './sanitize';
|
|
17
17
|
import { looksLikePlainProse } from './plainText';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { Components } from 'react-markdown';
|
|
3
|
-
import Mermaid from '
|
|
4
|
-
import { ANCHOR } from '
|
|
3
|
+
import Mermaid from '../../Mermaid';
|
|
4
|
+
import { ANCHOR } from '../../../chat/styles/bubbleTokens';
|
|
5
5
|
import { CodeBlock, CodeBlockFallback } from './CodeBlock';
|
|
6
6
|
import { extractTextFromChildren } from './plainText';
|
|
7
7
|
|
|
@@ -4,8 +4,8 @@ import { Highlight, Language, themes } from 'prism-react-renderer';
|
|
|
4
4
|
import React, { useMemo, useRef } from 'react';
|
|
5
5
|
|
|
6
6
|
import { useAppT } from '@djangocfg/i18n';
|
|
7
|
-
import { FloatingToolbar } from '
|
|
8
|
-
import { CopyAction } from '
|
|
7
|
+
import { FloatingToolbar } from '../../../../common/FloatingToolbar';
|
|
8
|
+
import { CopyAction } from '../../../../common/FloatingToolbar/actions';
|
|
9
9
|
|
|
10
10
|
// Surface palette — fixed dark regardless of host theme. Code blocks
|
|
11
11
|
// follow the IDE / GitHub / ChatGPT convention: syntax highlighting
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* import PrettyCode from '@djangocfg/ui-tools/pretty-code'
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { createLazyComponent } from '
|
|
13
|
+
import { createLazyComponent } from '../../../../common';
|
|
14
14
|
import type { Language } from 'prism-react-renderer';
|
|
15
15
|
|
|
16
16
|
// ============================================================================
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
// Adapted from jalcoui (MIT) — github.com/jal-co/ui
|
|
2
|
+
//
|
|
3
|
+
// Read-only environment variable table with masked values, click-to-reveal,
|
|
4
|
+
// and per-row copy. Designed for settings pages, deploy previews, and docs.
|
|
5
|
+
//
|
|
6
|
+
// - Semantic tokens only (success / warning / info / destructive / muted).
|
|
7
|
+
// - No motion library — Tailwind `transition-colors` for hover feedback.
|
|
8
|
+
// - Requires <UiProviders> at the host root; mounts no providers itself.
|
|
9
|
+
|
|
10
|
+
'use client';
|
|
11
|
+
|
|
12
|
+
import * as React from 'react';
|
|
13
|
+
import { Check, ClipboardList, Copy, Eye, EyeOff } from 'lucide-react';
|
|
14
|
+
import { cn } from '@djangocfg/ui-core/lib';
|
|
15
|
+
import {
|
|
16
|
+
ENV_TONE_CLASSES,
|
|
17
|
+
getEnvTone,
|
|
18
|
+
type EnvTableProps,
|
|
19
|
+
type EnvVariable,
|
|
20
|
+
} from './types';
|
|
21
|
+
import { maskValue, useEnvMask } from './hooks/useEnvMask';
|
|
22
|
+
|
|
23
|
+
interface RowProps {
|
|
24
|
+
variable: EnvVariable;
|
|
25
|
+
revealed: boolean;
|
|
26
|
+
copied: boolean;
|
|
27
|
+
onToggleReveal: () => void;
|
|
28
|
+
onCopy: () => void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function EnvRow({ variable, revealed, copied, onToggleReveal, onCopy }: RowProps) {
|
|
32
|
+
const tone = getEnvTone(variable.environment);
|
|
33
|
+
const displayValue = revealed ? variable.value : maskValue(variable.value);
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div
|
|
37
|
+
data-slot="env-row"
|
|
38
|
+
data-revealed={revealed}
|
|
39
|
+
className="group flex items-start gap-3 px-3 py-2.5 transition-colors hover:bg-accent sm:items-center sm:px-4"
|
|
40
|
+
>
|
|
41
|
+
<div className="flex min-w-0 flex-1 flex-col gap-1.5 sm:flex-row sm:items-center sm:gap-4">
|
|
42
|
+
{/* Key */}
|
|
43
|
+
<div className="flex shrink-0 items-center gap-2 sm:w-[220px]">
|
|
44
|
+
<span
|
|
45
|
+
className={cn(
|
|
46
|
+
'truncate font-mono text-xs font-semibold',
|
|
47
|
+
variable.required ? 'text-destructive' : 'text-foreground',
|
|
48
|
+
)}
|
|
49
|
+
>
|
|
50
|
+
{variable.key}
|
|
51
|
+
{variable.required && (
|
|
52
|
+
<span
|
|
53
|
+
aria-label="required"
|
|
54
|
+
className="ml-0.5 text-destructive"
|
|
55
|
+
title="Required"
|
|
56
|
+
>
|
|
57
|
+
*
|
|
58
|
+
</span>
|
|
59
|
+
)}
|
|
60
|
+
</span>
|
|
61
|
+
{variable.environment && (
|
|
62
|
+
<span
|
|
63
|
+
className={cn(
|
|
64
|
+
'shrink-0 rounded-full px-2 py-0.5 text-[10px] font-medium leading-none',
|
|
65
|
+
ENV_TONE_CLASSES[tone],
|
|
66
|
+
)}
|
|
67
|
+
>
|
|
68
|
+
{variable.environment}
|
|
69
|
+
</span>
|
|
70
|
+
)}
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
{/* Value */}
|
|
74
|
+
<div className="min-w-0 flex-1">
|
|
75
|
+
<span
|
|
76
|
+
className={cn(
|
|
77
|
+
'break-all font-mono text-xs',
|
|
78
|
+
revealed ? 'text-foreground' : 'text-muted-foreground',
|
|
79
|
+
)}
|
|
80
|
+
>
|
|
81
|
+
{displayValue}
|
|
82
|
+
</span>
|
|
83
|
+
{variable.description && (
|
|
84
|
+
<p className="mt-0.5 text-[11px] text-muted-foreground">
|
|
85
|
+
{variable.description}
|
|
86
|
+
</p>
|
|
87
|
+
)}
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
{/* Actions */}
|
|
92
|
+
<div className="flex shrink-0 items-center gap-0.5">
|
|
93
|
+
<button
|
|
94
|
+
type="button"
|
|
95
|
+
onClick={onToggleReveal}
|
|
96
|
+
aria-label={`${revealed ? 'Hide' : 'Reveal'} ${variable.key}`}
|
|
97
|
+
aria-pressed={revealed}
|
|
98
|
+
className="inline-flex items-center justify-center rounded-md p-1.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
99
|
+
>
|
|
100
|
+
{revealed ? (
|
|
101
|
+
<EyeOff className="size-3.5" />
|
|
102
|
+
) : (
|
|
103
|
+
<Eye className="size-3.5" />
|
|
104
|
+
)}
|
|
105
|
+
</button>
|
|
106
|
+
<button
|
|
107
|
+
type="button"
|
|
108
|
+
onClick={onCopy}
|
|
109
|
+
aria-label={`Copy ${variable.key} value`}
|
|
110
|
+
className="inline-flex items-center justify-center rounded-md p-1.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
111
|
+
>
|
|
112
|
+
{copied ? (
|
|
113
|
+
<Check className="size-3.5 text-success" />
|
|
114
|
+
) : (
|
|
115
|
+
<Copy className="size-3.5" />
|
|
116
|
+
)}
|
|
117
|
+
</button>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function EnvTable({
|
|
124
|
+
variables,
|
|
125
|
+
title,
|
|
126
|
+
defaultRevealed = false,
|
|
127
|
+
emptyLabel = 'No environment variables.',
|
|
128
|
+
className,
|
|
129
|
+
...props
|
|
130
|
+
}: EnvTableProps) {
|
|
131
|
+
const {
|
|
132
|
+
revealed,
|
|
133
|
+
allRevealed,
|
|
134
|
+
toggleIndex,
|
|
135
|
+
toggleAll,
|
|
136
|
+
copiedTarget,
|
|
137
|
+
copyValue,
|
|
138
|
+
copyAllAsEnv,
|
|
139
|
+
} = useEnvMask({ variables, defaultRevealed });
|
|
140
|
+
|
|
141
|
+
if (variables.length === 0) {
|
|
142
|
+
return (
|
|
143
|
+
<div
|
|
144
|
+
data-slot="env-table"
|
|
145
|
+
data-empty="true"
|
|
146
|
+
className={cn(
|
|
147
|
+
'flex items-center justify-center rounded-xl border border-border/60 bg-card py-10 text-sm text-muted-foreground shadow-sm',
|
|
148
|
+
className,
|
|
149
|
+
)}
|
|
150
|
+
{...props}
|
|
151
|
+
>
|
|
152
|
+
{emptyLabel}
|
|
153
|
+
</div>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const copiedAll = copiedTarget === 'all';
|
|
158
|
+
|
|
159
|
+
return (
|
|
160
|
+
<div
|
|
161
|
+
data-slot="env-table"
|
|
162
|
+
className={cn(
|
|
163
|
+
'overflow-hidden rounded-xl border border-border/60 bg-card shadow-sm',
|
|
164
|
+
className,
|
|
165
|
+
)}
|
|
166
|
+
{...props}
|
|
167
|
+
>
|
|
168
|
+
{/* Header */}
|
|
169
|
+
<div className="flex items-center justify-between border-b border-border/40 px-3 py-2.5 sm:px-4">
|
|
170
|
+
<div className="flex items-center gap-2">
|
|
171
|
+
{title && (
|
|
172
|
+
<h3 className="text-sm font-semibold text-foreground">{title}</h3>
|
|
173
|
+
)}
|
|
174
|
+
<span className="rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground">
|
|
175
|
+
{variables.length}
|
|
176
|
+
</span>
|
|
177
|
+
</div>
|
|
178
|
+
<div className="flex items-center gap-1">
|
|
179
|
+
<button
|
|
180
|
+
type="button"
|
|
181
|
+
onClick={toggleAll}
|
|
182
|
+
aria-label={allRevealed ? 'Hide all values' : 'Reveal all values'}
|
|
183
|
+
aria-pressed={allRevealed}
|
|
184
|
+
className="inline-flex items-center gap-1.5 rounded-md px-2 py-1.5 text-xs text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
185
|
+
>
|
|
186
|
+
{allRevealed ? (
|
|
187
|
+
<EyeOff className="size-3.5" />
|
|
188
|
+
) : (
|
|
189
|
+
<Eye className="size-3.5" />
|
|
190
|
+
)}
|
|
191
|
+
<span className="hidden sm:inline">
|
|
192
|
+
{allRevealed ? 'Hide all' : 'Reveal all'}
|
|
193
|
+
</span>
|
|
194
|
+
</button>
|
|
195
|
+
<button
|
|
196
|
+
type="button"
|
|
197
|
+
onClick={copyAllAsEnv}
|
|
198
|
+
aria-label="Copy all as .env"
|
|
199
|
+
className="inline-flex items-center gap-1.5 rounded-md px-2 py-1.5 text-xs text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
200
|
+
>
|
|
201
|
+
{copiedAll ? (
|
|
202
|
+
<Check className="size-3.5 text-success" />
|
|
203
|
+
) : (
|
|
204
|
+
<ClipboardList className="size-3.5" />
|
|
205
|
+
)}
|
|
206
|
+
<span className="hidden sm:inline">
|
|
207
|
+
{copiedAll ? 'Copied!' : 'Copy .env'}
|
|
208
|
+
</span>
|
|
209
|
+
</button>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
|
|
213
|
+
{/* Rows */}
|
|
214
|
+
<div className="divide-y divide-border/40">
|
|
215
|
+
{variables.map((variable, i) => (
|
|
216
|
+
<EnvRow
|
|
217
|
+
key={`${variable.key}-${i}`}
|
|
218
|
+
variable={variable}
|
|
219
|
+
revealed={revealed.has(i)}
|
|
220
|
+
copied={copiedTarget === i}
|
|
221
|
+
onToggleReveal={() => toggleIndex(i)}
|
|
222
|
+
onCopy={() => copyValue(i, variable.value)}
|
|
223
|
+
/>
|
|
224
|
+
))}
|
|
225
|
+
</div>
|
|
226
|
+
</div>
|
|
227
|
+
);
|
|
228
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# EnvTable
|
|
2
|
+
|
|
3
|
+
Environment-variable table with mask / reveal + copy. Per-row environment badge tinted via semantic tokens (`success` / `warning` / `info` / `muted`).
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { EnvTable } from '@djangocfg/ui-tools/env-table';
|
|
7
|
+
|
|
8
|
+
<EnvTable
|
|
9
|
+
variables={[
|
|
10
|
+
{ key: 'DATABASE_URL', value: 'postgres://…', environment: 'production', required: true },
|
|
11
|
+
{ key: 'DEBUG', value: 'false', environment: 'development' },
|
|
12
|
+
]}
|
|
13
|
+
/>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Props
|
|
17
|
+
|
|
18
|
+
| Prop | Type | Default | Description |
|
|
19
|
+
|---|---|---|---|
|
|
20
|
+
| `variables` | `EnvVariable[]` | — | Rows: `{ key, value, environment?, description?, required? }`. |
|
|
21
|
+
| `title` | `string` | — | Heading above the table. |
|
|
22
|
+
| `defaultRevealed` | `boolean` | `false` | Start with all values visible. |
|
|
23
|
+
| `emptyLabel` | `string` | `'No environment variables.'` | Empty state. |
|
|
24
|
+
|
|
25
|
+
Storybook: `apps/storybook/stories/ui-tools/dev/EnvTable.stories.tsx`
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
Adapted from jalcoui (MIT).
|