import { ElementAttributes } from "@/types/element_attibutes"; import { PptxSlideModel, PptxTextBoxModel, PptxAutoShapeBoxModel, PptxPictureBoxModel, PptxConnectorModel, PptxPositionModel, PptxFillModel, PptxStrokeModel, PptxShadowModel, PptxFontModel, PptxParagraphModel, PptxPictureModel, PptxObjectFitModel, PptxBoxShapeEnum, PptxObjectFitEnum, PptxAlignment, PptxShapeType, PptxConnectorType } from "@/types/pptx_models"; /** * Converts text alignment string to PptxAlignment enum value */ function convertTextAlignToPptxAlignment(textAlign?: string): PptxAlignment | undefined { if (!textAlign) return undefined; switch (textAlign.toLowerCase()) { case 'left': return PptxAlignment.LEFT; case 'center': return PptxAlignment.CENTER; case 'right': return PptxAlignment.RIGHT; case 'justify': return PptxAlignment.JUSTIFY; default: return PptxAlignment.LEFT; } } /** * Converts ElementAttributes[][] to PptxSlideModel[] * Each inner array represents elements on a slide */ export function convertElementAttributesToPptxSlides( slidesAttributes: ElementAttributes[][], backgroundColors?: (string | undefined)[] ): PptxSlideModel[] { return slidesAttributes.map((slideElements, index) => { const shapes = slideElements.map(element => { return convertElementToPptxShape(element); }).filter(Boolean); // Remove any null/undefined shapes const slide: PptxSlideModel = { shapes: shapes as (PptxTextBoxModel | PptxAutoShapeBoxModel | PptxConnectorModel | PptxPictureBoxModel)[] }; // Add background color if available if (backgroundColors && backgroundColors[index]) { slide.background = { color: backgroundColors[index]! }; } return slide; }); } /** * Converts a single ElementAttributes to the appropriate PPTX shape model */ function convertElementToPptxShape( element: ElementAttributes ): PptxTextBoxModel | PptxAutoShapeBoxModel | PptxConnectorModel | PptxPictureBoxModel | null { // Skip elements without position if (!element.position) { return null; } // Check if it's an image element if (element.tagName === 'img' || (element.className && typeof element.className === 'string' && element.className.includes('image'))) { return convertToPictureBox(element); } // Check if it's a text element if (element.innerText && element.innerText.trim().length > 0) { return convertToTextBox(element); } // Check if it's a connector/line element if (element.tagName === 'hr' || (element.className && typeof element.className === 'string' && (element.className.includes('connector') || element.className.includes('line')))) { return convertToConnector(element); } // Default to auto shape box for other elements return convertToAutoShapeBox(element); } /** * Converts element to PptxTextBoxModel */ function convertToTextBox(element: ElementAttributes): PptxTextBoxModel { const position: PptxPositionModel = { left: Math.round(element.position?.left ?? 0), top: Math.round(element.position?.top ?? 0), width: Math.round(element.position?.width ?? 0), height: Math.round(element.position?.height ?? 0) }; const fill: PptxFillModel | undefined = element.background?.color ? { color: element.background.color } : undefined; const font: PptxFontModel | undefined = element.font ? { name: element.font.name ?? "Inter", size: Math.round(element.font.size ?? 16), font_weight: element.font.weight ?? 400, italic: element.font.italic ?? false, color: element.font.color ?? "000000" } : undefined; const paragraph: PptxParagraphModel = { spacing: undefined, alignment: convertTextAlignToPptxAlignment(element.textAlign), font, text: element.innerText }; return { margin: undefined, fill, position, text_wrap: element.textWrap ?? true, paragraphs: [paragraph] }; } /** * Converts element to PptxAutoShapeBoxModel */ function convertToAutoShapeBox(element: ElementAttributes): PptxAutoShapeBoxModel { const position: PptxPositionModel = { left: Math.round(element.position?.left ?? 0), top: Math.round(element.position?.top ?? 0), width: Math.round(element.position?.width ?? 0), height: Math.round(element.position?.height ?? 0) }; const fill: PptxFillModel | undefined = element.background?.color ? { color: element.background.color } : undefined; const stroke: PptxStrokeModel | undefined = element.border?.color ? { color: element.border.color, thickness: element.border.width ?? 1 // float - keep as number } : undefined; const shadow: PptxShadowModel | undefined = element.shadow?.color ? { radius: Math.round(element.shadow.radius ?? 4), // int offset: Math.round(element.shadow.offset ? Math.sqrt(element.shadow.offset[0] ** 2 + element.shadow.offset[1] ** 2) : 0), // int color: element.shadow.color, opacity: element.shadow.opacity ?? 0.5, // float - keep as number angle: Math.round(element.shadow.angle ?? 0) // int } : undefined; // Check if element has text content const paragraphs: PptxParagraphModel[] | undefined = element.innerText ? [{ spacing: undefined, alignment: convertTextAlignToPptxAlignment(element.textAlign), font: element.font ? { name: element.font.name ?? "Inter", size: Math.round(element.font.size ?? 16), // int font_weight: element.font.weight ?? 400, italic: element.font.italic ?? false, color: element.font.color ?? "000000" } : undefined, text: element.innerText }] : undefined; return { type: PptxShapeType.ROUNDED_RECTANGLE, // Default to rounded rectangle margin: undefined, fill, stroke, shadow, position, text_wrap: element.textWrap ?? true, border_radius: element.borderRadius ? Math.round(element.borderRadius[0]) : 0, // int - use first value for autoshape paragraphs }; } /** * Converts element to PptxPictureBoxModel */ function convertToPictureBox(element: ElementAttributes): PptxPictureBoxModel { const position: PptxPositionModel = { left: Math.round(element.position?.left ?? 0), top: Math.round(element.position?.top ?? 0), width: Math.round(element.position?.width ?? 0), height: Math.round(element.position?.height ?? 0) }; const objectFit: PptxObjectFitModel = { fit: element.objectFit ? (element.objectFit as PptxObjectFitEnum) : PptxObjectFitEnum.CONTAIN }; // Extract image path from element attributes const picture: PptxPictureModel = { is_network: element.imageSrc ? element.imageSrc.startsWith('http') : false, path: element.imageSrc || '' }; return { position, margin: undefined, clip: element.clip ?? true, overlay: element.overlay, border_radius: element.borderRadius ? element.borderRadius.map(r => Math.round(r)) : undefined, // List[int] - 4 elements from route parsing shape: element.shape ? (element.shape as PptxBoxShapeEnum) : PptxBoxShapeEnum.RECTANGLE, object_fit: objectFit, picture }; } /** * Converts element to PptxConnectorModel */ function convertToConnector(element: ElementAttributes): PptxConnectorModel { const position: PptxPositionModel = { left: Math.round(element.position?.left ?? 0), top: Math.round(element.position?.top ?? 0), width: Math.round(element.position?.width ?? 0), height: Math.round(element.position?.height ?? 0) }; return { type: PptxConnectorType.STRAIGHT, // Default to straight connector position, thickness: element.border?.width ?? 0.5, // float - keep as number color: element.border?.color || element.background?.color || '000000' }; }