Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/components/agent/agent-chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1986,7 +1986,7 @@ I've made several changes to your content including creating new paragraphs, upd
return (
<TooltipProvider>
<aside
className="fixed left-0 z-10 flex flex-col border-r bg-background"
className="fixed left-0 z-[60] flex flex-col border-r bg-background"
style={{
top: topOffset,
bottom: 0,
Expand All @@ -1996,7 +1996,7 @@ I've made several changes to your content including creating new paragraphs, upd
>
{/* Resize handle */}
<div
className="absolute -right-2 top-0 bottom-0 w-4 cursor-col-resize z-20"
className="absolute -right-2 top-0 bottom-0 w-4 cursor-col-resize z-[70]"
onMouseDown={handleMouseDown}
>
{/* Visual hover effect - split 50-50 across the border line */}
Expand Down
4 changes: 2 additions & 2 deletions src/components/notification/notification-bell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ export function NotificationBell({ userId, className }: NotificationBellProps) {
{isOpen && (
<>
{/* Arrow pointing to the bell */}
<div className="absolute right-3 top-full w-0 h-0 border-l-[6px] border-r-[6px] border-b-[6px] border-l-transparent border-r-transparent border-b-border z-50" />
<div className="absolute right-0 top-full mt-1 w-80 bg-background border rounded-lg shadow-lg z-50 animate-in fade-in-0 zoom-in-95 duration-200">
<div className="absolute right-3 top-full w-0 h-0 border-l-[6px] border-r-[6px] border-b-[6px] border-l-transparent border-r-transparent border-b-border z-[70]" />
<div className="absolute right-0 top-full mt-1 w-80 bg-background border rounded-lg shadow-lg z-[70] animate-in fade-in-0 zoom-in-95 duration-200">
<div className="p-3 border-b">
<h3 className="font-semibold text-sm">Notifications</h3>
</div>
Expand Down
100 changes: 61 additions & 39 deletions src/components/team-blog/team-blog-selector.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import { useState, useRef, useEffect } from 'react'
import { useQuery } from '@tanstack/react-query'
import { createPortal } from 'react-dom'
import { useNavigate } from '@tanstack/react-router'
import { Button } from '@/components/ui/button'
import { StandardAvatar } from '@/components/ui/standard-avatar'
import { ChevronDown, Plus, Users, FileText } from 'lucide-react'
import { ChevronDown, Plus, FileText } from 'lucide-react'
import { TeamBlogDropdown } from './team-blog-dropdown'
import { CreateTeamModal } from './create-team-modal'
import { CreateBlogModal } from './create-blog-modal'
import { TeamSettingsModal } from './team-settings-modal'
import { BlogSettingsModal } from './blog-settings-modal'
import { useTeamBlog } from '@/hooks/use-team-blog'
import { useTeamBlogContext } from '@/contexts/team-blog-context'
import { getTeamsClient } from '@/lib/appwrite'
import { cn, truncateText } from '@/lib/utils'
import { truncateText } from '@/lib/utils'

interface TeamBlogSelectorProps {
userId: string
Expand All @@ -27,11 +25,31 @@ export function TeamBlogSelector({ userId }: TeamBlogSelectorProps) {
const [selectedTeam, setSelectedTeam] = useState<any>(null)
const [selectedBlog, setSelectedBlog] = useState<any>(null)
const [selectedTeamForBlog, setSelectedTeamForBlog] = useState<string>('')
const [buttonPosition, setButtonPosition] = useState({ top: 0, left: 0 })
const containerRef = useRef<HTMLDivElement>(null)
const buttonRef = useRef<HTMLButtonElement>(null)
const { currentTeam, currentBlog, setCurrentTeam, setCurrentBlog, teams } = useTeamBlogContext()
const navigate = useNavigate()

// Teams data now comes from shared context
// Update button position when dropdown opens or on scroll
useEffect(() => {
const updatePosition = () => {
if (buttonRef.current) {
const rect = buttonRef.current.getBoundingClientRect()
setButtonPosition({
top: rect.bottom + window.scrollY,
left: rect.left + window.scrollX
})
}
}

if (isOpen) {
updatePosition()
const handleScroll = () => updatePosition()
window.addEventListener('scroll', handleScroll, true)
return () => window.removeEventListener('scroll', handleScroll, true)
}
}, [isOpen])
Comment on lines +34 to +52
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix coordinate space: remove scroll offsets and handle resize.

You’re using a fixed-position portal but adding window.scrollX/Y to rect, which double-compensates on scroll. For position: fixed, use viewport coords (rect.* only). Also update on resize.

Apply:

   // Update button position when dropdown opens or on scroll
   useEffect(() => {
     const updatePosition = () => {
       if (buttonRef.current) {
         const rect = buttonRef.current.getBoundingClientRect()
         setButtonPosition({
-          top: rect.bottom + window.scrollY,
-          left: rect.left + window.scrollX
+          top: rect.bottom,
+          left: rect.left
         })
       }
     }

     if (isOpen) {
       updatePosition()
-      const handleScroll = () => updatePosition()
-      window.addEventListener('scroll', handleScroll, true)
-      return () => window.removeEventListener('scroll', handleScroll, true)
+      const handleScroll = () => updatePosition()
+      const handleResize = () => updatePosition()
+      window.addEventListener('scroll', handleScroll, true)
+      window.addEventListener('resize', handleResize)
+      return () => {
+        window.removeEventListener('scroll', handleScroll, true)
+        window.removeEventListener('resize', handleResize)
+      }
     }
   }, [isOpen])

Optional: throttle updatePosition with requestAnimationFrame for smoother scrolling.

📝 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
// Update button position when dropdown opens or on scroll
useEffect(() => {
const updatePosition = () => {
if (buttonRef.current) {
const rect = buttonRef.current.getBoundingClientRect()
setButtonPosition({
top: rect.bottom + window.scrollY,
left: rect.left + window.scrollX
})
}
}
if (isOpen) {
updatePosition()
const handleScroll = () => updatePosition()
window.addEventListener('scroll', handleScroll, true)
return () => window.removeEventListener('scroll', handleScroll, true)
}
}, [isOpen])
// Update button position when dropdown opens or on scroll
useEffect(() => {
const updatePosition = () => {
if (buttonRef.current) {
const rect = buttonRef.current.getBoundingClientRect()
setButtonPosition({
top: rect.bottom,
left: rect.left
})
}
}
if (isOpen) {
updatePosition()
const handleScroll = () => updatePosition()
const handleResize = () => updatePosition()
window.addEventListener('scroll', handleScroll, true)
window.addEventListener('resize', handleResize)
return () => {
window.removeEventListener('scroll', handleScroll, true)
window.removeEventListener('resize', handleResize)
}
}
}, [isOpen])
🤖 Prompt for AI Agents
In src/components/team-blog/team-blog-selector.tsx around lines 34 to 52, the
updatePosition function incorrectly adds window.scrollY/scrollX
(double-compensating for a fixed-position portal) and doesn't respond to
viewport resizes; change it to use the DOMRect viewport coordinates directly
(rect.bottom and rect.left) without adding scroll offsets, add a window 'resize'
listener alongside the 'scroll' listener and ensure both are cleaned up, and
optionally wrap updates in requestAnimationFrame (or a rAF-based throttle) to
avoid excessive reflows during continuous scroll/resize.


// Close dropdown when clicking outside
useEffect(() => {
Expand Down Expand Up @@ -113,9 +131,35 @@ export function TeamBlogSelector({ userId }: TeamBlogSelectorProps) {
setIsOpen(!isOpen)
}

const dropdownContent = isOpen && createPortal(
<div className="fixed z-[100]" style={{ top: `${buttonPosition.top}px`, left: `${buttonPosition.left}px` }}>
{/* Arrow pointing to the button */}
<div className="absolute left-6 sm:left-6 top-[-6px] w-0 h-0 border-l-[6px] border-r-[6px] border-b-[6px] border-l-transparent border-r-transparent border-b-border" />
<div className="mt-1 w-[80vw] sm:w-[600px] max-w-[600px] bg-background border rounded-lg shadow-lg animate-in fade-in-0 zoom-in-95 duration-200">
<TeamBlogDropdown
userId={userId}
onClose={() => setIsOpen(false)}
onCreateTeam={() => {
setShowCreateTeamModal(true)
setIsOpen(false)
}}
onCreateBlog={handleCreateBlog}
onTeamSettings={handleTeamSettings}
onBlogSettings={handleBlogSettings}
setCurrentTeam={setCurrentTeam}
setCurrentBlog={setCurrentBlog}
onBlogSelect={handleBlogSelect}
isOpen={isOpen}
/>
</div>
</div>,
document.body
)

return (
<div ref={containerRef} className="relative">
<Button
ref={buttonRef}
variant="ghost"
size="sm"
onClick={handleButtonClick}
Expand All @@ -129,39 +173,17 @@ export function TeamBlogSelector({ userId }: TeamBlogSelectorProps) {
<ChevronDown className="h-4 w-4" />
</Button>

{isOpen && (
<>
{/* Arrow pointing to the button */}
<div className="absolute left-6 sm:left-6 top-full w-0 h-0 border-l-[6px] border-r-[6px] border-b-[6px] border-l-transparent border-r-transparent border-b-border z-50" />
<div className="absolute left-0 sm:left-0 top-full mt-1 w-[80vw] sm:w-[600px] max-w-[600px] bg-background border rounded-lg shadow-lg z-50 animate-in fade-in-0 zoom-in-95 duration-200">
<TeamBlogDropdown
userId={userId}
onClose={() => setIsOpen(false)}
onCreateTeam={() => {
setShowCreateTeamModal(true)
setIsOpen(false)
}}
onCreateBlog={handleCreateBlog}
onTeamSettings={handleTeamSettings}
onBlogSettings={handleBlogSettings}
setCurrentTeam={setCurrentTeam}
setCurrentBlog={setCurrentBlog}
onBlogSelect={handleBlogSelect}
isOpen={isOpen}
/>
</div>
</>
)}

<CreateTeamModal
isOpen={showCreateTeamModal}
onClose={() => setShowCreateTeamModal(false)}
userId={userId}
onTeamCreated={(team, blog) => {
setCurrentTeam(team)
setCurrentBlog(blog)
}}
/>
{dropdownContent}

<CreateTeamModal
isOpen={showCreateTeamModal}
onClose={() => setShowCreateTeamModal(false)}
userId={userId}
onTeamCreated={(team, blog) => {
setCurrentTeam(team)
setCurrentBlog(blog)
}}
/>

<CreateBlogModal
isOpen={showCreateBlogModal}
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export function FullscreenLoader({ isVisible, onComplete }: FullscreenLoaderProp
initial={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.5, ease: "easeInOut" }}
className="fixed inset-0 z-50 bg-background loader-container"
className="fixed inset-0 z-[9999] bg-background loader-container"
>
{/* Centered Welcome Message */}
<div className="absolute inset-0 flex items-center justify-center">
Expand Down
4 changes: 2 additions & 2 deletions src/components/user-avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,8 @@ export function UserAvatar({ user, onSignOut }: UserAvatarProps) {
{isOpen && (
<>
{/* Arrow pointing to the avatar - matching notification style */}
<div className="absolute right-3 top-full w-0 h-0 border-l-[6px] border-r-[6px] border-b-[6px] border-l-transparent border-r-transparent border-b-border z-50" />
<div className="absolute right-0 top-full mt-1 w-80 bg-background border rounded-xl shadow-xl z-50 animate-in fade-in-0 zoom-in-95 duration-200 overflow-hidden">
<div className="absolute right-3 top-full w-0 h-0 border-l-[6px] border-r-[6px] border-b-[6px] border-l-transparent border-r-transparent border-b-border z-[70]" />
<div className="absolute right-0 top-full mt-1 w-80 bg-background border rounded-xl shadow-xl z-[70] animate-in fade-in-0 zoom-in-95 duration-200 overflow-hidden">
{/* User details section */}
<div className="p-4 space-y-4">
{/* Email */}
Expand Down
8 changes: 4 additions & 4 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -121,18 +121,18 @@
color: var(--foreground);
margin: 0;
padding: 0;
overscroll-behavior: none;
overscroll-behavior: contain;
-webkit-overflow-scrolling: touch;
}

/* Disable elastic scroll on the entire page */
/* Contain elastic scroll */
html {
overscroll-behavior-y: none;
overscroll-behavior-y: contain;
-webkit-overflow-scrolling: touch;
}

body {
overscroll-behavior: none;
overscroll-behavior: contain;
-webkit-overflow-scrolling: touch;
}

Expand Down
Loading