collapse skins under one banner (#4432)

## Description:

merges skins under one item with a circular button below it:

<img width="877" height="647" alt="image"
src="https://github.com/user-attachments/assets/a405ba34-a970-4e8c-9287-fe0055d6a02e"
/>


## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory

## Please put your Discord username so you can be contacted if a bug or
regression is found:

w.o.n
This commit is contained in:
Ryan
2026-06-27 19:09:05 -07:00
committed by GitHub
parent 6b95a23606
commit c622e8581c
4 changed files with 209 additions and 33 deletions
+68 -1
View File
@@ -1,4 +1,8 @@
import { resolveCosmetics } from "../src/client/Cosmetics";
import {
groupCosmeticVariants,
resolveCosmetics,
ResolvedCosmetic,
} from "../src/client/Cosmetics";
import { UserMeResponse } from "../src/core/ApiSchemas";
import { Cosmetics } from "../src/core/CosmeticSchemas";
@@ -289,6 +293,69 @@ describe("resolveCosmetics", () => {
});
});
describe("groupCosmeticVariants", () => {
const patternVariant = (
patternName: string,
paletteName: string | null,
): ResolvedCosmetic => ({
type: "pattern",
cosmetic: { name: patternName } as any,
colorPalette: paletteName
? { name: paletteName, primaryColor: "#fff", secondaryColor: "#000" }
: null,
relationship: "purchasable",
key: paletteName
? `pattern:${patternName}:${paletteName}`
: `pattern:${patternName}`,
});
const skinVariant = (name: string): ResolvedCosmetic => ({
type: "skin",
cosmetic: { name } as any,
colorPalette: null,
relationship: "purchasable",
key: `skin:${name}`,
});
test("collapses colour variants of the same pattern into one group", () => {
const groups = groupCosmeticVariants([
patternVariant("stripes", "red"),
patternVariant("stripes", "blue"),
patternVariant("stripes", "green"),
]);
expect(groups).toHaveLength(1);
expect(groups[0].map((r) => r.key)).toEqual([
"pattern:stripes:red",
"pattern:stripes:blue",
"pattern:stripes:green",
]);
});
test("keeps distinct patterns in separate groups, first-seen order", () => {
const groups = groupCosmeticVariants([
patternVariant("stripes", "red"),
patternVariant("dots", "red"),
patternVariant("stripes", "blue"),
]);
expect(groups).toHaveLength(2);
expect(groups[0].map((r) => r.key)).toEqual([
"pattern:stripes:red",
"pattern:stripes:blue",
]);
expect(groups[1].map((r) => r.key)).toEqual(["pattern:dots:red"]);
});
test("skins are never grouped — one group each", () => {
const groups = groupCosmeticVariants([
skinVariant("mountain"),
skinVariant("ocean"),
patternVariant("stripes", "red"),
]);
expect(groups).toHaveLength(3);
expect(groups.map((g) => g.length)).toEqual([1, 1, 1]);
});
});
describe("mixed cosmetics", () => {
test("returns all types in order: default, patterns, flags", () => {
const cosmetics = makeCosmetics({