Files
cc-switch/tests/components/ProviderIconBox.test.tsx
Jason f5db60db87 feat(ui): fill the icon box with tile-style provider icons
Provider icons all sat as an 18-20px glyph inside the same 32px bordered
box, so icons that carry their own solid background (88API, Qiniu,
CherryIN, ...) showed up as a small square inside a square.

- A new ProviderIconBox replaces the box duplicated across the provider
  card, the name field's icon button and the two preset selector lists.
  Icons marked `shape: "tile"` in metadata fill the whole box, clipped
  to its radius, with an inset ring drawn above the image so white
  tiles keep an edge on white cards. Transparent logos keep the bordered
  box and grow from 18px (forms) / 20px (card) to a shared 22px, which
  matches the visual weight of the tiles without crowding the border.
- 28 icons are marked as tiles: solid squares, rounded tiles, circles
  and white-background images. UCloud and SSSAiCode gain metadata
  entries for this, which also makes them searchable in the icon picker.
- Icons with wide transparent margins are cropped to their content:
  a6api, byteplus, nekocode, etok, sudocode-us, claudeapi and
  teamorouter as lossless square crops (kept pixels identical), and
  crazyrouter, aigocode, yi and zenmux through a tighter viewBox (paths
  untouched). The Pi mark keeps its padding: it is the official README
  mark and its viewBox is pinned by a test.
- Xiaomi MiMo switches from a one-line wordmark, which shrank to a thin
  line at icon size and turned black-on-dark in dark mode, to the
  official favicon style: the two-line lobe-icons wordmark in white on a
  black tile.
- FennoAI's webp had a fake transparency checkerboard baked in. It is
  replaced by a 256px PNG with real transparency, cropped to the fox.
2026-10-05 20:30:56 +08:00

41 lines
1.5 KiB
TypeScript

import { render } from "@testing-library/react";
import { describe, expect, it } from "vitest";
import { ProviderIconBox } from "@/components/ProviderIconBox";
import { hasIcon, isTileIcon } from "@/icons/extracted";
import { iconMetadata } from "@/icons/extracted/metadata";
describe("ProviderIconBox", () => {
it("lets icons with their own solid background fill the box", () => {
const { container } = render(<ProviderIconBox icon="88api" name="88API" />);
const box = container.firstElementChild as HTMLElement;
const img = box.querySelector("img") as HTMLImageElement;
expect(box.className).not.toContain("border-border");
expect(img.style.width).toBe("32px");
expect(img.className).toContain("object-cover");
expect(img.className).not.toContain("object-contain");
});
it("keeps transparent logos small and centered inside a bordered box", () => {
const { container } = render(
<ProviderIconBox icon="dmxapi" name="DMXAPI" />,
);
const box = container.firstElementChild as HTMLElement;
const img = box.querySelector("img") as HTMLImageElement;
expect(box.className).toContain("border-border");
expect(img.style.width).toBe("22px");
expect(img.className).toContain("object-contain");
});
it("only marks icons that exist in the icon index", () => {
const tiles = Object.keys(iconMetadata).filter(isTileIcon);
expect(tiles.length).toBeGreaterThan(0);
for (const name of tiles) {
expect(hasIcon(name), name).toBe(true);
}
});
});