From 7c89abe0a89d0d3e1845201d2d65b11be9812cd7 Mon Sep 17 00:00:00 2001 From: Hamhire Hu Date: Thu, 18 Jun 2026 13:46:18 +0800 Subject: [PATCH 1/2] =?UTF-8?q?refactor(components):=20=E9=A1=B6=E5=B1=82?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E6=8C=89=E9=A2=86=E5=9F=9F=E6=8B=86=E5=88=86?= =?UTF-8?q?=E5=88=B0=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit components/ 下扁平堆叠的 30 个组件按领域归入子目录: - common/ 基础公共 UI(Avatar / ConfirmModal / Loading / icons / Mermaid 等) - layout/ 应用骨架(MainPane / Sidebar / StatusBar / TitleBar) - pr/ · diff/ · comments/ · drafts/ · settings/ 各业务领域 纯文件位置调整 + import 路径改写(git 识别为 rename),无逻辑/界面变更。 Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/desktop/src/renderer/src/App.tsx | 10 +++--- .../renderer/src/components/chat/ChatPane.tsx | 6 ++-- .../components/chat/components/AgentStep.tsx | 2 +- .../components/chat/components/ChatEmpty.tsx | 2 +- .../chat/components/ChatInputBar.tsx | 2 +- .../chat/components/ConversationMessage.tsx | 2 +- .../chat/components/FindingCard.tsx | 4 +-- .../components/chat/components/QueuedView.tsx | 2 +- .../chat/components/RulePreviewModal.tsx | 2 +- .../chat/components/RunResultView.tsx | 2 +- .../src/components/chat/components/shared.tsx | 4 +-- .../{ => comments}/CommentEditEditor.tsx | 2 +- .../{ => comments}/CommentReplyEditor.tsx | 2 +- .../{ => comments}/CommentsPanel.tsx | 16 +++++----- .../{ => comments}/InlineCodeContext.tsx | 8 ++--- .../src/components/{ => common}/Avatar.tsx | 2 +- .../{ => common}/BitbucketImage.tsx | 2 +- .../components/{ => common}/ConfirmModal.tsx | 0 .../components/{ => common}/ErrorBoundary.tsx | 0 .../{ => common}/LlmProviderIcon.tsx | 0 .../src/components/{ => common}/Loading.tsx | 0 .../{ => common}/MermaidDiagram.tsx | 0 .../components/{ => common}/PlatformIcon.tsx | 0 .../src/components/{ => common}/icons.tsx | 0 .../{ => common}/markdownMermaid.tsx | 0 .../components/{ => diff}/DiffSearchPanel.tsx | 4 +-- .../src/components/{ => diff}/DiffView.tsx | 32 +++++++++---------- .../src/components/{ => diff}/FileTree.tsx | 2 +- .../src/components/{ => drafts}/DraftZone.tsx | 4 +-- .../components/{ => drafts}/DraftsPanel.tsx | 6 ++-- .../{ => drafts}/PublishReviewModal.tsx | 2 +- .../src/components/{ => layout}/MainPane.tsx | 20 ++++++------ .../src/components/{ => layout}/Sidebar.tsx | 6 ++-- .../src/components/{ => layout}/StatusBar.tsx | 8 ++--- .../src/components/{ => layout}/TitleBar.tsx | 0 .../onboarding/OnboardingWizard.tsx | 4 +-- .../components/onboarding/steps/DoneStep.tsx | 2 +- .../components/onboarding/steps/LlmStep.tsx | 4 +-- .../onboarding/steps/PlatformStep.tsx | 6 ++-- .../onboarding/steps/WelcomeStep.tsx | 2 +- .../src/components/{ => pr}/CommitsPanel.tsx | 6 ++-- .../src/components/{ => pr}/PrInfoView.tsx | 6 ++-- .../src/components/{ => pr}/PrItem.tsx | 4 +-- .../{ => settings}/ConnectionForm.tsx | 4 +-- .../{ => settings}/LlmProfileForm.tsx | 4 +-- .../{ => settings}/SettingsModal.tsx | 12 +++---- 46 files changed, 104 insertions(+), 104 deletions(-) rename apps/desktop/src/renderer/src/components/{ => comments}/CommentEditEditor.tsx (99%) rename apps/desktop/src/renderer/src/components/{ => comments}/CommentReplyEditor.tsx (98%) rename apps/desktop/src/renderer/src/components/{ => comments}/CommentsPanel.tsx (97%) rename apps/desktop/src/renderer/src/components/{ => comments}/InlineCodeContext.tsx (97%) rename apps/desktop/src/renderer/src/components/{ => common}/Avatar.tsx (99%) rename apps/desktop/src/renderer/src/components/{ => common}/BitbucketImage.tsx (99%) rename apps/desktop/src/renderer/src/components/{ => common}/ConfirmModal.tsx (100%) rename apps/desktop/src/renderer/src/components/{ => common}/ErrorBoundary.tsx (100%) rename apps/desktop/src/renderer/src/components/{ => common}/LlmProviderIcon.tsx (100%) rename apps/desktop/src/renderer/src/components/{ => common}/Loading.tsx (100%) rename apps/desktop/src/renderer/src/components/{ => common}/MermaidDiagram.tsx (100%) rename apps/desktop/src/renderer/src/components/{ => common}/PlatformIcon.tsx (100%) rename apps/desktop/src/renderer/src/components/{ => common}/icons.tsx (100%) rename apps/desktop/src/renderer/src/components/{ => common}/markdownMermaid.tsx (100%) rename apps/desktop/src/renderer/src/components/{ => diff}/DiffSearchPanel.tsx (99%) rename apps/desktop/src/renderer/src/components/{ => diff}/DiffView.tsx (98%) rename apps/desktop/src/renderer/src/components/{ => diff}/FileTree.tsx (99%) rename apps/desktop/src/renderer/src/components/{ => drafts}/DraftZone.tsx (99%) rename apps/desktop/src/renderer/src/components/{ => drafts}/DraftsPanel.tsx (98%) rename apps/desktop/src/renderer/src/components/{ => drafts}/PublishReviewModal.tsx (99%) rename apps/desktop/src/renderer/src/components/{ => layout}/MainPane.tsx (97%) rename apps/desktop/src/renderer/src/components/{ => layout}/Sidebar.tsx (98%) rename apps/desktop/src/renderer/src/components/{ => layout}/StatusBar.tsx (99%) rename apps/desktop/src/renderer/src/components/{ => layout}/TitleBar.tsx (100%) rename apps/desktop/src/renderer/src/components/{ => pr}/CommitsPanel.tsx (96%) rename apps/desktop/src/renderer/src/components/{ => pr}/PrInfoView.tsx (93%) rename apps/desktop/src/renderer/src/components/{ => pr}/PrItem.tsx (97%) rename apps/desktop/src/renderer/src/components/{ => settings}/ConnectionForm.tsx (98%) rename apps/desktop/src/renderer/src/components/{ => settings}/LlmProfileForm.tsx (99%) rename apps/desktop/src/renderer/src/components/{ => settings}/SettingsModal.tsx (99%) diff --git a/apps/desktop/src/renderer/src/App.tsx b/apps/desktop/src/renderer/src/App.tsx index 03d7e92..dcefd91 100644 --- a/apps/desktop/src/renderer/src/App.tsx +++ b/apps/desktop/src/renderer/src/App.tsx @@ -17,12 +17,12 @@ import { ChatPane, CHAT_MAX_WIDTH, CHAT_MIN_WIDTH } from './components/chat'; import { wireChatRunStore } from './stores/chat-run-store'; import { wireDraftsStore } from './stores/drafts-store'; import { wireRepoSyncStore } from './stores/repo-sync-store'; -import { MainPane } from './components/MainPane'; +import { MainPane } from './components/layout/MainPane'; import { OnboardingWizard, type OnboardingResult } from './components/onboarding/OnboardingWizard'; -import { SettingsModal } from './components/SettingsModal'; -import { Sidebar, SIDEBAR_MAX_WIDTH, SIDEBAR_MIN_WIDTH } from './components/Sidebar'; -import { StatusBar } from './components/StatusBar'; -import { TitleBar } from './components/TitleBar'; +import { SettingsModal } from './components/settings/SettingsModal'; +import { Sidebar, SIDEBAR_MAX_WIDTH, SIDEBAR_MIN_WIDTH } from './components/layout/Sidebar'; +import { StatusBar } from './components/layout/StatusBar'; +import { TitleBar } from './components/layout/TitleBar'; interface BootstrapState { info: AppInfo; diff --git a/apps/desktop/src/renderer/src/components/chat/ChatPane.tsx b/apps/desktop/src/renderer/src/components/chat/ChatPane.tsx index d6ac6c6..45a4062 100644 --- a/apps/desktop/src/renderer/src/components/chat/ChatPane.tsx +++ b/apps/desktop/src/renderer/src/components/chat/ChatPane.tsx @@ -1,9 +1,9 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { LocalPrStatus, PrAgentStatus, StoredPullRequest } from '@meebox/shared'; -import { ChatIcon, TrashIcon } from '../icons'; -import { ConfirmModal } from '../ConfirmModal'; -import { PaneLoading } from '../Loading'; +import { ChatIcon, TrashIcon } from '../common/icons'; +import { ConfirmModal } from '../common/ConfirmModal'; +import { PaneLoading } from '../common/Loading'; import { useChatRunStore } from '../../stores/chat-run-store'; import { useDraftsForPr } from '../../stores/drafts-store'; import { CHAT_MAX_WIDTH, CHAT_MIN_WIDTH } from './constants'; diff --git a/apps/desktop/src/renderer/src/components/chat/components/AgentStep.tsx b/apps/desktop/src/renderer/src/components/chat/components/AgentStep.tsx index 1aa1c7e..525682b 100644 --- a/apps/desktop/src/renderer/src/components/chat/components/AgentStep.tsx +++ b/apps/desktop/src/renderer/src/components/chat/components/AgentStep.tsx @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { AgentStep } from '@meebox/shared'; -import { RobotIcon } from '../../icons'; +import { RobotIcon } from '../../common/icons'; import { formatElapsed, formatTokens } from '../utils/format'; import { Spinner } from './shared'; diff --git a/apps/desktop/src/renderer/src/components/chat/components/ChatEmpty.tsx b/apps/desktop/src/renderer/src/components/chat/components/ChatEmpty.tsx index 7be5fd1..67165b7 100644 --- a/apps/desktop/src/renderer/src/components/chat/components/ChatEmpty.tsx +++ b/apps/desktop/src/renderer/src/components/chat/components/ChatEmpty.tsx @@ -1,6 +1,6 @@ import { useTranslation } from 'react-i18next'; import type { PrAgentStatus, StoredPullRequest } from '@meebox/shared'; -import { ChatIcon } from '../../icons'; +import { ChatIcon } from '../../common/icons'; import { Bullet } from './shared'; export function ChatEmpty({ diff --git a/apps/desktop/src/renderer/src/components/chat/components/ChatInputBar.tsx b/apps/desktop/src/renderer/src/components/chat/components/ChatInputBar.tsx index adffc79..1ddd361 100644 --- a/apps/desktop/src/renderer/src/components/chat/components/ChatInputBar.tsx +++ b/apps/desktop/src/renderer/src/components/chat/components/ChatInputBar.tsx @@ -1,7 +1,7 @@ import { useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { LocalPrStatus, PrAgentStatus, ReviewRunTool, StoredPullRequest } from '@meebox/shared'; -import { AutoReviewIcon, SendIcon, StopIcon } from '../../icons'; +import { AutoReviewIcon, SendIcon, StopIcon } from '../../common/icons'; import { COMMANDS, type CommandSpec } from '../commands'; import { loadChatHistory, pushChatHistory } from '../utils/chat-history'; diff --git a/apps/desktop/src/renderer/src/components/chat/components/ConversationMessage.tsx b/apps/desktop/src/renderer/src/components/chat/components/ConversationMessage.tsx index 35747db..74e61d5 100644 --- a/apps/desktop/src/renderer/src/components/chat/components/ConversationMessage.tsx +++ b/apps/desktop/src/renderer/src/components/chat/components/ConversationMessage.tsx @@ -1,6 +1,6 @@ import { useTranslation } from 'react-i18next'; import type { AgentMessage } from '@meebox/shared'; -import { ChatIcon } from '../../icons'; +import { ChatIcon } from '../../common/icons'; import { VERDICT_LABEL_KEY } from '../constants'; import { Md } from './shared'; diff --git a/apps/desktop/src/renderer/src/components/chat/components/FindingCard.tsx b/apps/desktop/src/renderer/src/components/chat/components/FindingCard.tsx index 8f9161f..ee2d483 100644 --- a/apps/desktop/src/renderer/src/components/chat/components/FindingCard.tsx +++ b/apps/desktop/src/renderer/src/components/chat/components/FindingCard.tsx @@ -4,8 +4,8 @@ import ReactMarkdown from 'react-markdown'; import remarkBreaks from 'remark-breaks'; import remarkGfm from 'remark-gfm'; import type { Finding, PrDocSectionKey, ReviewDraft } from '@meebox/shared'; -import { ChevronIcon } from '../../icons'; -import { mermaidComponents, walkthroughMdComponents } from '../../markdownMermaid'; +import { ChevronIcon } from '../../common/icons'; +import { mermaidComponents, walkthroughMdComponents } from '../../common/markdownMermaid'; import { REMOTE_REHYPE_PLUGINS } from '../../../markdown'; import { translatePrAgentLabels } from '../../../utils/translate-pr-agent'; import { diff --git a/apps/desktop/src/renderer/src/components/chat/components/QueuedView.tsx b/apps/desktop/src/renderer/src/components/chat/components/QueuedView.tsx index 17fd2b4..446814a 100644 --- a/apps/desktop/src/renderer/src/components/chat/components/QueuedView.tsx +++ b/apps/desktop/src/renderer/src/components/chat/components/QueuedView.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { ReviewRunTool } from '@meebox/shared'; -import { CloseIcon } from '../../icons'; +import { CloseIcon } from '../../common/icons'; import { AskQuestion } from './shared'; /** diff --git a/apps/desktop/src/renderer/src/components/chat/components/RulePreviewModal.tsx b/apps/desktop/src/renderer/src/components/chat/components/RulePreviewModal.tsx index 2ea7fe0..c13190c 100644 --- a/apps/desktop/src/renderer/src/components/chat/components/RulePreviewModal.tsx +++ b/apps/desktop/src/renderer/src/components/chat/components/RulePreviewModal.tsx @@ -2,7 +2,7 @@ import { useTranslation } from 'react-i18next'; import ReactMarkdown from 'react-markdown'; import remarkBreaks from 'remark-breaks'; import remarkGfm from 'remark-gfm'; -import { mermaidComponents } from '../../markdownMermaid'; +import { mermaidComponents } from '../../common/markdownMermaid'; import { REMOTE_REHYPE_PLUGINS } from '../../../markdown'; import type { MatchedRule } from '../types'; diff --git a/apps/desktop/src/renderer/src/components/chat/components/RunResultView.tsx b/apps/desktop/src/renderer/src/components/chat/components/RunResultView.tsx index 81717f5..1a513af 100644 --- a/apps/desktop/src/renderer/src/components/chat/components/RunResultView.tsx +++ b/apps/desktop/src/renderer/src/components/chat/components/RunResultView.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { Finding, ReviewDraft, ReviewRun } from '@meebox/shared'; -import { RetryIcon } from '../../icons'; +import { RetryIcon } from '../../common/icons'; import { orderFindings } from '../utils/findings'; import { formatStartTime, formatTokens, runStatusLabel } from '../utils/format'; import { extractTokenUsage, type TokenUsage } from '../utils/tokens'; diff --git a/apps/desktop/src/renderer/src/components/chat/components/shared.tsx b/apps/desktop/src/renderer/src/components/chat/components/shared.tsx index e6a2b2a..323c53f 100644 --- a/apps/desktop/src/renderer/src/components/chat/components/shared.tsx +++ b/apps/desktop/src/renderer/src/components/chat/components/shared.tsx @@ -3,8 +3,8 @@ import { useTranslation } from 'react-i18next'; import ReactMarkdown from 'react-markdown'; import remarkBreaks from 'remark-breaks'; import remarkGfm from 'remark-gfm'; -import { QuestionIcon } from '../../icons'; -import { mermaidComponents } from '../../markdownMermaid'; +import { QuestionIcon } from '../../common/icons'; +import { mermaidComponents } from '../../common/markdownMermaid'; import { REMOTE_REHYPE_PLUGINS } from '../../../markdown'; import { parseAnsi, segmentStyle } from '../../../utils/ansi'; diff --git a/apps/desktop/src/renderer/src/components/CommentEditEditor.tsx b/apps/desktop/src/renderer/src/components/comments/CommentEditEditor.tsx similarity index 99% rename from apps/desktop/src/renderer/src/components/CommentEditEditor.tsx rename to apps/desktop/src/renderer/src/components/comments/CommentEditEditor.tsx index e5ab58a..e613a4e 100644 --- a/apps/desktop/src/renderer/src/components/CommentEditEditor.tsx +++ b/apps/desktop/src/renderer/src/components/comments/CommentEditEditor.tsx @@ -1,6 +1,6 @@ import { useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { invoke } from '../api'; +import { invoke } from '../../api'; interface CommentEditEditorProps { prLocalId: string; diff --git a/apps/desktop/src/renderer/src/components/CommentReplyEditor.tsx b/apps/desktop/src/renderer/src/components/comments/CommentReplyEditor.tsx similarity index 98% rename from apps/desktop/src/renderer/src/components/CommentReplyEditor.tsx rename to apps/desktop/src/renderer/src/components/comments/CommentReplyEditor.tsx index 0deb1af..29581f3 100644 --- a/apps/desktop/src/renderer/src/components/CommentReplyEditor.tsx +++ b/apps/desktop/src/renderer/src/components/comments/CommentReplyEditor.tsx @@ -1,6 +1,6 @@ import { useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { invoke } from '../api'; +import { invoke } from '../../api'; interface CommentReplyEditorProps { prLocalId: string; diff --git a/apps/desktop/src/renderer/src/components/CommentsPanel.tsx b/apps/desktop/src/renderer/src/components/comments/CommentsPanel.tsx similarity index 97% rename from apps/desktop/src/renderer/src/components/CommentsPanel.tsx rename to apps/desktop/src/renderer/src/components/comments/CommentsPanel.tsx index 8c18fa7..56a15cd 100644 --- a/apps/desktop/src/renderer/src/components/CommentsPanel.tsx +++ b/apps/desktop/src/renderer/src/components/comments/CommentsPanel.tsx @@ -4,16 +4,16 @@ import ReactMarkdown from 'react-markdown'; import remarkBreaks from 'remark-breaks'; import remarkGfm from 'remark-gfm'; import type { PlatformCapabilities, PrComment, StoredPullRequest } from '@meebox/shared'; -import { invoke, subscribe } from '../api'; -import i18n from '../i18n'; -import { formatBackendError, type FormattedError } from '../errors'; -import { REMOTE_REHYPE_PLUGINS } from '../markdown'; -import { Avatar } from './Avatar'; -import { makeBitbucketImageFor, transformBitbucketUrl } from './BitbucketImage'; +import { invoke, subscribe } from '../../api'; +import i18n from '../../i18n'; +import { formatBackendError, type FormattedError } from '../../errors'; +import { REMOTE_REHYPE_PLUGINS } from '../../markdown'; +import { Avatar } from '../common/Avatar'; +import { makeBitbucketImageFor, transformBitbucketUrl } from '../common/BitbucketImage'; import { CommentEditEditor } from './CommentEditEditor'; import { CommentReplyEditor } from './CommentReplyEditor'; -import { ConfirmModal } from './ConfirmModal'; -import { mermaidComponents } from './markdownMermaid'; +import { ConfirmModal } from '../common/ConfirmModal'; +import { mermaidComponents } from '../common/markdownMermaid'; // 行内代码上下文用 Monaco,懒加载随 DiffView 同一套 Monaco chunk 按需拉取,不进入口包。 const InlineCodeContext = lazy(() => import('./InlineCodeContext').then((m) => ({ default: m.InlineCodeContext })), diff --git a/apps/desktop/src/renderer/src/components/InlineCodeContext.tsx b/apps/desktop/src/renderer/src/components/comments/InlineCodeContext.tsx similarity index 97% rename from apps/desktop/src/renderer/src/components/InlineCodeContext.tsx rename to apps/desktop/src/renderer/src/components/comments/InlineCodeContext.tsx index b4c0c32..af99dd9 100644 --- a/apps/desktop/src/renderer/src/components/InlineCodeContext.tsx +++ b/apps/desktop/src/renderer/src/components/comments/InlineCodeContext.tsx @@ -1,14 +1,14 @@ // 必须在用到 @monaco-editor/react 之前执行(见 DiffView 同款说明)。本文件经 // React.lazy 动态加载 → Monaco 随本 chunk 按需拉取,不进入口包。 -import '../monaco-setup'; +import '../../monaco-setup'; import { Editor, type Monaco } from '@monaco-editor/react'; import type { editor } from 'monaco-editor'; import { memo, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { PrCommentAnchor, StoredPullRequest } from '@meebox/shared'; -import { invoke } from '../api'; -import { editorFontSize } from '../editor-font'; -import { languageFor } from '../utils/language'; +import { invoke } from '../../api'; +import { editorFontSize } from '../../editor-font'; +import { languageFor } from '../../utils/language'; interface InlineCodeContextProps { pr: StoredPullRequest; diff --git a/apps/desktop/src/renderer/src/components/Avatar.tsx b/apps/desktop/src/renderer/src/components/common/Avatar.tsx similarity index 99% rename from apps/desktop/src/renderer/src/components/Avatar.tsx rename to apps/desktop/src/renderer/src/components/common/Avatar.tsx index 59e5471..f8fbc1d 100644 --- a/apps/desktop/src/renderer/src/components/Avatar.tsx +++ b/apps/desktop/src/renderer/src/components/common/Avatar.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react'; -import { invoke } from '../api'; +import { invoke } from '../../api'; interface AvatarProps { connectionId: string; diff --git a/apps/desktop/src/renderer/src/components/BitbucketImage.tsx b/apps/desktop/src/renderer/src/components/common/BitbucketImage.tsx similarity index 99% rename from apps/desktop/src/renderer/src/components/BitbucketImage.tsx rename to apps/desktop/src/renderer/src/components/common/BitbucketImage.tsx index dc5ef78..9ff3dec 100644 --- a/apps/desktop/src/renderer/src/components/BitbucketImage.tsx +++ b/apps/desktop/src/renderer/src/components/common/BitbucketImage.tsx @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react'; import { createPortal } from 'react-dom'; import { useTranslation } from 'react-i18next'; -import { invoke } from '../api'; +import { invoke } from '../../api'; /** * react-markdown 默认 url sanitize 只允许 http/https/mailto/tel 协议, diff --git a/apps/desktop/src/renderer/src/components/ConfirmModal.tsx b/apps/desktop/src/renderer/src/components/common/ConfirmModal.tsx similarity index 100% rename from apps/desktop/src/renderer/src/components/ConfirmModal.tsx rename to apps/desktop/src/renderer/src/components/common/ConfirmModal.tsx diff --git a/apps/desktop/src/renderer/src/components/ErrorBoundary.tsx b/apps/desktop/src/renderer/src/components/common/ErrorBoundary.tsx similarity index 100% rename from apps/desktop/src/renderer/src/components/ErrorBoundary.tsx rename to apps/desktop/src/renderer/src/components/common/ErrorBoundary.tsx diff --git a/apps/desktop/src/renderer/src/components/LlmProviderIcon.tsx b/apps/desktop/src/renderer/src/components/common/LlmProviderIcon.tsx similarity index 100% rename from apps/desktop/src/renderer/src/components/LlmProviderIcon.tsx rename to apps/desktop/src/renderer/src/components/common/LlmProviderIcon.tsx diff --git a/apps/desktop/src/renderer/src/components/Loading.tsx b/apps/desktop/src/renderer/src/components/common/Loading.tsx similarity index 100% rename from apps/desktop/src/renderer/src/components/Loading.tsx rename to apps/desktop/src/renderer/src/components/common/Loading.tsx diff --git a/apps/desktop/src/renderer/src/components/MermaidDiagram.tsx b/apps/desktop/src/renderer/src/components/common/MermaidDiagram.tsx similarity index 100% rename from apps/desktop/src/renderer/src/components/MermaidDiagram.tsx rename to apps/desktop/src/renderer/src/components/common/MermaidDiagram.tsx diff --git a/apps/desktop/src/renderer/src/components/PlatformIcon.tsx b/apps/desktop/src/renderer/src/components/common/PlatformIcon.tsx similarity index 100% rename from apps/desktop/src/renderer/src/components/PlatformIcon.tsx rename to apps/desktop/src/renderer/src/components/common/PlatformIcon.tsx diff --git a/apps/desktop/src/renderer/src/components/icons.tsx b/apps/desktop/src/renderer/src/components/common/icons.tsx similarity index 100% rename from apps/desktop/src/renderer/src/components/icons.tsx rename to apps/desktop/src/renderer/src/components/common/icons.tsx diff --git a/apps/desktop/src/renderer/src/components/markdownMermaid.tsx b/apps/desktop/src/renderer/src/components/common/markdownMermaid.tsx similarity index 100% rename from apps/desktop/src/renderer/src/components/markdownMermaid.tsx rename to apps/desktop/src/renderer/src/components/common/markdownMermaid.tsx diff --git a/apps/desktop/src/renderer/src/components/DiffSearchPanel.tsx b/apps/desktop/src/renderer/src/components/diff/DiffSearchPanel.tsx similarity index 99% rename from apps/desktop/src/renderer/src/components/DiffSearchPanel.tsx rename to apps/desktop/src/renderer/src/components/diff/DiffSearchPanel.tsx index 3b7b7fe..8e6b99d 100644 --- a/apps/desktop/src/renderer/src/components/DiffSearchPanel.tsx +++ b/apps/desktop/src/renderer/src/components/diff/DiffSearchPanel.tsx @@ -3,8 +3,8 @@ import { useTranslation } from 'react-i18next'; import type { TFunction } from 'i18next'; import { editor as MonacoEditorNs } from 'monaco-editor'; import type { DiffChangedFile } from '@meebox/shared'; -import { invoke } from '../api'; -import { languageFor } from '../utils/language'; +import { invoke } from '../../api'; +import { languageFor } from '../../utils/language'; /** * 搜索 PR diff 全部变更文件内容。仿 Bitbucket "Search code" 入口的行为: diff --git a/apps/desktop/src/renderer/src/components/DiffView.tsx b/apps/desktop/src/renderer/src/components/diff/DiffView.tsx similarity index 98% rename from apps/desktop/src/renderer/src/components/DiffView.tsx rename to apps/desktop/src/renderer/src/components/diff/DiffView.tsx index acad950..9d0dbbc 100644 --- a/apps/desktop/src/renderer/src/components/DiffView.tsx +++ b/apps/desktop/src/renderer/src/components/diff/DiffView.tsx @@ -1,6 +1,6 @@ // 必须在用到 @monaco-editor/react 之前执行(loader.config 指向本地 monaco)。 // 本文件经 React.lazy 动态加载,故 Monaco 随本 chunk 按需拉取,不进入口包。 -import '../monaco-setup'; +import '../../monaco-setup'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { createRoot, type Root } from 'react-dom/client'; @@ -21,23 +21,23 @@ import type { SyncProgressEvent, } from '@meebox/shared'; import { policyForPlatform } from '@meebox/shared'; -import { invoke, subscribe } from '../api'; -import { editorFontSize } from '../editor-font'; -import { formatBackendError, type FormattedError } from '../errors'; -import { REMOTE_REHYPE_PLUGINS } from '../markdown'; -import { useDraftsForPr } from '../stores/drafts-store'; -import { Avatar } from './Avatar'; -import { DraftZone } from './DraftZone'; -import { ErrorBoundary } from './ErrorBoundary'; -import { makeBitbucketImageFor, transformBitbucketUrl } from './BitbucketImage'; -import { CommentEditEditor } from './CommentEditEditor'; -import { CommentReplyEditor } from './CommentReplyEditor'; -import { ConfirmModal } from './ConfirmModal'; +import { invoke, subscribe } from '../../api'; +import { editorFontSize } from '../../editor-font'; +import { formatBackendError, type FormattedError } from '../../errors'; +import { REMOTE_REHYPE_PLUGINS } from '../../markdown'; +import { useDraftsForPr } from '../../stores/drafts-store'; +import { Avatar } from '../common/Avatar'; +import { DraftZone } from '../drafts/DraftZone'; +import { ErrorBoundary } from '../common/ErrorBoundary'; +import { makeBitbucketImageFor, transformBitbucketUrl } from '../common/BitbucketImage'; +import { CommentEditEditor } from '../comments/CommentEditEditor'; +import { CommentReplyEditor } from '../comments/CommentReplyEditor'; +import { ConfirmModal } from '../common/ConfirmModal'; import { DiffSearchPanel } from './DiffSearchPanel'; import { FileTree } from './FileTree'; -import { PaneLoading } from './Loading'; -import { FileTreeIcon, SearchIcon } from './icons'; -import { languageFor } from '../utils/language'; +import { PaneLoading } from '../common/Loading'; +import { FileTreeIcon, SearchIcon } from '../common/icons'; +import { languageFor } from '../../utils/language'; interface DiffViewProps { pr: StoredPullRequest; diff --git a/apps/desktop/src/renderer/src/components/FileTree.tsx b/apps/desktop/src/renderer/src/components/diff/FileTree.tsx similarity index 99% rename from apps/desktop/src/renderer/src/components/FileTree.tsx rename to apps/desktop/src/renderer/src/components/diff/FileTree.tsx index a4eaa3d..1a82781 100644 --- a/apps/desktop/src/renderer/src/components/FileTree.tsx +++ b/apps/desktop/src/renderer/src/components/diff/FileTree.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'; import type { TFunction } from 'i18next'; import { Icon } from '@iconify/react'; import type { DiffChangedFile } from '@meebox/shared'; -import { ChevronIcon } from './icons'; +import { ChevronIcon } from '../common/icons'; interface FileTreeProps { files: DiffChangedFile[]; diff --git a/apps/desktop/src/renderer/src/components/DraftZone.tsx b/apps/desktop/src/renderer/src/components/drafts/DraftZone.tsx similarity index 99% rename from apps/desktop/src/renderer/src/components/DraftZone.tsx rename to apps/desktop/src/renderer/src/components/drafts/DraftZone.tsx index e93d06d..b12ed10 100644 --- a/apps/desktop/src/renderer/src/components/DraftZone.tsx +++ b/apps/desktop/src/renderer/src/components/drafts/DraftZone.tsx @@ -4,8 +4,8 @@ import ReactMarkdown from 'react-markdown'; import remarkBreaks from 'remark-breaks'; import remarkGfm from 'remark-gfm'; import type { ReviewDraft } from '@meebox/shared'; -import { ConfirmModal } from './ConfirmModal'; -import { TrashIcon } from './icons'; +import { ConfirmModal } from '../common/ConfirmModal'; +import { TrashIcon } from '../common/icons'; interface DraftZoneProps { draft: ReviewDraft; diff --git a/apps/desktop/src/renderer/src/components/DraftsPanel.tsx b/apps/desktop/src/renderer/src/components/drafts/DraftsPanel.tsx similarity index 98% rename from apps/desktop/src/renderer/src/components/DraftsPanel.tsx rename to apps/desktop/src/renderer/src/components/drafts/DraftsPanel.tsx index 0d28354..6453bcd 100644 --- a/apps/desktop/src/renderer/src/components/DraftsPanel.tsx +++ b/apps/desktop/src/renderer/src/components/drafts/DraftsPanel.tsx @@ -4,9 +4,9 @@ import ReactMarkdown from 'react-markdown'; import remarkBreaks from 'remark-breaks'; import remarkGfm from 'remark-gfm'; import type { PlatformCapabilities, ReviewDraft, StoredPullRequest } from '@meebox/shared'; -import { invoke } from '../api'; -import { useDraftsForPr } from '../stores/drafts-store'; -import { ConfirmModal } from './ConfirmModal'; +import { invoke } from '../../api'; +import { useDraftsForPr } from '../../stores/drafts-store'; +import { ConfirmModal } from '../common/ConfirmModal'; // posted 已不存在 (发布成功即删本地),筛选项只保留 publishable / all / rejected type Filter = 'all' | 'publishable' | 'rejected'; diff --git a/apps/desktop/src/renderer/src/components/PublishReviewModal.tsx b/apps/desktop/src/renderer/src/components/drafts/PublishReviewModal.tsx similarity index 99% rename from apps/desktop/src/renderer/src/components/PublishReviewModal.tsx rename to apps/desktop/src/renderer/src/components/drafts/PublishReviewModal.tsx index 37ba806..f9e5ca8 100644 --- a/apps/desktop/src/renderer/src/components/PublishReviewModal.tsx +++ b/apps/desktop/src/renderer/src/components/drafts/PublishReviewModal.tsx @@ -1,7 +1,7 @@ import { useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { ReviewDraft } from '@meebox/shared'; -import { invoke } from '../api'; +import { invoke } from '../../api'; /** * 批量发布草稿到 Bitbucket 的确认 modal。M4 发布闭环最后一公里。 diff --git a/apps/desktop/src/renderer/src/components/MainPane.tsx b/apps/desktop/src/renderer/src/components/layout/MainPane.tsx similarity index 97% rename from apps/desktop/src/renderer/src/components/MainPane.tsx rename to apps/desktop/src/renderer/src/components/layout/MainPane.tsx index d7da308..b0f6f3d 100644 --- a/apps/desktop/src/renderer/src/components/MainPane.tsx +++ b/apps/desktop/src/renderer/src/components/layout/MainPane.tsx @@ -6,17 +6,17 @@ import type { ReviewerStatus, StoredPullRequest, } from '@meebox/shared'; -import { invoke } from '../api'; -import { useDraftsForPr } from '../stores/drafts-store'; -import { CommentsPanel } from './CommentsPanel'; -import { CommitsPanel } from './CommitsPanel'; +import { invoke } from '../../api'; +import { useDraftsForPr } from '../../stores/drafts-store'; +import { CommentsPanel } from '../comments/CommentsPanel'; +import { CommitsPanel } from '../pr/CommitsPanel'; // Monaco 编辑器(~10MB)懒加载:只有真正切到 Diff tab 才拉取 DiffView chunk, // 不阻塞窗口首帧 / PR 列表 / 首启向导。 -const DiffView = lazy(() => import('./DiffView').then((m) => ({ default: m.DiffView }))); -import { DraftsPanel } from './DraftsPanel'; -import { PaneLoading } from './Loading'; -import { PrInfoView } from './PrInfoView'; -import { PublishReviewModal } from './PublishReviewModal'; +const DiffView = lazy(() => import('../diff/DiffView').then((m) => ({ default: m.DiffView }))); +import { DraftsPanel } from '../drafts/DraftsPanel'; +import { PaneLoading } from '../common/Loading'; +import { PrInfoView } from '../pr/PrInfoView'; +import { PublishReviewModal } from '../drafts/PublishReviewModal'; import { ApproveIcon, GlobeIcon, @@ -24,7 +24,7 @@ import { PersonIcon, PullRequestIcon, WhitespaceIcon, -} from './icons'; +} from '../common/icons'; interface MainPaneProps { pr: StoredPullRequest | null; diff --git a/apps/desktop/src/renderer/src/components/Sidebar.tsx b/apps/desktop/src/renderer/src/components/layout/Sidebar.tsx similarity index 98% rename from apps/desktop/src/renderer/src/components/Sidebar.tsx rename to apps/desktop/src/renderer/src/components/layout/Sidebar.tsx index 349dc48..f27eafc 100644 --- a/apps/desktop/src/renderer/src/components/Sidebar.tsx +++ b/apps/desktop/src/renderer/src/components/layout/Sidebar.tsx @@ -6,9 +6,9 @@ import type { PrDiscoveryFilter, StoredPullRequest, } from '@meebox/shared'; -import { invoke, subscribe } from '../api'; -import { useChatRunStore } from '../stores/chat-run-store'; -import { PrItem } from './PrItem'; +import { invoke, subscribe } from '../../api'; +import { useChatRunStore } from '../../stores/chat-run-store'; +import { PrItem } from '../pr/PrItem'; // 'conflict' / 'mergeable' 是按远端 merge 状态跨 localStatus 横切的筛选;'all' 不限定 type FilterKey = 'all' | LocalPrStatus | 'conflict' | 'mergeable'; diff --git a/apps/desktop/src/renderer/src/components/StatusBar.tsx b/apps/desktop/src/renderer/src/components/layout/StatusBar.tsx similarity index 99% rename from apps/desktop/src/renderer/src/components/StatusBar.tsx rename to apps/desktop/src/renderer/src/components/layout/StatusBar.tsx index 5aeca64..6f5d9d4 100644 --- a/apps/desktop/src/renderer/src/components/StatusBar.tsx +++ b/apps/desktop/src/renderer/src/components/layout/StatusBar.tsx @@ -2,9 +2,9 @@ import { useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { TFunction } from 'i18next'; import type { Config, ConnectionSummary, PrAgentStatus, UpdateCheckResult } from '@meebox/shared'; -import { invoke } from '../api'; -import { useChatRunStore } from '../stores/chat-run-store'; -import { useRepoSyncStore } from '../stores/repo-sync-store'; +import { invoke } from '../../api'; +import { useChatRunStore } from '../../stores/chat-run-store'; +import { useRepoSyncStore } from '../../stores/repo-sync-store'; import { PanelToggleIcon, PersonIcon, @@ -13,7 +13,7 @@ import { RobotOffIcon, SettingsIcon, SyncIcon, -} from './icons'; +} from '../common/icons'; interface StatusBarProps { prsCount: number; diff --git a/apps/desktop/src/renderer/src/components/TitleBar.tsx b/apps/desktop/src/renderer/src/components/layout/TitleBar.tsx similarity index 100% rename from apps/desktop/src/renderer/src/components/TitleBar.tsx rename to apps/desktop/src/renderer/src/components/layout/TitleBar.tsx diff --git a/apps/desktop/src/renderer/src/components/onboarding/OnboardingWizard.tsx b/apps/desktop/src/renderer/src/components/onboarding/OnboardingWizard.tsx index 5ebdef8..5794127 100644 --- a/apps/desktop/src/renderer/src/components/onboarding/OnboardingWizard.tsx +++ b/apps/desktop/src/renderer/src/components/onboarding/OnboardingWizard.tsx @@ -8,8 +8,8 @@ import { fromConnDraft, type ConnDraft, type ConnEntry, -} from '../ConnectionForm'; -import { newProfileId } from '../LlmProfileForm'; +} from '../settings/ConnectionForm'; +import { newProfileId } from '../settings/LlmProfileForm'; import { WelcomeStep } from './steps/WelcomeStep'; import { PlatformStep } from './steps/PlatformStep'; import { LlmStep } from './steps/LlmStep'; diff --git a/apps/desktop/src/renderer/src/components/onboarding/steps/DoneStep.tsx b/apps/desktop/src/renderer/src/components/onboarding/steps/DoneStep.tsx index b9c3cf0..39d6634 100644 --- a/apps/desktop/src/renderer/src/components/onboarding/steps/DoneStep.tsx +++ b/apps/desktop/src/renderer/src/components/onboarding/steps/DoneStep.tsx @@ -1,5 +1,5 @@ import { useTranslation } from 'react-i18next'; -import { SuccessBadgeIcon } from '../../icons'; +import { SuccessBadgeIcon } from '../../common/icons'; export function DoneStep({ submitting, error }: { submitting: boolean; error: string | null }) { const { t } = useTranslation(); diff --git a/apps/desktop/src/renderer/src/components/onboarding/steps/LlmStep.tsx b/apps/desktop/src/renderer/src/components/onboarding/steps/LlmStep.tsx index 7eb409e..1d78c23 100644 --- a/apps/desktop/src/renderer/src/components/onboarding/steps/LlmStep.tsx +++ b/apps/desktop/src/renderer/src/components/onboarding/steps/LlmStep.tsx @@ -1,8 +1,8 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { LlmProfile } from '@meebox/shared'; -import { LLM_PROVIDERS, LlmProfileForm } from '../../LlmProfileForm'; -import { LlmProviderIcon } from '../../LlmProviderIcon'; +import { LLM_PROVIDERS, LlmProfileForm } from '../../settings/LlmProfileForm'; +import { LlmProviderIcon } from '../../common/LlmProviderIcon'; export function LlmStep({ draft, diff --git a/apps/desktop/src/renderer/src/components/onboarding/steps/PlatformStep.tsx b/apps/desktop/src/renderer/src/components/onboarding/steps/PlatformStep.tsx index 7bcacff..3f75689 100644 --- a/apps/desktop/src/renderer/src/components/onboarding/steps/PlatformStep.tsx +++ b/apps/desktop/src/renderer/src/components/onboarding/steps/PlatformStep.tsx @@ -1,8 +1,8 @@ import { useTranslation } from 'react-i18next'; import { invoke } from '../../../api'; -import { ConnectionForm, type ConnDraft } from '../../ConnectionForm'; -import { PLATFORM_META } from '../../PlatformIcon'; -import { FolderIcon } from '../../icons'; +import { ConnectionForm, type ConnDraft } from '../../settings/ConnectionForm'; +import { PLATFORM_META } from '../../common/PlatformIcon'; +import { FolderIcon } from '../../common/icons'; export function PlatformStep({ connDraft, diff --git a/apps/desktop/src/renderer/src/components/onboarding/steps/WelcomeStep.tsx b/apps/desktop/src/renderer/src/components/onboarding/steps/WelcomeStep.tsx index e6195c0..e643f15 100644 --- a/apps/desktop/src/renderer/src/components/onboarding/steps/WelcomeStep.tsx +++ b/apps/desktop/src/renderer/src/components/onboarding/steps/WelcomeStep.tsx @@ -1,7 +1,7 @@ import { useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { invoke } from '../../../api'; -import { PullRequestIcon } from '../../icons'; +import { PullRequestIcon } from '../../common/icons'; export function WelcomeStep({ onStart }: { onStart: () => void }) { const { t } = useTranslation(); diff --git a/apps/desktop/src/renderer/src/components/CommitsPanel.tsx b/apps/desktop/src/renderer/src/components/pr/CommitsPanel.tsx similarity index 96% rename from apps/desktop/src/renderer/src/components/CommitsPanel.tsx rename to apps/desktop/src/renderer/src/components/pr/CommitsPanel.tsx index 96c79d6..96b83a5 100644 --- a/apps/desktop/src/renderer/src/components/CommitsPanel.tsx +++ b/apps/desktop/src/renderer/src/components/pr/CommitsPanel.tsx @@ -2,9 +2,9 @@ import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { TFunction } from 'i18next'; import type { PrCommit, StoredPullRequest } from '@meebox/shared'; -import { invoke } from '../api'; -import { formatBackendError, type FormattedError } from '../errors'; -import { Avatar } from './Avatar'; +import { invoke } from '../../api'; +import { formatBackendError, type FormattedError } from '../../errors'; +import { Avatar } from '../common/Avatar'; interface CommitsPanelProps { pr: StoredPullRequest; diff --git a/apps/desktop/src/renderer/src/components/PrInfoView.tsx b/apps/desktop/src/renderer/src/components/pr/PrInfoView.tsx similarity index 93% rename from apps/desktop/src/renderer/src/components/PrInfoView.tsx rename to apps/desktop/src/renderer/src/components/pr/PrInfoView.tsx index cdf64ab..31c8933 100644 --- a/apps/desktop/src/renderer/src/components/PrInfoView.tsx +++ b/apps/desktop/src/renderer/src/components/pr/PrInfoView.tsx @@ -2,9 +2,9 @@ import { useMemo } from 'react'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import type { ReviewerStatus, StoredPullRequest } from '@meebox/shared'; -import { REMOTE_REHYPE_PLUGINS } from '../markdown'; -import { makeBitbucketImageFor, transformBitbucketUrl } from './BitbucketImage'; -import { mermaidComponents } from './markdownMermaid'; +import { REMOTE_REHYPE_PLUGINS } from '../../markdown'; +import { makeBitbucketImageFor, transformBitbucketUrl } from '../common/BitbucketImage'; +import { mermaidComponents } from '../common/markdownMermaid'; interface PrInfoViewProps { pr: StoredPullRequest; diff --git a/apps/desktop/src/renderer/src/components/PrItem.tsx b/apps/desktop/src/renderer/src/components/pr/PrItem.tsx similarity index 97% rename from apps/desktop/src/renderer/src/components/PrItem.tsx rename to apps/desktop/src/renderer/src/components/pr/PrItem.tsx index a6f3421..91d88d9 100644 --- a/apps/desktop/src/renderer/src/components/PrItem.tsx +++ b/apps/desktop/src/renderer/src/components/pr/PrItem.tsx @@ -1,7 +1,7 @@ import { useTranslation } from 'react-i18next'; import type { AgentRecommendationVerdict, StoredPullRequest } from '@meebox/shared'; -import { Avatar } from './Avatar'; -import { PersonIcon, PullRequestIcon, StarIcon } from './icons'; +import { Avatar } from '../common/Avatar'; +import { PersonIcon, PullRequestIcon, StarIcon } from '../common/icons'; /** 评审建议 verdict → 复用 chatPane.agent.* 文案(不另加 i18n)。 */ const VERDICT_TITLE: Record = { diff --git a/apps/desktop/src/renderer/src/components/ConnectionForm.tsx b/apps/desktop/src/renderer/src/components/settings/ConnectionForm.tsx similarity index 98% rename from apps/desktop/src/renderer/src/components/ConnectionForm.tsx rename to apps/desktop/src/renderer/src/components/settings/ConnectionForm.tsx index b666abb..aab6442 100644 --- a/apps/desktop/src/renderer/src/components/ConnectionForm.tsx +++ b/apps/desktop/src/renderer/src/components/settings/ConnectionForm.tsx @@ -2,8 +2,8 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { TFunction } from 'i18next'; import { GITHUB_DOTCOM_API_BASE, GITLAB_DOTCOM_API_BASE, type Config } from '@meebox/shared'; -import { invoke } from '../api'; -import { EyeIcon, EyeOffIcon } from './icons'; +import { invoke } from '../../api'; +import { EyeIcon, EyeOffIcon } from '../common/icons'; // 连接编辑用的扁平草稿(Connection 是嵌套的 auth/clone,拍平后表单好写),存盘前还原。 // 设置页 ConnectionEditorModal 与首启向导 PlatformStep 共用同一份草稿形状 + 表单。 diff --git a/apps/desktop/src/renderer/src/components/LlmProfileForm.tsx b/apps/desktop/src/renderer/src/components/settings/LlmProfileForm.tsx similarity index 99% rename from apps/desktop/src/renderer/src/components/LlmProfileForm.tsx rename to apps/desktop/src/renderer/src/components/settings/LlmProfileForm.tsx index 36cf3fa..521206b 100644 --- a/apps/desktop/src/renderer/src/components/LlmProfileForm.tsx +++ b/apps/desktop/src/renderer/src/components/settings/LlmProfileForm.tsx @@ -1,8 +1,8 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { LlmProfile, LlmProvider } from '@meebox/shared'; -import i18n from '../i18n'; -import { EyeIcon, EyeOffIcon } from './icons'; +import i18n from '../../i18n'; +import { EyeIcon, EyeOffIcon } from '../common/icons'; export interface ProviderMeta { value: LlmProvider; diff --git a/apps/desktop/src/renderer/src/components/SettingsModal.tsx b/apps/desktop/src/renderer/src/components/settings/SettingsModal.tsx similarity index 99% rename from apps/desktop/src/renderer/src/components/SettingsModal.tsx rename to apps/desktop/src/renderer/src/components/settings/SettingsModal.tsx index 016f189..5da65b3 100644 --- a/apps/desktop/src/renderer/src/components/SettingsModal.tsx +++ b/apps/desktop/src/renderer/src/components/settings/SettingsModal.tsx @@ -9,9 +9,9 @@ import { type SupportedLanguage, type UpdateCheckResult, } from '@meebox/shared'; -import { invoke } from '../api'; -import i18n, { persistLanguage, resolveUiLanguage } from '../i18n'; -import { ConfirmModal } from './ConfirmModal'; +import { invoke } from '../../api'; +import i18n, { persistLanguage, resolveUiLanguage } from '../../i18n'; +import { ConfirmModal } from '../common/ConfirmModal'; import { ConnectionForm, connDraftCanSave, @@ -30,9 +30,9 @@ import { PencilIcon, TagIcon, TrashIcon, -} from './icons'; -import { LlmProviderIcon } from './LlmProviderIcon'; -import { PLATFORM_META } from './PlatformIcon'; +} from '../common/icons'; +import { LlmProviderIcon } from '../common/LlmProviderIcon'; +import { PLATFORM_META } from '../common/PlatformIcon'; interface SettingsModalProps { info: AppInfo; From 050507902bd047bb6e96fb6ab7be4038bad54988 Mon Sep 17 00:00:00 2001 From: Hamhire Hu Date: Thu, 18 Jun 2026 13:49:19 +0800 Subject: [PATCH 2/2] =?UTF-8?q?refactor(components):=20=E4=B8=9A=E5=8A=A1?= =?UTF-8?q?=E9=A2=86=E5=9F=9F=E7=9B=AE=E5=BD=95=E5=BD=92=E5=85=A5=20featur?= =?UTF-8?q?es/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 承接上一步的领域拆分,把强业务属性的领域目录统一收进 features/,与 common/(基础公共 UI)、layout/(应用骨架)三类平级: components/ ├── common/ ├── layout/ └── features/{ pr · diff · comments · drafts · settings · chat · onboarding } 顶层只剩 common / layout / features 三个桶,分类轴统一(kind vs 业务领域不再混层)。 纯目录迁移 + import 路径改写(git 识别为 rename),无逻辑/界面变更。 Co-Authored-By: Claude Opus 4.8 (1M context) --- CHANGELOG.md | 3 ++- apps/desktop/src/renderer/src/App.tsx | 6 ++--- .../{ => features}/chat/ChatPane.tsx | 10 +++---- .../{ => features}/chat/commands.ts | 0 .../chat/components/AgentStep.tsx | 2 +- .../chat/components/ChatEmpty.tsx | 2 +- .../chat/components/ChatInputBar.tsx | 2 +- .../chat/components/ConversationMessage.tsx | 2 +- .../chat/components/FindingCard.tsx | 8 +++--- .../chat/components/QueuedView.tsx | 2 +- .../chat/components/RulePreviewModal.tsx | 4 +-- .../chat/components/RunResultView.tsx | 2 +- .../chat/components/RunningView.tsx | 0 .../{ => features}/chat/components/shared.tsx | 8 +++--- .../{ => features}/chat/constants.ts | 0 .../chat/hooks/useChatActions.ts | 2 +- .../chat/hooks/useChatSession.ts | 2 +- .../chat/hooks/useChatTimeline.ts | 0 .../components/{ => features}/chat/index.ts | 0 .../components/{ => features}/chat/types.ts | 0 .../{ => features}/chat/utils/chat-history.ts | 0 .../{ => features}/chat/utils/findings.ts | 0 .../{ => features}/chat/utils/format.ts | 0 .../{ => features}/chat/utils/tokens.ts | 0 .../comments/CommentEditEditor.tsx | 2 +- .../comments/CommentReplyEditor.tsx | 2 +- .../{ => features}/comments/CommentsPanel.tsx | 16 ++++++------ .../comments/InlineCodeContext.tsx | 8 +++--- .../{ => features}/diff/DiffSearchPanel.tsx | 4 +-- .../{ => features}/diff/DiffView.tsx | 26 +++++++++---------- .../{ => features}/diff/FileTree.tsx | 2 +- .../{ => features}/drafts/DraftZone.tsx | 4 +-- .../{ => features}/drafts/DraftsPanel.tsx | 6 ++--- .../drafts/PublishReviewModal.tsx | 2 +- .../onboarding/OnboardingWizard.tsx | 4 +-- .../onboarding/steps/DoneStep.tsx | 2 +- .../onboarding/steps/LlmStep.tsx | 2 +- .../onboarding/steps/PlatformStep.tsx | 6 ++--- .../onboarding/steps/WelcomeStep.tsx | 4 +-- .../{ => features}/pr/CommitsPanel.tsx | 6 ++--- .../{ => features}/pr/PrInfoView.tsx | 6 ++--- .../components/{ => features}/pr/PrItem.tsx | 4 +-- .../settings/ConnectionForm.tsx | 4 +-- .../settings/LlmProfileForm.tsx | 4 +-- .../{ => features}/settings/SettingsModal.tsx | 12 ++++----- .../src/components/layout/MainPane.tsx | 12 ++++----- .../src/components/layout/Sidebar.tsx | 2 +- 47 files changed, 98 insertions(+), 97 deletions(-) rename apps/desktop/src/renderer/src/components/{ => features}/chat/ChatPane.tsx (98%) rename apps/desktop/src/renderer/src/components/{ => features}/chat/commands.ts (100%) rename apps/desktop/src/renderer/src/components/{ => features}/chat/components/AgentStep.tsx (98%) rename apps/desktop/src/renderer/src/components/{ => features}/chat/components/ChatEmpty.tsx (98%) rename apps/desktop/src/renderer/src/components/{ => features}/chat/components/ChatInputBar.tsx (99%) rename apps/desktop/src/renderer/src/components/{ => features}/chat/components/ConversationMessage.tsx (97%) rename apps/desktop/src/renderer/src/components/{ => features}/chat/components/FindingCard.tsx (98%) rename apps/desktop/src/renderer/src/components/{ => features}/chat/components/QueuedView.tsx (96%) rename apps/desktop/src/renderer/src/components/{ => features}/chat/components/RulePreviewModal.tsx (92%) rename apps/desktop/src/renderer/src/components/{ => features}/chat/components/RunResultView.tsx (99%) rename apps/desktop/src/renderer/src/components/{ => features}/chat/components/RunningView.tsx (100%) rename apps/desktop/src/renderer/src/components/{ => features}/chat/components/shared.tsx (92%) rename apps/desktop/src/renderer/src/components/{ => features}/chat/constants.ts (100%) rename apps/desktop/src/renderer/src/components/{ => features}/chat/hooks/useChatActions.ts (99%) rename apps/desktop/src/renderer/src/components/{ => features}/chat/hooks/useChatSession.ts (99%) rename apps/desktop/src/renderer/src/components/{ => features}/chat/hooks/useChatTimeline.ts (100%) rename apps/desktop/src/renderer/src/components/{ => features}/chat/index.ts (100%) rename apps/desktop/src/renderer/src/components/{ => features}/chat/types.ts (100%) rename apps/desktop/src/renderer/src/components/{ => features}/chat/utils/chat-history.ts (100%) rename apps/desktop/src/renderer/src/components/{ => features}/chat/utils/findings.ts (100%) rename apps/desktop/src/renderer/src/components/{ => features}/chat/utils/format.ts (100%) rename apps/desktop/src/renderer/src/components/{ => features}/chat/utils/tokens.ts (100%) rename apps/desktop/src/renderer/src/components/{ => features}/comments/CommentEditEditor.tsx (99%) rename apps/desktop/src/renderer/src/components/{ => features}/comments/CommentReplyEditor.tsx (98%) rename apps/desktop/src/renderer/src/components/{ => features}/comments/CommentsPanel.tsx (97%) rename apps/desktop/src/renderer/src/components/{ => features}/comments/InlineCodeContext.tsx (97%) rename apps/desktop/src/renderer/src/components/{ => features}/diff/DiffSearchPanel.tsx (99%) rename apps/desktop/src/renderer/src/components/{ => features}/diff/DiffView.tsx (99%) rename apps/desktop/src/renderer/src/components/{ => features}/diff/FileTree.tsx (99%) rename apps/desktop/src/renderer/src/components/{ => features}/drafts/DraftZone.tsx (99%) rename apps/desktop/src/renderer/src/components/{ => features}/drafts/DraftsPanel.tsx (98%) rename apps/desktop/src/renderer/src/components/{ => features}/drafts/PublishReviewModal.tsx (99%) rename apps/desktop/src/renderer/src/components/{ => features}/onboarding/OnboardingWizard.tsx (99%) rename apps/desktop/src/renderer/src/components/{ => features}/onboarding/steps/DoneStep.tsx (92%) rename apps/desktop/src/renderer/src/components/{ => features}/onboarding/steps/LlmStep.tsx (97%) rename apps/desktop/src/renderer/src/components/{ => features}/onboarding/steps/PlatformStep.tsx (96%) rename apps/desktop/src/renderer/src/components/{ => features}/onboarding/steps/WelcomeStep.tsx (93%) rename apps/desktop/src/renderer/src/components/{ => features}/pr/CommitsPanel.tsx (96%) rename apps/desktop/src/renderer/src/components/{ => features}/pr/PrInfoView.tsx (95%) rename apps/desktop/src/renderer/src/components/{ => features}/pr/PrItem.tsx (97%) rename apps/desktop/src/renderer/src/components/{ => features}/settings/ConnectionForm.tsx (98%) rename apps/desktop/src/renderer/src/components/{ => features}/settings/LlmProfileForm.tsx (99%) rename apps/desktop/src/renderer/src/components/{ => features}/settings/SettingsModal.tsx (99%) diff --git a/CHANGELOG.md b/CHANGELOG.md index c45e52f..1543ed9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,8 @@ ### Changed - 聊天面板(PR Agent)内部重构:2578 行的单文件 `ChatPane.tsx` 按「容器 / 领域组件 / hooks / 工具方法」分层拆分到 `components/chat/`,状态与生命周期、业务动作、时间线归并各自成 hook,展示组件与工具方法独立成文件。对外接口与界面行为保持不变,仅改善可维护性;token 用量 ↑/↓ 的绿红色值一并从内联样式收进设计令牌与样式类。 -- 首启向导内部重构:`OnboardingWizard.tsx` 的四个步骤组件(欢迎 / 平台 / LLM / 完成)拆分到 `onboarding/steps/` 各自成文件,容器只留向导骨架(步骤指示 + 切换 + 导航)。对外接口与界面行为不变。 +- 首启向导内部重构:`OnboardingWizard.tsx` 的四个步骤组件(欢迎 / 平台 / LLM / 完成)拆分到 `steps/` 各自成文件,容器只留向导骨架(步骤指示 + 切换 + 导航)。对外接口与界面行为不变。 +- `components/` 目录按职责重组:扁平堆叠的组件归入三类——`common/`(基础公共 UI)、`layout/`(应用骨架)、`features/`(业务领域:pr / diff / comments / drafts / settings / chat / onboarding),顶层只剩这三个桶。纯文件位置调整 + import 路径改写,无逻辑 / 界面变更。 ### Fixed diff --git a/apps/desktop/src/renderer/src/App.tsx b/apps/desktop/src/renderer/src/App.tsx index dcefd91..4259f41 100644 --- a/apps/desktop/src/renderer/src/App.tsx +++ b/apps/desktop/src/renderer/src/App.tsx @@ -13,13 +13,13 @@ import type { UpdateCheckResult, } from '@meebox/shared'; import { invoke, subscribe } from './api'; -import { ChatPane, CHAT_MAX_WIDTH, CHAT_MIN_WIDTH } from './components/chat'; +import { ChatPane, CHAT_MAX_WIDTH, CHAT_MIN_WIDTH } from './components/features/chat'; import { wireChatRunStore } from './stores/chat-run-store'; import { wireDraftsStore } from './stores/drafts-store'; import { wireRepoSyncStore } from './stores/repo-sync-store'; import { MainPane } from './components/layout/MainPane'; -import { OnboardingWizard, type OnboardingResult } from './components/onboarding/OnboardingWizard'; -import { SettingsModal } from './components/settings/SettingsModal'; +import { OnboardingWizard, type OnboardingResult } from './components/features/onboarding/OnboardingWizard'; +import { SettingsModal } from './components/features/settings/SettingsModal'; import { Sidebar, SIDEBAR_MAX_WIDTH, SIDEBAR_MIN_WIDTH } from './components/layout/Sidebar'; import { StatusBar } from './components/layout/StatusBar'; import { TitleBar } from './components/layout/TitleBar'; diff --git a/apps/desktop/src/renderer/src/components/chat/ChatPane.tsx b/apps/desktop/src/renderer/src/components/features/chat/ChatPane.tsx similarity index 98% rename from apps/desktop/src/renderer/src/components/chat/ChatPane.tsx rename to apps/desktop/src/renderer/src/components/features/chat/ChatPane.tsx index 45a4062..8fc8c40 100644 --- a/apps/desktop/src/renderer/src/components/chat/ChatPane.tsx +++ b/apps/desktop/src/renderer/src/components/features/chat/ChatPane.tsx @@ -1,11 +1,11 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { LocalPrStatus, PrAgentStatus, StoredPullRequest } from '@meebox/shared'; -import { ChatIcon, TrashIcon } from '../common/icons'; -import { ConfirmModal } from '../common/ConfirmModal'; -import { PaneLoading } from '../common/Loading'; -import { useChatRunStore } from '../../stores/chat-run-store'; -import { useDraftsForPr } from '../../stores/drafts-store'; +import { ChatIcon, TrashIcon } from '../../common/icons'; +import { ConfirmModal } from '../../common/ConfirmModal'; +import { PaneLoading } from '../../common/Loading'; +import { useChatRunStore } from '../../../stores/chat-run-store'; +import { useDraftsForPr } from '../../../stores/drafts-store'; import { CHAT_MAX_WIDTH, CHAT_MIN_WIDTH } from './constants'; import { useChatSession } from './hooks/useChatSession'; import { useChatActions } from './hooks/useChatActions'; diff --git a/apps/desktop/src/renderer/src/components/chat/commands.ts b/apps/desktop/src/renderer/src/components/features/chat/commands.ts similarity index 100% rename from apps/desktop/src/renderer/src/components/chat/commands.ts rename to apps/desktop/src/renderer/src/components/features/chat/commands.ts diff --git a/apps/desktop/src/renderer/src/components/chat/components/AgentStep.tsx b/apps/desktop/src/renderer/src/components/features/chat/components/AgentStep.tsx similarity index 98% rename from apps/desktop/src/renderer/src/components/chat/components/AgentStep.tsx rename to apps/desktop/src/renderer/src/components/features/chat/components/AgentStep.tsx index 525682b..1c3c8d6 100644 --- a/apps/desktop/src/renderer/src/components/chat/components/AgentStep.tsx +++ b/apps/desktop/src/renderer/src/components/features/chat/components/AgentStep.tsx @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { AgentStep } from '@meebox/shared'; -import { RobotIcon } from '../../common/icons'; +import { RobotIcon } from '../../../common/icons'; import { formatElapsed, formatTokens } from '../utils/format'; import { Spinner } from './shared'; diff --git a/apps/desktop/src/renderer/src/components/chat/components/ChatEmpty.tsx b/apps/desktop/src/renderer/src/components/features/chat/components/ChatEmpty.tsx similarity index 98% rename from apps/desktop/src/renderer/src/components/chat/components/ChatEmpty.tsx rename to apps/desktop/src/renderer/src/components/features/chat/components/ChatEmpty.tsx index 67165b7..f3d351d 100644 --- a/apps/desktop/src/renderer/src/components/chat/components/ChatEmpty.tsx +++ b/apps/desktop/src/renderer/src/components/features/chat/components/ChatEmpty.tsx @@ -1,6 +1,6 @@ import { useTranslation } from 'react-i18next'; import type { PrAgentStatus, StoredPullRequest } from '@meebox/shared'; -import { ChatIcon } from '../../common/icons'; +import { ChatIcon } from '../../../common/icons'; import { Bullet } from './shared'; export function ChatEmpty({ diff --git a/apps/desktop/src/renderer/src/components/chat/components/ChatInputBar.tsx b/apps/desktop/src/renderer/src/components/features/chat/components/ChatInputBar.tsx similarity index 99% rename from apps/desktop/src/renderer/src/components/chat/components/ChatInputBar.tsx rename to apps/desktop/src/renderer/src/components/features/chat/components/ChatInputBar.tsx index 1ddd361..2616b37 100644 --- a/apps/desktop/src/renderer/src/components/chat/components/ChatInputBar.tsx +++ b/apps/desktop/src/renderer/src/components/features/chat/components/ChatInputBar.tsx @@ -1,7 +1,7 @@ import { useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { LocalPrStatus, PrAgentStatus, ReviewRunTool, StoredPullRequest } from '@meebox/shared'; -import { AutoReviewIcon, SendIcon, StopIcon } from '../../common/icons'; +import { AutoReviewIcon, SendIcon, StopIcon } from '../../../common/icons'; import { COMMANDS, type CommandSpec } from '../commands'; import { loadChatHistory, pushChatHistory } from '../utils/chat-history'; diff --git a/apps/desktop/src/renderer/src/components/chat/components/ConversationMessage.tsx b/apps/desktop/src/renderer/src/components/features/chat/components/ConversationMessage.tsx similarity index 97% rename from apps/desktop/src/renderer/src/components/chat/components/ConversationMessage.tsx rename to apps/desktop/src/renderer/src/components/features/chat/components/ConversationMessage.tsx index 74e61d5..54a06e6 100644 --- a/apps/desktop/src/renderer/src/components/chat/components/ConversationMessage.tsx +++ b/apps/desktop/src/renderer/src/components/features/chat/components/ConversationMessage.tsx @@ -1,6 +1,6 @@ import { useTranslation } from 'react-i18next'; import type { AgentMessage } from '@meebox/shared'; -import { ChatIcon } from '../../common/icons'; +import { ChatIcon } from '../../../common/icons'; import { VERDICT_LABEL_KEY } from '../constants'; import { Md } from './shared'; diff --git a/apps/desktop/src/renderer/src/components/chat/components/FindingCard.tsx b/apps/desktop/src/renderer/src/components/features/chat/components/FindingCard.tsx similarity index 98% rename from apps/desktop/src/renderer/src/components/chat/components/FindingCard.tsx rename to apps/desktop/src/renderer/src/components/features/chat/components/FindingCard.tsx index ee2d483..e8d325b 100644 --- a/apps/desktop/src/renderer/src/components/chat/components/FindingCard.tsx +++ b/apps/desktop/src/renderer/src/components/features/chat/components/FindingCard.tsx @@ -4,10 +4,10 @@ import ReactMarkdown from 'react-markdown'; import remarkBreaks from 'remark-breaks'; import remarkGfm from 'remark-gfm'; import type { Finding, PrDocSectionKey, ReviewDraft } from '@meebox/shared'; -import { ChevronIcon } from '../../common/icons'; -import { mermaidComponents, walkthroughMdComponents } from '../../common/markdownMermaid'; -import { REMOTE_REHYPE_PLUGINS } from '../../../markdown'; -import { translatePrAgentLabels } from '../../../utils/translate-pr-agent'; +import { ChevronIcon } from '../../../common/icons'; +import { mermaidComponents, walkthroughMdComponents } from '../../../common/markdownMermaid'; +import { REMOTE_REHYPE_PLUGINS } from '../../../../markdown'; +import { translatePrAgentLabels } from '../../../../utils/translate-pr-agent'; import { pillStyle, sectionLabel, diff --git a/apps/desktop/src/renderer/src/components/chat/components/QueuedView.tsx b/apps/desktop/src/renderer/src/components/features/chat/components/QueuedView.tsx similarity index 96% rename from apps/desktop/src/renderer/src/components/chat/components/QueuedView.tsx rename to apps/desktop/src/renderer/src/components/features/chat/components/QueuedView.tsx index 446814a..2319e28 100644 --- a/apps/desktop/src/renderer/src/components/chat/components/QueuedView.tsx +++ b/apps/desktop/src/renderer/src/components/features/chat/components/QueuedView.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { ReviewRunTool } from '@meebox/shared'; -import { CloseIcon } from '../../common/icons'; +import { CloseIcon } from '../../../common/icons'; import { AskQuestion } from './shared'; /** diff --git a/apps/desktop/src/renderer/src/components/chat/components/RulePreviewModal.tsx b/apps/desktop/src/renderer/src/components/features/chat/components/RulePreviewModal.tsx similarity index 92% rename from apps/desktop/src/renderer/src/components/chat/components/RulePreviewModal.tsx rename to apps/desktop/src/renderer/src/components/features/chat/components/RulePreviewModal.tsx index c13190c..ce57d3b 100644 --- a/apps/desktop/src/renderer/src/components/chat/components/RulePreviewModal.tsx +++ b/apps/desktop/src/renderer/src/components/features/chat/components/RulePreviewModal.tsx @@ -2,8 +2,8 @@ import { useTranslation } from 'react-i18next'; import ReactMarkdown from 'react-markdown'; import remarkBreaks from 'remark-breaks'; import remarkGfm from 'remark-gfm'; -import { mermaidComponents } from '../../common/markdownMermaid'; -import { REMOTE_REHYPE_PLUGINS } from '../../../markdown'; +import { mermaidComponents } from '../../../common/markdownMermaid'; +import { REMOTE_REHYPE_PLUGINS } from '../../../../markdown'; import type { MatchedRule } from '../types'; export function RulePreviewModal({ diff --git a/apps/desktop/src/renderer/src/components/chat/components/RunResultView.tsx b/apps/desktop/src/renderer/src/components/features/chat/components/RunResultView.tsx similarity index 99% rename from apps/desktop/src/renderer/src/components/chat/components/RunResultView.tsx rename to apps/desktop/src/renderer/src/components/features/chat/components/RunResultView.tsx index 1a513af..83e7f25 100644 --- a/apps/desktop/src/renderer/src/components/chat/components/RunResultView.tsx +++ b/apps/desktop/src/renderer/src/components/features/chat/components/RunResultView.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { Finding, ReviewDraft, ReviewRun } from '@meebox/shared'; -import { RetryIcon } from '../../common/icons'; +import { RetryIcon } from '../../../common/icons'; import { orderFindings } from '../utils/findings'; import { formatStartTime, formatTokens, runStatusLabel } from '../utils/format'; import { extractTokenUsage, type TokenUsage } from '../utils/tokens'; diff --git a/apps/desktop/src/renderer/src/components/chat/components/RunningView.tsx b/apps/desktop/src/renderer/src/components/features/chat/components/RunningView.tsx similarity index 100% rename from apps/desktop/src/renderer/src/components/chat/components/RunningView.tsx rename to apps/desktop/src/renderer/src/components/features/chat/components/RunningView.tsx diff --git a/apps/desktop/src/renderer/src/components/chat/components/shared.tsx b/apps/desktop/src/renderer/src/components/features/chat/components/shared.tsx similarity index 92% rename from apps/desktop/src/renderer/src/components/chat/components/shared.tsx rename to apps/desktop/src/renderer/src/components/features/chat/components/shared.tsx index 323c53f..1a4b173 100644 --- a/apps/desktop/src/renderer/src/components/chat/components/shared.tsx +++ b/apps/desktop/src/renderer/src/components/features/chat/components/shared.tsx @@ -3,10 +3,10 @@ import { useTranslation } from 'react-i18next'; import ReactMarkdown from 'react-markdown'; import remarkBreaks from 'remark-breaks'; import remarkGfm from 'remark-gfm'; -import { QuestionIcon } from '../../common/icons'; -import { mermaidComponents } from '../../common/markdownMermaid'; -import { REMOTE_REHYPE_PLUGINS } from '../../../markdown'; -import { parseAnsi, segmentStyle } from '../../../utils/ansi'; +import { QuestionIcon } from '../../../common/icons'; +import { mermaidComponents } from '../../../common/markdownMermaid'; +import { REMOTE_REHYPE_PLUGINS } from '../../../../markdown'; +import { parseAnsi, segmentStyle } from '../../../../utils/ansi'; export function Spinner() { return