From 435c11be49a73f32451318f1ae6ecf73d468dd3f Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 24 Jun 2026 22:48:54 +0000 Subject: [PATCH] refactor(icons): consolidate all inline SVGs into central icon registry Move every inline SVG defined in component JSX files into frontend/src/icons/index.jsx: - IconDragHandle (TreeNode.jsx drag handle) - IconSparkleSimple (Phrases.jsx phrase-block header) - IconRefreshCw with spinning prop (JiraAttachmentPanel.jsx) - IconJira, IconConfluence (JiraAttachmentPanel.jsx brand logos) - IconStatusStarted, IconStatusOk, IconStatusError (Message.jsx tool-call status) Reuse existing central icons where the inline duplicated them: - IconDoc replaces local IconFile (JiraAttachmentPanel) - IconEye, IconX, IconLink replace local copies (JiraAttachmentPanel) - IconWorld + IconChevronDown replace inline SVGs (LanguageSwitcher) Add className prop to IconWorld to support LanguageSwitcher styling. No component renders were changed; all 27 frontend tests pass. Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_01GZX5NKmXuTmFn6BMMRMw9e --- .../chatPanel/JiraAttachmentPanel.jsx | 112 +----------------- frontend/src/components/chatPanel/Message.jsx | 36 +----- frontend/src/components/chatPanel/Phrases.jsx | 19 +-- .../components/common/LanguageSwitcher.jsx | 34 +----- .../knowledgeBasePanel/TreeNode.jsx | 11 +- frontend/src/icons/index.jsx | 97 ++++++++++++++- 6 files changed, 111 insertions(+), 198 deletions(-) diff --git a/frontend/src/components/chatPanel/JiraAttachmentPanel.jsx b/frontend/src/components/chatPanel/JiraAttachmentPanel.jsx index 9240a80..c934f47 100644 --- a/frontend/src/components/chatPanel/JiraAttachmentPanel.jsx +++ b/frontend/src/components/chatPanel/JiraAttachmentPanel.jsx @@ -3,109 +3,7 @@ import { useTranslation } from 'react-i18next'; import './jiraAttachmentPanel.css'; import chatApi from '../../api/chatApi'; import { formatFileSize } from '../common/attachmentApi'; - -// ─── Icons ──────────────────────────────────────────────────────────────────── - -const IconJira = () => ( - - - - -); - -const IconConfluence = () => ( - - - - -); - -const IconFile = () => ( - - - - -); - -const IconRefresh = ({ spinning }) => ( - - - - -); - -const IconEye = () => ( - - - - -); - -const IconClose = () => ( - - - - -); - -const IconLink = () => ( - - - - -); +import { IconJira, IconConfluence, IconDoc, IconRefreshCw, IconEye, IconX, IconLink } from '../../icons'; // ─── Helpers ────────────────────────────────────────────────────────────────── @@ -153,7 +51,7 @@ const ContentDrawer = ({ attachment, onClose }) => {
{attachment.fileName}
@@ -178,7 +76,7 @@ const AttachmentCard = ({ attachment, onView }) => {
- {type === 'jira' ? : type === 'confluence' ? : } + {type === 'jira' ? : type === 'confluence' ? : } {attachment.fileName} @@ -199,7 +97,7 @@ const AttachmentCard = ({ attachment, onView }) => { rel="noopener noreferrer" onClick={(e) => e.stopPropagation()} > - {t('jira.openSource')} + {t('jira.openSource')} )}
@@ -276,7 +174,7 @@ const JiraAttachmentPanel = ({ conversationId, jiraUrl, onCountChange }) => { disabled={refreshing || loading} title={t('jira.refreshTitle')} > - + {refreshing ? t('jira.refreshing') : t('jira.refresh')} )} diff --git a/frontend/src/components/chatPanel/Message.jsx b/frontend/src/components/chatPanel/Message.jsx index 36cf3ab..4cf56b8 100644 --- a/frontend/src/components/chatPanel/Message.jsx +++ b/frontend/src/components/chatPanel/Message.jsx @@ -9,46 +9,20 @@ import CodeBlock from '../common/CodeBlock'; import HistoryModal from '../knowledgeBasePanel/HistoryModal'; import ToolCallDetailModal from './ToolCallDetailModal'; import { getToolIcon, toolLabelKey, humanizeTool, getDocChangeRef } from './toolMeta'; -import { IconCopySmall, IconCopied } from '../../icons'; +import { IconCopySmall, IconCopied, IconStatusStarted, IconStatusOk, IconStatusError } from '../../icons'; import { COPY_DONE_MS, GIST_PREVIEW_LEN } from '../../constants/ui'; import './styles/tool-call-detail-modal.css'; -/** SVG status indicators — not clickable, purely visual */ -const IconStarted = () => ( - - - -); -const IconOk = () => ( - - - - -); -const IconError = () => ( - - - - -); - const StatusIcon = ({ status }) => { switch (status) { case 'STARTED': - return ; + return ; case 'OK': - return ; + return ; case 'ERROR': - return ; + return ; default: - return ; + return ; } }; diff --git a/frontend/src/components/chatPanel/Phrases.jsx b/frontend/src/components/chatPanel/Phrases.jsx index c121bea..9d6e847 100644 --- a/frontend/src/components/chatPanel/Phrases.jsx +++ b/frontend/src/components/chatPanel/Phrases.jsx @@ -1,7 +1,7 @@ import React, { useState, useEffect, useMemo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { fetchPhrases, toggleFavorite } from './phrasesApi'; -import { IconStar } from '../../icons'; +import { IconStar, IconSparkleSimple } from '../../icons'; import './phrases.css'; // Сентинелы фильтров. Префиксы делают коллизию с пользовательской категорией @@ -9,23 +9,6 @@ import './phrases.css'; const ALL = '__all__'; const FAVORITES = '__fav__'; -// Простая звёздочка-вспышка для плейсхолдеров фраз. -// Дизайн отличается от IconSparkle из icons/ (та 16×16 с заливкой), поэтому локальная. -const IconSparkleSimple = () => ( - - - -); - /** * Блок готовых фраз над полем ввода (обычно на пустом чате). * Данные грузятся из GET /api/phrases. Клик по фразе → onSelect(text): diff --git a/frontend/src/components/common/LanguageSwitcher.jsx b/frontend/src/components/common/LanguageSwitcher.jsx index cd417ec..5068671 100644 --- a/frontend/src/components/common/LanguageSwitcher.jsx +++ b/frontend/src/components/common/LanguageSwitcher.jsx @@ -1,5 +1,6 @@ import React, { useState, useRef, useEffect, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; +import { IconWorld, IconChevronDown } from '../../icons'; import './languageSwitcher.css'; const LANGS = [ @@ -67,38 +68,9 @@ export default function LanguageSwitcher() { aria-label="Язык интерфейса" onClick={() => setOpen((v) => !v)} > - {/* глобус */} - + {currentLang.short} - + {open && ( diff --git a/frontend/src/components/knowledgeBasePanel/TreeNode.jsx b/frontend/src/components/knowledgeBasePanel/TreeNode.jsx index d383185..44ba312 100644 --- a/frontend/src/components/knowledgeBasePanel/TreeNode.jsx +++ b/frontend/src/components/knowledgeBasePanel/TreeNode.jsx @@ -1,6 +1,6 @@ import React, { useState, useEffect, useRef, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; -import { IconFolder, IconDoc, IconChevron, IconLock } from './icons'; +import { IconFolder, IconDoc, IconChevron, IconLock, IconDragHandle } from './icons'; import { findNodeById } from '../common/utils'; import { KB_PAGE_SIZE as PAGE_SIZE } from '../../constants/pagination'; @@ -17,14 +17,7 @@ const DragHandle = ({ disabled }) => {