From 9c5a5d49912d4273aeaca2af014e43a57cb96955 Mon Sep 17 00:00:00 2001 From: ishaanxgupta <124028055+ishaanxgupta@users.noreply.github.com> Date: Wed, 17 Jun 2026 04:06:59 +0000 Subject: [PATCH] Improve mobile integrations layout (#1097) ## Summary - Add a mobile-only Activity panel with Active and Recent tabs near the top of the integrations page. - Switch mobile integration cards from horizontal carousel cards to compact vertical list rows. - Keep the existing desktop right-column layout unchanged. image --- apps/web/components/integrations-view.tsx | 233 +++++++++++++++++++--- 1 file changed, 202 insertions(+), 31 deletions(-) diff --git a/apps/web/components/integrations-view.tsx b/apps/web/components/integrations-view.tsx index fe8233f6..62383466 100644 --- a/apps/web/components/integrations-view.tsx +++ b/apps/web/components/integrations-view.tsx @@ -481,13 +481,13 @@ const SECTIONS: Array<{ simpleTitle: "Text Poke to recall and save your memories", isNew: true, icon: ( -
+
Poke
), @@ -586,7 +586,7 @@ function IconBox({
@@ -1732,6 +1732,159 @@ function RecentlyAddedCard({ ) } +type MobileActivityTab = "active" | "recent" + +function MobileActivityPanel({ + entries, + docs, + connectionSource, + activeLoading, + recentsLoading, + onOpenDoc, + onViewAll, +}: { + entries: RailEntry[] + docs: RecentDoc[] + connectionSource: Map + activeLoading?: boolean + recentsLoading?: boolean + onOpenDoc: (doc: RecentDoc) => void + onViewAll: () => void +}) { + const [tab, setTab] = useState("active") + const hasActiveTab = activeLoading || entries.length > 0 + const hasRecentTab = recentsLoading || docs.length > 0 + const showTabs = hasActiveTab && hasRecentTab + const activeTab: MobileActivityTab = + hasActiveTab && (tab === "active" || !hasRecentTab) ? "active" : "recent" + + useEffect(() => { + if (!hasActiveTab && hasRecentTab && tab === "active") { + setTab("recent") + } + if (!hasRecentTab && hasActiveTab && tab === "recent") { + setTab("active") + } + }, [hasActiveTab, hasRecentTab, tab]) + + const tabClass = (value: MobileActivityTab) => + cn( + dmSans125ClassName(), + "flex h-8 flex-1 items-center justify-center gap-1.5 rounded-full px-3 text-[12px] font-medium transition-colors", + activeTab === value + ? "bg-white/[0.10] text-[#FAFAFA]" + : "text-[#A1A1AA] hover:text-[#FAFAFA]", + ) + + return ( + + ) +} + function ItemCard({ actionSlot, infoActionSlot, @@ -1775,7 +1928,7 @@ function ItemCard({ } }} className={cn( - "group relative flex h-full cursor-pointer flex-col gap-4 rounded-[12px] bg-[#14161A] p-4 transition-colors hover:bg-[#16181D] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#4BA0FA]/45", + "group relative flex h-full cursor-pointer flex-row items-center gap-2.5 rounded-[10px] bg-[#14161A] px-2.5 py-2 transition-colors hover:bg-[#16181D] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#4BA0FA]/45 sm:flex-col sm:items-stretch sm:gap-4 sm:rounded-[12px] sm:p-4", "shadow-[inset_2.42px_2.42px_4.263px_rgba(11,15,21,0.7)]", )} > @@ -1791,17 +1944,17 @@ function ItemCard({ open={infoOpen} onOpenChange={setInfoOpen} /> -
+
{icon}
-
-
+
+
{leftIndicator} {name} @@ -1812,16 +1965,16 @@ function ItemCard({
-
+
{/* biome-ignore lint/a11y/noStaticElementInteractions: stop card click from swallowing the status action. */}
e.stopPropagation()} onKeyDown={(e) => e.stopPropagation()} > @@ -1829,7 +1982,7 @@ function ItemCard({
{/* biome-ignore lint/a11y/noStaticElementInteractions: stop card click from swallowing the primary action. */}
e.stopPropagation()} onKeyDown={(e) => e.stopPropagation()} > @@ -1892,10 +2045,10 @@ function FeaturedHero({ picks }: { picks: FeaturedPick[] }) { onFocus={() => setPaused(true)} onBlur={() => setPaused(false)} className={cn( - "group relative flex w-full flex-col items-start justify-center overflow-hidden rounded-[14px] px-5 py-5 sm:px-6 sm:py-6 text-left cursor-pointer", + "group relative flex w-full flex-col items-start justify-center overflow-hidden rounded-[14px] px-5 py-4 text-left cursor-pointer sm:px-6 sm:py-6", "bg-[#191D24]", "shadow-[inset_2.42px_2.42px_4.263px_rgba(11,15,21,0.7)]", - "min-h-[160px]", + "min-h-[150px] sm:min-h-[160px]", )} > {pick.backdrop && ( @@ -1907,12 +2060,12 @@ function FeaturedHero({ picks }: { picks: FeaturedPick[] }) { exit={{ opacity: 0, x: 8 }} transition={{ duration: 0.45, ease: [0.4, 0, 0.2, 1] }} aria-hidden - className="pointer-events-none absolute inset-y-0 right-0 w-3/5 sm:w-2/3" + className="pointer-events-none absolute inset-y-0 right-0 w-[72%] overflow-hidden sm:w-2/3" > -
+
{pick.backdrop}
-
+
@@ -1972,12 +2125,12 @@ function FeaturedHero({ picks }: { picks: FeaturedPick[] }) { animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: -3 }} transition={{ duration: 0.2, ease: [0.4, 0, 0.2, 1] }} - className="relative flex max-w-[55%] flex-col gap-1.5" + className="relative flex max-w-[72%] flex-col gap-1.5 sm:max-w-[55%]" >

{pick.headline} @@ -1985,7 +2138,7 @@ function FeaturedHero({ picks }: { picks: FeaturedPick[] }) {

@@ -2187,7 +2340,7 @@ function SectionRail({ > {label}

-
+