sheets
This commit is contained in:
@@ -56,18 +56,9 @@ function normalizeExcelKey(value: string): string {
|
||||
.replace(/[^A-Z0-9]+/g, '');
|
||||
}
|
||||
|
||||
function extractDescriptionHtmlFromMdxBody(body: string): string {
|
||||
const content = String(body || '').trim();
|
||||
if (!content) return '';
|
||||
|
||||
// MDX product files are wrapped like:
|
||||
// <ProductTabs technicalData={...}>
|
||||
// <section>...</section>
|
||||
// </ProductTabs>
|
||||
// For PDF, we only want the inner description content.
|
||||
const withoutOpen = content.replace(/^\s*<ProductTabs[\s\S]*?>\s*/i, '');
|
||||
const withoutClose = withoutOpen.replace(/\s*<\/ProductTabs>\s*$/i, '');
|
||||
return withoutClose.trim();
|
||||
function extractDescriptionFromMdxFrontmatter(data: any): string {
|
||||
const description = normalizeValue(String(data?.description || ''));
|
||||
return description;
|
||||
}
|
||||
|
||||
function buildMdxIndex(locale: 'en' | 'de'): MdxIndex {
|
||||
@@ -93,7 +84,7 @@ function buildMdxIndex(locale: 'en' | 'de'): MdxIndex {
|
||||
const categories = Array.isArray(data.categories) ? data.categories.map((c: any) => normalizeValue(String(c))).filter(Boolean) : [];
|
||||
const images = Array.isArray(data.images) ? data.images.map((i: any) => normalizeValue(String(i))).filter(Boolean) : [];
|
||||
|
||||
const descriptionHtml = extractDescriptionHtmlFromMdxBody(parsed.content);
|
||||
const descriptionHtml = extractDescriptionFromMdxFrontmatter(data);
|
||||
|
||||
const slug = path.basename(file, '.mdx');
|
||||
idx.set(normalizeExcelKey(title), { slug, title, sku, categories, images, descriptionHtml });
|
||||
|
||||
@@ -639,10 +639,10 @@ function extractAbbrevColumnsFromMediumVoltageHeader(args: {
|
||||
function buildMediumVoltageCrossSectionTableFromNewExcel(args: {
|
||||
product: ProductData;
|
||||
locale: 'en' | 'de';
|
||||
}): BuildExcelModelResult {
|
||||
}): BuildExcelModelResult & { legendItems: KeyValueItem[] } {
|
||||
const mv = findMediumVoltageCrossSectionExcelForProduct(args.product) as MediumVoltageCrossSectionExcelMatch | null;
|
||||
if (!mv || !mv.rows.length) return { ok: false, technicalItems: [], voltageTables: [] };
|
||||
if (!mv.crossSectionKey) return { ok: false, technicalItems: [], voltageTables: [] };
|
||||
if (!mv || !mv.rows.length) return { ok: false, technicalItems: [], voltageTables: [], legendItems: [] };
|
||||
if (!mv.crossSectionKey) return { ok: false, technicalItems: [], voltageTables: [], legendItems: [] };
|
||||
|
||||
const abbrevCols = extractAbbrevColumnsFromMediumVoltageHeader({
|
||||
headerRow: mv.headerRow,
|
||||
@@ -651,7 +651,19 @@ function buildMediumVoltageCrossSectionTableFromNewExcel(args: {
|
||||
crossSectionKey: mv.crossSectionKey,
|
||||
ratedVoltageKey: mv.ratedVoltageKey,
|
||||
});
|
||||
if (!abbrevCols.length) return { ok: false, technicalItems: [], voltageTables: [] };
|
||||
if (!abbrevCols.length) return { ok: false, technicalItems: [], voltageTables: [], legendItems: [] };
|
||||
|
||||
// Collect legend items: abbreviation -> description from header row
|
||||
const legendItems: KeyValueItem[] = [];
|
||||
for (const col of abbrevCols) {
|
||||
const description = normalizeValue(String(mv.headerRow[col.colKey] || ''));
|
||||
if (description && description !== col.colKey) {
|
||||
legendItems.push({
|
||||
label: col.colKey,
|
||||
value: description,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const byVoltage = new Map<string, number[]>();
|
||||
for (let i = 0; i < mv.rows.length; i++) {
|
||||
@@ -710,7 +722,7 @@ function buildMediumVoltageCrossSectionTableFromNewExcel(args: {
|
||||
voltageTables.push({ voltageLabel: vKey, metaItems, crossSections, columns });
|
||||
}
|
||||
|
||||
return { ok: true, technicalItems: [], voltageTables };
|
||||
return { ok: true, technicalItems: [], voltageTables, legendItems };
|
||||
}
|
||||
|
||||
export function buildDatasheetModel(args: { product: ProductData; locale: 'en' | 'de' }): DatasheetModel {
|
||||
@@ -726,7 +738,7 @@ export function buildDatasheetModel(args: { product: ProductData; locale: 'en' |
|
||||
// Cross-section tables: for medium voltage only, prefer the new MV sheet (abbrev columns in header row).
|
||||
const crossSectionModel = isMediumVoltageProduct(args.product)
|
||||
? buildMediumVoltageCrossSectionTableFromNewExcel({ product: args.product, locale: args.locale })
|
||||
: { ok: false, technicalItems: [], voltageTables: [] };
|
||||
: { ok: false, technicalItems: [], voltageTables: [], legendItems: [] };
|
||||
|
||||
const voltageTablesSrc = crossSectionModel.ok
|
||||
? crossSectionModel.voltageTables
|
||||
@@ -762,5 +774,6 @@ export function buildDatasheetModel(args: { product: ProductData; locale: 'en' |
|
||||
labels,
|
||||
technicalItems: excelModel.ok ? excelModel.technicalItems : [],
|
||||
voltageTables,
|
||||
legendItems: crossSectionModel.legendItems || [],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -47,5 +47,6 @@ export type DatasheetModel = {
|
||||
};
|
||||
technicalItems: KeyValueItem[];
|
||||
voltageTables: DatasheetVoltageTable[];
|
||||
legendItems: KeyValueItem[];
|
||||
};
|
||||
|
||||
|
||||
@@ -62,12 +62,18 @@ export function DatasheetDocument(props: { model: DatasheetModel; assets: Assets
|
||||
<Footer locale={model.locale} siteUrl={CONFIG.siteUrl} />
|
||||
|
||||
{model.voltageTables.map((t: DatasheetVoltageTable) => (
|
||||
<View key={t.voltageLabel} style={{ marginBottom: 14 }}>
|
||||
<View key={t.voltageLabel} style={{ marginBottom: 14 }} break={false}>
|
||||
<Text style={styles.sectionTitle}>{`${model.labels.crossSection} — ${t.voltageLabel}`}</Text>
|
||||
|
||||
<DenseTable table={{ columns: t.columns, rows: t.rows }} firstColLabel={firstColLabel} />
|
||||
</View>
|
||||
))}
|
||||
|
||||
{model.legendItems.length ? (
|
||||
<Section title={model.locale === 'de' ? 'ABKÜRZUNGEN' : 'ABBREVIATIONS'}>
|
||||
<KeyValueGrid items={model.legendItems} />
|
||||
</Section>
|
||||
) : null}
|
||||
</Page>
|
||||
</Document>
|
||||
);
|
||||
|
||||
@@ -27,16 +27,19 @@ async function readBytesFromPublic(localPath: string): Promise<Uint8Array> {
|
||||
|
||||
function transformLogoSvgToPrintBlack(svg: string): string {
|
||||
return svg
|
||||
.replace(/fill\s*:\s*white/gi, 'fill:#0E2A47')
|
||||
.replace(/fill\s*=\s*"white"/gi, 'fill="#0E2A47"')
|
||||
.replace(/fill\s*=\s*'white'/gi, "fill='#0E2A47'");
|
||||
.replace(/fill\s*:\s*white/gi, 'fill:#000000')
|
||||
.replace(/fill\s*=\s*"white"/gi, 'fill="#000000"')
|
||||
.replace(/fill\s*=\s*'white'/gi, "fill='#000000'")
|
||||
.replace(/fill\s*:\s*#[0-9a-fA-F]{6}/gi, 'fill:#000000')
|
||||
.replace(/fill\s*=\s*"#[0-9a-fA-F]{6}"/gi, 'fill="#000000"')
|
||||
.replace(/fill\s*=\s*'#[0-9a-fA-F]{6}'/gi, "fill='#000000'");
|
||||
}
|
||||
|
||||
async function toPngBytes(inputBytes: Uint8Array, inputHint: string): Promise<Uint8Array> {
|
||||
const ext = (path.extname(inputHint).toLowerCase() || '').replace('.', '');
|
||||
if (ext === 'png') return inputBytes;
|
||||
|
||||
if (ext === 'svg' && /\/media\/logo\.svg$/i.test(inputHint)) {
|
||||
if (ext === 'svg' && (/\/media\/logo\.svg$/i.test(inputHint) || /\/logo-blue\.svg$/i.test(inputHint))) {
|
||||
const svg = Buffer.from(inputBytes).toString('utf8');
|
||||
inputBytes = new Uint8Array(Buffer.from(transformLogoSvgToPrintBlack(svg), 'utf8'));
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ export function DenseTable(props: {
|
||||
const headerFontSize = cols.length >= 14 ? 5.7 : cols.length >= 12 ? 5.9 : cols.length >= 10 ? 6.2 : 6.6;
|
||||
|
||||
return (
|
||||
<View style={styles.tableWrap}>
|
||||
<View style={styles.tableWrap} break={false}>
|
||||
<View style={styles.tableHeader} wrap={false}>
|
||||
<View style={{ width: cfgW }}>
|
||||
<Text
|
||||
|
||||
@@ -13,8 +13,8 @@ export async function generateDatasheetPdfBuffer(args: {
|
||||
const model = buildDatasheetModel({ product: args.product, locale: args.locale });
|
||||
|
||||
const logoDataUrl =
|
||||
(await loadImageAsPngDataUrl('/media/logo.svg')) ||
|
||||
(await loadImageAsPngDataUrl('/media/logo.webp')) ||
|
||||
(await loadImageAsPngDataUrl('/logo-blue.svg')) ||
|
||||
(await loadImageAsPngDataUrl('/logo-white.svg')) ||
|
||||
null;
|
||||
|
||||
const heroDataUrl = await loadImageAsPngDataUrl(model.product.heroSrc);
|
||||
|
||||
Reference in New Issue
Block a user