fix(app-iced): M102 页面几何 —— 正文块贴左吃满页宽、列表末行不再被裁半行、日志按词断行
① 正文列与页头不对齐(下载 / 日志):根因是 `frame::single_column` 把**行宽上限 424** 当成**整页块宽度**并水平居中(1180 下 1044 里只摆 424,左缘 422 对页头标题 112)。 现在两个量分开:`layout` 的 `column` 只管成段散文(≤424),页面块宽走新的 `frame::body_width`(= available / main_pane)。新增 `frame::body`(贴左吃满)与 `frame::prose`(散文锁 424)。1180×760 下下载 / 日志的块左缘 = 112 = 页头标题左缘。 ② 实例列表末行被裁半行:页级行距 `Space::X1`(4) 让行节奏变成 64、与可视高度除不尽, 且滚动区直贴卡片 1px 圆角描边。行距归零(下载页同改)+ 滚动区底部内缩 `Space::X2`(8) ⇒ 可视区 580−32−8 = 540 = 9×60,Redstone Lab 及其副标题完整可见,第 10 行整体在裁切线外。 ③ 日志断行把单词劈开(`graphics.gl_o` / `peration_failure`):新增 `layout::wrap::breakable`,在 `.` `_` `:` `/` `\` 后插零宽空格(U+200B 软断点), 日志行正文与一行摘要都过它;悬挂缩进不变(前缀仍是独立文本控件), `Line::text` 与 `Logs::summary()`(剪贴板)仍是原文。工具函数放 `pages/layout/`: 断点是「列宽之后」的另一半排版判据,纯函数、可单测、不碰控件树。 护栏:`body_block_starts_at_the_header_title_and_fills_the_page`、 `list_viewport_fits_whole_rows_and_still_overflow`(把 580/32/8/540/60 五个数钉住)、 `wrap::tests`(断点位置 / 不重复插 / 可还原 / 幂等)、`log_text_carries_soft_breaks_but_keeps_the_original`。 `download/tests.rs` 的「宽窗留白」口径按新分工改成「宽度归块、不归散文列」。
This commit is contained in:
1 parent
8574d6ba2d
commit
89d98184c1
15 files changed
+466
-53
No files matched your search
@@ -3,10 +3,22 @@
|
||||
//!
|
||||
//! ## 边界
|
||||
//!
|
||||
//! 这里只放「页面级」的东西:页头、页边距、内容列、两列骨架、空态位的摆放。
|
||||
//! 这里只放「页面级」的东西:页头、页边距、内容块、两列骨架、空态位的摆放。
|
||||
//! 具体控件(卡片 / 分隔线 / 文本按钮 / 图标)在 [`pieces`],它们是**占位实现**
|
||||
//! (同一份令牌,没有完整状态机),等 M75 的 `components/` 家族合入后由另一条 mission 换掉。
|
||||
//!
|
||||
//! ## 对齐口径(M102):页头标题左缘 = 正文块左缘
|
||||
//!
|
||||
//! 页头带与内容区共用同一个 `gutter`(`Padding::from([0.0, metrics.gutter])` / `padding(gutter)`),
|
||||
//! 所以页头标题的左缘 = `rail 88 + gutter 24 = 112`。正文块必须从**同一条线**起:
|
||||
//!
|
||||
//! - 单列页用 [`body`](贴左 + 吃满 `layout::available`);
|
||||
//! - 成段散文再套一层 [`prose`](宽度 ≤424,保证一行 ≤72 字符);
|
||||
//! - 两列页的正文在 [`panes`] 的主列里,左缘 = `112 + 列表列 336 + 间隙 24 = 472`(有据的分栏,不是错位)。
|
||||
//!
|
||||
//! 旧 [`single_column`] 把 424 的块**居中**摆进 1044,于是左缘 422、标题 112——视觉复审的 ① 就是这个。
|
||||
//! 它保留给设置页(`pages/settings/**`,几何归设置页线)。
|
||||
//!
|
||||
//! ## 判据落点(`research/12b`)
|
||||
//!
|
||||
//! | 部件 | 参考 | 落点 |
|
||||
@@ -38,7 +50,7 @@ use unlucky_design::typography::TypeRole;
|
||||
|
||||
use crate::theme::Ui;
|
||||
|
||||
use super::layout::{self, FrameMetrics};
|
||||
use super::layout::{self, FrameMetrics, PageLayout};
|
||||
use super::Message;
|
||||
|
||||
/// 页头操作区之间的间隔(`Space::X2`)。
|
||||
@@ -139,6 +151,10 @@ fn header_bar<'a>(ui: &'a Ui, metrics: FrameMetrics, header: Header<'a>) -> Elem
|
||||
}
|
||||
|
||||
/// 单列版面的正文列:宽 = 行宽上限内的实际列宽,**水平居中**。
|
||||
///
|
||||
/// > **M102 起产品页不再用它**:居中会把 424 摆到 1044 的正中(左缘 422 对页头标题 112),
|
||||
/// > 视觉复审判为「内容缩在中间一条窄栏」。设置页(`pages/settings/**`)仍走这条,
|
||||
/// > 它的几何归设置页线,本 mission 不动;下载 / 日志 / 窄窗实例改用 [`body`]。
|
||||
pub fn single_column<'a>(
|
||||
metrics: FrameMetrics,
|
||||
content: impl Into<Element<'a, Message>>,
|
||||
@@ -146,6 +162,47 @@ pub fn single_column<'a>(
|
||||
centered(metrics.column, content)
|
||||
}
|
||||
|
||||
/// **页面块宽度**:单列版面 = 整条可用宽度;两列版面 = 主列 pane 宽度。
|
||||
///
|
||||
/// 这是「表格 / 卡片 / 列表能有多宽」的答案,与 [`FrameMetrics::column`](一句话能有多宽,
|
||||
/// ≤424)是**两个量**。M102 的根因就是把后者当成了前者:424 的块在 1044 里居中,
|
||||
/// 于是正文左缘比页头标题右移了 310px(1180 窗宽下)。
|
||||
pub fn body_width(metrics: FrameMetrics) -> f32 {
|
||||
match metrics.layout {
|
||||
PageLayout::SingleColumn => metrics.available,
|
||||
PageLayout::SupportingPane | PageLayout::ListDetail => metrics.main_pane,
|
||||
}
|
||||
}
|
||||
|
||||
/// **正文块**:从页边距起(= 页头标题那条左缘)、铺满 [`body_width`]。
|
||||
///
|
||||
/// 与旧 `single_column` 的差别只有两点,但都是判据本身:**贴左**而不是居中,
|
||||
/// 宽度取 pane 而不是行宽上限。散文仍要自己套 [`prose`],别把整页块拉回 424。
|
||||
pub fn body<'a>(
|
||||
metrics: FrameMetrics,
|
||||
content: impl Into<Element<'a, Message>>,
|
||||
) -> Element<'a, Message> {
|
||||
container(content)
|
||||
.width(Length::Fixed(body_width(metrics)))
|
||||
.height(Length::Fill)
|
||||
.align_x(Alignment::Start)
|
||||
.align_y(Alignment::Start)
|
||||
.into()
|
||||
}
|
||||
|
||||
/// **散文块**:宽度锁在 [`FrameMetrics::column`](≤424 = 逐行 ≤72 字符)。
|
||||
///
|
||||
/// 只包「成段读的文字」(实例详情正文那样的 prose);卡片、列表、Tabs 吃的是 [`body_width`],
|
||||
/// 它们的宽度不承担行宽承诺(列宽只影响每行放几个字段,不影响读一句话的舒适度)。
|
||||
pub fn prose<'a>(
|
||||
metrics: FrameMetrics,
|
||||
content: impl Into<Element<'a, Message>>,
|
||||
) -> Element<'a, Message> {
|
||||
container(content)
|
||||
.width(Length::Fixed(metrics.column))
|
||||
.into()
|
||||
}
|
||||
|
||||
/// 两列版面:左列 `secondary`(独立滚动区由调用方自己加 `scrollable`)+ 右列 `main`。
|
||||
///
|
||||
/// 两列都**显式**取布局系统给的宽度,不吃 Fill:列表列必须固定 336,
|
||||
|
||||
Reference in new issue
Block a user