feat(domain,frontend): remplace le catalogue d'icônes projet par des emojis Unicode système — #345 (QA verte)

Reprend à zéro la liste des icônes projet: catalogue d'emojis Unicode rendus
par la police système, sans embarquer d'assets graphiques propriétaires.
- domain: variante `emoji` ajoutée à ProjectIconSet (serde kebab-case)
- ports TS: union ProjectIconSet alignée avec "emoji"
- frontend: catalogue réécrit en 7 groupes (smileys, nature, food,
  activities, travel, objects, symbols), registres légaux et métadonnées
  supprimés, assets SVG projet retirés (angular.svg, NOTICE.md)
- watermark CLI custom: rendu emoji direct avec libellé de repli dérivé du
  nom de dossier du cwd
- i18n FR/EN des groupes du picker et tests mis à jour (domain settings,
  adapter projet, picker, panneau settings, chat custom)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-09-13 10:52:29 +02:00
parent 1006f62001
commit ff1d9af53a
14 changed files with 304 additions and 280 deletions

View File

@ -213,9 +213,9 @@ describe("CustomAgentChatView", () => {
expect(watermark.getAttribute("aria-hidden")).toBe("true");
expect((watermark.firstElementChild as HTMLElement | null)?.style.width).toBe("92%");
expect((watermark.firstElementChild as HTMLElement | null)?.style.height).toBe("92%");
expect(watermark.textContent).toBe("Py");
publishProjectIconChanged({ projectId: "project-1", icon: { set: "lucide", name: "star" } });
await waitFor(() => expect(watermark.textContent).toBe("★"));
expect(watermark.textContent).toBe("🐍");
publishProjectIconChanged({ projectId: "project-1", icon: { set: "emoji", name: "star" } });
await waitFor(() => expect(watermark.textContent).toBe("⭐"));
});
it("settles an isolated conversation id without recovered turns as an actionable unavailable state (#307/#314)", async () => {

View File

@ -44,7 +44,7 @@ import {
markProjectCliInteractionStopped,
} from "@/features/projects/projectCliInteractionActivity";
import { Button, EntryTimestamp, Spinner, cn, normalizeTimestamp } from "@/shared";
import { onProjectIconChanged, ProjectIcon, resolveProjectIcon } from "@/features/projects/projectIcons";
import { onProjectIconChanged, ProjectIcon } from "@/features/projects/projectIcons";
import type {
ChatAttachmentInput,
ChatDraftScope,
@ -2478,9 +2478,7 @@ export function CustomAgentChatView({
}
}
const projectWatermarkRef = projectIcon && resolveProjectIcon(projectIcon, "watermark")
? projectIcon
: null;
const projectFallbackLabel = cwd.split(/[\\/]/).filter(Boolean).at(-1) ?? projectId;
return (
<div
@ -2488,22 +2486,21 @@ export function CustomAgentChatView({
data-testid="custom-agent-chat-view"
className="relative z-0 flex h-full min-h-0 flex-col overflow-hidden bg-surface text-content"
>
{projectWatermarkRef && (
<div
data-testid="project-icon-watermark"
aria-hidden="true"
className="pointer-events-none absolute inset-0 z-0 flex items-center justify-center overflow-hidden text-content opacity-[0.035]"
style={{ pointerEvents: "none", containerType: "size" }}
>
<ProjectIcon
icon={projectWatermarkRef}
surface="watermark"
size="92%"
decorative
style={{ fontSize: "min(34cqw, 34cqh)", maxWidth: "92cqh", maxHeight: "92cqw" }}
/>
</div>
)}
<div
data-testid="project-icon-watermark"
aria-hidden="true"
className="pointer-events-none absolute inset-0 z-0 flex items-center justify-center overflow-hidden text-content opacity-[0.035]"
style={{ pointerEvents: "none", containerType: "size" }}
>
<ProjectIcon
icon={projectIcon}
fallbackLabel={projectFallbackLabel}
surface="watermark"
size="92%"
decorative
style={{ fontSize: "min(34cqw, 34cqh)", maxWidth: "92cqh", maxHeight: "92cqw" }}
/>
</div>
<div
role="toolbar"
aria-label={t("custom.actions")}