feat(launcher): render detail panel content (title/desc/deps)

panels/detail.lua now renders the selected module's title, version,
author, markdown description, and per-dep status list with OK/WARN/ERR
glyphs. Dep-list order follows manifest.module::deps[] (L-Q6 load-
order, no re-sort). Whole-list bg-tint is bubbled to ctx.list_tint so
the list panel picks up a yellow/red ambient cue for warn/error
states. Hero strip remains a placeholder until L.5.
This commit is contained in:
Calic
2026-06-11 02:09:04 +02:00
parent b360ee6230
commit 0a96b009f1
2 changed files with 147 additions and 21 deletions

View File

@@ -1,36 +1,116 @@
local M = {}
local PADDING = 24
local COLOR_BG = 0x282828FF
local COLOR_TEXT = 0xE0E0E0FF
local COLOR_DIM = 0xA0A0A0FF
local FONT_TITLE = 28
local FONT_BODY = 14
local PADDING = 24
local COLOR_BG = 0x282828FF
local COLOR_TEXT = 0xE0E0E0FF
local COLOR_DIM = 0xA0A0A0FF
local COLOR_OK = 0x80C080FF
local COLOR_WARN = 0xE0C040FF
local COLOR_ERR = 0xE05040FF
local FONT_TITLE = 28
local FONT_SUB = 16
local FONT_BODY = 14
local FONT_DEP = 14
local md -- lazy-loaded markdown renderer
local function ensure_md(launcher_dir)
if not md then md = dofile(launcher_dir .. "/markdown.lua") end
end
local function status_glyph(dep_status)
if dep_status == "ok" then return "OK", COLOR_OK end
if dep_status == "warn" then return "WARN", COLOR_WARN end
if dep_status == "error" then return "ERR", COLOR_ERR end
return "?", COLOR_DIM
end
local function find_entry(ctx, id)
if id == "news" then return nil end
for _, e in ipairs(ctx.module_entries) do
if e.id == id then return e end
end
return nil
end
function M.render(ctx)
local p = ctx.detail_panel_rect
engine.render.draw_rect(p.x, p.y, p.w, p.h, COLOR_BG)
if not ctx.selected_entry then
-- Empty state: background image + hint text (L.10 ships the image).
if ctx.bg_texture then
engine.render.draw_texture(ctx.bg_texture, p.x, p.y)
end
if ctx.bg_texture then engine.render.draw_texture(ctx.bg_texture, p.x, p.y) end
local hint = ctx.t("empty_hint")
local w, h = engine.render.measure_text(hint, FONT_BODY)
engine.render.draw_text(hint,
p.x + (p.w - w) / 2, p.y + (p.h - h) / 2,
FONT_BODY, COLOR_DIM)
engine.render.draw_text(hint, p.x + (p.w - w) / 2, p.y + (p.h - h) / 2,
FONT_BODY, COLOR_DIM)
return
end
-- Stub for L.4/L.5/L.6/L.7: full content lands later.
engine.render.draw_text(tostring(ctx.selected_entry),
p.x + PADDING, p.y + PADDING, FONT_TITLE, COLOR_TEXT)
-- News: render news.md.
if ctx.selected_entry == "news" then
ensure_md(ctx.launcher_dir)
local body = ctx.news_body_blocks or {}
md.render(body, p.x + PADDING, p.y + PADDING, p.w - 2 * PADDING, nil)
return
end
local entry = find_entry(ctx, ctx.selected_entry)
if not entry then return end
local mc = ctx.manifest_cache[entry.id] or { meta = {}, blocks = {} }
-- Carousel hero placeholder: L.5 swaps this in. For now: a strip.
local hero_h = 160
if ctx.carousel_state[entry.id] and ctx.carousel_mod then
-- L.5 implements this; render call lands later.
else
engine.render.draw_rect(p.x, p.y, p.w, hero_h, 0x404040FF)
end
local cur_y = p.y + hero_h + PADDING
-- Title row.
local title = entry.summary or entry.name or entry.id
engine.render.draw_text(title, p.x + PADDING, cur_y, FONT_TITLE, COLOR_TEXT)
local _, title_h = engine.render.measure_text(title, FONT_TITLE)
-- Version + author right-aligned.
local sub = string.format("v%s %s", entry.version, mc.meta.author or "")
local sub_w, _ = engine.render.measure_text(sub, FONT_SUB)
engine.render.draw_text(sub, p.x + p.w - PADDING - sub_w, cur_y + 6,
FONT_SUB, COLOR_DIM)
cur_y = cur_y + title_h + 12
-- Description (rendered MD).
ensure_md(ctx.launcher_dir)
cur_y = md.render(mc.blocks, p.x + PADDING, cur_y,
p.w - 2 * PADDING, entry.id)
cur_y = cur_y + 12
-- Dep list — load-order from manifest.module per L-Q6.
local r = entry.status.dep_check_result
local dep_count = (r and r.deps and #r.deps) or 0
engine.render.draw_text(
string.format("%s (%d)", ctx.t("dependencies"), dep_count),
p.x + PADDING, cur_y, FONT_SUB, COLOR_TEXT)
cur_y = cur_y + 24
if r and r.deps then
for _, d in ipairs(r.deps) do
local glyph, col = status_glyph(d.status)
engine.render.draw_text(glyph, p.x + PADDING, cur_y, FONT_DEP, col)
engine.render.draw_text(string.format("%s %s", d.id, d.version),
p.x + PADDING + 40, cur_y, FONT_DEP, COLOR_TEXT)
cur_y = cur_y + 20
end
end
-- Whole-list tint hint: bubble up to ctx.list_tint so panels/list.lua picks it up.
if r and r.kind == "error" then ctx.list_tint = "error"
elseif r and r.kind == "warn" then ctx.list_tint = "warn"
end
end
function M.handle_click(ctx, mx, my)
-- Stub: real hit-tests for launch button + carousel arrows in L.5/L.7.
-- L.5/L.7 add carousel-arrow + launch-button hit-tests.
return false
end