diff --git a/package.json b/package.json
index 14160c49..949e4b20 100644
--- a/package.json
+++ b/package.json
@@ -31,21 +31,15 @@
"@trpc/client": "^10.45.2",
"@trpc/server": "^10.45.2",
"astro": "^4.16.10",
- "astro-i18next": "1.0.0-beta.21",
"body-scroll-lock": "^4.0.0-beta.0",
"buffer": "^6.0.3",
"bun": "^1.1.34",
- "caniuse-lite": "^1.0.30001684",
"csvtojson": "^2.0.10",
"express": "^4.21.1",
"flag-icons": "^6.15.0",
"fontkit": "^2.0.4",
- "i18next": "^23.16.5",
- "i18next-fs-backend": "^2.3.2",
- "i18next-http-backend": "^2.6.2",
"js-cookie": "^3.0.5",
"js-interpolate": "^1.3.1",
- "katex": "^0.16.11",
"moment": "^2.30.1",
"moment-timezone": "^0.5.46",
"pdf-lib": "^1.17.1",
diff --git a/public/images/sanierungsfahrplan/farbeEnergieEffizienzEins.svg b/public/images/sanierungsfahrplan/farbeEnergieEffizienzEins.svg
new file mode 100644
index 00000000..db6448d2
--- /dev/null
+++ b/public/images/sanierungsfahrplan/farbeEnergieEffizienzEins.svg
@@ -0,0 +1,50 @@
+
+
+
+
diff --git a/public/images/sanierungsfahrplan/farbeEnergieEffizienzZwei.svg b/public/images/sanierungsfahrplan/farbeEnergieEffizienzZwei.svg
new file mode 100644
index 00000000..51a348ea
--- /dev/null
+++ b/public/images/sanierungsfahrplan/farbeEnergieEffizienzZwei.svg
@@ -0,0 +1,47 @@
+
+
+
+
diff --git a/public/images/sanierungsfahrplan/farbenEnergieEffizienzHuelle.svg b/public/images/sanierungsfahrplan/farbenEnergieEffizienzHuelle.svg
new file mode 100644
index 00000000..32d0b957
--- /dev/null
+++ b/public/images/sanierungsfahrplan/farbenEnergieEffizienzHuelle.svg
@@ -0,0 +1,850 @@
+
+
+
+
diff --git a/public/images/sanierungsfahrplan/hausIconBoden.svg b/public/images/sanierungsfahrplan/hausIconBoden.svg
new file mode 100644
index 00000000..a84fd013
--- /dev/null
+++ b/public/images/sanierungsfahrplan/hausIconBoden.svg
@@ -0,0 +1,116 @@
+
+
+
+
diff --git a/public/images/sanierungsfahrplan/hausIconDach.svg b/public/images/sanierungsfahrplan/hausIconDach.svg
new file mode 100644
index 00000000..91f2a7b8
--- /dev/null
+++ b/public/images/sanierungsfahrplan/hausIconDach.svg
@@ -0,0 +1,192 @@
+
+
+
+
diff --git a/public/images/sanierungsfahrplan/hausIconFenster.svg b/public/images/sanierungsfahrplan/hausIconFenster.svg
new file mode 100644
index 00000000..517b9b1a
--- /dev/null
+++ b/public/images/sanierungsfahrplan/hausIconFenster.svg
@@ -0,0 +1,164 @@
+
+
+
+
diff --git a/public/images/sanierungsfahrplan/hausIconHaus.svg b/public/images/sanierungsfahrplan/hausIconHaus.svg
new file mode 100644
index 00000000..f1490c23
--- /dev/null
+++ b/public/images/sanierungsfahrplan/hausIconHaus.svg
@@ -0,0 +1,70 @@
+
+
+
+
diff --git a/public/images/sanierungsfahrplan/hausIconHeizung.svg b/public/images/sanierungsfahrplan/hausIconHeizung.svg
new file mode 100644
index 00000000..43d95c70
--- /dev/null
+++ b/public/images/sanierungsfahrplan/hausIconHeizung.svg
@@ -0,0 +1,130 @@
+
+
+
+
diff --git a/public/images/sanierungsfahrplan/hausIconLueftung.svg b/public/images/sanierungsfahrplan/hausIconLueftung.svg
new file mode 100644
index 00000000..d4fe66b9
--- /dev/null
+++ b/public/images/sanierungsfahrplan/hausIconLueftung.svg
@@ -0,0 +1,220 @@
+
+
+
+
diff --git a/public/images/sanierungsfahrplan/hausIconWaende.svg b/public/images/sanierungsfahrplan/hausIconWaende.svg
new file mode 100644
index 00000000..ab7c3dd4
--- /dev/null
+++ b/public/images/sanierungsfahrplan/hausIconWaende.svg
@@ -0,0 +1,124 @@
+
+
+
+
diff --git a/public/images/sanierungsfahrplan/hausIconWarmwasser.svg b/public/images/sanierungsfahrplan/hausIconWarmwasser.svg
new file mode 100644
index 00000000..9963d37a
--- /dev/null
+++ b/public/images/sanierungsfahrplan/hausIconWarmwasser.svg
@@ -0,0 +1,162 @@
+
+
+
+
diff --git a/public/images/sanierungsfahrplan/hausIconWarmwasserVerteilung.svg b/public/images/sanierungsfahrplan/hausIconWarmwasserVerteilung.svg
new file mode 100644
index 00000000..70c6fa54
--- /dev/null
+++ b/public/images/sanierungsfahrplan/hausIconWarmwasserVerteilung.svg
@@ -0,0 +1,186 @@
+
+
+
+
diff --git a/public/images/sanierungsfahrplan/skalaEnergieEffizienz.svg b/public/images/sanierungsfahrplan/skalaEnergieEffizienz.svg
new file mode 100644
index 00000000..b757436e
--- /dev/null
+++ b/public/images/sanierungsfahrplan/skalaEnergieEffizienz.svg
@@ -0,0 +1,98 @@
+
+
+
+
diff --git a/public/images/sanierungsfahrplan/skalaEnergieEffizienzVertikal.svg b/public/images/sanierungsfahrplan/skalaEnergieEffizienzVertikal.svg
new file mode 100644
index 00000000..694d2eaa
--- /dev/null
+++ b/public/images/sanierungsfahrplan/skalaEnergieEffizienzVertikal.svg
@@ -0,0 +1,89 @@
+
+
+
+
diff --git a/src/components/Katex.svelte b/src/components/Katex.svelte
deleted file mode 100644
index 87ebf45e..00000000
--- a/src/components/Katex.svelte
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
Ausweis ID: 1225432
+Adresse: Beispielstraße 15, 22587 Beispielnese
+ +Neubau
+Vermietung/Verkauf
+Modernisierung
+Sonstiges
+| Gebäudetyp | +Wohnfläche | +Leerstand | +Wohnungen | +
| Doppelhaushälfte | +DIN Wohnfläche innen 141m2 | +0% | +2 | +
| + | + | Dachgeschoss | +Keller | +
| + | + | unbeheizt | +nein | +
| + | Von: 01.01.2014 | +Von: 01.01.2015 | +Von: 01.01.2016 | +
| + | Bis: 31.12.2014 | +Bis: 31.12.2015 | +Bis: 31.12.2016 | +
| Heizöl EL | +1947 l | +1907 l | +2248 l | +
| Brennholz | +6 m3 | +6 m3 | +6 m3 | +
Warmwasseranteil: 18%
\ No newline at end of file diff --git a/src/lib/pdf/elements/Checkbox.ts b/src/lib/pdf/elements/Checkbox.ts new file mode 100644 index 00000000..04fca4ef --- /dev/null +++ b/src/lib/pdf/elements/Checkbox.ts @@ -0,0 +1,26 @@ +import { PDFPage, rgb } from 'pdf-lib'; +import { PDFElement } from './PDFElement.js'; + +export class Checkbox extends PDFElement { + private borderWidth: number = 1; + + constructor(protected _width: number, protected _height: number) { + super(); + } + + addChild(...children: PDFElement[]): void { + throw new Error('Method not supported.'); + } + + draw(page: PDFPage, x: number, y: number): void { + page.drawRectangle({ + x: x + this.borderWidth, + // NOTE: Keine Ahnung warum * 1.5 aber dann passt es... + y: y - this._height - this.borderWidth * 1.5, + width: this._width, + height: this._height, + borderColor: rgb(0, 0, 0), + borderWidth: this.borderWidth + }); + } +} diff --git a/src/lib/pdf/elements/Flex.ts b/src/lib/pdf/elements/Flex.ts new file mode 100644 index 00000000..f71216ad --- /dev/null +++ b/src/lib/pdf/elements/Flex.ts @@ -0,0 +1,175 @@ +import { PDFPage } from 'pdf-lib'; +import { PDFElement, Size } from './PDFElement.js'; + +export interface FlexOptions { + page: PDFPage; + width: number; + height: number; + x?: number; + y?: number; + direction?: 'row' | 'column'; + justify?: 'start' | 'center' | 'end' | 'space-between' | 'space-around'; + align?: 'start' | 'center' | 'end' | 'stretch'; + gap?: number; + children?: PDFElement[]; +} + +export class Flex extends PDFElement { + private page: PDFPage; + private x: number; + private y: number; + private direction: 'row' | 'column'; + private justifyContent: 'start' | 'center' | 'end' | 'space-between' | 'space-around'; + private alignItems: 'start' | 'center' | 'end' | 'stretch'; + private gap: number; + private children: PDFElement[]; + + constructor(options: FlexOptions) { + super(); + this.page = options.page; + this._width = options.width; + this._height = options.height; + this.x = options.x ?? 0; + this.y = options.y ?? 0; + this.direction = options.direction ?? 'row'; + this.justifyContent = options.justify ?? 'start'; + this.alignItems = options.align ?? 'start'; + this.gap = options.gap ?? 0; + this.children = options.children ?? []; + } + + addChild(...children: PDFElement[]): void { + this.children.push(...children) + } + + get height(): number { + if (typeof this._height === "number") { + return this._height; + } + + let currentHeight = 0 + + if (this.direction === "column") { + for (const child of this.children) { + currentHeight += child.height; + } + + currentHeight += this.gap * this.children.length - 1; + } else { + for (const child of this.children) { + if (child.height > currentHeight) { + currentHeight = child.height + } + } + } + + return currentHeight; + } + + set width(value: Size) { + this._width = value; + } + + get width(): number { + if (typeof this._width === "number") { + return this._width; + } + + let currentWidth = 0 + + if (this.direction === "row") { + for (const child of this.children) { + currentWidth += child.width; + } + + currentWidth += this.gap * this.children.length - 1; + } else { + for (const child of this.children) { + if (child.width > currentWidth) { + currentWidth = child.width + } + } + } + + return currentWidth; + } + + draw(page: PDFPage, x: number = this.x, y: number = this.y): void { + const childPositions = this.calculateChildPositions(x, y); + + // Draw each child + this.children.forEach((child, i) => { + const pos = childPositions[i]; + + child.draw(page, pos.x, pos.y); + }); + } + + private calculateChildPositions(x: number, y: number): { x: number; y: number }[] { + const positions: { x: number; y: number }[] = []; + let currentX = x; + let currentY = y; + + // Calculate total size of children and gaps + const totalChildrenSize = this.children.reduce( + (sum, child) => sum + (this.direction === 'row' ? child.width : child.height), + 0 + ); + + const totalGaps = this.gap * (this.children.length - 1); + + // Justify content + const justifyOffset = this.calculateJustifyOffset(totalChildrenSize, totalGaps); + + // Since the origin is at X: 0 Y: page height and everything will be drawn + // above the current position we first need to subtract the height of the + // element from the current Y + this.children.forEach((child, i) => { + const childX = this.direction === 'row' ? currentX : currentX + this.calculateAlignOffset(child.width); + const childY = this.direction === 'row' ? currentY - this.calculateAlignOffset(child.height) : currentY; + + if (this.direction === "row") { + currentX += child.width + this.gap + justifyOffset; + } + + if (this.direction === 'column') { + currentY -= child.height + this.gap; + } + + positions.push({ x: childX, y: childY }); + }); + + return positions; + } + + private calculateJustifyOffset(totalChildrenSize: number, totalGaps: number): number { + const remainingSpace = + this.direction === 'row' ? this.width - totalChildrenSize - totalGaps : this.height - totalChildrenSize - totalGaps; + + switch (this.justifyContent) { + case 'center': + return remainingSpace / 2; + case 'end': + return remainingSpace; + case 'space-between': + return totalGaps / (this.children.length - 1) + (this.width - totalChildrenSize) / this.children.length; + case 'space-around': + return remainingSpace / this.children.length; + default: + return 0; + } + } + + private calculateAlignOffset(childSize: number): number { + switch (this.alignItems) { + case 'center': + return (this.direction === 'row' ? this.height - childSize : this.width - childSize) / 2; + case 'end': + return this.direction === 'row' ? this.height - childSize : this.width - childSize; + case 'stretch': + return 0; + default: + return 0; + } + } +} diff --git a/src/lib/pdf/elements/Layout.ts b/src/lib/pdf/elements/Layout.ts new file mode 100644 index 00000000..1f542c3b --- /dev/null +++ b/src/lib/pdf/elements/Layout.ts @@ -0,0 +1,84 @@ +import { PDFPage } from "pdf-lib"; +import { PDFElement, Size } from "./PDFElement.js"; + +export type Margin = { + top: number, + left: number, + right: number, + bottom: number +} + +export type Padding = Margin; + +export class Layout extends PDFElement { + private margin: Margin + protected _height: Size = "auto"; + protected _width: Size = "auto"; + + private padding: Padding = { + bottom: 0, + left: 0, + right: 0, + top: 0 + }; + + public children: PDFElement[]; + + constructor(children: PDFElement[] = [], options?: { + margin?: Margin, + padding?: Padding + }) { + super() + + this.children = children + this.margin = options?.margin ?? { + bottom: 0, + left: 0, + right: 0, + top: 0 + }; + + this.padding = options?.padding ?? { + bottom: 0, + left: 0, + right: 0, + top: 0 + }; + } + + get height(): number { + if (typeof this._height === "number") { + return this._height; + } + + let currentHeight = 0 + + for (const child of this.children) { + currentHeight += child.height; + } + + return currentHeight; + } + + set height(value: number) { + this._height = value; + } + + draw(page: PDFPage, x: number, y: number): void { + let currentY = y - this.margin.top - this.padding.top; + + for (const child of this.children) { + child.draw(page, x + this.margin.left + this.padding.left, currentY); + + currentY -= child.height; + } + } + + addChild(...children: PDFElement[]): void { + this.children.push(...children) + } +} + +export function layout(...args: ConstructorParameters