mirror of
https://github.com/hectorqin/reader.git
synced 2026-11-12 05:50:54 +08:00
按钮里放的是 Unicode 字符——`☰` `⚙` `✕` `⟨` `⟩` `+` `🗂` `📁` `⮝`—— 和 emoji。八个字形来自八个字族,光学重量各不相同;`🗂` `📁` `⏮` 在部分平台 被渲染成彩色的,而一个彩色 emoji 出现在单色工具栏里,是「没有设计过」最直接的 信号。不同平台的字体回退还不同,同一个界面在 Android 和桌面浏览器上长得不一样。 此外样式表里所有按钮都没有 `:focus-visible` 规则,键盘走一遍看不到焦点在哪。 所以这次做三件事:图标改成自带字体、把缺失的交互状态补齐、把散落的字面量收成 设计令牌,并把规范写成文档。 图标用字体而不是内联 SVG,理由是**一致性可以被强制**:字体把字形变成字符,它 继承 `color` 和 `font-size`,没有自己的几何,因此没有可以漂移的地方;而三十个 内联 SVG 组件里,颜色、尺寸、线宽每一项都是单个字形可以漂移的位置。字体是 bundle 里的一个 16KB 相对路径文件,`file://` 下能加载,与「一份产物两个宿主」 的既有约束一致。 字形由 `web/tools/icons/` 下的脚本从描边路径编译:路径 → 折线 → 圆头矩形 → 精确布尔并(Clipper)→ TTF。先做过一版「栅格化 + 边界追踪」,失败了:笔画宽度 只有一个栅格单元,而逐单元的边界规则无法表达「边界在一格宽的图形上左右交替」, 结果是一个圆被追踪成 58 段碎片。精确布尔没有这种情形。 放弃的方案:内联 SVG(前面说的漂移问题)、把图标做成 React 组件并逐个手绘 (每个都是独立的几何,光学重量必然不一致)、从 CDN 引用图标字体(本产品必须 在无外网环境下工作)。 界面改动: - `Icon` 组件 + 37 个字形,码位表由生成器写出,测试直接解析字体 `cmap` 核对 - `IconButton` 的 `icon` 是字形名而非任意 `children`,传错名字是编译错误; `label` 必填,字形始终 `aria-hidden` - 补上全部按钮的 `:focus-visible`(本次之前完全缺失) - 间距/字号/动效收成令牌;`prefers-reduced-motion` 通过折叠时长令牌实现, 而不是给每条动画各加一个媒体查询 - 悬停包进 `@media (hover: hover) and (pointer: fine)`,避免触屏上按钮停在悬停态 验证:`web` 336 个测试通过(新增 9 个图标契约测试);`typecheck`、`build`、 `check-shell.sh`、`verify-web-assets.sh` 全过;字体已确认被打进 Android assets。 真浏览器(Chromium + 真实服务端)实测了书架、书库管理、阅读器三个屏幕的浅色与 深色主题,以及键盘 Tab 下的焦点环。产物 259.5KB → 259.5KB(gzip 81.4KB), 新增 16KB 字体、CSS 减到 24.4KB。 Ref: #29
46 lines
1.6 KiB
HTML
46 lines
1.6 KiB
HTML
<!doctype html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta
|
|
name="viewport"
|
|
content="width=device-width, initial-scale=1, viewport-fit=cover, maximum-scale=1"
|
|
/>
|
|
<!--
|
|
maximum-scale=1 disables pinch-zoom. That is deliberate: text size belongs
|
|
to the reader's own control, and a visual zoom fights CSS pagination, which
|
|
is measured in viewport units. Android WebView honours this; iOS Safari
|
|
ignores it, which is acceptable since iOS is out of scope for v1.
|
|
|
|
No external font: a self-hosted reader must work with no outbound network
|
|
at all, and a webfont would also fail on the LAN with no internet uplink.
|
|
The book's own embedded fonts are unaffected — they load from the archive.
|
|
|
|
The icon font is not an exception to this. It is a 16KB file in the bundle,
|
|
loaded by a relative URL from the same directory as this document, so it is
|
|
covered by the same rule: nothing here reaches the network.
|
|
-->
|
|
<meta name="color-scheme" content="light dark" />
|
|
<meta name="theme-color" content="#fbfaf7" />
|
|
<title>reader</title>
|
|
<style>
|
|
/* First paint only: prevents a white flash before the bundle applies the
|
|
stored theme, and gives the reader something to look at on a slow LAN. */
|
|
html,
|
|
body {
|
|
margin: 0;
|
|
height: 100%;
|
|
background: #fbfaf7;
|
|
}
|
|
html[data-theme='dark'],
|
|
html[data-theme='dark'] body {
|
|
background: #16171a;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="app"></div>
|
|
<script type="module" src="/src/main.ts"></script>
|
|
</body>
|
|
</html>
|