wip
This commit is contained in:
52
scripts/pdf/react-pdf/components/DenseTable.tsx
Normal file
52
scripts/pdf/react-pdf/components/DenseTable.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import * as React from 'react';
|
||||
import { Text, View } from '@react-pdf/renderer';
|
||||
|
||||
import type { DatasheetVoltageTable } from '../../model/types';
|
||||
import { styles } from '../styles';
|
||||
|
||||
function clamp(n: number, min: number, max: number): number {
|
||||
return Math.max(min, Math.min(max, n));
|
||||
}
|
||||
|
||||
export function DenseTable(props: {
|
||||
table: Pick<DatasheetVoltageTable, 'columns' | 'rows'>;
|
||||
firstColLabel: string;
|
||||
}): React.ReactElement {
|
||||
const cols = props.table.columns;
|
||||
const rows = props.table.rows;
|
||||
|
||||
const cfgPct = cols.length >= 12 ? 0.28 : 0.32;
|
||||
const dataPct = 1 - cfgPct;
|
||||
const each = cols.length ? dataPct / cols.length : dataPct;
|
||||
const cfgW = `${Math.round(cfgPct * 100)}%`;
|
||||
const dataW = `${Math.round(clamp(each, 0.03, 0.12) * 1000) / 10}%`;
|
||||
|
||||
return (
|
||||
<View style={styles.tableWrap}>
|
||||
<View style={styles.tableHeader}>
|
||||
<View style={{ width: cfgW }}>
|
||||
<Text style={styles.tableHeaderCell}>{props.firstColLabel}</Text>
|
||||
</View>
|
||||
{cols.map(c => (
|
||||
<View key={c.key} style={{ width: dataW }}>
|
||||
<Text style={styles.tableHeaderCell}>{c.label}</Text>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
|
||||
{rows.map((r, ri) => (
|
||||
<View key={`${r.configuration}-${ri}`} style={[styles.tableRow, ri % 2 === 0 ? styles.tableRowAlt : null]}>
|
||||
<View style={{ width: cfgW }}>
|
||||
<Text style={styles.tableCell}>{r.configuration}</Text>
|
||||
</View>
|
||||
{r.cells.map((cell, ci) => (
|
||||
<View key={`${cols[ci]?.key || ci}`} style={{ width: dataW }}>
|
||||
<Text style={styles.tableCell}>{cell}</Text>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
21
scripts/pdf/react-pdf/components/Footer.tsx
Normal file
21
scripts/pdf/react-pdf/components/Footer.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import * as React from 'react';
|
||||
import { Text, View } from '@react-pdf/renderer';
|
||||
|
||||
import { styles } from '../styles';
|
||||
|
||||
export function Footer(props: { leftText: string; locale: 'en' | 'de' }): React.ReactElement {
|
||||
const date = new Date().toLocaleDateString(props.locale === 'en' ? 'en-US' : 'de-DE', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
});
|
||||
|
||||
return (
|
||||
<View style={styles.footer} fixed>
|
||||
<Text>{props.leftText}</Text>
|
||||
<Text>{date}</Text>
|
||||
<Text render={({ pageNumber, totalPages }) => `${pageNumber}/${totalPages}`} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
26
scripts/pdf/react-pdf/components/Header.tsx
Normal file
26
scripts/pdf/react-pdf/components/Header.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import * as React from 'react';
|
||||
import { Image, Text, View } from '@react-pdf/renderer';
|
||||
|
||||
import { styles } from '../styles';
|
||||
|
||||
export function Header(props: { title: string; logoDataUrl?: string | null; qrDataUrl?: string | null }): React.ReactElement {
|
||||
return (
|
||||
<View style={styles.header} fixed>
|
||||
<View style={styles.headerLeft}>
|
||||
{props.logoDataUrl ? (
|
||||
<Image src={props.logoDataUrl} style={styles.logo} />
|
||||
) : (
|
||||
<View style={styles.brandFallback}>
|
||||
<Text style={styles.brandFallbackKlz}>KLZ</Text>
|
||||
<Text style={styles.brandFallbackCables}>Cables</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
<View style={styles.headerRight}>
|
||||
<Text style={styles.headerTitle}>{props.title}</Text>
|
||||
{props.qrDataUrl ? <Image src={props.qrDataUrl} style={styles.qr} /> : null}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
30
scripts/pdf/react-pdf/components/KeyValueGrid.tsx
Normal file
30
scripts/pdf/react-pdf/components/KeyValueGrid.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import * as React from 'react';
|
||||
import { Text, View } from '@react-pdf/renderer';
|
||||
|
||||
import type { KeyValueItem } from '../../model/types';
|
||||
import { styles } from '../styles';
|
||||
|
||||
export function KeyValueGrid(props: { items: KeyValueItem[] }): React.ReactElement | null {
|
||||
const items = (props.items || []).filter(i => i.label && i.value);
|
||||
if (!items.length) return null;
|
||||
|
||||
return (
|
||||
<View style={styles.kvGrid}>
|
||||
{items.map((item, index) => {
|
||||
const isLast = index === items.length - 1;
|
||||
const valueText = item.unit ? `${item.value} ${item.unit}` : item.value;
|
||||
return (
|
||||
<View key={`${item.label}-${index}`} style={[styles.kvRow, isLast ? styles.kvRowLast : null]}>
|
||||
<View style={styles.kvLabel}>
|
||||
<Text style={styles.kvLabelText}>{item.label}</Text>
|
||||
</View>
|
||||
<View style={styles.kvValue}>
|
||||
<Text style={styles.kvValueText}>{valueText}</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
14
scripts/pdf/react-pdf/components/Section.tsx
Normal file
14
scripts/pdf/react-pdf/components/Section.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import * as React from 'react';
|
||||
import { Text, View } from '@react-pdf/renderer';
|
||||
|
||||
import { styles } from '../styles';
|
||||
|
||||
export function Section(props: { title: string; children: React.ReactNode }): React.ReactElement {
|
||||
return (
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>{props.title}</Text>
|
||||
{props.children}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user