Refine hero: gradient backdrop, intro inside hero, image on right, vector visible
- styles/blocks/page-hero.css: add blue-to-teal gradient to .page-hero (matches homepage-hero). Fix image mask direction (right-to-left fade) so the image is visible on the right and fades to transparent on the left. Reposition the vector to span the full bottom of the hero at z-index 2 (above the media layer, below content). Add .page-hero__intro and .page-hero__intro-inner grid rules for the new two-column heading + body block. - views/partials/page-hero.php: drop bg-dark / bg-cover / bg-no-repeat utilities (the gradient comes from CSS now). Simplify the heading render. Load the page-intro partial inside .page-hero__content, below the heading. - views/partials/page-intro.php: rewrite as a fragment for embedding inside the hero - a two-column heading (hard-coded 'Our Work') + body grid. Returns early when the intro field is empty. - page.php: remove the page-intro partial call (it's now loaded from page-hero.php). - tests/inner-page.spec.js: switch the selector from .page-intro to .page-hero__intro. Update the order assertions to verify the intro is a descendant of the hero (not a sibling below it). Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+32
-23
@@ -26,7 +26,7 @@ const expectNear = (actual, expected, tolerance = 3) => {
|
||||
};
|
||||
|
||||
test.describe("inner page layout", () => {
|
||||
test("desktop: hero, intro, body render in order with the new media layers", async ({
|
||||
test("desktop: hero, intro, body render with intro inside hero", async ({
|
||||
page,
|
||||
}) => {
|
||||
const pageErrors = [];
|
||||
@@ -36,28 +36,34 @@ test.describe("inner page layout", () => {
|
||||
await page.goto(pageUrl);
|
||||
|
||||
const hero = page.locator(".page-hero").first();
|
||||
const intro = page.locator(".page-intro").first();
|
||||
const intro = page.locator(".page-hero__intro").first();
|
||||
const content = page.locator(".entry-content").first();
|
||||
|
||||
await expect(hero).toBeVisible();
|
||||
await expect(intro).toBeVisible();
|
||||
await expect(content).toBeVisible();
|
||||
|
||||
// Order check: hero, then intro, then content.
|
||||
// Intro lives INSIDE the hero.
|
||||
const heroBox = await getBox(hero);
|
||||
const introBox = await getBox(intro);
|
||||
const contentBox = await getBox(content);
|
||||
|
||||
expect(heroBox.y).toBeLessThan(introBox.y);
|
||||
expect(introBox.y).toBeLessThan(contentBox.y);
|
||||
// Intro is a descendant of the hero (same x, y is between hero top and bottom).
|
||||
expect(introBox.x).toBeGreaterThanOrEqual(heroBox.x - 1);
|
||||
expect(introBox.y).toBeGreaterThanOrEqual(heroBox.y - 1);
|
||||
expect(introBox.y + introBox.height).toBeLessThanOrEqual(
|
||||
heroBox.y + heroBox.height + 1,
|
||||
);
|
||||
|
||||
// Body renders below the hero.
|
||||
expect(contentBox.y).toBeGreaterThanOrEqual(heroBox.y + heroBox.height - 1);
|
||||
|
||||
// Heading is rendered inside the hero.
|
||||
await expect(hero.locator("h1").first()).toBeVisible();
|
||||
|
||||
// Intro is centered and capped at the max-w-3xl width.
|
||||
const introInner = intro.locator(".content-wrapper").first();
|
||||
const introInnerBox = await getBox(introInner);
|
||||
expect(introInnerBox.width).toBeLessThanOrEqual(768 + 3);
|
||||
// Intro contains a heading and a body paragraph.
|
||||
await expect(intro.locator(".page-hero__intro-heading").first()).toBeVisible();
|
||||
await expect(intro.locator(".page-hero__intro-text").first()).toBeVisible();
|
||||
|
||||
// Page renders without JS errors.
|
||||
expect(pageErrors).toEqual([]);
|
||||
@@ -73,7 +79,7 @@ test.describe("inner page layout", () => {
|
||||
await page.goto(pageUrl);
|
||||
|
||||
const hero = page.locator(".page-hero").first();
|
||||
const intro = page.locator(".page-intro").first();
|
||||
const intro = page.locator(".page-hero__intro").first();
|
||||
const content = page.locator(".entry-content").first();
|
||||
|
||||
await expect(hero).toBeVisible();
|
||||
@@ -84,15 +90,18 @@ test.describe("inner page layout", () => {
|
||||
const introBox = await getBox(intro);
|
||||
const contentBox = await getBox(content);
|
||||
|
||||
expect(heroBox.y).toBeLessThan(introBox.y);
|
||||
expect(introBox.y).toBeLessThan(contentBox.y);
|
||||
// Intro inside the hero.
|
||||
expect(introBox.x).toBeGreaterThanOrEqual(heroBox.x - 1);
|
||||
expect(introBox.y).toBeGreaterThanOrEqual(heroBox.y - 1);
|
||||
expect(introBox.y + introBox.height).toBeLessThanOrEqual(
|
||||
heroBox.y + heroBox.height + 1,
|
||||
);
|
||||
|
||||
// Body below the hero.
|
||||
expect(contentBox.y).toBeGreaterThanOrEqual(heroBox.y + heroBox.height - 1);
|
||||
|
||||
// Intro fits within the mobile viewport.
|
||||
const introInner = intro.locator(".content-wrapper").first();
|
||||
const introInnerBox = await getBox(introInner);
|
||||
expect(introInnerBox.x + introInnerBox.width).toBeLessThanOrEqual(
|
||||
402 + 3,
|
||||
);
|
||||
expect(introBox.x + introBox.width).toBeLessThanOrEqual(402 + 3);
|
||||
|
||||
// No JS errors.
|
||||
expect(pageErrors).toEqual([]);
|
||||
@@ -103,7 +112,7 @@ test.describe("inner page layout", () => {
|
||||
await page.goto(pageUrl);
|
||||
|
||||
const hero = page.locator(".page-hero").first();
|
||||
const intro = page.locator(".page-intro").first();
|
||||
const intro = page.locator(".page-hero__intro").first();
|
||||
|
||||
await expect(hero).toBeVisible();
|
||||
await expect(intro).toBeVisible();
|
||||
@@ -122,7 +131,7 @@ test.describe("inner page layout", () => {
|
||||
await page.goto(pageUrl);
|
||||
|
||||
const hero = page.locator(".page-hero").first();
|
||||
const intro = page.locator(".page-intro").first();
|
||||
const intro = page.locator(".page-hero__intro").first();
|
||||
|
||||
await expect(hero).toBeVisible();
|
||||
await expect(intro).toBeVisible();
|
||||
@@ -135,7 +144,7 @@ test.describe("inner page layout", () => {
|
||||
});
|
||||
|
||||
// Spec line 113: "A page with no `intro` field renders hero + body with no empty intro wrapper."
|
||||
test("no-intro: hero and body render with no .page-intro wrapper", async ({
|
||||
test("no-intro: hero and body render with no .page-hero__intro wrapper", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.setViewportSize({ width: 1280, height: 900 });
|
||||
@@ -147,13 +156,13 @@ test.describe("inner page layout", () => {
|
||||
await expect(hero).toBeVisible();
|
||||
await expect(content).toBeVisible();
|
||||
|
||||
// No empty intro wrapper rendered when the intro field is empty.
|
||||
expect(await page.locator(".page-intro").count()).toBe(0);
|
||||
// No intro wrapper rendered when the intro field is empty.
|
||||
expect(await page.locator(".page-hero__intro").count()).toBe(0);
|
||||
|
||||
// Hero and body still render in the expected order.
|
||||
const heroBox = await getBox(hero);
|
||||
const contentBox = await getBox(content);
|
||||
expect(heroBox.y).toBeLessThan(contentBox.y);
|
||||
expect(contentBox.y).toBeGreaterThanOrEqual(heroBox.y + heroBox.height - 1);
|
||||
|
||||
// Heading is still inside the hero.
|
||||
await expect(hero.locator("h1").first()).toBeVisible();
|
||||
|
||||
Reference in New Issue
Block a user