From d0825c5ec0ddd9056b5b0138d62ee761f1188a9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=A8=E9=9C=96=E9=93=83?= <2712495353@qq.com> Date: Tue, 30 Jun 2026 21:05:10 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E6=97=A0?= =?UTF-8?q?=E6=84=8F=E4=B9=89=E7=9A=84=20cn()=20=E5=8C=85=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 对仅含静态类名或单一三元表达式的 className 改用普通字符串,保留有条件合并或 prop 覆盖场景下的 cn() 用法。 Co-authored-by: Cursor --- src/components/ErrorFallback.tsx | 8 +++- src/components/ui/checkbox.tsx | 2 +- src/layout/TopBar/SearchDropdown.tsx | 6 +-- src/layout/TopBar/SearchInput.tsx | 16 ++++---- src/layout/TopBar/index.tsx | 4 +- src/layout/TopBar/useTopBar.ts | 37 +++++++++++-------- .../components/Base64ConverterSection.tsx | 12 ++---- src/pages/Dashboard/index.tsx | 29 +++------------ 8 files changed, 49 insertions(+), 65 deletions(-) diff --git a/src/components/ErrorFallback.tsx b/src/components/ErrorFallback.tsx index 637dc81..d7fae12 100644 --- a/src/components/ErrorFallback.tsx +++ b/src/components/ErrorFallback.tsx @@ -57,7 +57,11 @@ export function ErrorFallback({

{title}

)} -

+

{description}

