Skip to content

Improve mobile view rule page responsiveness#8

Open
R44VC0RP wants to merge 1 commit intomainfrom
cursor/improve-mobile-view-rule-page-responsiveness-0db2
Open

Improve mobile view rule page responsiveness#8
R44VC0RP wants to merge 1 commit intomainfrom
cursor/improve-mobile-view-rule-page-responsiveness-0db2

Conversation

@R44VC0RP
Copy link
Owner

@R44VC0RP R44VC0RP commented Aug 29, 2025

Add a hovering actions bar, hide the CLI card on mobile, and enable auto-expanding textarea on mobile to improve the view rule page's mobile experience and consistency.

The changes address three distinct issues:

  • The hovering actions bar provides quick access to actions, consistent with other pages.
  • Hiding the CLI card on mobile prevents UI overflow.
  • The auto-expanding textarea enhances readability by eliminating scrolling on small screens.

Open in Cursor Open in Web

Summary by CodeRabbit

  • New Features

    • Floating action bar with Download, Copy, CLI, and Share actions, including dynamic labels and status.
    • One-tap copy for page URL and CLI install command with toast feedback.
    • Auto-resizing editor on mobile for smoother typing.
    • Views and content stats surfaced in the action bar.
  • Style

    • Installation Instructions card hidden on mobile for a cleaner layout.
    • Token/character counts relocated to the floating bar with responsive visibility.
    • Increased editor minimum height on desktop and improved spacing around content.

Co-authored-by: raavtube <raavtube@icloud.com>
@cursor
Copy link

cursor bot commented Aug 29, 2025

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

@vercel
Copy link

vercel bot commented Aug 29, 2025

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

Project Deployment Preview Comments Updated (UTC)
cursor.link Ready Ready Preview Comment Aug 29, 2025 0:32am

@coderabbitai
Copy link

coderabbitai bot commented Aug 29, 2025

Walkthrough

Introduces a floating action bar with copy-to-clipboard (URL and CLI), download, and list actions; adds mobile textarea auto-resize; integrates tracking and toasts for copy actions; adjusts responsive visibility of installation instructions and stats; adds refs/state; reorganizes layout to accommodate the new bar. No exported signatures changed.

Changes

Cohort / File(s) Summary of Changes
Public Rule Page UI and Interactions
app/rule/[slug]/page.tsx
Added useRef and Share2 import; introduced urlCopied state and textareaRef; implemented mobile textarea auto-resize with resize listener; added handleCopyViewURL and handleCopyCLI with clipboard, tracking, and toasts; replaced action area with floating glass bar (Download, Copy, CLI, URL, AddToList); moved stats into bar; adjusted responsive classes; minor cleanup.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant P as PublicRulePage
  participant CB as Clipboard API
  participant T as Toast
  participant Tr as Tracking

  U->>P: Click "Copy URL"
  P->>CB: writeText(window.location.href)
  alt success
    P->>Tr: track(copy_url)
    P->>T: show("URL copied")
  else error
    P->>T: show("Failed to copy")
  end

  U->>P: Click "Copy CLI"
  P->>CB: writeText("npm i -g ...")
  alt success
    P->>Tr: track(copy_cli)
    P->>T: show("CLI copied")
  else error
    P->>T: show("Failed to copy")
  end
Loading
sequenceDiagram
  participant W as Window (resize/load)
  participant P as PublicRulePage effect
  participant TA as Textarea (ref)

  W-->>P: resize or content change
  P->>TA: measure scrollHeight
  P->>TA: set style.height to fit content (mobile only)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

A rabbit taps the floating bar—so sleek!
Copy, clip, and share with just a click.
The textarea stretches, calm and wide,
While tokens count and views abide.
I twitch my ears at toasts that chime—
Hop, paste, done—efficient time! 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch cursor/improve-mobile-view-rule-page-responsiveness-0db2

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbit in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbit in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbit gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbit read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbit help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbit ignore or @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbit summary or @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbit or @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Comment on lines +171 to +180
const handleCopyCLI = async () => {
if (!rule) return

const installCommand = `npx shadcn add ${window.location.origin}/api/registry/${rule.id}`
await navigator.clipboard.writeText(installCommand)
setCliCopied(true)
track("CLI Command Copied", { ruleId: rule.id })
setTimeout(() => setCliCopied(false), 2000)
toast.success("Install command copied to clipboard!")
}
Copy link

