From a3b708f9d4cd9c5f64a1f39974e4a77f5a0364d7 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 10 Oct 2026 13:59:47 +0800 Subject: [PATCH] fix(frontend): keep user center and user home avatar frames rounded The two large hero avatar frames go back to their legacy rounded-square look: the user center profile header keeps 6px and the public user home hero keeps var(--radius). Both declare an explicit radius because the global avatar primitive (img.avatar, 0,1,1) ties them on specificity and only the later route rule wins the cascade. Everything else stays: the primitive still circles the bare avatar-mini in the ban and report modals, the VIP modal avatar and the post-card meta avatar, the friends page avatar is circular, and the VIP icon still leads the badge row. The contract test now guards the two hero frames as rounded-square so the primitive cannot silently re-circularize them. --- assets/css/routes/profile/layout.css | 6 +++-- assets/css/routes/user-home.css | 4 ++- .../frontend-avatar-shape-contract.test.cjs | 26 ++++++++++++------- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/assets/css/routes/profile/layout.css b/assets/css/routes/profile/layout.css index 9474caab..37067fce 100644 --- a/assets/css/routes/profile/layout.css +++ b/assets/css/routes/profile/layout.css @@ -125,7 +125,9 @@ flex-shrink: 0; width: 140px; height: 140px; - border-radius: var(--radius-avatar, 50%); + /* 用户中心头图卡保持 legacy 圆角方形:显式声明圆角,避免被 public 捆绑里 + 同特异性(0,1,1)的全局头像原语 img.avatar 抢先。 */ + border-radius: 6px; } #aksrt-bg-file-input[hidden], @@ -133,7 +135,7 @@ display: none !important; } -/* 140px 正方形 → 正圆:统一前端用户头像形状(--radius-avatar) */ +/* 对齐 legacy: 140px, 6px 圆角 */ .uc-header__avatar img { display: block; box-sizing: border-box; diff --git a/assets/css/routes/user-home.css b/assets/css/routes/user-home.css index e7ca0465..bc280f8c 100644 --- a/assets/css/routes/user-home.css +++ b/assets/css/routes/user-home.css @@ -88,7 +88,9 @@ .aksrt-author-hero__avatar img { width: 120px; height: 120px; - border-radius: var(--radius-avatar, 50%); + /* 公开主页 hero 头像保持 legacy 圆角方形:显式声明圆角,避免被 public 捆绑里 + 同特异性(0,1,1)的全局头像原语 img.avatar 抢先。 */ + border-radius: var(--radius); border: 4px solid var(--surface-1); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12); object-fit: cover; diff --git a/tests/widget-system/frontend-avatar-shape-contract.test.cjs b/tests/widget-system/frontend-avatar-shape-contract.test.cjs index 63449839..2ab86fc0 100644 --- a/tests/widget-system/frontend-avatar-shape-contract.test.cjs +++ b/tests/widget-system/frontend-avatar-shape-contract.test.cjs @@ -8,10 +8,11 @@ const test = require('node:test'); const root = path.resolve(__dirname, '..', '..'); const read = (file) => fs.readFileSync(path.join(root, file), 'utf8'); -// --radius-avatar is the single source of truth for frontend avatar shape. -// Route CSS loads after the public bundle, and `.uc-header__avatar img` / -// `.aksrt-author-hero__avatar img` tie the primitive at 0,1,1 specificity, -// so every framed avatar must opt in explicitly. +// --radius-avatar is the single source of truth for frontend avatar shape, +// except the two large hero frames on the user center and the public user +// home, which intentionally keep their legacy rounded-square look. Route CSS +// loads after the public bundle and ties the primitive at 0,1,1 specificity, +// so each frame must declare its own radius to win the cascade. const primitiveSelectors = [ 'img.avatar,', 'img.avatar-mini,', @@ -37,18 +38,23 @@ test('the global avatar shape primitive renders every avatar image circular', () assert.ok(sizeSystem >= 0 && sizeSystem < start, 'primitive must sit after the avatar size system'); }); -test('user center and public user home avatar frames are circular', () => { +test('the user center and public user home keep their legacy rounded-square avatar frames', () => { const profile = read('assets/css/routes/profile/layout.css'); const userHome = read('assets/css/routes/user-home.css'); - const friends = read('assets/css/routes/friends.css'); - assert.match(profile, /\.uc-header__avatar\s*\{[^}]*border-radius:\s*var\(--radius-avatar,\s*50%\)/s); - assert.doesNotMatch(profile, /\.uc-header__avatar\s*\{[^}]*border-radius:\s*6px/s); + // Both frames must keep an explicit radius: the global primitive ties them at + // 0,1,1 specificity, so only the later route rule keeps them square. + assert.match(profile, /\.uc-header__avatar\s*\{[^}]*border-radius:\s*6px/s); + assert.doesNotMatch(profile, /\.uc-header__avatar\s*\{[^}]*--radius-avatar/s); // img and the upload overlay both inherit the frame radius. assert.match(profile, /\.uc-header__avatar img\s*\{[^}]*border-radius:\s*inherit/s); - assert.match(userHome, /\.aksrt-author-hero__avatar img\s*\{[^}]*border-radius:\s*var\(--radius-avatar,\s*50%\)/s); - assert.doesNotMatch(userHome, /\.aksrt-author-hero__avatar img\s*\{[^}]*border-radius:\s*var\(--radius\)/s); + assert.match(userHome, /\.aksrt-author-hero__avatar img\s*\{[^}]*border-radius:\s*var\(--radius\)/s); + assert.doesNotMatch(userHome, /\.aksrt-author-hero__avatar img\s*\{[^}]*--radius-avatar/s); +}); + +test('every other frontend avatar frame is circular', () => { + const friends = read('assets/css/routes/friends.css'); assert.match(friends, /\.friend-card__avatar\s*\{[^}]*border-radius:\s*var\(--radius-avatar,\s*50%\)/s); assert.doesNotMatch(friends, /\.friend-card__avatar\s*\{[^}]*border-radius:\s*var\(--radius\)/s);