From 729f5079e3df01ea4e17dd64e6a8150944a32857 Mon Sep 17 00:00:00 2001 From: Gaurav Jadhav Date: Thu, 3 Sep 2026 12:41:08 +0530 Subject: [PATCH 1/4] fix(web): align the hero H1 lines left on mobile and tablet --- apps/web/src/components/sections/home/HeroHeading.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/components/sections/home/HeroHeading.tsx b/apps/web/src/components/sections/home/HeroHeading.tsx index f5d18ed5..12f88ba0 100644 --- a/apps/web/src/components/sections/home/HeroHeading.tsx +++ b/apps/web/src/components/sections/home/HeroHeading.tsx @@ -23,7 +23,7 @@ export function HeroHeading() { return (

Date: Thu, 3 Sep 2026 12:42:10 +0530 Subject: [PATCH 2/4] feat(web): restructure the partner network into alliances and channel tracks The Global Network section now has two tabs instead of five region tabs. Technology Alliances holds Nutanix, Sysdig, Zensar and Orca Security, whose logo comes from their own 2025 SVG. Zensar was previously listed twice, under Global and North America; it now appears once, as an alliance. Channel Partners covers the remaining 22 companies. Regions become labelled bands inside the panel rather than a second row of tabs, so every partner is visible in one scroll and present in the DOM for crawlers. The View More toggle is gone for the same reason. Sechpoint Tech moves from the Middle East to Africa, at its Nairobi office. Logos were sized by height alone, which let a 6.2:1 wordmark render 274px wide next to a 2.6:1 one at 116px. A max-width caps the wide ones. --- .../images/partners/global/orca-security.svg | 1 + .../sections/partners/PartnersNetwork.tsx | 448 +++++++++--------- 2 files changed, 227 insertions(+), 222 deletions(-) create mode 100644 apps/web/public/images/partners/global/orca-security.svg diff --git a/apps/web/public/images/partners/global/orca-security.svg b/apps/web/public/images/partners/global/orca-security.svg new file mode 100644 index 00000000..f1de2045 --- /dev/null +++ b/apps/web/public/images/partners/global/orca-security.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/web/src/components/sections/partners/PartnersNetwork.tsx b/apps/web/src/components/sections/partners/PartnersNetwork.tsx index 0d3d5f63..b8eb671a 100644 --- a/apps/web/src/components/sections/partners/PartnersNetwork.tsx +++ b/apps/web/src/components/sections/partners/PartnersNetwork.tsx @@ -8,7 +8,7 @@ import { useReducedMotion, } from "motion/react"; import Image from "next/image"; -import { useEffect, useRef, useState } from "react"; +import { useState } from "react"; import { Container, Section } from "@/components/layout"; import { Reveal } from "@/components/ui/Reveal"; import { EASE_SOFT } from "@/lib/motion"; @@ -21,143 +21,134 @@ interface Partner { wordmark?: string; } -const REGIONS = ["Global", "Asia Pacific", "Europe", "Middle East", "North America"] as const; -type Region = (typeof REGIONS)[number]; +interface RegionGroup { + region: string; + partners: Partner[]; +} -const INITIAL_VISIBLE = 8; +const TRACKS = [ + { id: "technology-alliances", label: "Technology Alliances" }, + { id: "channel-partners", label: "Channel Partners" }, +] as const; -const CARD_SPRING = { type: "spring", stiffness: 280, damping: 30, mass: 0.8 } as const; +type TrackId = (typeof TRACKS)[number]["id"]; -const tabId = (region: Region): string => `region-tab-${region.replace(/\s+/g, "-").toLowerCase()}`; +const ALLIANCES: Partner[] = [ + { name: "Nutanix", country: "San Jose, USA", logo: "/images/partners/global/nutanix.jpg" }, + { name: "Sysdig", country: "San Francisco, USA", logo: "/images/partners/global/sysdig.png" }, + { + name: "Orca Security", + country: "Portland, USA", + logo: "/images/partners/global/orca-security.svg", + }, + { + name: "Zensar", + country: "San Jose, USA", + logo: "/images/partners/global/zensar.svg", + invertOnLight: true, + }, +]; -const PARTNERS: Record = { - Global: [ - { name: "Nutanix", country: "San Jose, USA", logo: "/images/partners/global/nutanix.jpg" }, - { name: "Sysdig", country: "San Francisco, USA", logo: "/images/partners/global/sysdig.png" }, - { - name: "Zensar", - country: "San Jose, USA", - logo: "/images/partners/global/zensar.svg", - invertOnLight: true, - }, - ], - "Asia Pacific": [ - { name: "Hitachi Systems", country: "India", logo: "/images/partners/global/hitachi.webp" }, - { name: "Citius Cloud", country: "India", logo: "/images/partners/global/citius.webp" }, - { name: "CyberNx", country: "India", logo: "/images/partners/global/cybernx.webp" }, - { name: "eCaps", country: "India", logo: "/images/partners/global/ecaps.webp" }, - { name: "SEESEC", country: "India", logo: "/images/partners/global/seesec.webp" }, - { name: "Imperium", country: "Singapore", logo: "/images/partners/global/imperium.webp" }, - { name: "R-Tech", country: "Indonesia", logo: "/images/partners/global/rtech.webp" }, - { name: "eSec Forte", country: "India", logo: "/images/partners/global/sec-forte.webp" }, - { name: "Raksha Technologies", country: "India", logo: "/images/partners/global/raksha.webp" }, - { name: "Flying Stars", country: "India", logo: "/images/partners/global/flying-stars.webp" }, - { name: "Softcell", country: "India", logo: "/images/partners/global/softcell.png" }, - ], - Europe: [ - { name: "NGIT", country: "Nordics", logo: "/images/partners/global/ngit.webp" }, - { - name: "Mactech Consultants", - country: "London, UK", - logo: "/images/partners/global/MactechProperties_logo.png", - }, - ], - "Middle East": [ - { - name: "Surakshate", - country: "UAE", - logo: "/images/partners/global/surakshate.webp", - invertOnLight: true, - }, - { - name: "Help AG", - country: "Dubai, UAE", - logo: "/images/partners/global/help-ag-logo-2048x603.png", - }, - { - name: "Paramount Assure", - country: "Dubai, UAE", - logo: "/images/partners/global/paramount.png", - }, - { - name: "Gulf IT", - country: "Dubai, UAE", - logo: "/images/partners/global/gulf-it.svg", - }, - { - name: "Sechpoint Tech", - country: "Dubai, UAE", - logo: "/images/partners/global/sechpoint.svg", - }, - { - name: "Sandbox Security", - country: "Dubai, UAE", - logo: "/images/partners/global/sandbox-security.png", - }, - { - name: "TecCentric", - country: "Doha, Qatar", - logo: "/images/partners/global/teccentric.svg", - }, - ], - "North America": [ - { - name: "PacGenesis", - country: "USA", - logo: "/images/partners/global/pacgenesis.png", - }, - { - name: "Fortifire", - country: "North America", - logo: "/images/partners/global/fortifire-icon.webp", - wordmark: "FORTIFIRE", - }, - { - name: "Zensar", - country: "San Jose, USA", - logo: "/images/partners/global/zensar.svg", - invertOnLight: true, - }, - ], -}; +const CHANNEL: RegionGroup[] = [ + { + region: "Asia Pacific", + partners: [ + { name: "Hitachi Systems", country: "India", logo: "/images/partners/global/hitachi.webp" }, + { name: "Citius Cloud", country: "India", logo: "/images/partners/global/citius.webp" }, + { name: "CyberNx", country: "India", logo: "/images/partners/global/cybernx.webp" }, + { name: "eCaps", country: "India", logo: "/images/partners/global/ecaps.webp" }, + { name: "SEESEC", country: "India", logo: "/images/partners/global/seesec.webp" }, + { name: "eSec Forte", country: "India", logo: "/images/partners/global/sec-forte.webp" }, + { + name: "Raksha Technologies", + country: "India", + logo: "/images/partners/global/raksha.webp", + }, + { + name: "Flying Stars", + country: "India", + logo: "/images/partners/global/flying-stars.webp", + }, + { name: "Softcell", country: "India", logo: "/images/partners/global/softcell.png" }, + { name: "Imperium", country: "Singapore", logo: "/images/partners/global/imperium.webp" }, + { name: "R-Tech", country: "Indonesia", logo: "/images/partners/global/rtech.webp" }, + ], + }, + { + region: "Middle East", + partners: [ + { + name: "Help AG", + country: "Dubai, UAE", + logo: "/images/partners/global/help-ag-logo-2048x603.png", + }, + { + name: "Paramount Assure", + country: "Dubai, UAE", + logo: "/images/partners/global/paramount.png", + }, + { name: "Gulf IT", country: "Dubai, UAE", logo: "/images/partners/global/gulf-it.svg" }, + { + name: "Sandbox Security", + country: "Dubai, UAE", + logo: "/images/partners/global/sandbox-security.png", + }, + { + name: "Surakshate", + country: "UAE", + logo: "/images/partners/global/surakshate.webp", + invertOnLight: true, + }, + { name: "TecCentric", country: "Doha, Qatar", logo: "/images/partners/global/teccentric.svg" }, + ], + }, + { + region: "Europe", + partners: [ + { name: "NGIT", country: "Nordics", logo: "/images/partners/global/ngit.webp" }, + { + name: "Mactech Consultants", + country: "London, UK", + logo: "/images/partners/global/MactechProperties_logo.png", + }, + ], + }, + { + region: "North America", + partners: [ + { name: "PacGenesis", country: "USA", logo: "/images/partners/global/pacgenesis.png" }, + { + name: "Fortifire", + country: "North America", + logo: "/images/partners/global/fortifire-icon.webp", + wordmark: "FORTIFIRE", + }, + ], + }, + { + region: "Africa", + partners: [ + { + name: "Sechpoint Tech", + country: "Nairobi, Kenya", + logo: "/images/partners/global/sechpoint.svg", + }, + ], + }, +]; export function PartnersNetwork(): React.ReactElement { const reduce = useReducedMotion(); - const [active, setActive] = useState("Global"); - const [expanded, setExpanded] = useState(false); - const partners = PARTNERS[active]; - const basePartners = partners.slice(0, INITIAL_VISIBLE); - const extraPartners = partners.slice(INITIAL_VISIBLE); - - // The tab bar is a single horizontal row that scrolls (no wrap) when it overflows a - // narrow viewport. Auto-center the active tab so the selection is never stuck off-screen; - // the first tab ("Global") rests at the left edge so the bar reads from the start. - const scrollerRef = useRef(null); - useEffect(() => { - const scroller = scrollerRef.current; - if (!scroller) return; - if (active === "Global") { - scroller.scrollTo({ left: 0, behavior: "smooth" }); - return; - } - const btn = scroller.querySelector(`#${tabId(active)}`); - if (!btn) return; - const target = btn.offsetLeft - (scroller.clientWidth - btn.offsetWidth) / 2; - scroller.scrollTo({ left: Math.max(0, target), behavior: "smooth" }); - }, [active]); - - const selectRegion = (region: Region): void => { - setActive(region); - setExpanded(false); - }; + const [active, setActive] = useState("technology-alliances"); + const showAlliances = active === "technology-alliances"; + const activeIndex = showAlliances ? 0 : 1; return (
+ {/* Two equal grid columns let the sliding indicator be exactly 50% wide with no + measurement: translateX(100%) lands it on the second column. */}
-
- {REGIONS.map((region) => { - const isActive = region === active; - return ( - - ); - })} -
+ /> + {TRACKS.map((track) => { + const isActive = track.id === active; + return ( + + ); + })}
-
- {partners.length === 0 ? ( -
- We're actively expanding in this region. Check back soon. -
- ) : ( - basePartners.map((p) => ) - )} - {/* Mobile/tablet: show every partner up front — no View More toggle below lg. */} -
- {extraPartners.map((p) => ( - - ))} -
- {/* Desktop (lg+): reveal the remaining partners via View More, with the spring entrance. */} -
- - {expanded && - extraPartners.map((p, i) => ( - - - + + + {showAlliances ? ( +
+ {ALLIANCES.map((partner) => ( + ))} - -
-
- - {partners.length > INITIAL_VISIBLE && ( -
- -
- )} +
+ ) : ( +
+ {CHANNEL.map((group) => ( +
+
+

+ {group.region} +

+ +
+
+ {group.partners.map((partner) => ( + + ))} +
+
+ ))} +
+ )} + +
); } -function PartnerCard({ partner }: { partner: Partner }): React.ReactElement { +function PartnerCard({ + partner, + headingLevel: NameTag, +}: { + partner: Partner; + headingLevel: "h3" | "h4"; +}): React.ReactElement { return (
-
+
{partner.logo.endsWith(".svg") ? ( // SVG logos render via plain — next/image needs dangerouslyAllowSVG, and // vectors gain nothing from the optimizer. @@ -334,7 +338,7 @@ function PartnerCard({ partner }: { partner: Partner }): React.ReactElement { height={36} loading="lazy" decoding="async" - className="h-full w-auto object-contain object-left" + className="h-full w-auto max-w-full object-contain object-left" style={partner.invertOnLight ? { filter: "brightness(0)" } : undefined} /> ) : ( @@ -344,7 +348,7 @@ function PartnerCard({ partner }: { partner: Partner }): React.ReactElement { width={partner.wordmark ? 36 : 160} height={36} sizes={partner.wordmark ? "36px" : "160px"} - className="h-full w-auto object-contain object-left" + className="h-full w-auto max-w-full object-contain object-left" style={partner.invertOnLight ? { filter: "brightness(0)" } : undefined} /> )} @@ -358,12 +362,12 @@ function PartnerCard({ partner }: { partner: Partner }): React.ReactElement { ) : null}
-

{partner.name} -

+

{partner.country}

From 914c32edb58c4e153ce4fadd2763fe1a4faea2a4 Mon Sep 17 00:00:00 2001 From: Gaurav Jadhav Date: Thu, 3 Sep 2026 12:49:55 +0530 Subject: [PATCH 3/4] fix(web): remove the blank gap when switching partner tracks Switching tracks took 710ms and ran in two phases. The old panel faded out over 340ms but kept its height, so the reader got 260ms of an empty panel. The DOM then swapped, changing the section height by 1487px in one frame, before the new cards faded in and slid up from 16px below. The panel now swaps in a single frame with an opacity-only fade of 160ms and no exit phase, so the height change happens alongside the content arriving rather than in the middle of an animation. The sliding pill already carries the feedback for the switch itself. The first paint is left un-animated because the section's FadeUp wrapper already owns that entrance. --- .../sections/partners/PartnersNetwork.tsx | 120 +++++++++--------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/apps/web/src/components/sections/partners/PartnersNetwork.tsx b/apps/web/src/components/sections/partners/PartnersNetwork.tsx index b8eb671a..d34e0274 100644 --- a/apps/web/src/components/sections/partners/PartnersNetwork.tsx +++ b/apps/web/src/components/sections/partners/PartnersNetwork.tsx @@ -1,14 +1,8 @@ "use client"; -import { - AnimatePresence, - domAnimation, - LazyMotion, - m, - useReducedMotion, -} from "motion/react"; +import { domAnimation, LazyMotion, m, useReducedMotion } from "motion/react"; import Image from "next/image"; -import { useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { Container, Section } from "@/components/layout"; import { Reveal } from "@/components/ui/Reveal"; import { EASE_SOFT } from "@/lib/motion"; @@ -142,6 +136,12 @@ export function PartnersNetwork(): React.ReactElement { const [active, setActive] = useState("technology-alliances"); const showAlliances = active === "technology-alliances"; const activeIndex = showAlliances ? 0 : 1; + // The panel fades only when the reader switches tracks. On first paint the section's own + // FadeUp wrapper owns the entrance, so a second fade here would double up. + const mounted = useRef(false); + useEffect(() => { + mounted.current = true; + }, []); return (
- - - {showAlliances ? ( -
- {ALLIANCES.map((partner) => ( - - ))} -
- ) : ( -
- {CHANNEL.map((group) => ( -
-
-

- {group.region} -

- + {showAlliances ? ( +
+ {ALLIANCES.map((partner) => ( + + ))} +
+ ) : ( +
+ {CHANNEL.map((group) => ( +
+
+

+ {group.region} +

+ +
+
+ {group.partners.map((partner) => ( + -
-
- {group.partners.map((partner) => ( - - ))} -
+ ))}
- ))} -
- )} - - +
+ ))} +
+ )} +
From e5f4a6726378072795b74576e9f9a56ad823e3c1 Mon Sep 17 00:00:00 2001 From: Gaurav Jadhav Date: Thu, 3 Sep 2026 13:55:23 +0530 Subject: [PATCH 4/4] refactor(web): merge the partner regions into Middle East & Africa Africa held a single card, so it read as a stub rather than a region. Folding it into Middle East & Africa matches how the territory is normally split and takes the channel list from five bands to four. --- .../sections/partners/PartnersNetwork.tsx | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/apps/web/src/components/sections/partners/PartnersNetwork.tsx b/apps/web/src/components/sections/partners/PartnersNetwork.tsx index d34e0274..5c161d1c 100644 --- a/apps/web/src/components/sections/partners/PartnersNetwork.tsx +++ b/apps/web/src/components/sections/partners/PartnersNetwork.tsx @@ -69,7 +69,7 @@ const CHANNEL: RegionGroup[] = [ ], }, { - region: "Middle East", + region: "Middle East & Africa", partners: [ { name: "Help AG", @@ -94,6 +94,11 @@ const CHANNEL: RegionGroup[] = [ invertOnLight: true, }, { name: "TecCentric", country: "Doha, Qatar", logo: "/images/partners/global/teccentric.svg" }, + { + name: "Sechpoint Tech", + country: "Nairobi, Kenya", + logo: "/images/partners/global/sechpoint.svg", + }, ], }, { @@ -119,16 +124,6 @@ const CHANNEL: RegionGroup[] = [ }, ], }, - { - region: "Africa", - partners: [ - { - name: "Sechpoint Tech", - country: "Nairobi, Kenya", - logo: "/images/partners/global/sechpoint.svg", - }, - ], - }, ]; export function PartnersNetwork(): React.ReactElement {