Commit bd61e8e6 authored by edy's avatar edy

feat(ui): add colorful expert icons

parent 763794d2
Pipeline #18480 failed
......@@ -31,6 +31,7 @@ typecheck_windows:
- node --version
- corepack --version
- corepack pnpm install --frozen-lockfile --store-dir "$env:PNPM_STORE_DIR"
- corepack pnpm --filter @qjclaw/ui run test:icons
- corepack pnpm typecheck
package_windows_installer:
......
......@@ -8,6 +8,7 @@
"clean": "rimraf dist",
"dev": "vite",
"lint": "tsc --noEmit",
"test:icons": "node --test test/expertIconSource.test.ts",
"typecheck": "tsc --noEmit"
},
"dependencies": {
......
This diff is collapsed.
import test from "node:test"
import assert from "node:assert/strict"
import { readFileSync } from "node:fs"
const uiPackageSource = readFileSync(new URL("../package.json", import.meta.url), "utf8")
const iconSource = readFileSync(new URL("../src/components/icons/AppIcons.tsx", import.meta.url), "utf8")
function functionBlock(name: string): string {
const start = iconSource.indexOf(`function ${name}()`)
assert.notEqual(start, -1, `Missing icon function: ${name}`)
const nextFunction = iconSource.indexOf("\nfunction ", start + 1)
const renderFunction = iconSource.indexOf("\nexport function renderExpertIcon", start + 1)
const candidates = [nextFunction, renderFunction].filter((index) => index > start)
const end = Math.min(...candidates)
assert.notEqual(end, Infinity, `Missing block end for icon function: ${name}`)
return iconSource.slice(start, end)
}
test("expert icon source test is exposed as a package script", () => {
const uiPackage = JSON.parse(uiPackageSource) as { scripts?: Record<string, string> }
assert.equal(uiPackage.scripts?.["test:icons"], "node --test test/expertIconSource.test.ts")
})
test("browser expert icon avoids reusable svg ids", () => {
const block = functionBlock("BrowserExpertIcon")
assert.doesNotMatch(block, /<defs|id=|url\(#/, "BrowserExpertIcon should avoid duplicate SVG ids across repeated renders")
})
test("non-redbook and non-douyin expert icons use fixed brand colors", () => {
const expectedColorsByIcon = new Map([
["BrowserExpertIcon", ["#3B82F6", "#22C55E"]],
["PlannerExpertIcon", ["#F97316", "#2563EB"]],
["ZhihuExpertIcon", ["#1769FF", "#ffffff"]],
["WechatExpertIcon", ["#22C55E", "#16A34A"]],
["XPlatformExpertIcon", ["#050505", "#ffffff"]],
["TikTokExpertIcon", ["#25F4EE", "#FE2C55"]],
["PosterExpertIcon", ["#EC4899", "#F59E0B"]],
["GeoExpertIcon", ["#2563EB", "#10B981"]],
["LeadsExpertIcon", ["#EF4444", "#F59E0B"]],
["SalesChampionExpertIcon", ["#F59E0B", "#FDE68A"]]
])
for (const [iconName, colors] of expectedColorsByIcon) {
const block = functionBlock(iconName)
assert.doesNotMatch(block, /currentColor/, `${iconName} should not inherit a monochrome text color`)
for (const color of colors) {
assert.match(block, new RegExp(color, "i"), `${iconName} should include ${color}`)
}
}
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment