Skip to content

fix(frontend): overlay main content with inbox when active#601

Merged
dembrane-sam-bot merged 3 commits into
mainfrom
sam/overlay-inbox-main-content
Jun 2, 2026
Merged

fix(frontend): overlay main content with inbox when active#601
dembrane-sam-bot merged 3 commits into
mainfrom
sam/overlay-inbox-main-content

Conversation

@dembrane-sam-bot
Copy link
Copy Markdown
Contributor

@dembrane-sam-bot dembrane-sam-bot commented May 27, 2026

What this changes

  • Inbox view overlays the main content on the right, keeping the sidebar layout completely untouched and avoiding any sidebar shift — BaseLayout.tsx
  • Inbox block in the sidebar stays active when the inbox overlay is active — InboxBlock.tsx
  • Inbox feed is beautifully centered with a maximum width of 2xl (672px) for maximum readability on wider desktop viewports — InboxView.tsx
  • URL state query parameter ?sidebar=inbox remains deep-linkable and shareable — useSidebarView.ts
  • Clicking the back arrow on the inbox overlay removes ?sidebar=inbox from the URL query parameters, automatically removing the overlay — useSidebarView.ts, BaseLayout.tsx

Confidence

Confidence: high. Built exactly according to Plan B + Sameer's overlay requirement. Verified the git diff and structural/indentation cleanliness.

Summary by CodeRabbit

  • New Features

    • Inbox can appear as a full-screen overlay over main content so users can view messages without changing sidebar navigation.
  • Refactor

    • Sidebar state updated to support overlay modes (inbox/help) and mark Inbox active based on overlay state.
    • Inbox layout and container styling adjusted for improved overlay positioning and presentation.

- keep sidebar view/layout untouched when opening inbox
- overlay main content on the right with the inbox centered max-width feed
- back link on inbox feed removes overlay and returns to prior view
@github-actions
Copy link
Copy Markdown

Hi @dembrane-sam-bot!

Thank you for contributing to Dembrane ECHO! Before we consider your Pull Request, we ask that you sign our Contributor License Agreement (CLA). This is only required for your first Pull Request.

Please review the CLA, and sign it by adding your GitHub username to the contributors.yml file. Thanks!

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 27, 2026

Review Change Stack

Walkthrough

Inbox rendering shifts from AppSidebar's view-routing system to an overlay mode: ResolvedSidebarView gains an overlay field, sidebar resolution sets it for inbox/help modes, AppSidebar drops inbox routing, InboxBlock reads overlay state instead, and BaseLayout conditionally renders InboxView as an absolutely positioned overlay.

Changes

Inbox Overlay Mode