Choose a reason for hiding this comment

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

The handleCopyCLI function is a duplicate of the existing handleInstallCopy function, creating unnecessary code duplication.

View Details

Analysis

The code contains two identical functions that perform the same operation:

  1. handleInstallCopy (lines 134-143) - original function used by the CLI card
  2. handleCopyCLI (lines 171-180) - duplicate function used by the floating action bar

Both functions:

  • Generate the same install command
  • Copy to clipboard
  • Set the same state (setCliCopied(true))
  • Show the same toast message
  • Use the same timeout duration

The only difference is the tracking event name ("CLI Copied" vs "CLI Command Copied"). This duplication increases bundle size and creates maintenance overhead. Since the CLI card is now hidden on mobile (hidden md:block on line 260), the floating action bar could reuse the existing handleInstallCopy function instead of duplicating it. Either remove the duplicate function and use handleInstallCopy, or remove the original and keep handleCopyCLI if the different tracking event name is intentional.

@R44VC0RP R44VC0RP marked this pull request as ready for review August 29, 2025 14:30
Copy link

@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: 3

Caution

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

⚠️ Outside diff range comments (2)
app/rule/[slug]/page.tsx (2)

291-294: Fix SSR crash: avoid window in render.

Referencing window during render can throw when pre-rendered. Use a guarded expression.

-                <code className="flex-1 text-sm text-gray-300 font-mono">
-                  npx shadcn add {window.location.origin}/api/registry/{rule.id}
-                </code>
+                <code className="flex-1 text-sm text-gray-300 font-mono">
+                  {`npx shadcn add ${typeof window !== "undefined" ? window.location.origin : ""}/api/registry/${rule.id}`}
+                </code>

151-153: Sanitize download filename.

Avoid invalid characters and overly long names.

-    a.download = `${rule.title}.txt`
+    const safeTitle = rule.title.replace(/[^\w\-]+/g, "_").slice(0, 64)
+    a.download = `${safeTitle}.txt`
♻️ Duplicate comments (1)
app/rule/[slug]/page.tsx (1)

171-180: Remove duplicate CLI copy handler and make CLI action visible on mobile.

Deduplicate by reusing handleInstallCopy and expose the CLI action on small screens (matches PR goals).

-  const handleCopyCLI = async () => {
-    if (!rule) return
-    
-    const installCommand = `npx shadcn add ${window.location.origin}/api/registry/${rule.id}`
-    await navigator.clipboard.writeText(installCommand)
-    setCliCopied(true)
-    track("CLI Command Copied", { ruleId: rule.id })
-    setTimeout(() => setCliCopied(false), 2000)
-    toast.success("Install command copied to clipboard!")
-  }
...
-            <Button
-              onClick={handleCopyCLI}
+            <Button
+              onClick={handleInstallCopy}
               variant="primary"
               size="sm"
-              className="hover:bg-[#90BAE0] px-2 py-2 sm:px-3 sm:py-1 aspect-square sm:aspect-auto hidden md:flex"
+              className="hover:bg-[#90BAE0] px-2 py-2 sm:px-3 sm:py-1 aspect-square sm:aspect-auto"
             >
               <Terminal className="h-3 w-3" />
               <span className="hidden md:inline ml-1">{cliCopied ? "Copied!" : "CLI"}</span>
             </Button>

Also applies to: 331-339

🧹 Nitpick comments (3)
app/rule/[slug]/page.tsx (3)

182-198: Smoother auto-resize: use rAF and avoid layout thrash.

Replace timeout with requestAnimationFrame and wrap resize handler.

