Skip to content

feat(search): add responsive search with manual expansion#2336

Merged
yujonglee merged 3 commits intomainfrom
feat/responsive-search-expansion
Dec 17, 2025
Merged

feat(search): add responsive search with manual expansion#2336
yujonglee merged 3 commits intomainfrom
feat/responsive-search-expansion

Conversation

@ComputelessComputer
Copy link
Collaborator

Description

  • Implemented responsive search functionality
  • Added manual expansion capability for
  • Enhanced search user experience with responsive design

@netlify
Copy link

netlify bot commented Dec 16, 2025

Deploy Preview for hyprnote-storybook ready!

Name Link
🔨 Latest commit ce9542c
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote-storybook/deploys/69420c74ba3a7e0008600443
😎 Deploy Preview https://deploy-preview-2336--hyprnote-storybook.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Dec 16, 2025

Deploy Preview for hyprnote ready!

Name Link
🔨 Latest commit ce9542c
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/69420c74dc1a7600097b1c4c
😎 Deploy Preview https://deploy-preview-2336--hyprnote.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 16, 2025

📝 Walkthrough

Walkthrough

Adds responsive header layout: parent header tracks available right-side space (ResizeObserver), manages manual search expansion and scroll state, and passes hasSpace and onManualExpandChange props to the Search component; ExpandedSearch width logic simplified and media-query usage removed.

Changes

