Repository navigation
feat(search): ✨ Add popular and suggest routes with popularity tracking - #877
Hidden character warning
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
React Doctor found 9 new issues in 4 files · 9 warnings · score 86 / 100 (Great) · 5 fixed · vs 9 warnings
Reviewed by React Doctor for commit |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f42c95a2c3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const suggestions = useQuery({ | ||
| ...searchSuggestQueryOptions({ locale, term: trimmedTerm }), | ||
| enabled: canSuggest, | ||
| placeholderData: canSuggest ? keepPreviousData : undefined, | ||
| }); |
There was a problem hiding this comment.
Prevent stale suggestions from remaining selectable
When the user changes one valid query to another, the debounced term still contains the previous query for 150 ms, and keepPreviousData continues exposing the previous results while the next request runs. Because entries and the Enter/click handlers remain active, typing a new term and immediately pressing Enter can open an unrelated result from the old term. Gate the displayed/selectable entries on the debounced term matching the current trimmed query, or disable selection while the query data is placeholder/stale.
Useful? React with 👍 / 👎.
- Introduced a new search source for external documentation, allowing results from Fumadocs to appear in the header search dialog. - Implemented `docsSearchSource` to fetch and display documentation results based on user input. - Enhanced the search dialog to include a dedicated group for documentation results, improving user experience. - Added a sidebar toggle component for better navigation within the documentation. - Updated search source configuration to support multiple sources and improved query handling.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 72d1835c18
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (await this.isListed(doc.itemType, contentIdKey(doc.itemId))) { | ||
| return null; | ||
| } |
There was a problem hiding this comment.
Track comment counting independently of public visibility
When an existing public comment is hidden or unpublished, its index row remains but isListed returns false because the row is no longer public. Restoring, unhiding, or republishing that comment therefore makes newCommentParent treat it as new and adds another weight-5 comment signal to the parent; repeating the visibility transition can indefinitely inflate the parent's popularity. Record whether the child has already contributed a comment signal independently of its current public state.
Useful? React with 👍 / 👎.
| .orderBy( | ||
| desc(core_search_popularity.logScore), | ||
| sql`${core_search_index.languageCode} = ${requestedLanguage} DESC`, | ||
| ) | ||
| .limit(limit * POPULAR_CANDIDATES_PER_SLOT); |
There was a problem hiding this comment.
Deduplicate translations before limiting popular items
When /popular is called without lang—which the new route explicitly permits—the join returns every translation of each item, but this limit is applied before the JavaScript deduplication below. A highly ranked item with many translations can consume most or all of limit * 3, causing the endpoint to return far fewer unique items than requested even when enough popular items exist. Select one preferred row per (itemType, itemId) in SQL before applying the requested limit.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b54e38a308
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| `variant="bar"` turns the floating header card into a flat, full-width bar that sits flush on the docs layout, and `--fd-banner-height` tells Fumadocs how tall it is, so its sidebar and page fit underneath. Need a button before the logo, like a sidebar toggle? Pass it as `leading`. Load the header's data in the docs route too, with `loadMainShell(context)` in its `loader`. | ||
|
|
||
| Got a layout with its own search button? `SearchDialog` from `@vitnode/core/tanstack/search` is the header dialog without its trigger. Give it `open`, `onOpenChange` and the same `firstSourceId`. |
There was a problem hiding this comment.
Export the documented standalone search dialog
Consumers following this new guidance cannot import or render SearchDialog: a repo-wide search finds only the exported HeaderSearch, whose API accepts firstSourceId but not the documented open or onOpenChange props. Either implement and export the standalone dialog from @vitnode/core/tanstack/search or remove this unsupported integration path from the documentation.
Useful? React with 👍 / 👎.
|
|
||
| const groupByPage = (results: DocsSearchResult[]): DocsPageHit[] => | ||
| results.reduce<DocsPageHit[]>((pages, result) => { | ||
| if (result.type === 'page') return [...pages, { page: result }] |
There was a problem hiding this comment.
React Doctor · react-doctor/no-spread-accumulator-in-reduce (warning)
This is O(n²) because spreading the accumulator copies the entire growing collection every step. Mutate and return the accumulator instead (acc[key] = value; return acc).
Fix → Mutate the accumulator and return it (acc[key] = value; return acc) so the fold stays O(n) instead of copying the whole accumulator every step.
| ); | ||
| }; | ||
|
|
||
| const HeaderSearchMorph = ({ |
There was a problem hiding this comment.
React Doctor · react-doctor/no-giant-component (warning)
Component "HeaderSearchMorph" is over 300 lines long, which is hard to read & change. Split it into a few smaller components.
Fix → Pull each section into its own component so the parent is easier to read, test, and change.
| ); | ||
| }; | ||
|
|
||
| const HeaderSearchMorph = ({ |
There was a problem hiding this comment.
React Doctor · react-doctor/no-high-complexity-react-function (warning)
HeaderSearchMorph has cyclomatic complexity 37, cognitive complexity 33, and maximum nesting depth 3, so its React logic is hard to understand and change. Extract independent branches into components or hooks.
Fix → Extract independent render branches and state logic into focused components or hooks until the control flow is easy to follow.
| <span className="invisible">{query}</span> | ||
| <span className="text-muted-foreground/50">{ghost}</span> | ||
| </span> | ||
| <input |
There was a problem hiding this comment.
React Doctor · react-doctor/no-enter-submit-without-ime-composition-guard (warning)
This text-entry Enter handler commits/submits without bailing on IME composition, so it fires mid-composition for CJK users pressing Enter to confirm a candidate. Bail first with if (e.nativeEvent.isComposing) return; (or track onCompositionStart/onCompositionEnd) before acting on Enter.
Fix → Bail on IME composition before acting on Enter: if (e.nativeEvent.isComposing) return; (or track composition with onCompositionStart/onCompositionEnd). Otherwise Enter fires mid-composition and commits a half-typed value for CJK users.
| aria-expanded={expanded} | ||
| aria-label={t("dialog.label")} | ||
| autoComplete="off" | ||
| autoFocus |
There was a problem hiding this comment.
React Doctor · react-doctor/no-autofocus (warning)
autoFocus moves focus on load, which can disrupt screen reader and keyboard users. Remove it and let users choose where to focus.
Fix → Do not use autoFocus. It disorients users on load.
| const pendingHrefRef = React.useRef<null | string>(null); | ||
| const [isApple, setIsApple] = React.useState<boolean | undefined>(undefined); | ||
|
|
||
| React.useEffect(() => { |
There was a problem hiding this comment.
React Doctor · react-doctor/rendering-hydration-no-flicker (warning)
useEffect(setState, []) runs after the first paint, so users can see the initial state flash. Initialize from a render-safe value or use useSyncExternalStore for external values.
Fix → Initialize state from a render-safe value before the first paint, or read external mutable values with useSyncExternalStore.
| onClick={() => setOpen(true)} | ||
| onPointerEnter={handlePrefetch} | ||
| > | ||
| <button |
There was a problem hiding this comment.
React Doctor · react-doctor/shadcn-input-group-no-raw-controls (warning)
This button sits directly inside InputGroup, so it keeps its own border and focus ring and the group's shared focus and error styling never applies. Use InputGroupButton inside an InputGroupAddon instead.
Fix → Compose InputGroup from its own parts (InputGroupInput, InputGroupTextarea, and InputGroupAddon with InputGroupButton) so the group owns one border, focus ring, and error state.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d83ede05b0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (url.href !== window.location.href) { | ||
| window.history.replaceState(window.history.state, "", url); |
There was a problem hiding this comment.
Keep the router synchronized with the edited search term
When a user edits the term on /search, this native replaceState updates the address bar without notifying TanStack Router, so router.latestLocation retains the original query. A subsequent action that derives its destination from router state—such as useSwitchLocale, whose planFor reads router.latestLocation.href—therefore restores the old term or drops the newly edited one. Update the URL through the router history API so the visible URL and router state remain consistent.
Useful? React with 👍 / 👎.
| const resolved = typeof next === "function" ? next(theme) : next; | ||
| setThemeState(resolved); |
There was a problem hiding this comment.
Preserve queued functional theme updates
When callers invoke setTheme with functional updates more than once before React re-renders, every updater is now evaluated against the same captured theme value rather than the latest queued state. This violates the exported React.SetStateAction contract—for example, two synchronous toggle updaters apply only one toggle and persist that incorrect result to local storage. Resolve functional actions through the real state updater, while moving persistence to a mechanism that does not rely on a stale closure.
Useful? React with 👍 / 👎.
Improving Documentation
pnpm lint:fixto fix formatting issues before opening the PR.Description
What?
Why?