mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-09-14 00:33:10 +00:00
refactor(cabinet): migrate inline SVG icons to the central react-icons set
Audit-driven sweep: replaced 168 hand-written inline <svg> icons across 77 files with the central Phosphor (react-icons/pi) components from @/components/icons, preserving each icon's size classes and colour (dynamic stroke colours via the parent's currentColor, RefreshIcon's spinning state, conditional rotate-180 chevrons). Verified: tsc + vite build + eslint clean; an adversarial diff review of all changed files found the replacements correct (70 files clean, 0 blockers). Remaining inline <svg> dropped from 262 to ~95 — the survivors are legitimate non-icons (brand/provider logos, loading spinners & framer-motion animations, charts/sparklines, background decoration) plus a few ambiguous glyphs.
This commit is contained in:
@@ -2,7 +2,7 @@ import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { CheckIcon, XCloseIcon } from '@/components/icons';
|
||||
import { CheckIcon, ChevronDownIcon, XCloseIcon, XIcon } from '@/components/icons';
|
||||
import { useFocusTrap } from '@/hooks/useFocusTrap';
|
||||
import { DropdownSelect } from './DropdownSelect';
|
||||
import type { UserListItem } from '../../../api/adminUsers';
|
||||
@@ -98,31 +98,11 @@ function ProgressView({ progress }: { progress: ProgressState }) {
|
||||
<div key={idx} className="flex items-start gap-2 text-xs">
|
||||
{entry.success ? (
|
||||
<span className="mt-0.5 shrink-0 text-success-400" aria-hidden="true">
|
||||
<svg
|
||||
className="h-3 w-3"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth={3}
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M4.5 12.75l6 6 9-13.5"
|
||||
/>
|
||||
</svg>
|
||||
<CheckIcon className="h-3 w-3" />
|
||||
</span>
|
||||
) : (
|
||||
<span className="mt-0.5 shrink-0 text-error-400" aria-hidden="true">
|
||||
<svg
|
||||
className="h-3 w-3"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth={3}
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
<XIcon className="h-3 w-3" />
|
||||
</span>
|
||||
)}
|
||||
<span className="font-mono text-dark-400">
|
||||
@@ -159,18 +139,12 @@ function ErrorDetails({ result }: { result: BulkActionResult }) {
|
||||
<span className="text-sm font-medium text-error-400">
|
||||
{t('admin.bulkActions.errors.title', { count: result.error_count })}
|
||||
</span>
|
||||
<svg
|
||||
<ChevronDownIcon
|
||||
className={cn(
|
||||
'h-4 w-4 text-error-400 transition-transform duration-200',
|
||||
expanded && 'rotate-180',
|
||||
)}
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth={2}
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
|
||||
</svg>
|
||||
/>
|
||||
</button>
|
||||
{expanded && (
|
||||
<div className="max-h-48 overflow-y-auto border-t border-error-500/20 px-4 py-3">
|
||||
@@ -178,15 +152,7 @@ function ErrorDetails({ result }: { result: BulkActionResult }) {
|
||||
{result.errors.map((err, idx) => (
|
||||
<div key={idx} className="flex items-start gap-2 text-xs">
|
||||
<span className="mt-0.5 shrink-0 text-error-400" aria-hidden="true">
|
||||
<svg
|
||||
className="h-3 w-3"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth={3}
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
<XIcon className="h-3 w-3" />
|
||||
</span>
|
||||
<span className="shrink-0 font-mono text-dark-400">
|
||||
{err.username ? `@${err.username}` : `#${err.user_id}`}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useRef, useState, type ReactNode } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { TrashIcon } from '@/components/icons';
|
||||
import { ChevronDownIcon } from './DropdownSelect';
|
||||
import { isSubscriptionLevelAction } from './actionTargets';
|
||||
import type { BulkActionType } from '../../../api/adminBulkActions';
|
||||
@@ -112,21 +113,7 @@ export function FloatingActionBar({
|
||||
{
|
||||
type: 'delete_subscription',
|
||||
labelKey: 'admin.bulkActions.actions.deleteSubscription',
|
||||
icon: (
|
||||
<svg
|
||||
className="h-3.5 w-3.5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth={2}
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
icon: <TrashIcon className="h-3.5 w-3.5" />,
|
||||
colorClass: 'text-error-400 hover:bg-error-500/10',
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { CheckIcon } from '@/components/icons';
|
||||
import { ChevronDownIcon } from './DropdownSelect';
|
||||
|
||||
// ──────────────────────────────────────────────────────────────────
|
||||
@@ -135,21 +136,7 @@ export function MultiSelectDropdown({
|
||||
: 'border-dark-500 bg-dark-700/60',
|
||||
)}
|
||||
>
|
||||
{isChecked && (
|
||||
<svg
|
||||
className="h-2.5 w-2.5 text-white"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth={4}
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M4.5 12.75l6 6 9-13.5"
|
||||
/>
|
||||
</svg>
|
||||
)}
|
||||
{isChecked && <CheckIcon className="h-2.5 w-2.5 text-white" />}
|
||||
</div>
|
||||
<span className={cn('text-sm', isChecked ? 'text-dark-100' : 'text-dark-300')}>
|
||||
{option.label}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { CheckIcon } from '@/components/icons';
|
||||
import type { UserListItemSubscription } from '../../../api/adminUsers';
|
||||
|
||||
// ──────────────────────────────────────────────────────────────────
|
||||
@@ -68,17 +69,7 @@ export function SubscriptionSubRow({
|
||||
: t('admin.bulkActions.selectUser', { name: subscription.tariff_name || '' })
|
||||
}
|
||||
>
|
||||
{isSelected && (
|
||||
<svg
|
||||
className="h-3 w-3 text-white"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth={4}
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M4.5 12.75l6 6 9-13.5" />
|
||||
</svg>
|
||||
)}
|
||||
{isSelected && <CheckIcon className="h-3 w-3 text-white" />}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user