refactor: Phase E — types de réponses API standardisés + SVGs inline → Icon

E1 - API responses:
- Crée responses.rs avec OkResponse, DeletedResponse, UpdatedResponse,
  RevokedResponse, UnlinkedResponse, StatusResponse (6 tests de sérialisation)
- Remplace ~15 json!() inline par des types structurés dans books, libraries,
  tokens, users, handlers, anilist, metadata, download_detection, torrent_import
- Signatures de retour des handlers typées (plus de serde_json::Value)

E2 - SVGs → Icon component:
- Ajoute icon "lock" au composant Icon
- Remplace ~30 SVGs inline par <Icon> dans 9 composants
  (FolderPicker, FolderBrowser, LiveSearchForm, JobRow, LibraryActions,
  ReadingStatusModal, EditBookForm, EditSeriesForm, UserSwitcher)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-29 17:02:39 +02:00
parent 2670969d7e
commit e34d7a671a
21 changed files with 197 additions and 110 deletions

View File

@@ -4,7 +4,7 @@ import { useState } from "react";
import { createPortal } from "react-dom";
import { FolderBrowser } from "./FolderBrowser";
import { FolderItem } from "../../lib/api";
import { Button } from "./ui";
import { Button, Icon } from "./ui";
import { useTranslation } from "../../lib/i18n/context";
interface FolderPickerProps {
@@ -45,9 +45,7 @@ export function FolderPicker({ initialFolders, selectedPath, onSelect }: FolderP
onClick={() => onSelect("")}
className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-destructive transition-colors"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
<Icon name="x" size="sm" />
</button>
)}
</div>
@@ -57,9 +55,7 @@ export function FolderPicker({ initialFolders, selectedPath, onSelect }: FolderP
onClick={() => setIsOpen(true)}
className="flex items-center gap-2"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" />
</svg>
<Icon name="folder" size="sm" />
{t("common.browse")}
</Button>
</div>
@@ -79,9 +75,7 @@ export function FolderPicker({ initialFolders, selectedPath, onSelect }: FolderP
{/* Header */}
<div className="flex items-center justify-between px-4 py-3 border-b border-border/50 bg-muted/30">
<div className="flex items-center gap-2">
<svg className="w-5 h-5 text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" />
</svg>
<Icon name="folder" size="md" className="text-primary" />
<span className="font-medium">{t("folder.selectFolderTitle")}</span>
</div>
<button
@@ -89,9 +83,7 @@ export function FolderPicker({ initialFolders, selectedPath, onSelect }: FolderP
onClick={() => setIsOpen(false)}
className="text-muted-foreground hover:text-foreground transition-colors p-1 hover:bg-accent rounded"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
<Icon name="x" size="md" />
</button>
</div>