// Renders the share images (Open Graph and Twitter) from the real hero, one per // language, so they always match the site. Run it after the hero headline or its // design changes: // // pnpm --filter @mintel/web share-image (uses the live site) // pnpm --filter @mintel/web share-image http://localhost:3000 // // It drives the locally installed Chrome through Playwright and writes // src/assets/share/share-de.png and share-en.png (used by app/[locale]/layout.tsx). import { chromium } from "playwright"; const origin = (process.argv[2] ?? "https://mintel.me").replace(/\/$/, ""); // The browser language matches the page, so the language detection lets it through. const SHOTS = [ { locale: "de", path: "/", browserLocale: "de-DE" }, { locale: "en", path: "/en", browserLocale: "en-US" }, ]; const browser = await chromium.launch({ channel: "chrome", headless: true }); for (const shot of SHOTS) { const out = `src/assets/share/share-${shot.locale}.png`; const page = await browser.newPage({ viewport: { width: 1200, height: 630 }, deviceScaleFactor: 1, locale: shot.browserLocale, }); await page.goto(`${origin}${shot.path}`, { waitUntil: "load", timeout: 90000, }); await page.addStyleTag({ content: ` header, footer, #hero-cta, [class*="fixed"], nextjs-portal { display: none !important; } main > div > section:first-of-type > div.relative { min-height: 630px !important; height: 630px !important; padding: 0 72px !important; justify-content: center !important; max-width: none !important; } main > div > section:first-of-type ul { display: none !important; } main > div > section:first-of-type h1 { font-size: 150px !important; } main > div > section:first-of-type p { font-size: 34px !important; max-width: 900px !important; margin-top: 36px !important; } main > div > section:first-of-type .grid { margin-top: 0 !important; display: block !important; } main > div > section:first-of-type h1 span:nth-of-type(2) { color: rgba(15, 23, 42, 0.2) !important; } main > div > section:first-of-type > div.relative { padding-top: 34px !important; } html, body { overflow: hidden !important; } `, }); // Let the page finish starting up first; it would discard the added labels. await page.waitForTimeout(2000); await page.evaluate(() => { const section = document.querySelector("main section"); const tag = document.createElement("div"); tag.textContent = "MARC MINTEL"; tag.style.cssText = "position:absolute;left:72px;top:54px;z-index:20;font:700 15px ui-monospace,Menlo,monospace;letter-spacing:.3em;color:#0f172a"; const site = document.createElement("div"); site.textContent = "mintel.me"; site.style.cssText = "position:absolute;right:72px;top:54px;z-index:20;font:500 15px ui-monospace,Menlo,monospace;letter-spacing:.2em;color:#64748b"; section.style.position = "relative"; section.append(tag, site); window.scrollTo(0, 0); }); await page.waitForTimeout(4500); await page.screenshot({ path: out, clip: { x: 0, y: 0, width: 1200, height: 630 }, }); await page.close(); console.log("written:", out); } await browser.close();