Skip to content

Eclipse Specific Design (Ongoing)#7695

Open
beseku wants to merge 13 commits intomainfrom
apply-eclispe-design
Open

Eclipse Specific Design (Ongoing)#7695
beseku wants to merge 13 commits intomainfrom
apply-eclispe-design

Conversation

@beseku
Copy link
Copy Markdown
Contributor

@beseku beseku commented Mar 24, 2026

Redesigns the Eclipse design system app to use its own simplified component architecture while maintaining fumadocs integration for content, search, navigation, and heading
tracking.

What changed

Architecture — Replaced the previous fumadocs-ui layout system (~3,800 lines across layout/notebook/, layout/sidebar/, toc/, ui/) with a flat component structure (~950 lines
across 6 files):

  • layout.tsx — DocsLayout with TreeContext, SidebarProvider, and per-page sidebar control
  • sidebar.tsx — SidebarProvider, desktop SidebarContent, mobile SidebarDrawer with animation-based show/hide, SidebarPageTree using fumadocs TreeContext/TreePath
  • page.tsx — Composable DocsPage, DocsHeader, DocsTitle, DocsDescription, DocsBody, DocsFooter
  • toc.tsx — TOCProvider using fumadocs-core AnchorProvider, TocThumb with animated active indicator
  • nav.tsx — Minimal header with mobile sidebar toggle
  • search.tsx — Custom Eclipse-styled search dialog wired through fumadocs SearchProvider

Fumadocs integration preserved:

  • TreeContextProvider / useTreeContext / useTreePath for sidebar page tree
  • AnchorProvider / useActiveAnchors for TOC heading tracking
  • useFooterItems for prev/next page navigation
  • SearchProvider / useSearchContext for search (CMD+K, toggle, dialog)
  • useOnChange, useMediaQuery from fumadocs-core utilities
  • Fetch-based search via /api/search route

Removed:

  • All fumadocs-ui layout components (DocsLayout, DocsPage, Sidebar, TOC variants, theme toggle, language toggle, search toggle, link items, sidebar tabs)
  • All fumadocs-ui UI primitives (button, collapsible, popover, scroll-area)
  • page-actions.tsx (unused LLM copy/view options)
  • cli.json, components.json (unused scaffolding configs)
  • @prisma-docs/ui, @base-ui/react, @fumadocs/cli, class-variance-authority, next-themes, zod, rimraf, tw-animate-css dependencies

Other changes:

  • Removed output: "export" — now uses server mode like docs
  • Added root layout metadata with title template
  • Added suppressHydrationWarning on
  • Added merge-refs.ts utility

Known issue

@prisma/eclipse CodeBlock component uses fd-* CSS tokens from fumadocs-ui. These need to be replaced with Eclipse design tokens in a follow-up PR to the eclipse package.

Summary by CodeRabbit

  • New Features
    • Responsive sidebar, top navigation, updated table of contents, and a rebuilt search dialog with keyboard support.
  • Refactor
    • Simplified docs layout, headers, typography, and consolidated global styling/prose rules.
  • Documentation
    • Rewrote “Introduction” to a shorter “Getting Started” guide with updated setup and prerequisites.
  • Removed
    • Legacy sidebar/TOC implementations, language selector, theme toggle, and several UI primitives/components.
  • Chores
    • Cleaned package scripts/dependencies and updated CSS theme variables.

}

