Skip to Content
Welcome to RitoSwap's documentation!

Bottom Bar

The Bottom Bar is a custom navigation and AI control plane integrated into Nextra. It replaces the usual floating TOC UX with a two-panel drawer, custom AI workflows, and scroll controls that feel native to the RitoVision docs.

Architecture map

    • BottomBar.tsx
    • BottomBar.module.css

Where the TOC comes from (standard)

The docs pages already include a Nextra-generated TOC. The Bottom Bar injects itself into that flow and renders the TOC in a custom drawer instead of the default layout.

Step 1: Nextra builds the TOC per page

Each MDX page imported by Nextra returns a toc array.

Step 2: The TOC is provided to the app

docs/app/[[...slug]]/page.tsx wraps content with <TOCProvider initialTOC={toc} />.

Step 3: Bottom Bar consumes the TOC

BottomBar.tsx pulls the live toc from useTOC() and wires it into the TOC drawer.

Drawer system (shared infrastructure)

The bar uses a single drawer shell that hosts two panels: TOC and AI. The panel switch is instant, but the drawer height is measured, clamped, and animated for stability.

  • useDrawerController manages active tab, open/close state, and height measurement.
  • Drawer height clamps to 60% viewport height (DRAWER_MAX_HEIGHT_RATIO) and enables scroll overflow only when needed.
  • The drawer closes on outside clicks or Escape with modal-priority logic (useDrawerDismiss).

TOC drawer (custom presentation of a standard feature)

The TOC experience is standard Nextra data with custom presentation and behavior:

  • TOCDrawer renders the nested list and anchors.
  • useActiveHeading uses IntersectionObserver to highlight the current section.
  • Clicking a heading uses scrollIntoView({ behavior: 'smooth' }) and closes the drawer after the jump.
  • Keyboard support: Enter/Space activates a TOC item via onKeyDown handlers.

The TOC button disables itself when a page has no headings. This prevents empty drawers and makes the bar context-aware.

AI drawer (non-standard, custom workflow)

This is the part that is not standard for Nextra: a full prompt system and AI provider launcher that lives inside the docs UI.

Prompting system (Zustand store + local persistence)

The AI prompt system is stored locally in the browser and persists across sessions.

  • Store: docs/app/stores/promptStore.ts using Zustand + persist.
  • Storage key: ai-prompts.
  • Default prompt: “Please explain this webpage to me”.
  • Users can create, edit, delete, and select prompts in the UI.

The prompt selection modal sorts the active prompt to the top and uses a short “Prompt Activated!” animation to confirm the change.

Prompt editing flow

  • PromptSelectionModal lists prompts and lets you activate or edit.
  • PromptEditModal is used for create/edit and validates name + content.
  • Deletes are guarded with confirmation modals.

The drawer launches external AI sessions, prefilled with prompt + current page URL:

This is done via openAIDeeplink in docs/app/components/navigation/BottomBar/utils/aiDeeplinks.ts.

Copy page as markdown

The AI drawer also includes a Copy Page as Markdown action:

  • copyPageAsMarkdown() converts the current DOM into markdown.
  • Script/style/nav/header/footer are stripped before conversion.
  • The result includes the page title + URL for context.
  • A transient status label uses aria-live=“polite” to announce success/failure.

Scroll controls and visibility

The right side of the bar hosts up/down scroll arrows with smart visibility:

  • useScrollIndicators shows the up arrow only when not near the top and the down arrow only when not near the bottom.
  • Scrolls are smooth and set a short “sticky” active state to keep the button highlighted.
  • Hover/active states fade out automatically after a short timeout.

When the page nears the footer, the entire bar fades out so the footer stays readable.

  • Computed by FOOTER_NEAR_RATIO inside useScrollIndicators.
  • BottomBar.module.css applies opacity: 0 and disables pointer events via .fadeOut.
  • The fade-out is suppressed while the drawer is open to avoid interrupting interactions.

The bar includes a sidebar toggle that bridges to Nextra instead of duplicating state.

  • useSidebarBridge finds the native Nextra sidebar button via ARIA attributes.
  • A MutationObserver tracks aria-expanded to keep state in sync.
  • When no native button is found, it dispatches nextra:toggleSidebar.
  • The button only appears at the breakpoints defined in BottomBar.module.css (hidden on small screens, visible from 768px up).

Accessibility details

Accessibility is treated as a first-class behavior:

  • aria-expanded on AI and TOC toggles.
  • aria-label on all icon buttons and action controls.
  • aria-live on copy status feedback.
  • Keyboard controls for TOC and prompt list entries.
  • Escape key closes modals first, then the drawer.

Key files

  • docs/app/components/navigation/BottomBar/BottomBar.tsx
  • docs/app/components/navigation/BottomBar/drawers/AIDrawer/AIDrawer.tsx
  • docs/app/components/navigation/BottomBar/drawers/TOCDrawer/TOCDrawer.tsx
  • docs/app/stores/promptStore.ts
  • docs/app/components/navigation/BottomBar/utils/markdownCopy.ts
  • docs/app/components/navigation/BottomBar/utils/aiDeeplinks.ts
Last updated on