Task #514: Align note composer with folders rail

Original task: On the Notes page the "اكتب ملاحظة" composer sat alone
in a full-width row above the content row, while the "المجلدات"
FoldersRail started in the row below. Composer appeared high, rail
visibly lower with empty space between them.

Change:
- Switched the folders+content row in
  `artifacts/tx-os/src/pages/notes.tsx` from flex to CSS grid:
  `grid md:grid-cols-[14rem_minmax(0,1fr)]`. Composer is placed in
  col 2 row 1, FoldersRail in col 1 (row-span-2 when composer is
  shown), content in col 2 row 2. Result: composer's top edge aligns
  with the rail's top edge on desktop and the empty gap is gone.
- On mobile (`grid-cols-1`), `order-1 / order-2 / order-3` give the
  exact original mobile reading order: composer → rail → content.
- Added a `className?: string` prop to `FoldersRail`
  (`artifacts/tx-os/src/components/notes/folders-rail.tsx`) appended
  to its root `<aside>`, so the page can pass grid placement
  classes.
- Hidden-composer views (Inbox / Sent / Archived / Shared-with-me)
  collapse cleanly via conditional `md:row-span-2` on the rail and
  conditional `md:row-start-1 / md:row-start-2` on the content
  column — desktop becomes a simple two-cell row and mobile stays
  rail → content, matching the original behavior.

Behavior preserved:
- `showTopComposer` gating unchanged.
- `data-testid="notes-top-composer"` preserved.
- FoldersRail's existing internal classes unchanged; new className
  prop is purely additive.
- Mobile reading order in active/non-shared view: composer → rail →
  content (same as before this task, when composer was a standalone
  block above the row).
- Mobile reading order in hidden-composer views: rail → content
  (unchanged).

Verification: `pnpm --filter @workspace/tx-os exec tsc --noEmit`
passes. No test files reference the composer block by structural
selectors that the move would break.

No deviations from the plan.
This commit is contained in:
riyadhafraa
2026-05-12 11:30:09 +00:00
parent d1875141aa
commit cb6b067386
+34 -19
View File
@@ -777,14 +777,32 @@ export default function NotesPage() {
The sticky header above keeps the controls pinned. */}
<div className="flex-1 flex flex-col">
{/* Task #514: composer moved INSIDE the main content column so it
shares the same row (and same top edge) as the FoldersRail on
desktop. On narrow widths the row stacks (`flex-col`); the
`order-*` classes keep the composer ABOVE the folders rail in
that case so the original mobile reading order is preserved.
Hidden conditions (Inbox/Sent/Archived/Shared) are unchanged
— see `showTopComposer`. */}
<div className="flex-1 px-4 py-6 max-w-6xl w-full mx-auto flex flex-col md:flex-row gap-6">
{/* Task #514: switched the folders+content row from flex to CSS
grid so the top composer can sit at the SAME vertical
position as the FoldersRail on desktop, while still
preserving the original mobile reading order
(composer → rail → content). Pure flex can't do both: on
desktop we need composer + content stacked in the right
column, on mobile we need composer above the rail —
incompatible with a single flex direction. Grid solves it
with explicit `col-start` / `row-start` placement on md+
and natural `order-*` flow on mobile. Hidden-composer views
(Inbox / Sent / Archived / Shared-with-me) collapse cleanly
to the original two-cell layout via conditional row-span
/ row-start. */}
<div className="flex-1 px-4 py-6 max-w-6xl w-full mx-auto grid gap-4 md:gap-x-6 md:gap-y-4 md:grid-cols-[14rem_minmax(0,1fr)]">
{showTopComposer && (
<div
className="order-1 md:order-none md:col-start-2 md:row-start-1"
data-testid="notes-top-composer"
>
<Composer
labels={labels}
folderSelection={folderSelection}
onSend={(id) => setSendForNoteId(id)}
/>
</div>
)}
{showFolders && (
<FoldersRail
folders={folders}
@@ -794,19 +812,16 @@ export default function NotesPage() {
totalCount={notes.length}
onShareFolder={(f) => setFolderShareFor(f)}
mode={view === "active" && folderSelection.kind === "all" ? "chips-only" : "rail"}
className={showTopComposer ? "order-2 md:order-1" : undefined}
className={`order-2 md:order-none md:col-start-1 md:row-start-1${
showTopComposer ? " md:row-span-2" : ""
}`}
/>
)}
<div className={`flex-1 min-w-0${showTopComposer ? " order-1 md:order-2" : ""}`}>
{showTopComposer && (
<div className="mb-4" data-testid="notes-top-composer">
<Composer
labels={labels}
folderSelection={folderSelection}
onSend={(id) => setSendForNoteId(id)}
/>
</div>
)}
<div
className={`min-w-0 order-3 md:order-none md:col-start-2 ${
showTopComposer ? "md:row-start-2" : "md:row-start-1"
}`}
>
{view === "active" && folderSelection.kind === "shared-folder" && (
// Recipient view of a folder shared with the current user. Rendered
// before the regular active branch so we never mount the Composer