-- footer menu: second cursor zone; ←/→ pick, 🅾 activate, x/select return. in_menu=false menu_sel=1 menu_labels=split"reply,repost,quote,like,post,credits" -- footer icons parallel to menu_labels; "•" separates engagement (1-4) from global (5-6). menu_icons={8,9,14,11,12,15} function mobile() return (rpin(126)&1)>0 end -- footer label for the 🅾 button: the 🅾 glyph (\142) on mobile, the "z" key on -- desktop (where 🅾 is bound to z, so showing the glyph would mislead). function obtn() return mobile() and "\142" or "z" end -- "like"/"repost" are contextual: show the undo verb once already done. function menu_label(i) local l=menu_labels[i] local p=posts[sel] if l=="like" then return (p and p.liked) and "unlike" or "like" end if l=="repost" then return (p and p.reposted) and "unrepost" or "repost" end return l end -- bump a plain-integer count field by d (formatted "k" counts are left alone). function bump_count(p,k,d) local n=tonum(p[k]) if n and n==flr(n) then p[k]=tostr(flr(n+d)) end end -- toggle like on a post/comment: optimistic local flip + tell js (op_like). function toggle_like(p) if not p then return end p.liked=not p.liked bump_count(p,"likes",p.liked and 1 or -1) if ONLINE then enqueue(op_like,p.refid,p.liked and "1" or "0") end sfx(p.liked and 3 or 1) end -- toggle repost: same shape as like, against an app.bsky.feed.repost record. function toggle_repost(p) if not p then return end p.reposted=not p.reposted bump_count(p,"reposts",p.reposted and 1 or -1) if ONLINE then enqueue(op_repost,p.refid,p.reposted and "1" or "0") end sfx(p.reposted and 3 or 1) end function toggle_menu() in_menu=not in_menu if in_menu then menu_sel=1 end -- always open on the first item (reply) sfx(0) end function menu_activate() local m=menu_labels[menu_sel] local p=posts[sel] in_menu=false if m=="reply" then if p then open_compose(p.refid) sfx(3) end elseif m=="like" then toggle_like(p) elseif m=="repost" then toggle_repost(p) elseif m=="quote" then if p then open_compose(0,p.refid,p.name) sfx(3) end elseif m=="post" then open_compose(0) sfx(3) elseif m=="credits" then enter_demo() end end -- 1 when the next 🅾 press opens compose (feed, or menu on post/quote) function compose_intent() if scr==scr_timeline or scr==scr_thread then if in_menu then local m=menu_labels[menu_sel] return (m=="post" or m=="quote" or m=="reply") and 1 or 0 end return 0 end return 0 end function update_nav() local is_nav=scr==scr_timeline or scr==scr_thread -- handle keyboard: menu keys take priority over global shortcuts while stat(30) do local c=stat(31) if is_nav and in_menu then if c=="\13" then menu_activate() return elseif c=="\27" then toggle_menu() return end elseif is_nav and c=="\27" and scr==scr_thread then open_timeline(false) sfx(1) return elseif is_nav and (c=="l" or c=="L") then toggle_like(posts[sel]) elseif is_nav and (c=="s" or c=="S") then toggle_repost(posts[sel]) elseif is_nav and (c=="q" or c=="Q") then local p=posts[sel] if p then open_compose(0,p.refid,p.name) sfx(3) end elseif c=="t" or c=="T" then theme=1-theme sfx(0) elseif c=="r" or c=="R" then open_timeline(true) elseif c=="d" or c=="D" then enter_demo() elseif c=="n" or c=="N" then open_compose(0) sfx(3) end end if is_nav then -- cursor in the footer menu: ←/→ pick, 🅾/z/enter activate, x/esc exit if in_menu then if btnp(0) then menu_sel=max(1,menu_sel-1) sfx(0) end if btnp(1) then menu_sel=min(#menu_labels,menu_sel+1) sfx(0) end if btnp(4) then menu_activate() end if btnp(5) then in_menu=false sfx(1) end return end local p=posts[sel] local expanded=p and p.expanded if expanded then -- up/down scroll within the expanded post; navigate at boundaries if btnp(2) then if (p.scroll or 0)>0 then p.scroll-=1 sfx(0) else sel=max(1,sel-1) sfx(0) end end if btnp(3) then local total=p.lines and #p.lines or 0 local cap=p.vis_lines or 3 if (p.scroll or 0)