Phase B: Eliminate duplication

- workspace_nav helper replaces 4x duplicated nav bar patterns
- Hoisted make_diagnostics_action_context call in process_clicks (computed once, reused 4 times)
- Removed duplicate section header comments in workspaces.odin

workspaces.odin: 328 → 280 lines (down 15%)
All 156 tests pass.
This commit is contained in:
echo 2026-05-22 17:36:24 +02:00
parent abc74582d6
commit be0ccc1539
2 changed files with 26 additions and 57 deletions

View File

@ -413,27 +413,15 @@ process_clicks :: proc(app: ^GUI_App_State, can_gen_panels, can_layout, can_expo
}
if clicked(clay.ID("btn_autosave_toggle")) { push_status(&app.status_msg, &app.action_log, toggle_autosave_with_message(&app.autosave_enabled)) }
if clicked(clay.ID("btn_help")) { toggle_help_overlay(&app.show_help_overlay) }
diag_ctx := make_diagnostics_action_context(&app.controller, &app.action_log, app.is_dirty, app.autosave_enabled, proj_ok, export_ok, autosave_secs, app.project_path, app.export_path, app.log_show_lines, app.log_oldest_first)
if clicked(clay.ID("btn_log_reset")) { push_status(&app.status_msg, &app.action_log, reset_log_view_with_message(&app.log_show_lines, &app.log_oldest_first)) }
if clicked(clay.ID("btn_log_clear")) { set_status(&app.status_msg, clear_action_log_with_message(&app.action_log)) }
if clicked(clay.ID("btn_log_report")) {
diag_ctx := make_diagnostics_action_context(&app.controller, &app.action_log, app.is_dirty, app.autosave_enabled, proj_ok, export_ok, autosave_secs, app.project_path, app.export_path, app.log_show_lines, app.log_oldest_first)
push_status(&app.status_msg, &app.action_log, write_session_report_with_message(diag_ctx))
}
if clicked(clay.ID("btn_log_copy")) {
diag_ctx := make_diagnostics_action_context(&app.controller, &app.action_log, app.is_dirty, app.autosave_enabled, proj_ok, export_ok, autosave_secs, app.project_path, app.export_path, app.log_show_lines, app.log_oldest_first)
push_status(&app.status_msg, &app.action_log, copy_action_log_snapshot_with_message(diag_ctx))
}
if clicked(clay.ID("btn_log_diag")) {
diag_ctx := make_diagnostics_action_context(&app.controller, &app.action_log, app.is_dirty, app.autosave_enabled, proj_ok, export_ok, autosave_secs, app.project_path, app.export_path, app.log_show_lines, app.log_oldest_first)
push_status(&app.status_msg, &app.action_log, write_diagnostics_with_message(diag_ctx))
}
if clicked(clay.ID("btn_log_status_copy")) {
push_status(&app.status_msg, &app.action_log, copy_text_with_status(app.status_msg, "Copied status to clipboard"))
}
if clicked(clay.ID("btn_log_diag_copy")) {
diag_ctx := make_diagnostics_action_context(&app.controller, &app.action_log, app.is_dirty, app.autosave_enabled, proj_ok, export_ok, autosave_secs, app.project_path, app.export_path, app.log_show_lines, app.log_oldest_first)
push_status(&app.status_msg, &app.action_log, copy_diagnostics_with_message(diag_ctx))
}
if clicked(clay.ID("btn_log_report")) { push_status(&app.status_msg, &app.action_log, write_session_report_with_message(diag_ctx)) }
if clicked(clay.ID("btn_log_copy")) { push_status(&app.status_msg, &app.action_log, copy_action_log_snapshot_with_message(diag_ctx)) }
if clicked(clay.ID("btn_log_diag")) { push_status(&app.status_msg, &app.action_log, write_diagnostics_with_message(diag_ctx)) }
if clicked(clay.ID("btn_log_status_copy")) { push_status(&app.status_msg, &app.action_log, copy_text_with_status(app.status_msg, "Copied status to clipboard")) }
if clicked(clay.ID("btn_log_diag_copy")) { push_status(&app.status_msg, &app.action_log, copy_diagnostics_with_message(diag_ctx)) }
screen := app.controller.active_screen

View File

