Repository source: docs/plans/home_compact_thread_compose_plan_v1.md
Home Compact Thread Compose Plan
Goal
As a user, I want to be able to start a new thread from the home page, using a compact compose field above the feed, similar to the x.com homepage.
Current Context
The home/feed route is rendered by
Application::renderBoard()insrc/ForumRewrite/Application.php.The board template is
templates/pages/board.php.Full thread composition already exists in
templates/pages/compose_thread.php.Thread creation already uses
/api/create_threadand the browser-signing flow inpublic/assets/browser_signing.js.Optimistic thread creation already exists in
submitOptimisticThread()and inserts a pending thread shell before navigation.The board page should stay cheap to load. The compact compose form can be rendered with the page, but the heavier signing/OpenPGP assets should load only after the user shows intent to compose.
Plan
Extract reusable thread-compose markup from
templates/pages/compose_thread.phpinto a new partial, likelytemplates/partials/thread_compose_form.php.Parameters:
boardTags,subject,body,notice,error, and acompactflag.Preserve
data-compose-root,data-compose-form,data-compose-kind="thread", identity status, normalization status nodes, and field names sobrowser_signing.jscontinues to work.
Update
templates/pages/compose_thread.phpto render the shared partial in full mode.Keep the existing
/compose/threadpage as the full-screen and no-JS fallback.Avoid maintaining two independent thread compose forms.
Render the compact composer above the feed in
templates/pages/board.php.Place it after the board controls and before the thread feed loop.
Default
board_tagstogeneral.Use a compact layout: small subject input, short body textarea, primary
Postsubmit, optional anonymous submit, and clear action.Keep the existing
New Postnav link as a fallback until the inline composer is verified.
Add lazy signing initialization for the board composer.
Application::renderBoard()currently rendersboard.phpwithout extra scripts.Add a small board-only bootstrap asset, likely
/assets/lazy_compose_signing.js, to the board render call instead of eagerly loading/assets/openpgp_loader.jsand/assets/browser_signing.js.The bootstrap should listen for first user intent on the compact composer, such as
focusin,pointerdown, orinputon the subject/body fields.On first intent, dynamically load
/assets/openpgp_loader.jsand then/assets/browser_signing.js.Guard against duplicate loads with an in-flight promise and a loaded flag.
Keep
/compose/threadand reply compose pages loading the signing assets eagerly, because those routes are already explicit compose flows.
Make
browser_signing.jssafe to initialize after page load.Check whether
browser_signing.jscurrently initializes immediately or only from aDOMContentLoadedhandler.Expose an idempotent initializer, for example
window.ForumBrowserSigning.init(), that can be called both on normal script load and after lazy loading.Ensure calling the initializer more than once does not bind duplicate listeners, duplicate draft handlers, or duplicate pending-operation state.
The lazy bootstrap should call the initializer after both signing assets have loaded.
If initialization needs OpenPGP readiness, preserve the current
openpgp_loader.jscontract rather than duplicating loading logic.
Verify optimistic insertion behavior.
browser_signing.jsalready handles thread creation insubmitOptimisticThread().Confirm
insertPendingThreadShell()behaves correctly when the compose root is embedded in the board feed.If the pending shell appears inside the composer instead of the feed, add a board-specific wrapper or
data-thread-feedhook and adjust insertion logic narrowly.
Add compact styles in
public/assets/site.css.Add classes such as
.compact-thread-compose,.compact-thread-compose-fields, and.compact-thread-compose-actions.Keep the composer visually lighter than the full compose card.
Use existing theme variables rather than introducing a new palette.
Ensure the layout works on mobile, including stacked actions and textarea sizing.
Add tests.
Extend
tests/LocalAppSmokeTest.phportests/WriteApiSmokeTest.phpto assert/threads/includesdata-compose-root,data-compose-kind="thread",name="subject",name="body", and the lazy compose bootstrap script.Assert
/threads/does not eagerly include/assets/openpgp_loader.jsor/assets/browser_signing.js.Add focused JavaScript coverage for
/assets/lazy_compose_signing.jsif the existing test setup supports asset-level JS tests. Cover first-focus loading, duplicate-interaction dedupe, and calling the exposed signing initializer after load.Add or adjust JS coverage for
browser_signing.jsinitialization idempotence if there is already a browser-signing test harness.Add or adjust a smoke test to confirm the board page still renders feed cards.
Keep existing thread creation tests around
/api/create_threadand/compose/threadpassing.
Manual verification.
Load
/threads/.Confirm the compact composer appears above the feed.
Confirm the network panel does not show OpenPGP or browser-signing assets before interacting with the compact composer.
Focus the compact compose textarea and confirm the lazy bootstrap loads OpenPGP and browser-signing assets once.
Create a thread with browser identity.
Create a thread anonymously.
Confirm validation and Unicode normalization messages still appear.
Confirm failed submission restores draft text and successful submission navigates to the created thread.
Implementation Progress
2026-06-24: Created branch
home-compact-thread-composeand recorded the implementation plan as the baseline slice.2026-06-24: Extracted the full thread compose form into
templates/partials/thread_compose_form.phpso the board and full compose page can share one markup path.2026-06-24: Rendered the compact thread composer above the board feed and added responsive compact compose styles.
2026-06-24: Made
browser_signing.jsexpose an idempotentwindow.ForumBrowserSigning.init()initializer for lazy-loaded compose flows.2026-06-24: Added
lazy_compose_signing.js, wired it to the board route, and asserted the board does not eagerly include OpenPGP or browser-signing assets.2026-06-24: Added a Node-backed asset test for lazy compose signing load order, duplicate intent dedupe, and initializer invocation.
2026-06-24: Marked the board composer so optimistic pending thread shells insert after the composer and before the feed.
2026-06-24: Completed the planned implementation slices and verified the full test suite.
2026-06-24: Revised the board composer to use the inline reply expand pattern and reduced the compact thread form to a body-only visible surface with hidden defaults.
2026-06-24: Added deterministic body-excerpt display titles for titleless threads and wrote the follow-up LLM-generated title plan.