Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Q
qjclaw-dmg
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
AI-甘富林
qjclaw-dmg
Commits
bd61e8e6
Commit
bd61e8e6
authored
May 22, 2026
by
edy
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(ui): add colorful expert icons
parent
763794d2
Pipeline
#18480
failed
Changes
4
Pipelines
1
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
92 additions
and
28 deletions
+92
-28
.gitlab-ci.yml
.gitlab-ci.yml
+1
-0
package.json
apps/ui/package.json
+1
-0
AppIcons.tsx
apps/ui/src/components/icons/AppIcons.tsx
+37
-28
expertIconSource.test.ts
apps/ui/test/expertIconSource.test.ts
+53
-0
No files found.
.gitlab-ci.yml
View file @
bd61e8e6
...
...
@@ -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
:
...
...
apps/ui/package.json
View file @
bd61e8e6
...
...
@@ -8,6 +8,7 @@
"clean"
:
"rimraf dist"
,
"dev"
:
"vite"
,
"lint"
:
"tsc --noEmit"
,
"test:icons"
:
"node --test test/expertIconSource.test.ts"
,
"typecheck"
:
"tsc --noEmit"
},
"dependencies"
:
{
...
...
apps/ui/src/components/icons/AppIcons.tsx
View file @
bd61e8e6
This diff is collapsed.
Click to expand it.
apps/ui/test/expertIconSource.test.ts
0 → 100644
View file @
bd61e8e6
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
(
"
\n
function "
,
start
+
1
)
const
renderFunction
=
iconSource
.
indexOf
(
"
\n
export 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
}
`
)
}
}
})
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment