FAB follows bottom nav, subtle shadow, fixed positioning
This commit is contained in:
@@ -11,10 +11,7 @@ import { ReplyComposeModal } from '@/components/ReplyComposeModal';
|
||||
import { useCurrentUser } from '@/hooks/useCurrentUser';
|
||||
import { getAvatarShape, getEmojiMaskUrl } from '@/lib/avatarShape';
|
||||
|
||||
/** Drop shadow style for the planet FAB — hoisted to avoid re-creating on every render. */
|
||||
const fabShadowStyle: React.CSSProperties = {
|
||||
filter: 'drop-shadow(0 4px 12px hsl(var(--primary) / 0.4)) drop-shadow(0 2px 4px hsl(var(--primary) / 0.2))',
|
||||
};
|
||||
|
||||
|
||||
interface FloatingComposeButtonProps {
|
||||
/** The Nostr event kind this FAB creates. kind=1 opens compose; others show "Coming soon". */
|
||||
@@ -73,7 +70,8 @@ export function FloatingComposeButton({ kind = 1, href, onFabClick, icon }: Floa
|
||||
<button
|
||||
onClick={handleClick}
|
||||
className="relative size-16 transition-transform hover:scale-105 active:scale-95"
|
||||
style={fabShadowStyle}
|
||||
style={{ filter: 'drop-shadow(0 2px 8px hsl(var(--primary) / 0.25))' }}
|
||||
|
||||
>
|
||||
{/* FAB background: user's avatar shape (emoji mask) or circle (default) */}
|
||||
<div
|
||||
|
||||
@@ -10,6 +10,8 @@ import { CursorFireEffect } from '@/components/CursorFireEffect';
|
||||
import { Skeleton } from '@/components/ui/skeleton';
|
||||
import { LayoutStore, LayoutStoreContext, useLayoutSnapshot } from '@/contexts/LayoutContext';
|
||||
import { useAppContext } from '@/hooks/useAppContext';
|
||||
import { useScrollDirection } from '@/hooks/useScrollDirection';
|
||||
import { ARC_UP_OVERHANG_PX } from '@/components/ArcBackground';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
/** Skeleton shown in the content area while a lazy page chunk is loading. */
|
||||
@@ -64,9 +66,10 @@ function PageSkeleton() {
|
||||
|
||||
/** Inner component that reads layout options from the context store. */
|
||||
function MainLayoutInner() {
|
||||
const { rightSidebar, showFAB = false, fabKind = 1, fabHref, onFabClick, fabIcon, wrapperClassName, noOverscroll, noMaxWidth } = useLayoutSnapshot();
|
||||
const { rightSidebar, showFAB = false, fabKind = 1, fabHref, onFabClick, fabIcon, wrapperClassName, noOverscroll, noMaxWidth, scrollContainer } = useLayoutSnapshot();
|
||||
const [drawerOpen, setDrawerOpen] = useState(false);
|
||||
const { config } = useAppContext();
|
||||
const { hidden: navHidden } = useScrollDirection(scrollContainer);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -96,13 +99,6 @@ function MainLayoutInner() {
|
||||
content underneath. Only active below the sidebar breakpoint. */}
|
||||
<div className={cn("relative flex-1 min-w-0 sidebar:border-l sidebar:border-r border-border bg-background/85 -mt-mobile-bar", !noMaxWidth && "sidebar:max-w-[600px]", !noOverscroll && "pb-overscroll")}>
|
||||
<Outlet />
|
||||
{showFAB && (
|
||||
<div className="sticky bottom-fab sidebar:bottom-6 z-30 pointer-events-none flex justify-end pr-6">
|
||||
<div className="pointer-events-auto">
|
||||
<FloatingComposeButton kind={fabKind} href={fabHref} onFabClick={onFabClick} icon={fabIcon} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{rightSidebar !== null && (rightSidebar ?? <RightSidebar />)}
|
||||
</Suspense>
|
||||
@@ -110,6 +106,18 @@ function MainLayoutInner() {
|
||||
|
||||
{/* Mobile bottom nav - only on small screens, slides out on scroll */}
|
||||
<MobileBottomNav />
|
||||
|
||||
{/* FAB - fixed, mirrors bottom nav hide/show transition on mobile */}
|
||||
{showFAB && (
|
||||
<div
|
||||
className="fixed bottom-fab sidebar:bottom-6 right-6 z-30 pointer-events-none sidebar:transition-none transition-transform duration-300 ease-in-out"
|
||||
style={navHidden ? { transform: `translateY(calc(var(--bottom-nav-height) + env(safe-area-inset-bottom, 0px)))` } : undefined}
|
||||
>
|
||||
<div className="pointer-events-auto">
|
||||
<FloatingComposeButton kind={fabKind} href={fabHref} onFabClick={onFabClick} icon={fabIcon} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user