@ -4,6 +4,18 @@ import clay "clay:."
import "core:fmt"
import "../core"
// Shared Helpers
workspace_nav :: proc(id_prefix, pos_label: string) {
if clay.UI(clay.ID(fmt.tprintf("%sNav", id_prefix)))({
layout = {sizing = {width = clay.SizingGrow({}), height = clay.SizingFixed(36)}, layoutDirection = .LeftToRight, childGap = 8, childAlignment = {y = .Center}},
}) {
clay_body_text(pos_label, color = CLAY_ACCENT)
declare_button_small(fmt.tprintf("btn_%s_prev", id_prefix), "< Prev")
declare_button_small(fmt.tprintf("btn_%s_next", id_prefix), "Next >")
}
}
// Script Workspace
declare_script_workspace :: proc(app: ^GUI_App_State) {
page_count := len(app.controller.state.script.pages)
@ -18,27 +30,15 @@ declare_script_workspace :: proc(app: ^GUI_App_State) {
}
idx := clamp_script_cursor(page_count, app.summary_opts.script_page_cursor)
page := app.controller.state.script.pages[idx]
workspace_nav("script", fmt.tprintf("Page %d/%d", idx+1, page_count))
// Nav bar
if clay.UI(clay.ID("ScriptNav"))({
layout = {sizing = {width = clay.SizingGrow({}), height = clay.SizingFixed(36)}, layoutDirection = .LeftToRight, childGap = 8, childAlignment = {y = .Center}},
}) {
clay_body_text(fmt.tprintf("Page %d/%d", idx+1, page_count), color = CLAY_ACCENT)
declare_button_small("btn_script_prev", "< Prev")
declare_button_small("btn_script_next", "Next >")
// Title info
title := app.controller.state.script.title
if len(title) > 50 { title = fmt.tprintf("%s...", title[:47]) }
clay_muted_text(title)
}
// Detail card
declare_script_detail(app)
}
// Panels Workspace
// Panels Workspace
declare_panels_workspace :: proc(app: ^GUI_App_State) {
panel_count := count_script_panels(app.controller.state.script)
@ -52,20 +52,10 @@ declare_panels_workspace :: proc(app: ^GUI_App_State) {
}
idx := clamp_panel_cursor(panel_count, app.summary_opts.panel_cursor)
if clay.UI(clay.ID("PanelsNav"))({
layout = {sizing = {width = clay.SizingGrow({}), height = clay.SizingFixed(36)}, layoutDirection = .LeftToRight, childGap = 8, childAlignment = {y = .Center}},
}) {
clay_body_text(fmt.tprintf("Panel %d/%d", idx+1, panel_count), color = CLAY_ACCENT)
declare_button_small("btn_panels_prev", "< Prev")
declare_button_small("btn_panels_next", "Next >")
}
workspace_nav("panels", fmt.tprintf("Panel %d/%d", idx+1, panel_count))
declare_panels_detail(app)
}
// Layout Workspace
// Layout Workspace
declare_layout_workspace :: proc(app: ^GUI_App_State) {
layout_count := len(app.controller.state.page_layouts)
@ -79,20 +69,10 @@ declare_layout_workspace :: proc(app: ^GUI_App_State) {
}
idx := clamp_layout_cursor(layout_count, app.summary_opts.layout_page_cursor)
if clay.UI(clay.ID("LayoutNav"))({
layout = {sizing = {width = clay.SizingGrow({}), height = clay.SizingFixed(36)}, layoutDirection = .LeftToRight, childGap = 8, childAlignment = {y = .Center}},
}) {
clay_body_text(fmt.tprintf("Page %d/%d", idx+1, layout_count), color = CLAY_ACCENT)
declare_button_small("btn_layout_prev", "< Prev")
declare_button_small("btn_layout_next", "Next >")
}
workspace_nav("layout", fmt.tprintf("Page %d/%d", idx+1, layout_count))
declare_layout_detail(app)
}
// Bubbles Workspace
// Bubbles Workspace
declare_bubbles_workspace :: proc(app: ^GUI_App_State) {
layout_count := len(app.controller.state.page_layouts)
@ -109,6 +89,7 @@ declare_bubbles_workspace :: proc(app: ^GUI_App_State) {
layout_val := app.controller.state.page_layouts[page_idx]
panel_count := len(layout_val.panels)
// Bubbles needs dual nav (page + panel)
if clay.UI(clay.ID("BubblesNav"))({
layout = {sizing = {width = clay.SizingGrow({}), height = clay.SizingFixed(36)}, layoutDirection = .LeftToRight, childGap = 8, childAlignment = {y = .Center}},
}) {