Layer / File(s) Summary
Sidebar view type and resolution logic
echo/frontend/src/features/sidebar/types.ts, echo/frontend/src/features/sidebar/hooks/useSidebarView.ts
ResolvedSidebarView adds optional overlay field (`"inbox"
Sidebar component overlay integration
echo/frontend/src/features/sidebar/AppSidebar.tsx, echo/frontend/src/features/sidebar/blocks/InboxBlock.tsx
AppSidebar removes the inbox view case and its InboxView import; InboxBlock switches from view === "inbox" to overlay === "inbox" for determining active state.
BaseLayout overlay rendering
echo/frontend/src/components/layout/BaseLayout.tsx
BaseLayout imports useSidebarView, reads the overlay value, adds relative to <main> for positioning context, and conditionally renders a full-inset absolute InboxView wrapper when overlay === "inbox".
InboxView layout refinement
echo/frontend/src/features/sidebar/views/InboxView.tsx
Refactors JSX structure to wrap content in a centered outer div and updates nav classes to constrain width and padding consistently.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Dembrane/echo#585: The main PR’s sidebar overlay/inbox-state refactor builds on the sidebar implementation introduced in PR #585.

LGTM.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(frontend): overlay main content with inbox when active' directly and accurately summarizes the main change: conditionally overlaying the inbox view on top of main content when active.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sam/overlay-inbox-main-content

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added the bug Something isn't working label May 27, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@echo/frontend/src/components/layout/BaseLayout.tsx`:
- Around line 56-63: Wrap the overlay container for the InboxView with proper
ARIA attributes to make it a announced modal: add role="dialog" and
aria-modal="true" to the div, and provide either aria-labelledby pointing to a
heading ID inside InboxView (create a unique id in InboxView and reference it)
or an aria-label like "Inbox" on the wrapper; also ensure the wrapper is
focusable (e.g., tabIndex={-1}) so you can move focus into it when opened.
Reference the overlay variable and the InboxView component inside BaseLayout to
locate where to add these attributes.

In `@echo/frontend/src/features/sidebar/types.ts`:
- Line 26: Remove the redundant "| null" from the overlay property type so it
reads overlay?: "inbox" | "help"; — update the declaration that currently shows
overlay?: "inbox" | "help" | null; (in
echo/frontend/src/features/sidebar/types.ts) and ensure any code that may rely
on explicit null handling instead treats absent values as undefined.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a038dbcf-aa2b-48fc-9236-6f692f1f334d

📥 Commits

Reviewing files that changed from the base of the PR and between b12baf5 and 7c48fa3.

📒 Files selected for processing (6)
  • echo/frontend/src/components/layout/BaseLayout.tsx
  • echo/frontend/src/features/sidebar/AppSidebar.tsx
  • echo/frontend/src/features/sidebar/blocks/InboxBlock.tsx
  • echo/frontend/src/features/sidebar/hooks/useSidebarView.ts
  • echo/frontend/src/features/sidebar/types.ts
  • echo/frontend/src/features/sidebar/views/InboxView.tsx
💤 Files with no reviewable changes (1)
  • echo/frontend/src/features/sidebar/AppSidebar.tsx

Comment thread echo/frontend/src/components/layout/BaseLayout.tsx
Comment thread echo/frontend/src/features/sidebar/types.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
echo/frontend/src/components/layout/BaseLayout.tsx (2)

56-67: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Move focus into the overlay when it opens.

You've got tabIndex={-1} on the dialog but nothing actually shifts focus into it. Keyboard users and screen reader users get stranded in the background content. Track the overlay state and imperatively focus the container when it mounts.

♿ Proposed focus management
+import { useEffect, useRef } from "react";
+
 export const BaseLayout = ({ children }: PropsWithChildren) => {
   const { isAuthenticated } = useAuthenticated();
   const { overlay } = useSidebarView();
+  const overlayRef = useRef<HTMLDivElement>(null);
+
+  useEffect(() => {
+    if (overlay === "inbox" && overlayRef.current) {
+      overlayRef.current.focus();
+    }
+  }, [overlay]);
   {overlay === "inbox" && (
     <div
+      ref={overlayRef}
       role="dialog"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@echo/frontend/src/components/layout/BaseLayout.tsx` around lines 56 - 67, The
overlay div in BaseLayout (the element rendered when overlay === "inbox") has
tabIndex={-1} but never receives focus; add a ref (e.g., inboxRef) to that
container and, in a useEffect that watches overlay, imperatively call
inboxRef.current?.focus() when overlay becomes "inbox" so keyboard/screen-reader
users are moved into the dialog; keep the role="dialog" and tabIndex={-1} on the
same element and ensure cleanup/no-op if ref is null.

56-67: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Add ESC key handler to close the overlay.

Standard dialog UX: ESC dismisses. Users expect it. Hook into the back navigation or param clearing logic from useSidebarView when ESC fires.

⌨️ Proposed ESC handler
+import { useEffect, useRef } from "react";
+import { useNavigate } from "react-router";
+
 export const BaseLayout = ({ children }: PropsWithChildren) => {
   const { isAuthenticated } = useAuthenticated();
   const { overlay } = useSidebarView();
+  const navigate = useNavigate();
   const overlayRef = useRef<HTMLDivElement>(null);
 
   useEffect(() => {
     if (overlay === "inbox" && overlayRef.current) {
       overlayRef.current.focus();
     }
   }, [overlay]);
+
+  useEffect(() => {
+    if (overlay !== "inbox") return;
+    const handleEscape = (e: KeyboardEvent) => {
+      if (e.key === "Escape") {
+        const params = new URLSearchParams(window.location.search);
+        params.delete("sidebar");
+        navigate({ search: params.toString() }, { replace: true });
+      }
+    };
+    document.addEventListener("keydown", handleEscape);
+    return () => document.removeEventListener("keydown", handleEscape);
+  }, [overlay, navigate]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@echo/frontend/src/components/layout/BaseLayout.tsx` around lines 56 - 67, The
inbox overlay should close on ESC: import and use the existing useSidebarView
hook in BaseLayout and, when overlay === "inbox", register a keydown listener
(useEffect) that listens for the Escape key and calls the sidebar-close/back
navigation function returned by useSidebarView (the hook that currently controls
overlay/params). Ensure the listener is only active while the dialog is mounted,
properly cleans up on unmount, and does not interfere with other keys or inputs
(ignore events when focus is inside an input/textarea). Also keep the existing
accessibility attributes (role="dialog", aria-modal) and tabIndex handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@echo/frontend/src/components/layout/BaseLayout.tsx`:
- Line 60: Replace the hardcoded aria-label="Inbox" in BaseLayout.tsx with a
localized string using your i18n utilities: locate the JSX element with
aria-label="Inbox" and change it to use the Trans component or the t`...`
template literal (per project conventions) so the value is translated (e.g.,
aria-label={<Trans>Inbox</Trans>} or aria-label={t`Inbox`}); ensure you import
the corresponding Trans or t from your i18n module and run a build/lint to pick
up missing translation keys.

---

Outside diff comments:
In `@echo/frontend/src/components/layout/BaseLayout.tsx`:
- Around line 56-67: The overlay div in BaseLayout (the element rendered when
overlay === "inbox") has tabIndex={-1} but never receives focus; add a ref
(e.g., inboxRef) to that container and, in a useEffect that watches overlay,
imperatively call inboxRef.current?.focus() when overlay becomes "inbox" so
keyboard/screen-reader users are moved into the dialog; keep the role="dialog"
and tabIndex={-1} on the same element and ensure cleanup/no-op if ref is null.
- Around line 56-67: The inbox overlay should close on ESC: import and use the
existing useSidebarView hook in BaseLayout and, when overlay === "inbox",
register a keydown listener (useEffect) that listens for the Escape key and
calls the sidebar-close/back navigation function returned by useSidebarView (the
hook that currently controls overlay/params). Ensure the listener is only active
while the dialog is mounted, properly cleans up on unmount, and does not
interfere with other keys or inputs (ignore events when focus is inside an
input/textarea). Also keep the existing accessibility attributes (role="dialog",
aria-modal) and tabIndex handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 554c4ac2-a5ad-487f-83b3-013d38929823

📥 Commits

Reviewing files that changed from the base of the PR and between 7c48fa3 and bd6f993.

📒 Files selected for processing (2)
  • echo/frontend/src/components/layout/BaseLayout.tsx
  • echo/frontend/src/features/sidebar/types.ts

<div
role="dialog"
aria-modal="true"
aria-label="Inbox"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Internationalize the aria-label.

That hardcoded "Inbox" string breaks i18n. Wrap it in a translation call so it ships properly localized.

🌐 Proposed i18n fix
+import { useTranslation } from "react-i18next";
+
 export const BaseLayout = ({ children }: PropsWithChildren) => {
+  const { t } = useTranslation();
   const { isAuthenticated } = useAuthenticated();
   const { overlay } = useSidebarView();
   <div
     role="dialog"
     aria-modal="true"
-    aria-label="Inbox"
+    aria-label={t("inbox.title")}
     tabIndex={-1}

As per coding guidelines: "Use <Trans> component or t` template literal for translations in React components"

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@echo/frontend/src/components/layout/BaseLayout.tsx` at line 60, Replace the
hardcoded aria-label="Inbox" in BaseLayout.tsx with a localized string using
your i18n utilities: locate the JSX element with aria-label="Inbox" and change
it to use the Trans component or the t`...` template literal (per project
conventions) so the value is translated (e.g., aria-label={<Trans>Inbox</Trans>}
or aria-label={t`Inbox`}); ensure you import the corresponding Trans or t from
your i18n module and run a build/lint to pick up missing translation keys.

@ussaama ussaama self-requested a review June 2, 2026 16:39
@dembrane-sam-bot dembrane-sam-bot added this pull request to the merge queue Jun 2, 2026
Merged via the queue into main with commit e0e2faf Jun 2, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants