Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 22 additions & 19 deletions app/[lang]/(hyperjump)/components/clients.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="relative px-8 py-4 md:px-20">
<div className="flex flex-wrap items-center justify-center gap-8">
{clients.map(({ imageUrl, name }) => (
<Image
key={name}
src={imageUrl}
alt={name}
height={36}
width={120}
className="h-6 w-auto object-contain opacity-60 grayscale transition hover:opacity-100 sm:h-7"
priority={isPriorityLoad}
/>
))}
<div className="relative overflow-hidden px-8 py-6 md:px-20">
<div className="marquee">
<div className="marquee__track">
{repeatedClients.map(({ imageUrl, name }, index) => (
<Image
key={`${name}-${index}`}
src={imageUrl}
alt={name}
width={120}
height={36}
className="h-6 w-auto object-contain sm:h-7"
/>
))}
</div>
</div>
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion app/[lang]/(hyperjump)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ function Hero({ lang }: HeroProps) {
</p>
</div>
<div className="relative top-15">
<Clients clients={data.clients} isPriorityLoad />
<Clients clients={data.clients} />
</div>
</div>
</section>
Expand Down
21 changes: 21 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -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%);
}
}
39 changes: 38 additions & 1 deletion data.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
{
Expand All @@ -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.",
Expand Down
30 changes: 14 additions & 16 deletions e2e/homepage.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
});
Expand Down
23 changes: 15 additions & 8 deletions e2e/shared-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
});
Expand Down
16 changes: 13 additions & 3 deletions e2e/text-content.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
}

Expand Down
10 changes: 10 additions & 0 deletions public/images/clients/1engage.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading