feat(launcher): trim list rows to name+tags, scrollable detail panel

List rows showed the long `summary` (name+id+description fallback chain)
and overflowed. Now each row shows the module name with a small genre-
tags subline sourced from manifest.launcher.md (meta.tags, threaded onto
the entry in init). The list also scrolls properly now (wheel dispatch +
upper clamp) — it was wired but dead without a wheel binding.

Detail panel: description + dependency list ran off the bottom of the
window. The mid-section (title/description/deps) now scrolls inside a
begin_view/end_view scissor region between the fixed hero strip and the
fixed launch button; news view scrolls too. Both panels get an inline
scrollbar. Detail scroll resets on module switch.

Depends on engine.input.get_mouse_wheel (sporel-engine). README controls/
demonstrates synced.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Calic
2026-06-11 11:58:43 +00:00
parent 2595759b3e
commit a7dc368712
4 changed files with 154 additions and 21 deletions

View File

@@ -199,7 +199,10 @@ function init(ctx)
module_entries = {}, -- filled below from engine.module.list
news_entry = { title = nil, body_path = "news.md" },
selected_entry = nil,
scroll_y = 0,
scroll_y = 0, -- list-panel vertical scroll
detail_scroll_y = 0, -- detail-panel content scroll
detail_content_h = 0, -- set by detail.render each frame
detail_view_h = 0, -- scrollable viewport height, set by detail.render
list_tint = nil, -- nil | "warn" | "error" — set in L.4
list_panel_rect = nil, -- set below from window size
detail_panel_rect = nil,
@@ -263,6 +266,7 @@ function init(ctx)
local meta, blocks = manifest_loader.load_for(entry.id)
ctx_panels.manifest_cache[entry.id] = { meta = meta, blocks = blocks }
entry.summary = meta.summary
entry.tags = meta.tags -- L-fix: list-row subline (genre tags)
-- L.4: also surface manifest.module::deps[] verbatim so the
-- detail-panel can render per-dep status glyphs in load order
@@ -392,6 +396,16 @@ function update(ctx, dt)
end
if state == STATE_LIST then
-- Mouse-wheel scroll: route to whichever panel the cursor is over.
local wheel = engine.input.get_mouse_wheel()
if wheel ~= 0 then
if hit(ctx_panels.detail_panel_rect, mx, my) then
detail_panel.handle_scroll(ctx_panels, wheel)
elseif hit(ctx_panels.list_panel_rect, mx, my) then
list_panel.handle_scroll(ctx_panels, wheel)
end
end
if input.was_action_pressed("ui_back") then
state = fsm.next(state, "esc")
elseif input.was_action_pressed("ui_click") then