figmatic-print-builder/utils/exportToHtml.js

301 lines
8.8 KiB
JavaScript
Raw Normal View History

2026-06-16 12:58:18 +05:30
import { bindData } from "./dynamicBinder";
function generateTextElement(el, data) {
const fontWeight = el.bold ? "bold" : el.fontWeight || "normal";
const fontStyle = el.italic ? "italic" : "normal";
const textDecoration = el.underline ? "underline" : "none";
return `
<div style="
position: absolute;
top: ${el.y}px;
left: ${el.x}px;
font-size: ${el.fontSize}px;
font-family: ${el.fontFamily || 'Arial'};
font-weight: ${fontWeight};
font-style: ${fontStyle};
text-decoration: ${textDecoration};
color: ${el.color || '#000000'};
text-align: ${el.align || 'left'};
transform: rotate(${el.rotation || 0}deg);
transform-origin: top left;
white-space: pre-wrap;
">
${bindData(el.text, data)}
</div>
`;
}
function generateImageElement(el, data) {
if (!el.src) return '';
return `
<img src="${bindData(el.src, data)}" style="
position: absolute;
top: ${el.y}px;
left: ${el.x}px;
width: ${el.width}px;
height: ${el.height}px;
transform: rotate(${el.rotation || 0}deg);
transform-origin: top left;
" />
`;
}
function generateQRCodeElement(el, data) {
// For HTML export, we'll use a QR code API or placeholder
const qrData = encodeURIComponent(bindData(el.data, data));
const qrUrl = `https://api.qrserver.com/v1/create-qr-code/?size=${el.size}x${el.size}&data=${qrData}`;
return `
<img src="${qrUrl}" style="
position: absolute;
top: ${el.y}px;
left: ${el.x}px;
width: ${el.size}px;
height: ${el.size}px;
transform: rotate(${el.rotation || 0}deg);
transform-origin: top left;
" />
`;
}
function generateLineElement(el) {
return `
<div style="
position: absolute;
top: ${el.y}px;
left: ${el.x}px;
width: ${el.width}px;
height: ${el.thickness}px;
background-color: ${el.color || '#000000'};
transform: rotate(${el.rotation || 0}deg);
transform-origin: top left;
"></div>
`;
}
function generateRectangleElement(el) {
return `
<div style="
position: absolute;
top: ${el.y}px;
left: ${el.x}px;
width: ${el.width}px;
height: ${el.height}px;
background-color: ${el.fill || 'transparent'};
border: ${el.strokeWidth || 0}px solid ${el.stroke || '#000000'};
border-radius: ${el.cornerRadius || 0}px;
transform: rotate(${el.rotation || 0}deg);
transform-origin: top left;
box-sizing: border-box;
"></div>
`;
}
function generateTableElement(el, data) {
const visibleColumns = el.columns.filter(col => col.visible);
const tableData = data?.tableData || el.sampleData || [];
let tableHtml = `
<div style="
position: absolute;
top: ${el.y}px;
left: ${el.x}px;
transform: rotate(${el.rotation || 0}deg);
transform-origin: top left;
">
<table style="
border-collapse: collapse;
width: auto;
">
<thead>
<tr>
`;
// Header row
visibleColumns.forEach(col => {
tableHtml += `
<th style="
width: ${col.width}px;
height: ${el.rowHeight}px;
background-color: ${el.headerBg || '#f0f0f0'};
border: 1px solid ${el.borderColor || '#000000'};
padding: 5px;
font-size: 12px;
font-weight: bold;
text-align: left;
">
${col.label}
</th>
`;
});
tableHtml += `
</tr>
</thead>
<tbody>
`;
// Data rows
if (el.showSampleData && tableData.length > 0) {
tableData.forEach(row => {
tableHtml += '<tr>';
visibleColumns.forEach(col => {
const cellValue = bindData(row[col.key] || '', data);
tableHtml += `
<td style="
width: ${col.width}px;
height: ${el.rowHeight}px;
border: 1px solid ${el.borderColor || '#000000'};
padding: 5px;
font-size: 11px;
text-align: left;
">
${cellValue}
</td>
`;
});
tableHtml += '</tr>';
});
}
tableHtml += `
</tbody>
</table>
</div>
`;
return tableHtml;
}
function generateSummaryElement(el, data) {
const visibleFields = el.fields.filter(field => field.visible);
let summaryHtml = `
<div style="
position: absolute;
top: ${el.y}px;
left: ${el.x}px;
transform: rotate(${el.rotation || 0}deg);
transform-origin: top left;
">
`;
visibleFields.forEach((field, index) => {
const yPos = index * (el.fontSize + el.spacing);
const value = bindData(`{{${field.key}}}`, data);
summaryHtml += `
<div style="
position: relative;
margin-bottom: ${el.spacing}px;
display: flex;
align-items: center;
">
<span style="
font-size: ${el.fontSize}px;
color: ${el.labelColor || '#000000'};
font-weight: bold;
display: inline-block;
width: ${field.width}px;
">
${field.label}:
</span>
<span style="
font-size: ${el.fontSize}px;
color: ${el.valueColor || '#000000'};
margin-left: 10px;
">
${value}
</span>
</div>
`;
});
summaryHtml += '</div>';
return summaryHtml;
}
export function generateHtml(template, data = {}) {
const elementsHtml = template.elements
.map((el) => {
switch (el.type) {
case "text":
return generateTextElement(el, data);
case "image":
return generateImageElement(el, data);
case "qrcode":
return generateQRCodeElement(el, data);
case "line":
return generateLineElement(el);
case "rectangle":
return generateRectangleElement(el);
case "table":
return generateTableElement(el, data);
case "summary":
return generateSummaryElement(el, data);
default:
return "";
}
})
.join("");
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Invoice</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
background: #f5f5f5;
padding: 20px;
}
.page-container {
position: relative;
width: ${template.page.width}px;
height: ${template.page.height}px;
background: white;
margin: 0 auto;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
@media print {
body {
background: white;
padding: 0;
}
.page-container {
width: ${template.page.width}px;
height: ${template.page.height}px;
box-shadow: none;
margin: 0;
page-break-after: always;
}
@page {
size: ${template.page.width}px ${template.page.height}px;
margin: 0;
}
}
</style>
</head>
<body>
<div class="page-container">
${elementsHtml}
</div>
</body>
</html>
`;
}