第九轮(部分):修复日报徽章配色、彻底重做PIN定位方案、清理静态文件品牌残留
- 日报卡片"已提交/未提交"状态徽章补色:DailyReportCard用<article><header><em>结构,原选择器
要求.report-cards直接子<button>,日报卡片永远命中不了、只落到不分状态的兜底样式;月报因为
行本身就是<button>所以没受影响。详情页.report-author em同理补了区分色(原来恒为绿色,"未
提交"用绿色在语义上很怪)。
- 青少年模式/独立密码设置的PIN输入定位改用结构性方案,不再靠猜一个rem偏移量:给
.auth-pin-boxes/.auth-pin-input包一层.auth-pin-wrap,输入框inset:0精确覆盖方块的真实
渲染框,不管外层页面有没有标题、padding多少都自动对齐。上一轮的补丁(.youth-password-gate
.auth-pin-input{top:1.75rem})把重叠率从0%提到32.5%,本轮实测确认还是不够(方块下方
67.5%的面积点不中),根治后4个采样点(四角+中心)全部精确命中输入框。过程中额外发现并
修复了两个更隐蔽的层叠问题:全局input[type=text]的height:2.5rem特异度反超裸class、
textarea/input共享的margin:0.25rem重置——不清掉这两个会让inset:0看起来生效了、实际尺寸/
位置还是被悄悄改掉。
- .report-loading(举报原因页加载态)补基础样式,原来在base.css里零匹配,吃浏览器默认<p>样式。
- 清理静态文件里的Tinode品牌残留:index.html/index-dev.html的<meta>标签(application-name/
description/og:*/canonical,此前只改了<title>,meta标签一直没跟上)、manifest.json(name/
short_name/description改MeetingIM;prefer_related_applications+related_applications整个
删掉——这两个字段会让Android/Chrome"添加到主屏幕"时引导用户去装无关的第三方开源Tinode App,
不只是文案问题);删除.well-known/assetlinks.json(声明了无关第三方App对本域名的URL处理/
登录凭据代理权限,属于遗留模板残留,无真实对应关系,直接移除而非编造虚假内容)。
manifest.json里的图标文件(logo96.png/logo192.png/logo.svg)本身画的就是Tinode的蓝绿橙"t"标志,
是真实的视觉品牌泄漏,但重新设计一套图标涉及视觉识别决策,本次未动,留给用户决定。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
f688578714
commit
d573b38d10
@@ -1,26 +0,0 @@
|
||||
[{
|
||||
"relation": ["delegate_permission/common.handle_all_urls"],
|
||||
"target": {
|
||||
"namespace": "android_app",
|
||||
"package_name": "co.tinode.tindroidx",
|
||||
"sha256_cert_fingerprints":
|
||||
["25:9A:71:EE:BD:2E:9F:D3:2D:64:1E:90:49:33:BD:F3:E3:42:BD:C4:DD:FA:BA:68:EE:D2:EB:76:65:33:DC:92"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"relation": ["delegate_permission/common.get_login_creds"],
|
||||
"target": {
|
||||
"namespace": "web",
|
||||
"site": "https://web.tinode.co"
|
||||
}
|
||||
},
|
||||
{
|
||||
"relation": ["delegate_permission/common.get_login_creds"],
|
||||
"target": {
|
||||
"namespace": "android_app",
|
||||
"package_name": "co.tinode.tindroidx",
|
||||
"sha256_cert_fingerprints":
|
||||
["5B:BE:6A:C4:A7:66:A8:BB:4B:C1:52:66:E5:A4:BD:66:3C:33:50:04:11:CB:17:44:45:89:5E:3C:8D:55:77:7A"]
|
||||
}
|
||||
}
|
||||
]
|
||||
+43
-13
@@ -1099,6 +1099,13 @@
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* DailyReportCard renders <article><header><em>, not the <button> the two rules below (1196-1197)
|
||||
assume -- so submitted/draft there always fell through to this rule's one fixed color, unable to
|
||||
tell the two states apart (MonthlyReportList's own rows really are <button>s, so it never hit
|
||||
this gap). Same colors as the button-based rules, just re-declared at matching structure. */
|
||||
.report-cards article > header em.submitted { color: #28784f; background: #e5f5ec; }
|
||||
.report-cards article > header em.draft { color: #ad6c11; background: #fff2dd; }
|
||||
|
||||
.report-cards article p {
|
||||
display: -webkit-box;
|
||||
margin: 0.8rem 0;
|
||||
@@ -1288,10 +1295,14 @@
|
||||
}
|
||||
|
||||
.report-author em {
|
||||
color: #2c8257;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* Was one fixed color (green) regardless of report.status's actual value -- a "未提交" (not yet
|
||||
submitted) badge showing the same green as "已提交" reads backwards. */
|
||||
.report-author em.submitted { color: #28784f; }
|
||||
.report-author em.draft { color: #ad6c11; }
|
||||
|
||||
.report-detail h2,
|
||||
.report-detail h3,
|
||||
.report-detail p {
|
||||
@@ -6795,6 +6806,20 @@ div.toast.show {
|
||||
margin-top: 1.2rem;
|
||||
}
|
||||
|
||||
/* .auth-pin-input used to be sized/positioned with hardcoded top/width/height values guessed to
|
||||
match wherever .auth-pin-boxes happened to render on each page -- .auth-pin-content's <h1> and
|
||||
.youth-password-gate's shorter top padding push the boxes to two different heights, so one
|
||||
shared guessed `top` could only ever be right for one of them (confirmed live twice: the two
|
||||
pages' real box positions differ by ~9.25rem, and a value tuned for one left the other's boxes
|
||||
only ~32% overlapping the real input, still mostly unclickable). Wrapping both in their own
|
||||
tightly-fitting, positioned container instead -- inset:0 on the input then always matches
|
||||
.auth-pin-boxes' actual rendered box exactly, on any page, with no measured constant to keep
|
||||
in sync. */
|
||||
.auth-pin-wrap {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.auth-pin-boxes {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 4rem);
|
||||
@@ -6812,21 +6837,19 @@ div.toast.show {
|
||||
|
||||
.auth-pin-input {
|
||||
position: absolute;
|
||||
top: 11rem;
|
||||
width: 19rem;
|
||||
height: 5rem;
|
||||
inset: 0;
|
||||
margin: 0;
|
||||
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;
|
||||
/* input[type="text"]'s global reset (2131 above) sets a fixed height:2.5rem at higher specificity
|
||||
(0,1,1) than a bare .auth-pin-input's (0,1,0) -- it was winning and pinning this input to 2.5rem
|
||||
tall regardless of the boxes' actual height, undoing the inset:0 fix above for the vertical axis
|
||||
(width happened to still come out right only because the reset's own width:100% agrees with this
|
||||
element's actual need). Selector bumped to definitively outrank it, not just happen to. */
|
||||
.auth-pin-wrap .auth-pin-input {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.auth-pin-content .auth-primary {
|
||||
@@ -14061,6 +14084,13 @@ div.toast.show {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.report-loading {
|
||||
margin: 0;
|
||||
padding: 1rem;
|
||||
color: #6e7781;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.report-reason-list {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+8
-8
@@ -5,24 +5,24 @@
|
||||
<title>MeetingIM</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="application-name" content="Tinode Web, version for developers" />
|
||||
<meta name="description" content="Tinode instant messenger, development version" />
|
||||
<meta name="application-url" content="https://web.tinode.co/">
|
||||
<meta name="application-name" content="MeetingIM, version for developers" />
|
||||
<meta name="description" content="MeetingIM instant messenger, development version" />
|
||||
<meta name="application-url" content="https://web.118im.com/">
|
||||
<!-- Browser styling for Chrome, FF, Opera -->
|
||||
<meta name="theme-color" content="#3949AB" />
|
||||
<!-- Ask Google not to offer page translation -->
|
||||
<meta name="google" value="notranslate" />
|
||||
<!-- Open Graph description -->
|
||||
<meta name="og:url" content="https://web.tinode.co/">
|
||||
<meta name="og:title" content="Tinode Web Development">
|
||||
<meta name="og:url" content="https://web.118im.com/">
|
||||
<meta name="og:title" content="MeetingIM Development">
|
||||
<meta name="og:image" content="img/og-logo.jpeg">
|
||||
<meta name="og:description" content="Tinode instant messenger, development version" />
|
||||
<meta name="og:description" content="MeetingIM instant messenger, development version" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<link rel="manifest" href="manifest.json" />
|
||||
<link rel="shortcut icon" id="shortcut-icon" href="img/logo32x32.png" type="image/png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="img/logo192.png" type="image/png" />
|
||||
<link rel="canonical" href="https://web.tinode.co/" />
|
||||
<link rel="canonical" href="https://web.118im.com/" />
|
||||
<!-- Google's Roboto font -->
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,500,700,700i" />
|
||||
<!-- Google's material design icons -->
|
||||
@@ -43,7 +43,7 @@
|
||||
<body>
|
||||
<noscript><div id="noscript-message"><div id="noscript-title">Javascript support is required.</div>
|
||||
<div id="noscript-content">It appears JavaScript is turned off or is not supported by your browser.
|
||||
TinodeWeb does not work without JavaScript. Please enable JavaScript by changing your browser options,
|
||||
MeetingIM does not work without JavaScript. Please enable JavaScript by changing your browser options,
|
||||
then <a href="">try again</a>.
|
||||
</div>
|
||||
</div></noscript>
|
||||
|
||||
+8
-8
@@ -4,22 +4,22 @@
|
||||
<title>MeetingIM</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="application-name" content="Tinode Web" />
|
||||
<meta name="description" content="Tinode instant messenger in a browser" />
|
||||
<meta name="application-url" content="https://web.tinode.co/">
|
||||
<meta name="application-name" content="MeetingIM" />
|
||||
<meta name="description" content="MeetingIM instant messenger in a browser" />
|
||||
<meta name="application-url" content="https://web.118im.com/">
|
||||
<meta name="theme-color" content="#3949AB" />
|
||||
<meta name="google" value="notranslate" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<meta name="og:url" content="https://web.tinode.co/">
|
||||
<meta name="og:title" content="Tinode Web">
|
||||
<meta name="og:url" content="https://web.118im.com/">
|
||||
<meta name="og:title" content="MeetingIM">
|
||||
<meta name="og:image" content="img/og-logo.jpeg">
|
||||
<meta name="og:description" content="Tinode instant messenger in a browser" />
|
||||
<meta name="og:description" content="MeetingIM instant messenger in a browser" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<link rel="manifest" href="manifest.json" />
|
||||
<link rel="shortcut icon" id="shortcut-icon" href="img/logo32x32.png" type="image/png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="img/logo192.png" type="image/png" />
|
||||
<link rel="canonical" href="https://web.tinode.co/" />
|
||||
<link rel="canonical" href="https://web.118im.com/" />
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,500,700,700i" />
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
|
||||
<link rel="stylesheet" href="css/base.min.css" />
|
||||
@@ -32,7 +32,7 @@
|
||||
<body>
|
||||
<noscript><div id="noscript-message"><div id="noscript-title">Javascript support is required.</div>
|
||||
<div id="noscript-content">It appears JavaScript is turned off or is not supported by your browser.
|
||||
TinodeWeb does not work without JavaScript. Please enable JavaScript by changing your browser options,
|
||||
MeetingIM does not work without JavaScript. Please enable JavaScript by changing your browser options,
|
||||
then <a href="">try again</a>.</div></div></noscript>
|
||||
<div id="mountPoint"></div>
|
||||
<script src="firebase-init.js"></script>
|
||||
|
||||
+4
-15
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Tinode",
|
||||
"short_name": "Tinode",
|
||||
"description": "Tinode Web App.\nSee more at https://tinode.co/",
|
||||
"name": "MeetingIM",
|
||||
"short_name": "MeetingIM",
|
||||
"description": "MeetingIM instant messenger.",
|
||||
"categories": ["chat", "communication", "productivity"],
|
||||
"icons": [
|
||||
{
|
||||
@@ -25,18 +25,7 @@
|
||||
"theme_color": "#3949AB",
|
||||
"display": "standalone",
|
||||
"gcm_sender_id": "103953800507",
|
||||
"prefer_related_applications": true,
|
||||
"related_applications": [
|
||||
{
|
||||
"platform": "play",
|
||||
"url": "https://play.google.com/store/apps/details?id=co.tinode.tindroidx",
|
||||
"id": "co.tinode.tindroidx"
|
||||
},
|
||||
{
|
||||
"platform": "itunes",
|
||||
"url": "https://apps.apple.com/us/app/tinode/id1483763538"
|
||||
}
|
||||
],
|
||||
"prefer_related_applications": false,
|
||||
"permissions": {
|
||||
"audio-capture": {
|
||||
"description": "Required for recording voice messages"
|
||||
|
||||
@@ -765,8 +765,10 @@ function IndependentPassword({authenticated, hashParams}) {
|
||||
<Header title="" back={authenticated ? 'security' : 'login'} />
|
||||
<main className="auth-pin-content">
|
||||
<h1>设置独立密码</h1>
|
||||
<div className="auth-pin-boxes" aria-hidden="true">{[0,1,2,3].map(i => <span key={i}>{pin[i] ? '●' : ''}</span>)}</div>
|
||||
<input className="auth-pin-input" type="text" value={pin} onChange={e => setPin(e.target.value.replace(/\D/g, '').slice(0, 4))} inputMode="numeric" autoComplete="off" aria-label="四位独立密码" autoFocus />
|
||||
<div className="auth-pin-wrap">
|
||||
<div className="auth-pin-boxes" aria-hidden="true">{[0,1,2,3].map(i => <span key={i}>{pin[i] ? '●' : ''}</span>)}</div>
|
||||
<input className="auth-pin-input" type="text" value={pin} onChange={e => setPin(e.target.value.replace(/\D/g, '').slice(0, 4))} inputMode="numeric" autoComplete="off" aria-label="四位独立密码" autoFocus />
|
||||
</div>
|
||||
{error ? <div className="auth-field-error">{error}</div> : null}
|
||||
<button className="auth-primary" disabled={pin.length !== 4 || busy} onClick={submit}>{busy ? '提交中…' : '确定'}</button>
|
||||
</main>
|
||||
|
||||
@@ -705,9 +705,11 @@ function YouthModeVerify({hashParams, onToast}) {
|
||||
return <div className="personal-page youth-mode-page">
|
||||
<Header title={mode === 'enable' ? '开启青少年模式' : '关闭青少年模式'} back={mode === 'enable' ? 'youth-mode-off' : 'youth-mode-on'} />
|
||||
<main className="youth-password-gate">
|
||||
<div className="auth-pin-boxes" aria-hidden="true">{[0, 1, 2, 3].map(i => <span key={i}>{password[i] ? '●' : ''}</span>)}</div>
|
||||
<input className="auth-pin-input" type="text" inputMode="numeric" autoComplete="off" autoFocus
|
||||
value={password} onChange={e => setPassword(e.target.value.replace(/\D/g, '').slice(0, 4))} aria-label="独立密码" />
|
||||
<div className="auth-pin-wrap">
|
||||
<div className="auth-pin-boxes" aria-hidden="true">{[0, 1, 2, 3].map(i => <span key={i}>{password[i] ? '●' : ''}</span>)}</div>
|
||||
<input className="auth-pin-input" type="text" inputMode="numeric" autoComplete="off" autoFocus
|
||||
value={password} onChange={e => setPassword(e.target.value.replace(/\D/g, '').slice(0, 4))} aria-label="独立密码" />
|
||||
</div>
|
||||
{error ? <div className="auth-field-error">{error}</div> : null}
|
||||
<button type="button" className="auth-primary" disabled={password.length !== 4 || busy || remainingLockSeconds > 0} onClick={submit}>
|
||||
{busy ? '验证中…' : remainingLockSeconds > 0 ? `请 ${remainingLockSeconds} 秒后重试` : '确定'}
|
||||
|
||||
+36
-30
@@ -6817,21 +6817,24 @@ function IndependentPassword({
|
||||
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("h1", {
|
||||
children: "设置独立密码"
|
||||
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", {
|
||||
className: "auth-pin-boxes",
|
||||
"aria-hidden": "true",
|
||||
children: [0, 1, 2, 3].map(i => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", {
|
||||
children: pin[i] ? '●' : ''
|
||||
}, i, false))
|
||||
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("input", {
|
||||
className: "auth-pin-input",
|
||||
type: "text",
|
||||
value: pin,
|
||||
onChange: e => setPin(e.target.value.replace(/\D/g, '').slice(0, 4)),
|
||||
inputMode: "numeric",
|
||||
autoComplete: "off",
|
||||
"aria-label": "四位独立密码",
|
||||
autoFocus: true
|
||||
}, void 0, false), error ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", {
|
||||
className: "auth-pin-wrap",
|
||||
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", {
|
||||
className: "auth-pin-boxes",
|
||||
"aria-hidden": "true",
|
||||
children: [0, 1, 2, 3].map(i => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", {
|
||||
children: pin[i] ? '●' : ''
|
||||
}, i, false))
|
||||
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("input", {
|
||||
className: "auth-pin-input",
|
||||
type: "text",
|
||||
value: pin,
|
||||
onChange: e => setPin(e.target.value.replace(/\D/g, '').slice(0, 4)),
|
||||
inputMode: "numeric",
|
||||
autoComplete: "off",
|
||||
"aria-label": "四位独立密码",
|
||||
autoFocus: true
|
||||
}, void 0, false)]
|
||||
}, void 0, true), error ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", {
|
||||
className: "auth-field-error",
|
||||
children: error
|
||||
}, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", {
|
||||
@@ -16197,21 +16200,24 @@ function YouthModeVerify({
|
||||
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("main", {
|
||||
className: "youth-password-gate",
|
||||
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
|
||||
className: "auth-pin-boxes",
|
||||
"aria-hidden": "true",
|
||||
children: [0, 1, 2, 3].map(i => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", {
|
||||
children: password[i] ? '●' : ''
|
||||
}, i, false))
|
||||
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("input", {
|
||||
className: "auth-pin-input",
|
||||
type: "text",
|
||||
inputMode: "numeric",
|
||||
autoComplete: "off",
|
||||
autoFocus: true,
|
||||
value: password,
|
||||
onChange: e => setPassword(e.target.value.replace(/\D/g, '').slice(0, 4)),
|
||||
"aria-label": "独立密码"
|
||||
}, void 0, false), error ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
|
||||
className: "auth-pin-wrap",
|
||||
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
|
||||
className: "auth-pin-boxes",
|
||||
"aria-hidden": "true",
|
||||
children: [0, 1, 2, 3].map(i => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", {
|
||||
children: password[i] ? '●' : ''
|
||||
}, i, false))
|
||||
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("input", {
|
||||
className: "auth-pin-input",
|
||||
type: "text",
|
||||
inputMode: "numeric",
|
||||
autoComplete: "off",
|
||||
autoFocus: true,
|
||||
value: password,
|
||||
onChange: e => setPassword(e.target.value.replace(/\D/g, '').slice(0, 4)),
|
||||
"aria-label": "独立密码"
|
||||
}, void 0, false)]
|
||||
}, void 0, true), error ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
|
||||
className: "auth-field-error",
|
||||
children: error
|
||||
}, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", {
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user