@@ -83,7 +87,7 @@ export function ErrorFallback({ variant="destructive" size={isApp ? 'default' : 'sm'} onClick={onAction} - className={cn(isApp ? 'rounded-lg font-bold shadow-sm' : 'font-medium shadow-sm')} + className={isApp ? 'rounded-lg font-bold shadow-sm' : 'font-medium shadow-sm'} > {actionLabel} diff --git a/src/components/ui/checkbox.tsx b/src/components/ui/checkbox.tsx index adcef7b..c1bac23 100644 --- a/src/components/ui/checkbox.tsx +++ b/src/components/ui/checkbox.tsx @@ -16,7 +16,7 @@ const Checkbox = React.forwardRef< )} {...props} > - + diff --git a/src/layout/TopBar/SearchDropdown.tsx b/src/layout/TopBar/SearchDropdown.tsx index 17368c4..cd194ce 100644 --- a/src/layout/TopBar/SearchDropdown.tsx +++ b/src/layout/TopBar/SearchDropdown.tsx @@ -16,16 +16,16 @@ export default function SearchDropdown({ selectedIndex, onSelect, }: SearchDropdownProps) { - const isSearching = searchQuery.trim().length > 0; + const isSearching = !!searchQuery.trim(); const items = isSearching ? searchResults : recentFeatures; return (
    {!isSearching && items.length > 0 && ( -
    +
  • 最近搜索 -
  • + )} {isSearching && items.length === 0 ? (
  • 未找到相关工具
  • diff --git a/src/layout/TopBar/SearchInput.tsx b/src/layout/TopBar/SearchInput.tsx index 689405c..2a10aab 100644 --- a/src/layout/TopBar/SearchInput.tsx +++ b/src/layout/TopBar/SearchInput.tsx @@ -1,4 +1,4 @@ -import { type RefObject } from 'react'; +import { type KeyboardEvent, type RefObject } from 'react'; import { Search, X } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; @@ -9,7 +9,7 @@ interface SearchInputProps { searchQuery: string; onSearchQueryChange: (value: string) => void; onFocus: () => void; - onKeyDown: (e: React.KeyboardEvent) => void; + onKeyDown: (e: KeyboardEvent) => void; onClear: () => void; } @@ -26,7 +26,6 @@ export default function SearchInput({ onSearchQueryChange(e.target.value)} @@ -35,12 +34,7 @@ export default function SearchInput({ aria-label="搜索工具..." className="h-9 rounded-lg border-border/60 bg-muted/40 pl-9 pr-16 shadow-none focus-visible:ring-1 focus-visible:ring-offset-0 placeholder:text-muted-foreground/50" /> - {!searchQuery && ( - - {getSearchShortcutLabel()} - - )} - {searchQuery && ( + {searchQuery ? ( + ) : ( + + {getSearchShortcutLabel()} + )}
); diff --git a/src/layout/TopBar/index.tsx b/src/layout/TopBar/index.tsx index 6513e12..2ad7d57 100644 --- a/src/layout/TopBar/index.tsx +++ b/src/layout/TopBar/index.tsx @@ -33,9 +33,7 @@ export default function TopBar() { id: 'open-in-tab', icon: ExternalLink, title: '在标签页打开', - onClick: () => { - void handleOpenInTab(); - }, + onClick: () => void handleOpenInTab(), }, ]; diff --git a/src/layout/TopBar/useTopBar.ts b/src/layout/TopBar/useTopBar.ts index 1e4b87c..290ac17 100644 --- a/src/layout/TopBar/useTopBar.ts +++ b/src/layout/TopBar/useTopBar.ts @@ -1,4 +1,11 @@ -import { useEffect, useMemo, useRef, useState, type RefObject } from 'react'; +import { + useEffect, + useMemo, + useRef, + useState, + type KeyboardEvent as ReactKeyboardEvent, + type RefObject, +} from 'react'; import { Monitor, Moon, Sun } from 'lucide-react'; import { useRouter } from '@/providers/RouterProvider'; import { useThemeMode } from '@/providers/ThemeModeProvider'; @@ -21,7 +28,7 @@ export interface UseTopBarReturn { handleSearchQueryChange: (value: string) => void; handleSearchFocus: () => void; handleSelectFeature: (feature: FeatureConfig) => void; - handleKeyDown: (e: React.KeyboardEvent) => void; + handleKeyDown: (e: ReactKeyboardEvent) => void; cycleThemeMode: () => void; handleOpenInTab: () => Promise; goHome: () => void; @@ -80,7 +87,7 @@ export function useTopBar(): UseTopBarReturn { }); }, [searchQuery]); - const displayedHistory = useMemo(() => { + const recentFeatures = useMemo(() => { if (searchQuery.trim()) return []; return searchHistory .slice(0, SEARCH_HISTORY_DISPLAY) @@ -111,8 +118,10 @@ export function useTopBar(): UseTopBarReturn { const themeTitle = mode === 'light' ? '切换到深色模式' : mode === 'dark' ? '切换到系统模式' : '切换到浅色模式'; - const handleKeyDown = (e: React.KeyboardEvent) => { - const totalItems = searchQuery.trim() ? searchResults.length : displayedHistory.length; + const handleKeyDown = (e: ReactKeyboardEvent) => { + const isSearching = !!searchQuery.trim(); + const items = isSearching ? searchResults : recentFeatures; + const totalItems = items.length; if (e.key === 'ArrowDown') { e.preventDefault(); @@ -122,13 +131,12 @@ export function useTopBar(): UseTopBarReturn { setSelectedIndex((prev) => (prev > 0 ? prev - 1 : prev)); } else if (e.key === 'Enter') { e.preventDefault(); - const items = searchQuery.trim() ? searchResults : displayedHistory; - const feature = - selectedIndex >= 0 && selectedIndex < totalItems - ? items[selectedIndex] - : searchQuery.trim() && searchResults.length > 0 - ? searchResults[0] - : undefined; + let feature: FeatureConfig | undefined; + if (selectedIndex >= 0 && selectedIndex < totalItems) { + feature = items[selectedIndex]; + } else if (isSearching && searchResults.length > 0) { + feature = searchResults[0]; + } if (feature) handleSelectFeature(feature); } else if (e.key === 'Escape') { setShowResults(false); @@ -149,13 +157,12 @@ export function useTopBar(): UseTopBarReturn { const handleSearchFocus = () => setShowResults(true); - const showDropdown = - showResults && (searchQuery.trim().length > 0 || displayedHistory.length > 0); + const showDropdown = showResults && (!!searchQuery.trim() || recentFeatures.length > 0); return { searchQuery, searchResults, - recentFeatures: displayedHistory, + recentFeatures, selectedIndex, showDropdown, isDashboard: currentPage === 'dashboard', diff --git a/src/pages/Base64Converter/components/Base64ConverterSection.tsx b/src/pages/Base64Converter/components/Base64ConverterSection.tsx index a3ec4ee..0118872 100644 --- a/src/pages/Base64Converter/components/Base64ConverterSection.tsx +++ b/src/pages/Base64Converter/components/Base64ConverterSection.tsx @@ -50,10 +50,6 @@ export default function Base64ConverterSection({ mode }: Base64ConverterSectionP setDirection(next); }; - const handleDownload = () => { - if (decoded) downloadBlob(decoded.blob, decodedFileName); - }; - return (
@@ -115,7 +111,7 @@ export default function Base64ConverterSection({ mode }: Base64ConverterSectionP />
)} - + {info.name} @@ -137,11 +133,11 @@ export default function Base64ConverterSection({ mode }: Base64ConverterSectionP {mode === 'image' ? '点击或拖拽图像到此处' : '点击或拖拽文件到此处'} - {`最大文件大小:${maxFileSizeStr}`} + 最大文件大小:{maxFileSizeStr} {mode === 'image' && ( - {'支持 PNG、JPG、WEBP、GIF、BMP、SVG 等格式'} + 支持 PNG、JPG、WEBP、GIF、BMP、SVG 等格式 )}
@@ -231,7 +227,7 @@ export default function Base64ConverterSection({ mode }: Base64ConverterSectionP blobSize={decoded.blob.size} fileName={decodedFileName} onFileNameChange={setCustomFileName} - onDownload={handleDownload} + onDownload={() => downloadBlob(decoded.blob, decodedFileName)} > {mode === 'image' && (
diff --git a/src/pages/Dashboard/index.tsx b/src/pages/Dashboard/index.tsx index 69acdde..37cb368 100644 --- a/src/pages/Dashboard/index.tsx +++ b/src/pages/Dashboard/index.tsx @@ -1,11 +1,10 @@ -import { cn } from '@/lib/utils'; import { useDashboard } from './useDashboard'; export default function Index() { const { visibleFeatures, recentFeatures, showRecent, navigateTo } = useDashboard(); return ( -
+
{showRecent && (

@@ -19,12 +18,7 @@ export default function Index() { key={key} type="button" onClick={() => navigateTo(key)} - className={cn( - 'inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium', - 'border border-border/60 bg-card text-card-foreground', - 'hover:bg-muted/40 hover:border-primary/30', - 'transition-colors cursor-pointer', - )} + className="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium border border-border/60 bg-card text-card-foreground hover:bg-muted/40 hover:border-primary/30 transition-colors cursor-pointer" > {feature.label} @@ -42,9 +36,7 @@ export default function Index() { {visibleFeatures.length === 0 ? (

没有可用的工具

) : ( -
+
{visibleFeatures.map(({ key, feature }) => { const IconComponent = feature.icon; return ( @@ -52,20 +44,9 @@ export default function Index() { key={key} type="button" onClick={() => navigateTo(key)} - className={cn( - 'group flex flex-col items-center justify-center gap-1.5', - 'py-3 px-2 rounded-xl border border-border/50 bg-card', - 'hover:bg-muted/40 hover:border-primary/30', - 'transition-colors cursor-pointer', - )} + className="group flex flex-col items-center justify-center gap-1.5 py-3 px-2 rounded-xl border border-border/50 bg-card hover:bg-muted/40 hover:border-primary/30 transition-colors cursor-pointer" > - + {feature.label}