Cohort / File(s) Summary
Header layout & state
apps/desktop/src/components/main/body/index.tsx
Added useResizeObserver and a right-side container ref; introduced hasSpaceForSearch and isSearchManuallyExpanded state, useScrollState integration, conditional rendering of New Tab / Plus button, and layout tweaks (ml-auto, shrink-0). Passes hasSpace and onManualExpandChange to Search.
Search API & rendering
apps/desktop/src/components/main/body/search.tsx
Updated Search and ExpandedSearch signatures to accept hasSpace and optional onManualExpandChange; removed internal useMediaQuery; propagate manual expansion state via callback; simplified ExpandedSearch width logic (uses fixed 180px on narrow when expanded).
Dependencies
apps/desktop/package.json
Added dependency usehooks-ts ^3.1.1.
Linting config
eslint.config.js
Expanded ignore patterns to include **/*.gen.*.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Areas to focus:
    • Correct setup/teardown and sizing logic of the ResizeObserver in index.tsx.
    • All call sites comply with new Search / ExpandedSearch props.
    • Interaction between isSearchManuallyExpanded and hasSpaceForSearch for conditional New Tab rendering.
    • Width change for ExpandedSearch (180px) and removal of useMediaQuery.
    • useScrollState integration and scroll container behavior.

Possibly related PRs

Pre-merge checks and finishing touches

❌ 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%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the main changes: adding responsive search functionality with manual expansion capability, which aligns with the core modifications across multiple components.
Description check ✅ Passed The description is related to the changeset, covering the main objectives of implementing responsive search, adding manual expansion, and enhancing user experience, though it is somewhat brief and incomplete.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/responsive-search-expansion

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.

Copy link
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: 0

🧹 Nitpick comments (1)
apps/desktop/src/components/main/body/index.tsx (1)

253-262: Consider simplifying the conditional logic.

The double negative !(isSearchManuallyExpanded && !hasSpaceForSearch) is logically correct but harder to parse.

Apply this diff for better readability:

-        {!(isSearchManuallyExpanded && !hasSpaceForSearch) && (
+        {(!isSearchManuallyExpanded || hasSpaceForSearch) && (
           <Button
             onClick={handleNewEmptyTab}
             variant="ghost"
             size="icon"
             className="text-neutral-600"
           >
             <PlusIcon size={16} />
           </Button>
         )}

Both expressions are logically equivalent (De Morgan's law), but the refactored version more directly expresses "show when NOT manually expanded OR when there IS space."

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 52bc01c and a9b3cda.

📒 Files selected for processing (2)
  • apps/desktop/src/components/main/body/index.tsx (3 hunks)
  • apps/desktop/src/components/main/body/search.tsx (3 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*

📄 CodeRabbit inference engine (AGENTS.md)

Format using dprint fmt from the root. Do not use cargo fmt.

Files:

  • apps/desktop/src/components/main/body/index.tsx
  • apps/desktop/src/components/main/body/search.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid creating a bunch of types/interfaces if they are not shared. Especially for function props. Just inline them.
Never do manual state management for form/mutation. Use useForm from tanstack-form and useQuery/useMutation from tanstack-query for 99% cases.

Files:

  • apps/desktop/src/components/main/body/index.tsx
  • apps/desktop/src/components/main/body/search.tsx
**/*.{ts,tsx,rs,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

By default, avoid writing comments at all. If you write one, it should be about 'Why', not 'What'.

Files:

  • apps/desktop/src/components/main/body/index.tsx
  • apps/desktop/src/components/main/body/search.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: If there are many classNames with conditional logic, use cn (import from @hypr/utils). Always pass an array and split by logical grouping.
Use motion/react instead of framer-motion.

Files:

  • apps/desktop/src/components/main/body/index.tsx
  • apps/desktop/src/components/main/body/search.tsx
🧬 Code graph analysis (2)
apps/desktop/src/components/main/body/index.tsx (2)
apps/desktop/src/components/main/body/update.tsx (1)
  • Update (11-79)
apps/desktop/src/components/main/body/search.tsx (1)
  • Search (11-67)
apps/desktop/src/components/main/body/search.tsx (2)
apps/desktop/src/contexts/search/ui.tsx (1)
  • useSearch (261-267)
apps/desktop/src/hooks/useCmdKeyPressed.tsx (1)
  • useCmdKeyPressed (3-35)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Pages changed - hyprnote
  • GitHub Check: fmt
🔇 Additional comments (8)
apps/desktop/src/components/main/body/index.tsx (4)

106-109: LGTM!

State declarations are appropriate for tracking manual expansion and available space.


111-126: Verify the 220px threshold is appropriate for your design.

The ResizeObserver implementation is correct with proper cleanup. However, the 220px threshold appears to be a fixed value that determines when the search bar switches between collapsed and expanded states.

Ensure this threshold value:

  1. Accounts for the minimum width needed to display the expanded search comfortably (currently 180px based on search.tsx line 109)
  2. Leaves adequate buffer space for other header elements
  3. Aligns with your responsive design breakpoints

You can test this by resizing the window and observing the transition point.


169-169: LGTM!

Adding shrink-0 prevents the toggle button from shrinking and maintains layout stability.


264-270: LGTM!

The integration with the Search component is correct:

  • hasSpace prop communicates available space to enable responsive behavior
  • onManualExpandChange callback tracks manual expansion state
  • ml-auto properly positions the search controls to the right
apps/desktop/src/components/main/body/search.tsx (4)

11-17: LGTM!

The props are properly typed inline per coding guidelines. The signature clearly defines:

  • hasSpace: required boolean for space-aware rendering
  • onManualExpandChange: optional callback for parent coordination

23-25: LGTM with a note on callback stability.

The effect correctly propagates manual expansion state to the parent. Since setIsSearchManuallyExpanded from the parent (line 268 in index.tsx) is a stable setState function, the dependency array is safe and won't cause unnecessary re-renders.


105-109: Verify the width behavior change is intentional.

When !hasSpace (manually expanded on narrow screens), the search bar now uses a fixed w-[180px] regardless of focus state, whereas when hasSpace is true, it expands from 180px to 250px on focus.

This means manually expanded search on narrow screens won't grow wider when focused. Confirm this matches your intended UX:

  • Before: Unknown (removed code not shown)
  • After: Manual expansion always 180px; auto-expanded can grow to 250px on focus

Test by:

  1. Narrowing window until search collapses
  2. Clicking to manually expand
  3. Focusing the input and verifying 180px width is adequate for user input

90-96: LGTM!

The ExpandedSearch signature correctly accepts hasSpace for width calculation, along with focus/blur handlers for manual expansion control.

@yujonglee yujonglee merged commit afbba30 into main Dec 17, 2025
12 of 15 checks passed
@yujonglee yujonglee deleted the feat/responsive-search-expansion branch December 17, 2025 01:52
Copy link
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: 0

🧹 Nitpick comments (1)
apps/desktop/package.json (1)

116-116: Clarify the purpose for adding usehooks-ts if overlapping with @uidotdev/usehooks.

With both usehooks-ts and @uidotdev/usehooks (line 83) now in dependencies, verify that this addition serves a specific need not met by the existing library. Both libraries offer similar hooks like useLocalStorage and useCopyToClipboard. If usehooks-ts is being added purely for additional functionality not present in @uidotdev/usehooks, document this decision. If there is significant overlap, consider consolidating to a single library.

Note: usehooks-ts@3.1.1 is a stable, actively maintained release with no known security vulnerabilities. The library is tree-shakable, so unused hooks will not increase bundle size.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a9b3cda and ce9542c.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (3)
  • apps/desktop/package.json (1 hunks)
  • apps/desktop/src/components/main/body/index.tsx (5 hunks)
  • eslint.config.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/desktop/src/components/main/body/index.tsx
🧰 Additional context used
📓 Path-based instructions (3)
**/*

📄 CodeRabbit inference engine (AGENTS.md)

Format using dprint fmt from the root. Do not use cargo fmt.

Files:

  • eslint.config.js
  • apps/desktop/package.json
**/*.{ts,tsx,rs,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

By default, avoid writing comments at all. If you write one, it should be about 'Why', not 'What'.

Files:

  • eslint.config.js
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: If there are many classNames with conditional logic, use cn (import from @hypr/utils). Always pass an array and split by logical grouping.
Use motion/react instead of framer-motion.

Files:

  • eslint.config.js
🧠 Learnings (1)
📚 Learning: 2025-11-24T16:32:24.348Z
Learnt from: CR
Repo: fastrepl/hyprnote PR: 0
File: apps/desktop-e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T16:32:24.348Z
Learning: Applies to apps/desktop-e2e/**/*.{test,spec}.{js,ts,tsx} : Refer to `scripts/setup-desktop-e2e.sh` for end-to-end test environment setup if setup is missing

Applied to files:

  • eslint.config.js
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Pages changed - hyprnote
  • GitHub Check: Redirect rules - hyprnote-storybook
  • GitHub Check: Header rules - hyprnote-storybook
  • GitHub Check: Pages changed - hyprnote-storybook
  • GitHub Check: desktop_ci (linux, depot-ubuntu-24.04-8)
  • GitHub Check: desktop_ci (linux, depot-ubuntu-22.04-8)
  • GitHub Check: fmt
🔇 Additional comments (1)
eslint.config.js (1)

7-7: LGTM!

The ignore pattern for generated files is appropriate and follows common conventions.

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.

2 participants