第八轮最小粒度测试:修复CSS选择器/JSX结构不匹配的一整类bug,清理Tinode品牌残留
第八轮改用"读CSS选择器+核对JSX结构"的方式复测全部11章,命中了7轮纯接口测试从未发现的一类 问题——选择器写对了但目标元素的实际DOM结构/className对不上,样式静默失效: - 语音通话最小化胶囊按钮尺寸被同特异度规则覆盖;移动端悬浮通话窗口left/right/width三值同时 生效导致过度约束;来电全屏页认证徽章/姓名标题缺少专属样式覆盖 - 我的收藏-语音卡片三列grid对应实际只有1个子元素,播放器被压缩到卡片左侧一角;链接/记录头部 完全没有基础样式,退化成浏览器默认外观 - 多选模式下"收到的"消息气泡被flex auto-margin一起拖到最右侧;.avatar-box/#send-message-panel 两处逗号断句错误导致后半句选择器丢失祖先限定 - 按住说话悬浮反馈渲染成内联胶囊,而参考图要求的居中悬浮卡片样式其实已经存在(挂在了另一个非 生产demo组件上);批量转发确认框沿用了80%视口高度;audio-player.jsx的playback类点在canvas 上而非包裹层,波形和计时器可能纵向堆叠 - "消息已撤回"占位符误拼了日期分隔条的class而非专属的deleted 品牌清理:浏览器标签页标题、未读数标题更新均硬编码"Tinode";LINK_CONTACT_US等三个链接常量 指向开源Tinode项目自己的域名(联系我们改为跟用户条款/隐私协议一致的toast,不再发起外部mailto)。 以及:空会话丢失.chat-box样式类、青少年模式PIN定位、若干收藏/文件类型展示细节。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
5e173c55e8
commit
d759f67b11
+154
-85
@@ -1258,7 +1258,12 @@
|
||||
|
||||
.report-author {
|
||||
display: grid;
|
||||
grid-template-columns: 3rem minmax(0, 1fr) auto;
|
||||
/* Same dead-avatar-column issue .report-cards article > header had (see its comment) and was
|
||||
fixed for -- DailyReportDetail/MonthlyReportDetail (the only two renderers of this class)
|
||||
never render an <img> here either, just the name+badge span and the status <em>. The unused
|
||||
leading 3rem column squeezed the name into a column narrow enough to wrap "员工" onto its own
|
||||
line, while the status badge landed in what should've been the name's share of the row. */
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
align-items: center;
|
||||
gap: 0.7rem;
|
||||
}
|
||||
@@ -2117,6 +2122,8 @@ input[type="email"],
|
||||
input[type="password"],
|
||||
input[type="search"],
|
||||
input[type="tel"],
|
||||
input[type="date"],
|
||||
input[type="time"],
|
||||
textarea {
|
||||
height: 2.5rem;
|
||||
border-bottom: 1px solid var(--clr-input-border);
|
||||
@@ -2128,6 +2135,8 @@ input[type="text"],
|
||||
input[type="email"],
|
||||
input[type="password"],
|
||||
input[type="tel"],
|
||||
input[type="date"],
|
||||
input[type="time"],
|
||||
textarea {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -2137,7 +2146,9 @@ input[type="text"]:focus,
|
||||
input[type="email"]:focus,
|
||||
input[type="password"]:focus,
|
||||
input[type="search"]:focus,
|
||||
input[type="tel"]:focus {
|
||||
input[type="tel"]:focus,
|
||||
input[type="date"]:focus,
|
||||
input[type="time"]:focus {
|
||||
border-bottom: 1px solid var(--clr-input-border-focus);
|
||||
box-shadow: 0 1px 0 var(--clr-input-shadow-focus);
|
||||
}
|
||||
@@ -3114,7 +3125,7 @@ img.channel {
|
||||
}
|
||||
|
||||
/* Online-offline indicator positioned inside avatar-box */
|
||||
.avatar-box .online, .offline {
|
||||
.avatar-box .online, .avatar-box .offline {
|
||||
position: absolute;
|
||||
width: 0.75rem;
|
||||
min-width: 0.75rem;
|
||||
@@ -3582,9 +3593,15 @@ img.channel {
|
||||
.select-checkbox.blue {
|
||||
color: var(--clr-primary-accent);
|
||||
}
|
||||
/* Flexbox auto-margin trick: pins the checkbox to the far left of the row regardless of
|
||||
whether the message itself is left- or right-aligned (docs/images/多选-选中对话框.png). */
|
||||
.chat-box li .select-checkbox {
|
||||
/* Flexbox auto-margin trick: pins the checkbox to the far left of the row for sent (.right)
|
||||
messages, where it would otherwise cluster next to the bubble at the row's right edge along with
|
||||
everything else justify-content:flex-end pulls there. Scoped to .right only -- applying it
|
||||
unconditionally (as this rule originally did) claims 100% of the row's remaining space for the
|
||||
auto margin regardless of alignment, which on a received (.left) message drags the avatar+bubble
|
||||
that follow the checkbox all the way to the row's right edge instead of leaving them where
|
||||
justify-content's default flex-start already puts them: immediately after the checkbox, at the
|
||||
row's left edge (docs/images/多选-选中对话框.png). */
|
||||
.chat-box li.right .select-checkbox {
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
@@ -3637,12 +3654,29 @@ img.channel {
|
||||
.batch-forward-confirm {
|
||||
max-width: 24rem;
|
||||
}
|
||||
/* Also carries .forward-dialog for its base sheet chrome, but that class's own height:80% (right
|
||||
for forward-dialog.jsx's long contact list) leaves this content-sized confirm sheet mostly empty
|
||||
space below its buttons. Same (single-class) specificity as .forward-dialog itself, so a bare
|
||||
.batch-forward-confirm{height:auto} would depend on which rule happens to come later in this
|
||||
file to win -- the compound selector here beats it unconditionally instead. */
|
||||
.forward-dialog.batch-forward-confirm {
|
||||
height: auto;
|
||||
}
|
||||
.batch-forward-target {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.6rem 0;
|
||||
}
|
||||
/* .contact-box > li (2969 above) is more specific than the bare .batch-forward-target class above,
|
||||
so its padding and its avatar-reserving divider (the gradient's gap starts at 3.5rem, assuming an
|
||||
avatar occupies that space) win by default -- this row has no avatar, so the divider ends up
|
||||
looking like it starts partway across the row. Reasserted here at matching specificity with a
|
||||
full-width divider instead. */
|
||||
.contact-box > li.batch-forward-target {
|
||||
padding: 0.6rem 0;
|
||||
background: linear-gradient(to right, var(--clr-background-extra-light-gray), var(--clr-background-extra-light-gray)) 0 100% / 100% 1px no-repeat, var(--clr-bright);
|
||||
}
|
||||
/* 从只读 div 改成可输入的留言框后,要显式清掉 input 的原生边框/宽度,否则会缩成一个小方框。 */
|
||||
.batch-forward-comment {
|
||||
box-sizing: border-box;
|
||||
@@ -3900,7 +3934,18 @@ img.channel {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
#send-message-panel .material-icons.secondary, .material-icons.disabled {
|
||||
#send-message-panel .material-icons.secondary {
|
||||
color: var(--clr-text-tertiary)!important;
|
||||
}
|
||||
|
||||
/* Split out from the rule above -- it was originally a second, unscoped clause on it (a copy-paste
|
||||
slip, matching the same .avatar-box .online/.offline mistake elsewhere in this file), which in
|
||||
practice is the only rule greying out letter-tile.jsx's generic (no-letter) deleted-topic icon
|
||||
(`<i class="material-icons {color} disabled">`, no wrapper class of its own to hang a scoped rule
|
||||
off of) -- letter-tile.jsx's *other* deleted-avatar case (.lettertile.disabled) has its own real
|
||||
rule and was never affected. Kept as an explicit, separately-scoped rule instead of silently
|
||||
dropping a behavior nothing else provides. */
|
||||
i.material-icons.disabled {
|
||||
color: var(--clr-text-tertiary)!important;
|
||||
}
|
||||
|
||||
@@ -4221,7 +4266,7 @@ button.full-screen {
|
||||
min-width: unset;
|
||||
}
|
||||
|
||||
.minimized button.full-screen {
|
||||
.minimized:not(.audio-minimized) button.full-screen {
|
||||
top: 1rem;
|
||||
left: 1rem;
|
||||
width: 2rem;
|
||||
@@ -4236,7 +4281,7 @@ button.full-screen .material-icons {
|
||||
font-size: x-large;
|
||||
}
|
||||
|
||||
.minimized button.full-screen .material-icons {
|
||||
.minimized:not(.audio-minimized) button.full-screen .material-icons {
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
@@ -4362,7 +4407,7 @@ video {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.caller-card .trusted-badge {
|
||||
.caller-card .trusted-badge, .call-peer-card h1 .trusted-badge {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@@ -5497,29 +5542,12 @@ ul.tabbar li.active > a {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.audio-hold {
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
.audio-hold canvas {
|
||||
/* .compose-record-overlay (8588 below) replaced this holdMode presentation -- see
|
||||
audio-recorder.jsx's holdMode render for why. */
|
||||
.compose-record-overlay canvas {
|
||||
width: 6rem;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.audio-hold-hint {
|
||||
color: var(--clr-text-tertiary);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.audio-hold.cancelling {
|
||||
background-color: var(--clr-danger-text, #d93025);
|
||||
}
|
||||
|
||||
.audio-hold.cancelling .duration,
|
||||
.audio-hold.cancelling .audio-hold-hint {
|
||||
color: #fff;
|
||||
height: 1.8rem;
|
||||
margin-top: 0.4rem;
|
||||
}
|
||||
|
||||
.audio .duration {
|
||||
@@ -5550,7 +5578,11 @@ ul.tabbar li.active > a {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.audio-player div.playback {
|
||||
/* Targets the wrapper div around canvas.playback + .timer (audio-player.jsx's non-short render) --
|
||||
was accidentally written as div.playback, but "playback" is the canvas's own class, not this
|
||||
wrapper's (which had no class at all), so this never matched anything; canvas+timer fell back to
|
||||
block-level stacking (timer on its own line below the waveform) instead of sitting side by side. */
|
||||
.audio-player .playback-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -6786,6 +6818,17 @@ div.toast.show {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* .auth-pin-input's shared top:11rem was measured against .auth-pin-content's layout (6rem
|
||||
top padding + an <h1> pushing .auth-pin-boxes further down) -- .youth-password-gate has no
|
||||
title and only 3rem of top padding, so .auth-pin-boxes sits ~9.25rem higher here and the
|
||||
invisible real input ended up entirely below the visible boxes (confirmed live: boxes at
|
||||
86.7-140px, input at 210-243px, a real click on the boxes hit nothing and never refocused
|
||||
the input). Re-anchored to this container's own shorter layout instead of reusing the other
|
||||
page's absolute value. */
|
||||
.youth-password-gate .auth-pin-input {
|
||||
top: 1.75rem;
|
||||
}
|
||||
|
||||
.auth-pin-content .auth-primary {
|
||||
width: min(100%, 24rem);
|
||||
margin-top: 3rem;
|
||||
@@ -7056,6 +7099,7 @@ div.toast.show {
|
||||
margin-top: 0.4rem;
|
||||
overflow: hidden;
|
||||
font-size: 0.78rem;
|
||||
line-height: 1.3;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -7552,22 +7596,6 @@ div.toast.show {
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.system-notification-card p button {
|
||||
display: inline;
|
||||
width: auto;
|
||||
min-width: 0;
|
||||
height: auto;
|
||||
min-height: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
color: #1683f8;
|
||||
background: transparent;
|
||||
font: inherit;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.system-notification-card dl {
|
||||
margin: 0;
|
||||
}
|
||||
@@ -9162,7 +9190,8 @@ div.toast.show {
|
||||
.group-list button > span:nth-child(2),
|
||||
.group-request-list article > div,
|
||||
.group-admin-page article > span:nth-child(2),
|
||||
.group-muted-list article > span:nth-child(2) {
|
||||
.group-muted-list article > span:nth-child(2),
|
||||
.group-member-picker > button > span:nth-child(2) {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
flex-direction: column;
|
||||
@@ -9353,15 +9382,6 @@ div.toast.show {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.people-search-result em {
|
||||
padding: 0.4rem 0.8rem;
|
||||
border-radius: 0.3rem;
|
||||
color: #fff;
|
||||
background: #398afa;
|
||||
font-size: 0.78rem;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.people-qr-page main,
|
||||
.group-qr-page main {
|
||||
display: flex;
|
||||
@@ -9684,8 +9704,12 @@ div.toast.show {
|
||||
|
||||
.people-settings section small,
|
||||
.group-settings section small {
|
||||
min-width: 0;
|
||||
margin-left: auto;
|
||||
overflow: hidden;
|
||||
color: #949ba4;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.people-switch,
|
||||
@@ -10212,20 +10236,6 @@ div.toast.show {
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.group-announcement-detail footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.7rem;
|
||||
margin-top: 2rem;
|
||||
padding-top: 1rem;
|
||||
border-top: 1px solid #eceef1;
|
||||
}
|
||||
|
||||
.group-announcement-detail footer > span {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.group-announcement-detail > small {
|
||||
display: block;
|
||||
margin-top: 1rem;
|
||||
@@ -10309,12 +10319,15 @@ div.toast.show {
|
||||
flex: 0 0 3.6rem;
|
||||
}
|
||||
|
||||
/* "添加"格:跟成员头像同样尺寸的浅色方块,视觉上与真实成员头像区分开 */
|
||||
/* "添加"格:跟成员头像同样尺寸的浅色方块,视觉上与真实成员头像区分开。宽高本该跟上面那条规则
|
||||
一致(3.6rem)——之前这里写成了3rem,两条规则特异性相同、这条排在后面,字面覆盖了 width/
|
||||
height,但没盖到上面那条的 flex:0 0 3.6rem(这条完全没提 flex),容器又是 flex-direction:
|
||||
column,主轴尺寸吃 flex-basis 不吃 height,实际渲成了 3rem 宽、3.6rem 高的长方形。 */
|
||||
.group-member-tile-action {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
width: 3.6rem;
|
||||
height: 3.6rem;
|
||||
border-radius: 0.45rem;
|
||||
color: #98a0aa;
|
||||
background: #f0f2f5;
|
||||
@@ -10569,11 +10582,6 @@ div.toast.show {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.group-member-picker > button > span:nth-child(2) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.group-check {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
@@ -10866,7 +10874,7 @@ div.toast.show {
|
||||
|
||||
.library-favorite-content > footer {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto 2rem;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-top: 0.65rem;
|
||||
@@ -10959,6 +10967,32 @@ div.toast.show {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.library-link-text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
height: auto;
|
||||
min-height: 2.8rem;
|
||||
margin: 0;
|
||||
padding: 0.6rem 0.8rem;
|
||||
border: 1px solid #eceef1;
|
||||
border-radius: 0.4rem;
|
||||
box-shadow: none;
|
||||
color: var(--clr-primary-accent);
|
||||
background: #fafbfc;
|
||||
text-align: left;
|
||||
text-transform: none;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.library-link-text span {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Shared by VoiceCard/LinkText/MediaThumb's "removed" state (content-library-view.jsx) -- same
|
||||
opacity + red label language as .library-file-card.removed/em above, but these three don't share
|
||||
its grid layout (voice/media assume an icon+waveform or an image backdrop that isn't there once
|
||||
@@ -10982,8 +11016,7 @@ div.toast.show {
|
||||
}
|
||||
|
||||
.library-voice-card {
|
||||
display: grid;
|
||||
grid-template-columns: 2rem minmax(4rem, 12rem) auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
width: min(100%, 20rem);
|
||||
@@ -11501,8 +11534,39 @@ div.toast.show {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.library-record-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.6rem;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
height: auto;
|
||||
margin: 0 0 0.4rem;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
color: inherit;
|
||||
background: transparent;
|
||||
text-align: left;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.library-record-header strong {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.library-record-header small {
|
||||
flex: none;
|
||||
color: #9299a2;
|
||||
font-size: 0.74rem;
|
||||
}
|
||||
|
||||
.library-record-files .library-file-card,
|
||||
.library-record-links .library-link-card {
|
||||
.library-record-links .library-link-text {
|
||||
margin-bottom: 0.7rem;
|
||||
}
|
||||
|
||||
@@ -11851,6 +11915,10 @@ div.toast.show {
|
||||
margin: 1.3rem 0 0.45rem;
|
||||
color: #fff;
|
||||
font-size: 1.55rem;
|
||||
max-width: 100%;
|
||||
overflow-x: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.call-peer-card p {
|
||||
@@ -12606,6 +12674,7 @@ div.toast.show {
|
||||
#video-container.minimized {
|
||||
flex-direction: row;
|
||||
left: 0;
|
||||
right: auto;
|
||||
top: var(--caption-panel-height);
|
||||
width: 100%;
|
||||
height: 11rem;
|
||||
|
||||
Reference in New Issue
Block a user