-  useEffect(() => {
-    const adjustTextareaHeight = () => {
-      if (textareaRef.current && window.innerWidth < 768) {
-        textareaRef.current.style.height = 'auto'
-        textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`
-      }
-    }
-
-    if (rule?.content) {
-      setTimeout(adjustTextareaHeight, 100)
-    }
-
-    window.addEventListener('resize', adjustTextareaHeight)
-    return () => window.removeEventListener('resize', adjustTextareaHeight)
-  }, [rule?.content])
+  useEffect(() => {
+    const adjustTextareaHeight = () => {
+      if (textareaRef.current && window.innerWidth < 768) {
+        textareaRef.current.style.height = 'auto'
+        const el = textareaRef.current
+        requestAnimationFrame(() => {
+          if (el) el.style.height = `${el.scrollHeight}px`
+        })
+      }
+    }
+    if (rule?.content) requestAnimationFrame(adjustTextareaHeight)
+    const onResize = () => requestAnimationFrame(adjustTextareaHeight)
+    window.addEventListener('resize', onResize)
+    return () => window.removeEventListener('resize', onResize)
+  }, [rule?.content])

306-309: Respect safe-area and add toolbar semantics.

Prevent overlap with iOS home indicator and improve a11y.

-      <div className="fixed bottom-4 left-1/2 transform -translate-x-1/2 z-40 max-w-[calc(100vw-2rem)]">
+      <div className="fixed left-1/2 transform -translate-x-1/2 z-40 max-w-[calc(100vw-2rem)]" style={{ bottom: 'max(1rem, env(safe-area-inset-bottom))' }}>
         <div className="bg-neutral-300/20 dark:bg-neutral-400/20 text-neutral-600 dark:text-neutral-300 backdrop-blur-[1px] border border-neutral-400/20 rounded-xl p-2 sm:p-3 shadow-2xl overflow-x-auto">
-          <div className="flex items-center gap-2 sm:gap-3 min-w-max">
+          <div className="flex items-center gap-2 sm:gap-3 min-w-max" role="toolbar" aria-label="Rule actions">

125-143: Analytics naming consistency.

Events use mixed names (“CLI Copied” vs “CLI Command Copied”). Standardize for clean dashboards, e.g., “Public Rule CLI Copied”.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0465814 and 9808fbb.

📒 Files selected for processing (1)
  • app/rule/[slug]/page.tsx (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
app/rule/[slug]/page.tsx (1)
components/lists/add-to-list-button.tsx (1)
  • AddToListButton (15-48)

Comment on lines +160 to +169
const handleCopyViewURL = async () => {
if (!rule) return

const viewURL = window.location.href
await navigator.clipboard.writeText(viewURL)
setUrlCopied(true)
track("Public Rule View URL Copied", { ruleId: rule.id })
setTimeout(() => setUrlCopied(false), 2000)
toast.success("View URL copied to clipboard!")
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Harden clipboard copy with error handling.

Wrap in try/catch and show a failure toast.

-  const handleCopyViewURL = async () => {
-    if (!rule) return
-    
-    const viewURL = window.location.href
-    await navigator.clipboard.writeText(viewURL)
-    setUrlCopied(true)
-    track("Public Rule View URL Copied", { ruleId: rule.id })
-    setTimeout(() => setUrlCopied(false), 2000)
-    toast.success("View URL copied to clipboard!")
-  }
+  const handleCopyViewURL = async () => {
+    if (!rule) return
+    try {
+      const viewURL = window.location.href
+      await navigator.clipboard.writeText(viewURL)
+      setUrlCopied(true)
+      track("Public Rule View URL Copied", { ruleId: rule.id })
+      setTimeout(() => setUrlCopied(false), 2000)
+      toast.success("View URL copied to clipboard!")
+    } catch (e) {
+      toast.error("Failed to copy URL. Please copy it manually.")
+    }
+  }

Apply the same pattern to handleCopy and handleInstallCopy.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleCopyViewURL = async () => {
if (!rule) return
const viewURL = window.location.href
await navigator.clipboard.writeText(viewURL)
setUrlCopied(true)
track("Public Rule View URL Copied", { ruleId: rule.id })
setTimeout(() => setUrlCopied(false), 2000)
toast.success("View URL copied to clipboard!")
}
const handleCopyViewURL = async () => {
if (!rule) return
try {
const viewURL = window.location.href
await navigator.clipboard.writeText(viewURL)
setUrlCopied(true)
track("Public Rule View URL Copied", { ruleId: rule.id })
setTimeout(() => setUrlCopied(false), 2000)
toast.success("View URL copied to clipboard!")
} catch (e) {
toast.error("Failed to copy URL. Please copy it manually.")
}
}

value={rule.content}
readOnly
className="min-h-[500px] resize-none border-0 bg-[#1B1D21] text-white leading-relaxed"
className="min-h-[500px] md:min-h-[500px] resize-none border-0 bg-[#1B1D21] text-white leading-relaxed"
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Honor PR goal on mobile: remove 500px min-height for small screens.

Currently forces 500px on mobile, causing overflow.

-                className="min-h-[500px] md:min-h-[500px] resize-none border-0 bg-[#1B1D21] text-white leading-relaxed"
+                className="min-h-0 md:min-h-[500px] resize-none border-0 bg-[#1B1D21] text-white leading-relaxed"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
className="min-h-[500px] md:min-h-[500px] resize-none border-0 bg-[#1B1D21] text-white leading-relaxed"
className="min-h-0 md:min-h-[500px] resize-none border-0 bg-[#1B1D21] text-white leading-relaxed"
🤖 Prompt for AI Agents
In app/rule/[slug]/page.tsx around line 252, the textarea/class currently forces
min-h-[500px] on all screen sizes which causes overflow on mobile; change the
classes so the 500px minimum only applies at md and above (for example remove
the global min-h-[500px] and use md:min-h-[500px] or add min-h-0
md:min-h-[500px]) and keep the rest of the classes intact to honor the PR goal
of no 500px min-height on small screens.

Comment on lines +311 to +319
<Button
onClick={handleDownload}
variant="primary"
size="sm"
className="hover:bg-[#70A7D7] px-2 py-2 sm:px-3 sm:py-1 aspect-square sm:aspect-auto"
>
<Download className="h-3 w-3" />
<span className="hidden md:inline ml-1">Download</span>
</Button>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add aria-labels for icon-only buttons on mobile.

Improves screen reader accessibility.

             <Button
               onClick={handleDownload}
               variant="primary"
               size="sm"
               className="hover:bg-[#70A7D7] px-2 py-2 sm:px-3 sm:py-1 aspect-square sm:aspect-auto"
+              aria-label="Download rule"
             >
...
             <Button
               onClick={handleCopy}
               variant="primary"
               size="sm"
               className="hover:bg-[#90BAE0] px-2 py-2 sm:px-3 sm:py-1 aspect-square sm:aspect-auto"
+              aria-label="Copy rule"
             >
...
-            <Button
-              onClick={handleInstallCopy}
+            <Button
+              onClick={handleInstallCopy}
               variant="primary"
               size="sm"
               className="hover:bg-[#90BAE0] px-2 py-2 sm:px-3 sm:py-1 aspect-square sm:aspect-auto"
+              aria-label="Copy CLI install command"
             >
...
             <Button
               onClick={handleCopyViewURL}
               variant="primary"
               size="sm"
               className="hover:bg-[#90BAE0] px-2 py-2 sm:px-3 sm:py-1 aspect-square sm:aspect-auto"
+              aria-label="Copy view URL"
             >

Also applies to: 321-329, 331-339, 341-349

🤖 Prompt for AI Agents
In app/rule/[slug]/page.tsx around lines 311-319 (and similarly for 321-329,
331-339, 341-349), several Button components render as icon-only on mobile
without aria-labels; add an appropriate aria-label prop to each icon-only Button
(e.g., aria-label="Download", "Copy", "Share", etc.) ensuring labels are
descriptive and match the button action so screen readers can announce their
purpose, and keep existing visible text for larger viewports unchanged.

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