function stripHtml(str: string): string {
return str.replace(/<[^>]*>/g, '');

Check failure

Code scanning / CodeQL

Incomplete multi-character sanitization High

This string may still contain
<script
, which may cause an HTML element injection vulnerability.
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 24, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
blog Ready Ready Preview, Comment Mar 24, 2026 3:28pm
docs Ready Ready Preview, Comment Mar 24, 2026 3:28pm
eclipse Ready Ready Preview, Comment Mar 24, 2026 3:28pm
site Ready Ready Preview, Comment Mar 24, 2026 3:28pm

Request Review

@beseku beseku changed the title Eclipse Specific Design Eclipse Specific Design (Ongoing) Mar 24, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 24, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cdb92801-c646-4452-9ce5-f56f9e617b93

📥 Commits

Reviewing files that changed from the base of the PR and between d925be6 and 33e7677.

📒 Files selected for processing (1)
  • apps/eclipse/src/app/global.css

Walkthrough

Large refactor of the Eclipse app: removed many fumadocs/shadcn config and legacy notebook/layout modules, replaced sidebar/TOC/search/layout primitives with new implementations, rewrote global styles and MDX content, and pruned several dependencies and scripts.

Changes

Cohort / File(s) Summary
Build & Config
apps/eclipse/cli.json, apps/eclipse/components.json, apps/eclipse/next.config.mjs
Deleted Fumadocs CLI and shadcn UI config files; removed output: "export" from Next.js config.
Package Manifest
apps/eclipse/package.json
Removed prebuild script and several dependencies/devDependencies.
Global Styles
apps/eclipse/src/app/global.css, packages/eclipse/src/styles/globals.css
Rewrote global CSS (removed external UI imports, added Tailwind theme animations/utilities/prose rules); renamed mono font CSS variable.
App Layout & Metadata
apps/eclipse/src/app/layout.tsx, apps/eclipse/src/app/(design-system)/layout.tsx
Simplified layout implementations (async→sync), removed Google font setup and external widget, added exported metadata and simplified body classes.
Docs Page & MDX
apps/eclipse/content/design-system/index.mdx, apps/eclipse/src/app/(design-system)/[[...slug]]/page.tsx
Rewrote MDX to a Getting Started guide; simplified MDX page rendering, changed MDX link handling, removed last-update footer.
Docs Page Composition
apps/eclipse/src/components/page.tsx
Added DocsPage composition, header components, and sidebar-enable context/sync primitives.
Provider & Search Mapping
apps/eclipse/src/components/provider.tsx
Replaced NextProvider with RootProvider, set theme disabled, swapped custom search dialog mapping to EclipseSearchDialog.
Search API & UI
apps/eclipse/src/app/api/search/route.ts, apps/eclipse/src/components/search.tsx, apps/eclipse/src/components/page-actions.tsx (deleted)
Added fetch-backed /api/search route; replaced fumadocs search dialog with a portal/modal using fetch search; removed LLM copy/view-options components.
Sidebar Core (new)
apps/eclipse/src/components/sidebar.tsx
Added responsive SidebarProvider, SidebarContent, SidebarDrawer, Folder primitives, auto-scroll, and SidebarPageTree renderer.
Sidebar / Layout Removed
apps/eclipse/src/components/layout/sidebar/*, apps/eclipse/src/components/layout/notebook/*, apps/eclipse/src/components/layout/shared.tsx, apps/eclipse/src/lib/layout.shared.tsx, apps/eclipse/src/lib/urls.ts
Removed legacy notebook-based DocsLayout, sidebar base, many sidebar/tab/dropdown/link-item/language/theme/search primitives, shared helpers, logo/baseOptions, and URL helpers (normalize, isActive).
TOC / Table of Contents
apps/eclipse/src/components/toc.tsx, apps/eclipse/src/components/toc/clerk.tsx (deleted), apps/eclipse/src/components/toc/default.tsx (deleted)
Consolidated TOC into new TableOfContents implementation; removed previous clerk/default TOC variants and mask/depth helpers.
UI Primitives Removed
apps/eclipse/src/components/ui/*
apps/eclipse/src/components/ui/button.tsx, .../collapsible.tsx, .../popover.tsx, .../scroll-area.tsx
Deleted CVA-based button variants and wrapper components around base primitives (collapsible, popover, scroll-area).
Nav & Header Changes
apps/eclipse/src/components/nav.tsx, apps/eclipse/src/components/layout/link-item.tsx (deleted), .../language-toggle.tsx (deleted)
Added new Nav header with sidebar toggle; removed prior link-item and language-toggle modules.
Page Layout Pieces Removed
apps/eclipse/src/components/layout/notebook/*, apps/eclipse/src/components/layout/notebook/page/*, apps/eclipse/src/components/layout/notebook/sidebar.tsx
Large deletions of client-side layout utilities: header/body context, header tabs, TOC popover, breadcrumbs, page footer, and sidebar composition.
Page Actions Removed
apps/eclipse/src/components/page-actions.tsx
Removed LLMCopyButton and ViewOptions (external links/LLM helpers).
Nav/Search UI Changes
apps/eclipse/src/components/search.tsx, apps/eclipse/src/components/layout/search-toggle.tsx (deleted)
Search UI replaced with custom portal/modal and SearchToggle added; former search toggle components removed.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title "Eclipse Specific Design (Ongoing)" is vague and generic, using non-descriptive language that doesn't convey the actual scope of changes. Provide a specific, actionable title that captures the main refactoring effort—e.g., "Refactor Eclipse layout to simplified component architecture" or "Replace fumadocs-ui layout with flat Eclipse-specific components."
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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


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.

@argos-ci
Copy link
Copy Markdown

argos-ci bot commented Mar 24, 2026

The latest updates on your projects. Learn more about Argos notifications ↗︎

Build Status Details Updated (UTC)
default (Inspect) ✅ No changes detected - Mar 24, 2026, 3:34 PM

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: 12

Caution

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

⚠️ Outside diff range comments (1)
apps/eclipse/src/components/toc.tsx (1)

83-103: ⚠️ Potential issue | 🟡 Minor

Guard the no-match path in calc().

If active contains ids that are not rendered in this TOC, upper stays at Number.MAX_VALUE and the thumb gets garbage CSS values. Returning [0, 0] when nothing matches avoids the jump.

Proposed fix
 function calc(container: HTMLElement, active: string[]): TocThumbType {
   if (active.length === 0 || container.clientHeight === 0) {
     return [0, 0];
   }
 
   let upper = Number.MAX_VALUE,
     lower = 0;
+  let matched = false;
 
   for (const item of active) {
     const element = container.querySelector<HTMLElement>(`a[href="#${item}"]`);
     if (!element) continue;
+    matched = true;
 
     const styles = getComputedStyle(element);
     upper = Math.min(upper, element.offsetTop + parseFloat(styles.paddingTop));
     lower = Math.max(
       lower,
       element.offsetTop + element.clientHeight - parseFloat(styles.paddingBottom),
     );
   }
+
+  if (!matched) {
+    return [0, 0];
+  }
 
   return [upper, lower - upper];
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/eclipse/src/components/toc.tsx` around lines 83 - 103, In
calc(container: HTMLElement, active: string[]): TocThumbType ensure the case
where none of the active ids match rendered TOC anchors is handled: after
iterating active and computing upper/lower (the variables inside calc), check if
upper is still Number.MAX_VALUE (meaning no element matched) and return [0, 0]
instead of continuing to compute and return garbage values; update the function
calc to return early in that no-match path so the thumb CSS values remain valid.
♻️ Duplicate comments (1)
apps/eclipse/src/components/search.tsx (1)

107-109: ⚠️ Potential issue | 🟡 Minor

Incomplete HTML sanitization — XSS vector remains.

The regex /<[^>]*>/g doesn't handle malformed tags like <scr<script>ipt>. After one pass, this becomes <script>. CodeQL correctly flagged this. Since result.content comes from the search API which indexes your own content, the risk is lower, but defense-in-depth matters.

🔒 Iterative sanitization or DOM-based approach
 function stripHtml(str: string): string {
-  return str.replace(/<[^>]*>/g, '');
+  // Iteratively strip until no more tags remain
+  let result = str;
+  let previous: string;
+  do {
+    previous = result;
+    result = result.replace(/<[^>]*>/g, '');
+  } while (result !== previous);
+  return result;
 }

Alternatively, use a DOM-based approach:

function stripHtml(str: string): string {
  if (typeof document === 'undefined') return str.replace(/<[^>]*>/g, '');
  const doc = new DOMParser().parseFromString(str, 'text/html');
  return doc.body.textContent ?? '';
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/eclipse/src/components/search.tsx` around lines 107 - 109, The stripHtml
function uses a single-pass regex which allows crafted input like
"<scr<script>ipt>" to bypass filtering; update stripHtml to robustly remove HTML
by using a DOM-based sanitizer in the browser (use DOMParser to parse to
'text/html' and return body.textContent) and provide a safe server-side fallback
(either run iterative stripping until the string no longer changes or use a
proper HTML parser/sanitizer library such as htmlparser2 or sanitize-html) so
that malformed nested tags cannot reconstitute dangerous markup; ensure the
function (stripHtml) returns the sanitized plain text in both environments and
handles the typeof document === 'undefined' case by using the fallback.
🧹 Nitpick comments (7)
apps/eclipse/content/design-system/index.mdx (2)

54-57: CSS import order matters—consider adding a note.

The @import "tailwindcss" must come before Eclipse styles for proper cascade ordering. This is implied by the code order but could trip up users who rearrange imports.

A brief inline comment in the code block could help:

/* Import Tailwind first, then Eclipse styles */
`@import` "tailwindcss";
`@import` "@prisma/eclipse/styles/globals.css";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/eclipse/content/design-system/index.mdx` around lines 54 - 57, Add a
short inline comment above the CSS imports in the code block to explicitly state
that "@import 'tailwindcss';" must come before the Eclipse styles import
("@import '@prisma/eclipse/styles/globals.css';") to preserve cascade ordering;
update the MDX snippet near the existing import lines to include that
single-line explanatory comment so future editors don't accidentally reorder
them.

20-22: Consider specifying minimum versions more precisely.

The prerequisites list tailwindcss v4 and @tailwindcss/postcss v4, but Tailwind v4 is relatively new. It might help users to know the exact minimum version tested (e.g., 4.0.0 or 4.1.0) to avoid compatibility surprises with early v4 releases.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/eclipse/content/design-system/index.mdx` around lines 20 - 22, Update
the prerequisites to specify explicit minimum tested versions instead of loose
"v4" for clarity: replace the entries for `tailwindcss` and
`@tailwindcss/postcss` (currently listed as "v4") with a precise minimum like
"tailwindcss >= 4.0.0" and "@tailwindcss/postcss >= 4.0.0" (or the exact patch
you tested, e.g., "4.1.0") and adjust the surrounding phrasing to indicate these
are the minimum tested versions to avoid ambiguity.
apps/eclipse/src/components/sidebar.tsx (2)

217-219: ReactDOM.flushSync in animation handlers can cause performance issues.

flushSync forces synchronous re-renders, bypassing React's batching. While it ensures the hidden state is set immediately after animation ends, it can cause jank. The animation end is already async, so the sync flush may not be necessary.

Consider testing without flushSync—React 18+ batches state updates by default, and the visual result should be the same:

-onAnimationEnd={() => {
-  if (!open) ReactDOM.flushSync(() => setOverlayHidden(true));
-}}
+onAnimationEnd={() => {
+  if (!open) setOverlayHidden(true);
+}}

Also applies to: 226-228

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/eclipse/src/components/sidebar.tsx` around lines 217 - 219, The
animation end handlers use ReactDOM.flushSync which forces synchronous
re-renders and can cause jank; replace the flushSync call in the onAnimationEnd
handlers with a normal state update (call setOverlayHidden(true) directly) and
verify visuals—if you need to prioritize responsiveness consider using
startTransition around less critical updates; update both occurrences that call
ReactDOM.flushSync (the onAnimationEnd handlers that reference setOverlayHidden)
to avoid flushSync and rely on React 18+ batching instead.

343-353: Complex click handling on folder links could confuse users.

Clicking the icon toggles the folder, clicking the text navigates and conditionally toggles. This dual behavior on a single link element can be unexpected. Users might accidentally toggle when they meant to navigate.

The [data-icon] selector approach is clever but somewhat fragile—it depends on the SVG having data-icon and not being wrapped differently.

Consider separating the toggle button from the link more explicitly, similar to SidebarFolderTrigger, to make the interaction clearer.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/eclipse/src/components/sidebar.tsx` around lines 343 - 353, The current
onClick handler on the folder link (using e.target.matches('[data-icon],
[data-icon] *') and toggling via setOpen) mixes navigation and toggle behavior
and relies on the fragile data-icon selector; change this to separate concerns
by extracting the icon into an explicit toggle control (like
SidebarFolderTrigger) with its own onClick that stops propagation and calls
setOpen(!open), and leave the link's onClick to only handle navigation (or to
setOpen(active ? !open : true) without icon-based detection); update references
in this component to remove the data-icon selector and wire the new toggle
button handler so clicking the icon only toggles and clicking the link only
navigates.
apps/eclipse/src/components/page.tsx (2)

131-138: Footer navigation lookup uses exact pathname match, which may miss trailing slashes or query params.

The findIndex comparison item.url === pathname is strict. If pathname has a trailing slash and item.url doesn't (or vice versa), navigation won't be found.

🔗 Normalize paths before comparison
 const { previous, next } = useMemo(() => {
-  const idx = footerList.findIndex((item) => item.url === pathname);
+  const normalizedPathname = pathname.replace(/\/$/, '');
+  const idx = footerList.findIndex((item) => item.url.replace(/\/$/, '') === normalizedPathname);
   if (idx === -1) return {};
   return {
     previous: footerList[idx - 1],
     next: footerList[idx + 1],
   };
 }, [footerList, pathname]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/eclipse/src/components/page.tsx` around lines 131 - 138, The footer
lookup fails on mismatched path formats; inside the useMemo that computes
{previous, next} (the findIndex using footerList and pathname), normalize both
item.url and pathname before comparing (e.g., strip query/hash and trailing
slashes, treat root "/" consistently) and use the normalized values in
findIndex; implement a small helper (normalizePath) and replace the strict
equality check item.url === pathname with normalizePath(item.url) ===
normalizePath(pathname) in the useMemo that computes previous and next.

143-143: Footer has inconsistent padding class compared to other page sections.

DocsFooter uses p-6 (padding all sides) while DocsHeader and DocsBody use px-6 ... py-6. This creates visual inconsistency on mobile where DocsFooter gets top padding from p-6 but also has md:py-12.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/eclipse/src/components/page.tsx` at line 143, DocsFooter's footer
element uses p-6 which applies uniform padding and causes extra top padding on
mobile; change the class on the footer element (the <footer className="p-6
md:pl-[18.5rem] md:pr-12 md:py-12 ..."> in the DocsFooter/Docs page component)
from p-6 to px-6 py-6 so it matches DocsHeader and DocsBody and keeps consistent
horizontal and vertical padding across breakpoints.
apps/eclipse/src/components/search.tsx (1)

28-31: Body scroll lock cleanup may leave stale state if component unmounts unexpectedly.

The cleanup function restores overflow to an empty string, which works if no other code modifies document.body.style.overflow. However, if another modal or overlay sets overflow while this dialog is open, the cleanup will clobber that value.

🛡️ Safer scroll lock that preserves previous value
  useEffect(() => {
+   const previousOverflow = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
-   return () => { document.body.style.overflow = ''; };
+   return () => { document.body.style.overflow = previousOverflow; };
  }, []);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/eclipse/src/components/search.tsx` around lines 28 - 31, Store the
previous body overflow when the effect runs and restore it only if we still own
the lock: in the useEffect that currently sets document.body.style.overflow =
'hidden' (in apps/eclipse/src/components/search.tsx), capture const prevOverflow
= document.body.style.overflow before setting it to 'hidden', and in the cleanup
check if document.body.style.overflow === 'hidden' (i.e., still our lock) then
restore document.body.style.overflow = prevOverflow; this preserves other
modals' changes and avoids clobbering their value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/eclipse/src/app/global.css`:
- Around line 52-54: The .font-mono-settings rule uses the wrong CSS variable
name (--font-mono--settings) so the font-feature settings won't be applied;
change the variable reference inside the .font-mono-settings declaration to the
correct token (--font-mono-settings) so font-feature-settings:
var(--font-mono-settings) uses the intended value; update any other occurrences
of --font-mono--settings to --font-mono-settings to keep names consistent.
- Around line 132-134: The global rule targets every li and forces list-disc,
which removes numbering from ordered lists; change the selector so only
unordered lists get the disc style (e.g., replace the global li selector with a
selector targeting ul li or add a utility-class for unordered lists) and keep
the `@apply` mx-6 list-outside on li elements that need the spacing; update the
selector that contains "@apply mx-6 list-disc list-outside;" (the li rule) to
restrict list-disc to unordered lists only so ol items keep their numbers.
- Line 4: The Stylelint failure is caused by the standard SCSS rule
at-rule-no-unknown flagging Tailwind v4 at-rules like `@theme` (and Tailwind uses
`@import/`@keyframes in its scope); update .stylelintrc.json to configure the
at-rule-no-unknown rule to ignore Tailwind-specific at-rules (add the Tailwind
at-rules array or disable at-rule-no-unknown and enable
stylelint-config-tailwindcss/at-rule exceptions) so `@theme`, `@import`, `@keyframes`
used by Tailwind v4 no longer trigger errors.

In `@apps/eclipse/src/components/layout.tsx`:
- Around line 12-18: DocsLayoutProps declares sidebar.banner but the
implementation builds its own searchBanner and ignores that prop; fix by wiring
the prop through: in the component that creates searchBanner (reference
searchBanner) read props.sidebar?.banner (from DocsLayoutProps) and either
replace searchBanner with that node when provided or merge them (e.g., render
both nodes or wrap them in a fragment) so the passed banner is used;
alternatively, if you prefer to remove the unused API, delete sidebar.banner
from DocsLayoutProps to keep the interface in sync with the implementation.
- Around line 43-54: layout.tsx currently only checks the layout prop
sidebarEnabled before rendering SidebarContent and SidebarDrawer, so per-page
disables via SidebarEnabledFromPageProvider/SidebarEnabledSync are ignored;
update the rendering gate to consume the SidebarEnabledContext (or use the
existing SidebarEnabledGate) and use the context's effective value instead of
the raw sidebarEnabled prop when deciding to render SidebarContent and
SidebarDrawer (keep SidebarEnabledFromPageProvider in place to provide the
context to children and ensure SidebarEnabledSync can update pageEnabled).

In `@apps/eclipse/src/components/page.tsx`:
- Around line 39-43: SidebarEnabledSync currently calls setEnabled during render
which violates React rules; change it to call setEnabled inside a useEffect
hook: import useEffect from React, then inside SidebarEnabledSync use
useEffect(() => { if (!enabled) setEnabled(false); }, [enabled, setEnabled]);
keep the component returning null as before and mention
SidebarEnabledSetterContext and the parent SidebarEnabledFromPageProvider so
reviewers can locate the related state provider.
- Around line 81-92: DocsHeader currently destructures className and ...props
but never uses them, so custom classes and attributes passed to DocsHeader are
ignored; update the function to merge the incoming className with the existing
header class string (using your project's utility like clsx or a template
literal) and spread ...props onto the <header> element so attributes like id,
aria-*, or event handlers are preserved; locate the DocsHeader component and
modify the <header> element to include the merged className and {...props}.

In `@apps/eclipse/src/components/search.tsx`:
- Around line 144-146: The KBD label is hardcoded to "CMD+K"; change it to
detect platform (mac vs others) and render the appropriate modifier string
(e.g., "⌘K" or "Ctrl+K") where the <kbd> element is rendered in the Search
component (the kbd element shown in search.tsx); add a small helper (e.g., isMac
using navigator.platform or userAgent guard for SSR) and use that boolean to
choose the displayed text so Windows/Linux users see "Ctrl+K" while mac users
see the Command symbol.
- Around line 47-53: Wrap the dialog container div (the element with
onClick={(e) => e.stopPropagation()} and onKeyDown handling Escape/onClose) with
proper ARIA attributes and a focus trap: add role="dialog", aria-modal="true"
and aria-labelledby pointing to the dialog title element (create an id on the
title) so screen readers recognize it, ensure the container has tabIndex={-1}
and programmatically focus it (or the first interactive element) when mounted,
and implement keyboard focus trapping (handle Tab and Shift+Tab to keep focus
inside the dialog) and restore focus to the previously focused element when
onClose is called.

In `@apps/eclipse/src/components/sidebar.tsx`:
- Around line 205-206: The current render directly calls setOverlayHidden(false)
and setDrawerHidden(false) when open is true, which is an anti-pattern; move
this logic into a useEffect that runs when open changes (e.g., useEffect(() => {
if (open) { if (overlayHidden) setOverlayHidden(false); if (drawerHidden)
setDrawerHidden(false); } }, [open, overlayHidden, drawerHidden])), referencing
the state setters setOverlayHidden and setDrawerHidden and the state values
overlayHidden and drawerHidden so updates only occur inside the effect and only
when necessary.
- Line 375: The SidebarItem component declares an external prop but never uses
it; update the SidebarItem function signature and implementation to either
remove the external prop or apply appropriate external-link behavior: when
external is true, render the anchor with target="_blank" and rel="noopener
noreferrer" and optionally show an external-link icon next to children; ensure
any callers passing external remain compatible or remove the prop type from
callers if you choose to delete it. Reference: SidebarItem (function) and the
external prop in its props type.
- Around line 167-181: The hover timeout referenced by timerRef (used in the
onPointerLeave handler) can fire after unmount; add a cleanup to clear the
timeout on component unmount: implement a useEffect cleanup that calls
window.clearTimeout(timerRef.current) (and optionally sets timerRef.current = 0)
so any pending timer from onPointerLeave is cancelled; ensure this ties to the
same timerRef used alongside onPointerEnter/onPointerLeave and does not rely on
event handlers to clear it.

---

Outside diff comments:
In `@apps/eclipse/src/components/toc.tsx`:
- Around line 83-103: In calc(container: HTMLElement, active: string[]):
TocThumbType ensure the case where none of the active ids match rendered TOC
anchors is handled: after iterating active and computing upper/lower (the
variables inside calc), check if upper is still Number.MAX_VALUE (meaning no
element matched) and return [0, 0] instead of continuing to compute and return
garbage values; update the function calc to return early in that no-match path
so the thumb CSS values remain valid.

---

Duplicate comments:
In `@apps/eclipse/src/components/search.tsx`:
- Around line 107-109: The stripHtml function uses a single-pass regex which
allows crafted input like "<scr<script>ipt>" to bypass filtering; update
stripHtml to robustly remove HTML by using a DOM-based sanitizer in the browser
(use DOMParser to parse to 'text/html' and return body.textContent) and provide
a safe server-side fallback (either run iterative stripping until the string no
longer changes or use a proper HTML parser/sanitizer library such as htmlparser2
or sanitize-html) so that malformed nested tags cannot reconstitute dangerous
markup; ensure the function (stripHtml) returns the sanitized plain text in both
environments and handles the typeof document === 'undefined' case by using the
fallback.

---

Nitpick comments:
In `@apps/eclipse/content/design-system/index.mdx`:
- Around line 54-57: Add a short inline comment above the CSS imports in the
code block to explicitly state that "@import 'tailwindcss';" must come before
the Eclipse styles import ("@import '@prisma/eclipse/styles/globals.css';") to
preserve cascade ordering; update the MDX snippet near the existing import lines
to include that single-line explanatory comment so future editors don't
accidentally reorder them.
- Around line 20-22: Update the prerequisites to specify explicit minimum tested
versions instead of loose "v4" for clarity: replace the entries for
`tailwindcss` and `@tailwindcss/postcss` (currently listed as "v4") with a
precise minimum like "tailwindcss >= 4.0.0" and "@tailwindcss/postcss >= 4.0.0"
(or the exact patch you tested, e.g., "4.1.0") and adjust the surrounding
phrasing to indicate these are the minimum tested versions to avoid ambiguity.

In `@apps/eclipse/src/components/page.tsx`:
- Around line 131-138: The footer lookup fails on mismatched path formats;
inside the useMemo that computes {previous, next} (the findIndex using
footerList and pathname), normalize both item.url and pathname before comparing
(e.g., strip query/hash and trailing slashes, treat root "/" consistently) and
use the normalized values in findIndex; implement a small helper (normalizePath)
and replace the strict equality check item.url === pathname with
normalizePath(item.url) === normalizePath(pathname) in the useMemo that computes
previous and next.
- Line 143: DocsFooter's footer element uses p-6 which applies uniform padding
and causes extra top padding on mobile; change the class on the footer element
(the <footer className="p-6 md:pl-[18.5rem] md:pr-12 md:py-12 ..."> in the
DocsFooter/Docs page component) from p-6 to px-6 py-6 so it matches DocsHeader
and DocsBody and keeps consistent horizontal and vertical padding across
breakpoints.

In `@apps/eclipse/src/components/search.tsx`:
- Around line 28-31: Store the previous body overflow when the effect runs and
restore it only if we still own the lock: in the useEffect that currently sets
document.body.style.overflow = 'hidden' (in
apps/eclipse/src/components/search.tsx), capture const prevOverflow =
document.body.style.overflow before setting it to 'hidden', and in the cleanup
check if document.body.style.overflow === 'hidden' (i.e., still our lock) then
restore document.body.style.overflow = prevOverflow; this preserves other
modals' changes and avoids clobbering their value.

In `@apps/eclipse/src/components/sidebar.tsx`:
- Around line 217-219: The animation end handlers use ReactDOM.flushSync which
forces synchronous re-renders and can cause jank; replace the flushSync call in
the onAnimationEnd handlers with a normal state update (call
setOverlayHidden(true) directly) and verify visuals—if you need to prioritize
responsiveness consider using startTransition around less critical updates;
update both occurrences that call ReactDOM.flushSync (the onAnimationEnd
handlers that reference setOverlayHidden) to avoid flushSync and rely on React
18+ batching instead.
- Around line 343-353: The current onClick handler on the folder link (using
e.target.matches('[data-icon], [data-icon] *') and toggling via setOpen) mixes
navigation and toggle behavior and relies on the fragile data-icon selector;
change this to separate concerns by extracting the icon into an explicit toggle
control (like SidebarFolderTrigger) with its own onClick that stops propagation
and calls setOpen(!open), and leave the link's onClick to only handle navigation
(or to setOpen(active ? !open : true) without icon-based detection); update
references in this component to remove the data-icon selector and wire the new
toggle button handler so clicking the icon only toggles and clicking the link
only navigates.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 40dddb08-795d-4e6b-bcdb-b0ada8420f72

📥 Commits

Reviewing files that changed from the base of the PR and between 74746d2 and 4b9bfe9.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (41)
  • apps/eclipse/cli.json
  • apps/eclipse/components.json
  • apps/eclipse/content/design-system/index.mdx
  • apps/eclipse/next.config.mjs
  • apps/eclipse/package.json
  • apps/eclipse/src/app/(design-system)/[[...slug]]/page.tsx
  • apps/eclipse/src/app/(design-system)/layout.tsx
  • apps/eclipse/src/app/api/search/route.ts
  • apps/eclipse/src/app/global.css
  • apps/eclipse/src/app/layout.tsx
  • apps/eclipse/src/components/layout.tsx
  • apps/eclipse/src/components/layout/language-toggle.tsx
  • apps/eclipse/src/components/layout/link-item.tsx
  • apps/eclipse/src/components/layout/notebook/client.tsx
  • apps/eclipse/src/components/layout/notebook/index.tsx
  • apps/eclipse/src/components/layout/notebook/page/client.tsx
  • apps/eclipse/src/components/layout/notebook/page/index.tsx
  • apps/eclipse/src/components/layout/notebook/sidebar.tsx
  • apps/eclipse/src/components/layout/search-toggle.tsx
  • apps/eclipse/src/components/layout/shared.tsx
  • apps/eclipse/src/components/layout/sidebar/base.tsx
  • apps/eclipse/src/components/layout/sidebar/link-item.tsx
  • apps/eclipse/src/components/layout/sidebar/page-tree.tsx
  • apps/eclipse/src/components/layout/sidebar/tabs/dropdown.tsx
  • apps/eclipse/src/components/layout/sidebar/tabs/index.tsx
  • apps/eclipse/src/components/layout/theme-toggle.tsx
  • apps/eclipse/src/components/nav.tsx
  • apps/eclipse/src/components/page-actions.tsx
  • apps/eclipse/src/components/page.tsx
  • apps/eclipse/src/components/provider.tsx
  • apps/eclipse/src/components/search.tsx
  • apps/eclipse/src/components/sidebar.tsx
  • apps/eclipse/src/components/toc.tsx
  • apps/eclipse/src/components/toc/clerk.tsx
  • apps/eclipse/src/components/toc/default.tsx
  • apps/eclipse/src/components/ui/button.tsx
  • apps/eclipse/src/components/ui/collapsible.tsx
  • apps/eclipse/src/components/ui/popover.tsx
  • apps/eclipse/src/components/ui/scroll-area.tsx
  • apps/eclipse/src/lib/layout.shared.tsx
  • apps/eclipse/src/lib/urls.ts
💤 Files with no reviewable changes (27)
  • apps/eclipse/next.config.mjs
  • apps/eclipse/cli.json
  • apps/eclipse/components.json
  • apps/eclipse/src/lib/urls.ts
  • apps/eclipse/src/components/ui/button.tsx
  • apps/eclipse/src/components/layout/sidebar/tabs/index.tsx
  • apps/eclipse/src/components/layout/notebook/sidebar.tsx
  • apps/eclipse/src/components/toc/default.tsx
  • apps/eclipse/src/components/layout/language-toggle.tsx
  • apps/eclipse/src/components/ui/scroll-area.tsx
  • apps/eclipse/src/lib/layout.shared.tsx
  • apps/eclipse/src/components/layout/theme-toggle.tsx
  • apps/eclipse/src/components/layout/link-item.tsx
  • apps/eclipse/src/components/layout/shared.tsx
  • apps/eclipse/src/components/layout/sidebar/tabs/dropdown.tsx
  • apps/eclipse/src/components/layout/sidebar/link-item.tsx
  • apps/eclipse/src/components/layout/notebook/index.tsx
  • apps/eclipse/src/components/ui/collapsible.tsx
  • apps/eclipse/src/components/layout/notebook/page/client.tsx
  • apps/eclipse/src/components/layout/sidebar/page-tree.tsx
  • apps/eclipse/src/components/layout/sidebar/base.tsx
  • apps/eclipse/src/components/ui/popover.tsx
  • apps/eclipse/src/components/layout/search-toggle.tsx
  • apps/eclipse/src/components/layout/notebook/page/index.tsx
  • apps/eclipse/src/components/layout/notebook/client.tsx
  • apps/eclipse/src/components/page-actions.tsx
  • apps/eclipse/src/components/toc/clerk.tsx

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

♻️ Duplicate comments (1)
apps/eclipse/src/components/search.tsx (1)

50-59: ⚠️ Potential issue | 🟠 Major

Please finish the modal focus management.

Most of the dialog semantics are in place, but Tab/Shift+Tab can still escape into the page behind the modal, and the clickable ESC chip is not a keyboard-accessible control. Please trap focus while the dialog is open and make the close affordance a real button.

Also applies to: 69-74

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/eclipse/src/components/search.tsx` around lines 50 - 59, The modal
currently uses a plain div and inline onKeyDown but lacks focus trapping and a
semantic close control; update the Search component to make the "ESC" affordance
a real <button> that calls onClose and is keyboard-focusable, add a ref (e.g.,
modalRef) to the dialog root and on mount save document.activeElement and move
focus into the modal (preferably to the search input), and implement a focus
trap in a useEffect that listens for Tab/Shift+Tab to loop focus among focusable
elements inside modalRef (querySelectorAll for anchors, inputs, buttons,
[tabindex]:not([tabindex="-1"])), restoring the previously focused element on
unmount; keep the existing Escape handling but ensure it also triggers onClose
from the same effect.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/eclipse/src/app/global.css`:
- Around line 101-102: The `@apply` directive in apps/eclipse/src/app/global.css
is missing a trailing semicolon (currently `@apply mt-6` before the closing
brace); update that CSS rule by adding the semicolon so it reads `@apply mt-6;`
to ensure PostCSS/Tailwind parsing is valid and avoids errors in stricter
environments.

---

Duplicate comments:
In `@apps/eclipse/src/components/search.tsx`:
- Around line 50-59: The modal currently uses a plain div and inline onKeyDown
but lacks focus trapping and a semantic close control; update the Search
component to make the "ESC" affordance a real <button> that calls onClose and is
keyboard-focusable, add a ref (e.g., modalRef) to the dialog root and on mount
save document.activeElement and move focus into the modal (preferably to the
search input), and implement a focus trap in a useEffect that listens for
Tab/Shift+Tab to loop focus among focusable elements inside modalRef
(querySelectorAll for anchors, inputs, buttons,
[tabindex]:not([tabindex="-1"])), restoring the previously focused element on
unmount; keep the existing Escape handling but ensure it also triggers onClose
from the same effect.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3d73381a-cdb1-4c94-a261-cc080f9eacbe

📥 Commits

Reviewing files that changed from the base of the PR and between 4b9bfe9 and d925be6.

📒 Files selected for processing (6)
  • apps/eclipse/src/app/global.css
  • apps/eclipse/src/components/layout.tsx
  • apps/eclipse/src/components/page.tsx
  • apps/eclipse/src/components/search.tsx
  • apps/eclipse/src/components/sidebar.tsx
  • packages/eclipse/src/styles/globals.css
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/eclipse/src/components/sidebar.tsx
  • apps/eclipse/src/components/page.tsx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant