4 Commits

Author SHA1 Message Date
codex-bot 1e57e908d4 Add a workspace dashboard script example 2026-11-05 00:53:30 +08:00
Zayden-Jung 303c823eb0 Merge pull request 'test: 修正窗口 chrome 引入后的布局测试尺寸预期' (#2) from codex/fix-layout-ci into main
Verify Tessera GUI / verify (push) Successful in 3m36s
Reviewed-on: #2
2026-10-29 20:28:36 +00:00
Zayden-Jung f787ff25e0 Merge pull request 'ci: 仅 main 分支执行 CI/CD' (#1) from codex/main-only-cicd into main
Verify Tessera GUI / verify (push) Has been cancelled
Reviewed-on: #1
2026-10-29 20:28:29 +00:00
codex-bot 1fb6dc3b8f test: account for window chrome in viewport layout assertions 2026-10-30 03:45:21 +08:00
3 changed files with 112 additions and 3 deletions
+1
View File
@@ -21,6 +21,7 @@
| [main.endor](main.endor) | The earlier function-entry form, producing the same frame as page.endor. |
| [hello.endor](hello.endor) | Richer function-entry example covering a helper, Row/Column and Spacer. |
| [fonts.endor](fonts.endor) | Mixed Chinese/Latin text and proportional widths, with rectangles following narrow and wide letters. |
| [workspace.endor](workspace.endor) | Larger static workspace dashboard with reusable functions, metrics, progress bars and an activity column. Paste the complete file into Console in Script mode; all displayed data is illustrative. |
Submit a file as the UTF-8 body of a namespace PUT request. No namespace,
scene, render block or imports belong in the source.
+83
View File
@@ -0,0 +1,83 @@
// Paste the complete file into Console in Script mode, then Run.
// All numbers, progress values and activity entries below are demo data.
function metric(label: Text, value: Text, note: Text, color: Text): View {
return ui.column(0, 6,
ui.text(label, 1, "#637082"),
ui.text(value, 2, "#243047"),
ui.text(note, 1, "#637082"),
ui.rect(160, 4, 2, color)
)
}
function project(name: Text, state: Text, detail: Text, filled: Number, remaining: Number, color: Text): View {
let caption = ui.row(0, 12,
ui.text(name, 1, "#243047"),
ui.text(state, 1, color)
)
let progress = ui.row(0, 0,
ui.rect(filled, 6, 3, color),
ui.rect(remaining, 6, 3, "#E5EAF2")
)
return ui.column(0, 6,
caption,
ui.text(detail, 1, "#637082"),
progress
)
}
function activity(time: Text, title: Text, detail: Text, color: Text): View {
let dot = ui.column(0, 0, ui.spacer(7), ui.rect(6, 6, 3, color))
let stamp = ui.row(0, 8, dot, ui.text(time, 1, "#8490A0"))
return ui.column(0, 4,
stamp,
ui.text(title, 1, "#243047"),
ui.text(detail, 1, "#637082")
)
}
let heading = ui.column(0, 6,
ui.text("ENDOR STUDIO / WORKSPACE", 1, "#5263D6"),
ui.text("项目工作台", 2, "#243047"),
ui.text("把想法组织成对象,把对象组合成界面。", 1, "#637082")
)
let statistics = ui.row(0, 20,
metric("活跃任务", "24", "本周新增 6 项", "#6574E8"),
metric("已完成", "18", "持续推进中", "#299C82"),
metric("页面草稿", "08", "等待下一次灵感", "#D9A34A")
)
let projects = ui.column(0, 14,
ui.text("项目进度", 1, "#243047"),
project("Aster", "进行中", "语言解析 / 编译 / 执行", 240, 60, "#6574E8"),
project("Tessera", "构建中", "桌面界面 / 布局 / 开发工具", 186, 114, "#299C82"),
project("设计文档", "草稿", "Block / Page / 对象模型", 108, 192, "#D9A34A")
)
let timeline = ui.column(0, 14,
ui.text("最近活动", 1, "#243047"),
activity("10:24", "更新字体", "中英文混排预览", "#6574E8"),
activity("09:48", "组织界面", "用函数组合不同区块", "#299C82"),
activity("09:12", "记录想法", "准备下一版页面设计", "#D9A34A")
)
let body = ui.row(0, 20, projects, timeline)
let note = ui.row(0, 12,
ui.rect(4, 46, 2, "#6574E8"),
ui.column(0, 6,
ui.text("下一步:让对象参与交互", 1, "#243047"),
ui.text("当前展示为静态示例,进度条和活动记录均为演示数据。", 1, "#637082")
)
)
let page = ui.page()
page.render(ui.column(24, 20,
heading,
statistics,
ui.rect(520, 1, 0, "#DFE5EE"),
body,
note,
ui.text("DEMO DATA / 函数组合 / 中文字体 / 嵌套布局", 1, "#8490A0")
))
+28 -3
View File
@@ -207,8 +207,10 @@ page.render(Column(0,8,Column(0,8,paragraph,tail),Column(50,8,paragraph)))
})
.collect();
assert_eq!(commands.len(), 2);
assert_eq!(commands[0][0], 240.0);
assert_eq!(commands[1][0], 140.0);
// The 240px window reserves 56px for the rail and 8px for its inset.
// The second occurrence additionally has 50px padding on each side.
assert_eq!(commands[0][0], 176.0);
assert_eq!(commands[1][0], 76.0);
assert!(commands[1][1] > commands[0][1]);
let tail = initial
.frame
@@ -236,6 +238,20 @@ page.render(Column(0,8,Column(0,8,paragraph,tail),Column(50,8,paragraph)))
.map(|m| m.id)
.collect::<Vec<_>>()
);
let widths: Vec<_> = resized
.frame
.commands
.iter()
.filter_map(|command| match command {
RenderCommand::Text {
value,
wrap_bounds: Some(bounds),
..
} if value == &text => Some(bounds[0]),
_ => None,
})
.collect();
assert_eq!(widths, [336.0, 236.0]);
let heights: Vec<_> = resized
.frame
.commands
@@ -1758,6 +1774,15 @@ fn viewport_resize_changes_constraints_and_preserves_mount_identity_without_sour
}),
)
.unwrap();
// Page content excludes the 56px rail, 8px inset and 24px root padding
// on each side, both initially and after resizing the outer window.
assert!(
initial
.frame
.mounts
.iter()
.any(|mount| mount.width == 688.0 && mount.height == 24.0)
);
let ids: Vec<_> = initial.frame.mounts.iter().map(|mount| mount.id).collect();
let document = session
.resize(Some(crate::layout::Size {
@@ -1780,7 +1805,7 @@ fn viewport_resize_changes_constraints_and_preserves_mount_identity_without_sour
.frame
.mounts
.iter()
.any(|mount| mount.width == 312.0 && mount.height == 24.0)
.any(|mount| mount.width == 248.0 && mount.height == 24.0)
);
assert_eq!(session.inputs, 0);
assert!(