From e3c103966a9ef99382f56a9c9209b0d0c34063ef Mon Sep 17 00:00:00 2001
From: Nicholas Cunningham <ndcunningham@gmail.com>
Date: Tue, 7 Jan 2025 14:19:33 -0700
Subject: [PATCH] feat(nx-dev): Enhance customer testimonial carousel and icon
 grid layout

---
 .../src/lib/customer-icon-grid.tsx            |  2 +-
 .../src/lib/customer-testimonial-carousel.tsx | 57 +++++++++++++++----
 .../src/lib/enterprise-customers.tsx          |  2 +-
 .../src/lib/download-case-study.tsx           | 41 +++++--------
 4 files changed, 64 insertions(+), 38 deletions(-)

diff --git a/nx-dev/ui-customers/src/lib/customer-icon-grid.tsx b/nx-dev/ui-customers/src/lib/customer-icon-grid.tsx
index bda32105364384..8bcece655ba5ab 100644
--- a/nx-dev/ui-customers/src/lib/customer-icon-grid.tsx
+++ b/nx-dev/ui-customers/src/lib/customer-icon-grid.tsx
@@ -38,7 +38,7 @@ function getBorderClass(index: number, totalIcons: number, columns = 4) {
 
 const CustomerIconGrid: FC<CustomerIconGridProps> = ({ icons }) => {
   return (
-    <div className="grid grid-cols-2 justify-between px-4 md:grid-cols-4">
+    <div className="grid grid-cols-2 justify-between md:grid-cols-4">
       {icons.map((customerIcon, index) => {
         const borderClass = getBorderClass(index, icons.length);
 
diff --git a/nx-dev/ui-customers/src/lib/customer-testimonial-carousel.tsx b/nx-dev/ui-customers/src/lib/customer-testimonial-carousel.tsx
index 3d8656b5b8aecc..a31a4d3900261f 100644
--- a/nx-dev/ui-customers/src/lib/customer-testimonial-carousel.tsx
+++ b/nx-dev/ui-customers/src/lib/customer-testimonial-carousel.tsx
@@ -1,7 +1,11 @@
 'use client';
 import { Fragment, useState, useEffect } from 'react';
 import { Dialog, Transition } from '@headlessui/react';
-import { PlayIcon } from '@heroicons/react/24/outline';
+import {
+  ChevronLeftIcon,
+  ChevronRightIcon,
+  PlayIcon,
+} from '@heroicons/react/24/outline';
 import Image from 'next/image';
 import {
   CasewareIcon,
@@ -56,12 +60,21 @@ const testimonials: Testimonial[] = [
   {
     title: 'Customer story',
     subtitle:
-      'Scaling 700+ projects: How Nx Enterprise became a no-brainer for Caseware',
+      'Scaling 700+ projects: How Nx Enterprise became a no-brainer for Caseware.',
     metrics: [
-      { value: '700+', label: 'Monorepo projects scaled effortlessly' },
       {
-        value: 'Efficiency',
-        label: 'Unified workflows: frontend to backend',
+        value: 'Massive scale',
+        label:
+          '600–700 projects, unifying frontends and backends company wide.',
+      },
+      {
+        value: 'Instant impact',
+        label: 'Trialing Nx Enterprise cut build times immediately.',
+      },
+      {
+        value: 'Actionable insights',
+        label:
+          'Nx Cloud’s metrics uncovered inefficiencies across 10+ year old codebase.',
       },
     ],
     company: 'Caseware',
@@ -167,7 +180,6 @@ export function CustomerTestimonialCarousel(): JSX.Element {
   useEffect(() => {
     let timer: NodeJS.Timeout;
 
-    // Clear the current timer and start a new one
     if (!isOpen) {
       timer = setInterval(() => {
         setCurrentIndex((prevIndex) => {
@@ -177,7 +189,6 @@ export function CustomerTestimonialCarousel(): JSX.Element {
       }, slideLogoTimeOut);
     }
 
-    // Cleanup on unmount or when dependencies change
     return () => {
       clearInterval(timer);
     };
@@ -230,7 +241,7 @@ export function CustomerTestimonialCarousel(): JSX.Element {
             <div className="flex h-full flex-col justify-center space-y-8">
               {currentTestimonial.metrics?.map((metric, index) => (
                 <div key={index} className="space-y-2">
-                  <div className="text-4xl font-bold text-blue-500 lg:text-5xl">
+                  <div className="text-xl font-bold text-sky-600 lg:text-2xl">
                     {metric.value}
                   </div>
                   <div className="text-base text-slate-500 lg:text-lg dark:text-slate-400">
@@ -245,6 +256,19 @@ export function CustomerTestimonialCarousel(): JSX.Element {
         {/* Right side - Video Card */}
         <div className="col-span-2 md:col-span-3">
           <div className="flex items-center gap-4">
+            {/* Prev Button Mobile only */}
+            <button
+              disabled={currentIndex === 0}
+              title={`See ${testimonials[currentIndex - 1]?.company} again!`}
+              className="flex h-12 w-12 items-center justify-center rounded-full p-2 transition hover:text-slate-950 disabled:pointer-events-none disabled:opacity-0 md:hidden dark:hover:text-white"
+              onClick={() => {
+                setCurrentIndex(
+                  (currentIndex - 1 + testimonials.length) % testimonials.length
+                );
+              }}
+            >
+              <ChevronLeftIcon className="h-8 w-8" />
+            </button>
             <div
               className="group relative h-[450px] w-full cursor-pointer self-stretch overflow-hidden rounded-lg xl:shadow-2xl"
               onClick={() => setIsOpen(true)}
@@ -272,6 +296,19 @@ export function CustomerTestimonialCarousel(): JSX.Element {
                 </button>
               </div>
             </div>
+            {/* Next Button - Mobile only */}
+            <button
+              className="flex h-12 w-12 items-center justify-center rounded-full p-2 transition hover:text-slate-950 disabled:pointer-events-none disabled:opacity-0 md:hidden dark:hover:text-white"
+              disabled={currentIndex === testimonials.length - 1}
+              title={`Next ${testimonials[currentIndex + 1]?.company}!`}
+              onClick={() => {
+                setCurrentIndex(
+                  (currentIndex + 1 + testimonials.length) % testimonials.length
+                );
+              }}
+            >
+              <ChevronRightIcon className="h-8 w-8" />
+            </button>
           </div>
 
           {/* Mobile Navigation display dots */}
@@ -290,7 +327,7 @@ export function CustomerTestimonialCarousel(): JSX.Element {
         </div>
       </div>
 
-      {/* Carosel Navigation */}
+      {/* Carosel Navigation - Larger screens */}
       <div className="relative mx-auto hidden max-w-7xl grid-cols-6 items-center justify-center px-4 pt-16 md:grid">
         {testimonials.map(({ company, logo }, i) => (
           <button
@@ -308,7 +345,7 @@ export function CustomerTestimonialCarousel(): JSX.Element {
               className={`${logo.height} ${logo.width} transition-transform duration-300`}
             />
 
-            {/* Progress Bar at the Top */}
+            {/* Progress Bar */}
             {i === currentIndex && !isOpen && (
               <div className="absolute left-0 top-0 h-[2px] w-full overflow-hidden bg-gray-300/80 transition-all">
                 <div
diff --git a/nx-dev/ui-customers/src/lib/enterprise-customers.tsx b/nx-dev/ui-customers/src/lib/enterprise-customers.tsx
index 9c657c947ec610..15953a67490aed 100644
--- a/nx-dev/ui-customers/src/lib/enterprise-customers.tsx
+++ b/nx-dev/ui-customers/src/lib/enterprise-customers.tsx
@@ -274,7 +274,7 @@ export function EnterpriseCustomers(): JSX.Element {
         <div className="mx-auto max-w-7xl">
           <CustomerIconGrid icons={secondCustomerIcons} />
 
-          <div className="grid-cols grid justify-center gap-4 px-4 py-6 md:grid-cols-3">
+          <div className="grid-cols grid justify-center gap-4 px-2 py-6 md:grid-cols-3">
             <DownloadCaseStudy
               title="Financial Institution Case Study"
               description="$28B Fortune 500 financial institution reduces CI times by 79% with Nx Cloud."
diff --git a/nx-dev/ui-enterprise/src/lib/download-case-study.tsx b/nx-dev/ui-enterprise/src/lib/download-case-study.tsx
index 4ac80d2cfa0af1..9cfdec13625781 100644
--- a/nx-dev/ui-enterprise/src/lib/download-case-study.tsx
+++ b/nx-dev/ui-enterprise/src/lib/download-case-study.tsx
@@ -1,9 +1,5 @@
 import { ButtonLink } from '@nx/nx-dev/ui-common';
 import { ReactElement } from 'react';
-import {
-  ArrowDownTrayIcon,
-  ChevronRightIcon,
-} from '@heroicons/react/24/outline';
 
 export interface DownloadCaseStudyProps {
   title: string;
@@ -23,31 +19,24 @@ export function DownloadCaseStudy({
   variant = 'primary',
 }: DownloadCaseStudyProps): ReactElement {
   return (
-    <div className="border border-slate-100 bg-white shadow-lg sm:rounded-lg dark:border-slate-800/60 dark:bg-slate-950">
-      <div className="px-4 py-5 sm:p-6">
+    <div className="flex h-full flex-col border border-slate-100 bg-white shadow-lg sm:rounded-lg dark:border-slate-800/60 dark:bg-slate-950">
+      <div className="flex flex-1 flex-col  px-4 py-5 sm:p-6">
         <h3 className="text-base font-semibold leading-6 text-slate-900 dark:text-slate-100">
           {title}
         </h3>
-        <div className="mt-2 sm:flex sm:items-start sm:justify-between">
-          <div className="max-w-xl text-sm">
-            <p>{description}</p>
-          </div>
-          <div className="mt-5 sm:ml-6 sm:mt-0 sm:flex sm:flex-shrink-0 sm:items-center">
-            <ButtonLink
-              href={buttonHref}
-              title={`${buttonCTA} ${title}`}
-              variant={variant}
-              target="_blank"
-              size="small"
-            >
-              {buttonText}{' '}
-              {buttonCTA === 'Read more' ? (
-                <ChevronRightIcon className="h-4 w-4" />
-              ) : (
-                <ArrowDownTrayIcon className="h-4 w-4 translate-x-1" />
-              )}
-            </ButtonLink>
-          </div>
+        <div className="mt-2 max-w-xl flex-1 text-sm">
+          <p>{description}</p>
+        </div>
+        <div className="mt-auto pt-5">
+          <ButtonLink
+            href={buttonHref}
+            title={`${buttonCTA} ${title}`}
+            variant={variant}
+            target={buttonCTA === 'Download' ? '_blank' : undefined}
+            size="small"
+          >
+            {buttonText}
+          </ButtonLink>
         </div>
       </div>
     </div>