feat(nextjs): elements with background image style will be extractly correctly on export

This commit is contained in:
sauravniraula 2025-07-26 00:52:18 +05:45
parent b3815493c9
commit 7122325401
No known key found for this signature in database
GPG key ID: 60FCC1B5A5E83326
3 changed files with 36 additions and 11 deletions

View file

@ -77,6 +77,9 @@ async function getBrowserAndPage(id: string): Promise<[Browser, Page]> {
waitUntil: "networkidle0",
timeout: 60000,
});
page.on('console', (msg) => {
console.log('console', msg.text());
});
return [browser, page];
}
@ -284,14 +287,14 @@ async function getAllChildElementsAttributes({ element, rootRect = null, depth =
const isCanvas = attributes.tagName === 'canvas';
const isTable = attributes.tagName === 'table';
const isRootPosition = attributes.position &&
const occupiesRoot = attributes.position &&
attributes.position.left === 0 &&
attributes.position.top === 0 &&
attributes.position.width === rootRect!.width &&
attributes.position.height === rootRect!.height;
const hasOtherProperties = hasBackground || hasBorder || hasShadow || hasText || hasImage || isSvg || isCanvas || isTable;
return hasOtherProperties && !isRootPosition;
return hasOtherProperties && (!occupiesRoot || hasImage);
}) : allResults;
if (depth === 0) {
@ -430,6 +433,23 @@ async function getElementAttributes(element: ElementHandle<Element>): Promise<El
return background;
}
function parseBackgroundImage(computedStyles: CSSStyleDeclaration) {
const backgroundImage = computedStyles.backgroundImage;
if (!backgroundImage || backgroundImage === 'none') {
return undefined;
}
// Extract URL from background-image style
const urlMatch = backgroundImage.match(/url\(['"]?([^'"]+)['"]?\)/);
if (urlMatch && urlMatch[1]) {
return urlMatch[1];
}
return undefined;
}
function parseBorder(computedStyles: CSSStyleDeclaration) {
const borderColorResult = colorToHex(computedStyles.borderColor);
const borderWidth = parseFloat(computedStyles.borderWidth);
@ -809,7 +829,7 @@ async function getElementAttributes(element: ElementHandle<Element>): Promise<El
if (match) {
const filterType = match[1];
const value = parseFloat(match[2]);
if (!isNaN(value)) {
switch (filterType) {
case 'invert':
@ -850,6 +870,8 @@ async function getElementAttributes(element: ElementHandle<Element>): Promise<El
}
function parseElementAttributes(el: Element) {
let tagName = el.tagName.toLowerCase();
const computedStyles = window.getComputedStyle(el);
const position = parsePosition(el);
@ -875,7 +897,9 @@ async function getElementAttributes(element: ElementHandle<Element>): Promise<El
const textAlign = computedStyles.textAlign as 'left' | 'center' | 'right' | 'justify';
const objectFit = computedStyles.objectFit as 'contain' | 'cover' | 'fill' | undefined;
const imageSrc = (el as HTMLImageElement).src;
const parsedBackgroundImage = parseBackgroundImage(computedStyles);
const imageSrc = (el as HTMLImageElement).src || parsedBackgroundImage;
const borderRadiusValue = parseBorderRadius(computedStyles, el);
@ -886,7 +910,7 @@ async function getElementAttributes(element: ElementHandle<Element>): Promise<El
const filters = parseFilters(computedStyles);
return {
tagName: el.tagName.toLowerCase(),
tagName: tagName,
id: el.id,
className: (el.className && typeof el.className === 'string') ? el.className : (el.className ? el.className.toString() : undefined),
innerText: innerText,

View file

@ -48,7 +48,7 @@ const QuoteSlideLayout: React.FC<QuoteSlideLayoutProps> = ({ data: slideData })
}}
>
{/* Background Image */}
<div
<div
className="absolute inset-0 w-full h-full bg-cover bg-center bg-no-repeat"
style={{
backgroundImage: `url('${slideData?.backgroundImage?.__image_url__ || ''}')`,
@ -66,7 +66,7 @@ const QuoteSlideLayout: React.FC<QuoteSlideLayoutProps> = ({ data: slideData })
{/* Main Content */}
<div className="relative z-10 px-8 sm:px-12 lg:px-20 py-12 flex-1 flex flex-col justify-center h-full">
<div className="text-center space-y-8 max-w-4xl mx-auto">
{/* Heading */}
<div className="space-y-4">
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-bold text-white leading-tight">
@ -80,12 +80,12 @@ const QuoteSlideLayout: React.FC<QuoteSlideLayoutProps> = ({ data: slideData })
<div className="space-y-6">
{/* Quote Icon */}
<div className="flex justify-center">
<svg
className="w-12 h-12 text-purple-300 opacity-80"
fill="currentColor"
<svg
className="w-12 h-12 text-purple-300 opacity-80"
fill="currentColor"
viewBox="0 0 24 24"
>
<path d="M14.017 21v-7.391c0-5.704 3.731-9.57 8.983-10.609l.995 2.151c-2.432.917-3.995 3.638-3.995 5.849h4v10h-9.983zm-14.017 0v-7.391c0-5.704 3.748-9.57 9-10.609l.996 2.151c-2.433.917-3.996 3.638-3.996 5.849h3.983v10h-9.983z"/>
<path d="M14.017 21v-7.391c0-5.704 3.731-9.57 8.983-10.609l.995 2.151c-2.432.917-3.995 3.638-3.995 5.849h4v10h-9.983zm-14.017 0v-7.391c0-5.704 3.748-9.57 9-10.609l.996 2.151c-2.433.917-3.996 3.638-3.996 5.849h3.983v10h-9.983z" />
</svg>
</div>

View file

@ -78,6 +78,7 @@ export function convertElementAttributesToPptxSlides(
function convertElementToPptxShape(
element: ElementAttributes
): PptxTextBoxModel | PptxAutoShapeBoxModel | PptxConnectorModel | PptxPictureBoxModel | null {
if (!element.position) {
return null;
}