diff --git a/app/[lang]/(hyperjump)/components/clients.tsx b/app/[lang]/(hyperjump)/components/clients.tsx index 03f95b627..b0012367c 100644 --- a/app/[lang]/(hyperjump)/components/clients.tsx +++ b/app/[lang]/(hyperjump)/components/clients.tsx @@ -1,33 +1,36 @@ +"use client"; + import Image from "next/image"; type Client = { - imageUrl: string; name: string; + imageUrl: string; }; type ClientsProps = { - isPriorityLoad?: boolean; clients: Client[]; }; -export function Clients({ - clients = [], - isPriorityLoad = false -}: ClientsProps) { +export function Clients({ clients }: ClientsProps) { + if (clients.length === 0) return null; + + const repeatedClients = Array(4).fill(clients).flat(); + return ( -
-
- {clients.map(({ imageUrl, name }) => ( - {name} - ))} +
+
+
+ {repeatedClients.map(({ imageUrl, name }, index) => ( + {name} + ))} +
); diff --git a/app/[lang]/(hyperjump)/page.tsx b/app/[lang]/(hyperjump)/page.tsx index e4265d13d..f5edd5364 100644 --- a/app/[lang]/(hyperjump)/page.tsx +++ b/app/[lang]/(hyperjump)/page.tsx @@ -137,7 +137,7 @@ function Hero({ lang }: HeroProps) {

- +
diff --git a/app/globals.css b/app/globals.css index a78f974d6..af0f7e9be 100644 --- a/app/globals.css +++ b/app/globals.css @@ -183,3 +183,24 @@ rgba(21, 19, 55, 0) 23.58% ); } + +.marquee { + overflow: hidden; + width: 100%; +} + +.marquee__track { + display: flex; + gap: 3rem; + width: max-content; + animation: marquee 35s linear infinite; +} + +@keyframes marquee { + from { + transform: translateX(0); + } + to { + transform: translateX(-25%); + } +} diff --git a/data.json b/data.json index 6187505fa..98a700676 100644 --- a/data.json +++ b/data.json @@ -9,7 +9,7 @@ "imageUrl": "/images/clients/bank-tabungan-negara.svg" }, { - "name": "Eka Mas Republik", + "name": "Eka Mas Republik (MyRepublic)", "imageUrl": "/images/clients/my-republic.svg" }, { @@ -23,6 +23,43 @@ { "name": "Smartfren", "imageUrl": "/images/clients/smartfren.svg" + }, + + { + "name": "IDN Media", + "imageUrl": "/images/clients/idn-media.svg" + }, + { + "name": "Ismaya Group", + "imageUrl": "/images/clients/ismaya.svg" + }, + { + "name": "Aruna", + "imageUrl": "/images/clients/aruna.svg" + }, + { + "name": "Cashbac", + "imageUrl": "/images/clients/cashbac.svg" + }, + { + "name": "Ausvet", + "imageUrl": "/images/clients/ausvet.svg" + }, + { + "name": "CoHive", + "imageUrl": "/images/clients/cohive.svg" + }, + { + "name": "Trimegah Sekuritas", + "imageUrl": "/images/clients/trimegah.svg" + }, + { + "name": "Bali United", + "imageUrl": "/images/clients/bali-united.svg" + }, + { + "name": "1Engage", + "imageUrl": "/images/clients/1engage.svg" } ], "description": "Your partner in building reliable, modern software.", diff --git a/e2e/homepage.spec.ts b/e2e/homepage.spec.ts index a0da6b97c..ea39ca813 100644 --- a/e2e/homepage.spec.ts +++ b/e2e/homepage.spec.ts @@ -39,31 +39,29 @@ test.describe("Homepage", () => { }); // Test Structure / UI Sections - test("Hero Section: should display hero title, subtitle, and CTA button correctly", async ({ - page - }) => { + test("Hero Section: should display partner logos", async ({ page }) => { await page.goto(URL); - // Hero title and subtitle - const heroHeading = page.getByRole("heading", { - name: "Your partner in building" - }); - await expect(heroHeading).toBeVisible(); - - const heroSubtitle = page.getByText("We help organizations deliver"); - await expect(heroSubtitle).toBeVisible(); - - // Partner logos const partnerLogos = [ "Amman Mineral Internasional", "Bank Tabungan Negara", - "Eka Mas Republik", + "Eka Mas Republik (MyRepublic)", "Sinar Mas Digital Day", - "Smartfren" + "SMDV", + "Smartfren", + "IDN Media", + "Ismaya Group", + "Aruna", + "Cashbac", + "Ausvet", + "CoHive", + "Trimegah Sekuritas", + "Bali United", + "1Engage" ]; for (const name of partnerLogos) { - const logo = page.getByRole("img", { name }); + const logo = page.locator(`img[alt="${name}"]`).first(); await expect(logo).toBeVisible(); } }); diff --git a/e2e/shared-test.ts b/e2e/shared-test.ts index e472c6a10..a5e8ee8f7 100644 --- a/e2e/shared-test.ts +++ b/e2e/shared-test.ts @@ -109,20 +109,27 @@ async function expectAllImagesLoaded(page: Page) { for (let i = 0; i < count; i++) { const el = images.nth(i); - const tag = await el.evaluate((n: any) => n.tagName.toLowerCase()); + const { tag, isAnimated } = await el.evaluate((n: any) => { + const tag = n.tagName.toLowerCase(); + const isAnimated = !!n.closest(".marquee"); + return { tag, isAnimated }; + }); if (tag === "img" || tag === "image") { - await el.scrollIntoViewIfNeeded(); + if (!isAnimated) { + await el.scrollIntoViewIfNeeded(); + } + await expect(el, `Image #${i} not visible`).toBeVisible(); const { isLoaded, src } = await el.evaluate((img: any) => { - const nw = img.naturalWidth ?? 1; - const nh = img.naturalHeight ?? 1; - const isSVG = img.href?.baseVal; - - // Allow lazy images that are replaced with placeholder - const isLoaded = (nw > 0 && nh > 0) || isSVG; const src = img.currentSrc || img.src || img.href?.baseVal || "(none)"; + const isSvgFile = typeof src === "string" && src.endsWith(".svg"); + const rect = img.getBoundingClientRect(); + const hasLayoutSize = rect.width > 0 && rect.height > 0; + const hasRasterSize = + (img.naturalWidth ?? 0) > 0 && (img.naturalHeight ?? 0) > 0; + const isLoaded = hasRasterSize || (isSvgFile && hasLayoutSize); return { isLoaded, src }; }); diff --git a/e2e/text-content.spec.ts b/e2e/text-content.spec.ts index fb7c680b5..240de9804 100644 --- a/e2e/text-content.spec.ts +++ b/e2e/text-content.spec.ts @@ -85,13 +85,23 @@ test.describe("Text and Content", () => { const partners = [ "Amman Mineral Internasional", "Bank Tabungan Negara", - "Eka Mas Republik", + "Eka Mas Republik (MyRepublic)", "Sinar Mas Digital Day", - "Smartfren" + "SMDV", + "Smartfren", + "IDN Media", + "Ismaya Group", + "Aruna", + "Cashbac", + "Ausvet", + "CoHive", + "Trimegah Sekuritas", + "Bali United", + "1Engage" ]; for (const partner of partners) { - const logo = page.getByRole("img", { name: partner }); + const logo = page.locator(`img[alt="${partner}"]`).first(); await expect(logo).toBeVisible({ timeout: 10_000 }); } diff --git a/public/images/clients/1engage.svg b/public/images/clients/1engage.svg new file mode 100644 index 000000000..00b4f3550 --- /dev/null +++ b/public/images/clients/1engage.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/images/clients/amman.svg b/public/images/clients/amman.svg index f7c14da31..0a07ff8ef 100644 --- a/public/images/clients/amman.svg +++ b/public/images/clients/amman.svg @@ -1,9 +1,10 @@ - - - - - - - - + + + + + + + + + diff --git a/public/images/clients/aruna.svg b/public/images/clients/aruna.svg new file mode 100644 index 000000000..a1c47a4e7 --- /dev/null +++ b/public/images/clients/aruna.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/public/images/clients/ausvet.svg b/public/images/clients/ausvet.svg new file mode 100644 index 000000000..95d370ed3 --- /dev/null +++ b/public/images/clients/ausvet.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/clients/bali-united.svg b/public/images/clients/bali-united.svg new file mode 100644 index 000000000..9a8a69db0 --- /dev/null +++ b/public/images/clients/bali-united.svg @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/clients/bank-tabungan-negara.svg b/public/images/clients/bank-tabungan-negara.svg index 3e91d0c53..41d36c683 100644 --- a/public/images/clients/bank-tabungan-negara.svg +++ b/public/images/clients/bank-tabungan-negara.svg @@ -1,13 +1,13 @@ - - - - - - + + + + + + - - + + diff --git a/public/images/clients/cashbac.svg b/public/images/clients/cashbac.svg new file mode 100644 index 000000000..03b571fa6 --- /dev/null +++ b/public/images/clients/cashbac.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/public/images/clients/cohive.svg b/public/images/clients/cohive.svg new file mode 100644 index 000000000..43a66c170 --- /dev/null +++ b/public/images/clients/cohive.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/clients/idn-media.svg b/public/images/clients/idn-media.svg new file mode 100644 index 000000000..2e0eed123 --- /dev/null +++ b/public/images/clients/idn-media.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/public/images/clients/ismaya.svg b/public/images/clients/ismaya.svg new file mode 100644 index 000000000..6bf319185 --- /dev/null +++ b/public/images/clients/ismaya.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/public/images/clients/my-republic.svg b/public/images/clients/my-republic.svg index c61dc3593..6d7f049bc 100644 --- a/public/images/clients/my-republic.svg +++ b/public/images/clients/my-republic.svg @@ -1,26 +1,26 @@ - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - + + diff --git a/public/images/clients/smartfren.svg b/public/images/clients/smartfren.svg index f66030a1c..2d0e3bfec 100644 --- a/public/images/clients/smartfren.svg +++ b/public/images/clients/smartfren.svg @@ -1,11 +1,11 @@ - - - - + + + + - - + + diff --git a/public/images/clients/smdd.svg b/public/images/clients/smdd.svg index e43690bf2..d7de74fdd 100644 --- a/public/images/clients/smdd.svg +++ b/public/images/clients/smdd.svg @@ -1,15 +1,15 @@ - - - - - - - - + + + + + + + + - - + + diff --git a/public/images/clients/smdv.svg b/public/images/clients/smdv.svg index e998ad467..fbb9fdc7f 100644 --- a/public/images/clients/smdv.svg +++ b/public/images/clients/smdv.svg @@ -1,8 +1,8 @@ - - - - - - - + + + + + + + diff --git a/public/images/clients/trimegah.svg b/public/images/clients/trimegah.svg new file mode 100644 index 000000000..6d27e997a --- /dev/null +++ b/public/images/clients/trimegah.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +