@cenk1cenk2/md-printer 2.17.3 → 2.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/_@oxc-project_runtime@0.139.0/helpers/esm/decorate.mjs +10 -0
- package/dist/_virtual/_@oxc-project_runtime@0.139.0/helpers/esm/decorateMetadata.mjs +7 -0
- package/dist/commands/index.mjs +31 -3
- package/dist/constants/index.mjs +2 -2
- package/dist/constants/template.constants.mjs +8 -1
- package/dist/services/i18n.service.mjs +40 -0
- package/dist/services/index.mjs +3 -0
- package/oclif.manifest.json +10 -2
- package/package.json +5 -3
- package/templates/invoice/i18n/de.yaml +24 -0
- package/templates/invoice/i18n/en.yaml +24 -0
- package/templates/invoice/settings.json +4 -0
- package/templates/invoice/tailwind.css +2 -0
- package/templates/invoice/template.html.j2 +40 -40
- package/templates/privat-rechnung/footer.html +0 -26
- package/templates/privat-rechnung/header.html +0 -16
- package/templates/privat-rechnung/settings.json +0 -9
- package/templates/privat-rechnung/tailwind.config.cjs +0 -74
- package/templates/privat-rechnung/tailwind.css +0 -43
- package/templates/privat-rechnung/template.html.j2 +0 -128
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region \0@oxc-project+runtime@0.139.0/helpers/esm/decorate.js
|
|
2
|
+
function __decorate(decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
//#endregion
|
|
10
|
+
export { __decorate as default };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
//#region \0@oxc-project+runtime@0.139.0/helpers/esm/decorateMetadata.js
|
|
2
|
+
function __decorateMetadata(k, v) {
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
//#endregion
|
|
7
|
+
export { __decorateMetadata as default };
|
package/dist/commands/index.mjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { RequiredTemplateFiles, TEMPLATE_DIRECTORY, TemplateFiles } from "../constants/template.constants.mjs";
|
|
1
|
+
import { DEFAULT_LANGUAGE, I18N_DIRECTORY, RequiredTemplateFiles, TEMPLATE_DIRECTORY, TemplateFiles } from "../constants/template.constants.mjs";
|
|
2
2
|
import { InputFileType, OutputFileType } from "../constants/file.constants.mjs";
|
|
3
|
+
import { I18nService } from "../services/i18n.service.mjs";
|
|
4
|
+
import "../services/index.mjs";
|
|
3
5
|
import tailwind from "@tailwindcss/postcss";
|
|
4
6
|
import { watch } from "chokidar";
|
|
5
7
|
import graymatter from "gray-matter";
|
|
@@ -51,6 +53,10 @@ var MDPrinter = class extends Command {
|
|
|
51
53
|
char: "T",
|
|
52
54
|
description: "Overwrite document title."
|
|
53
55
|
}),
|
|
56
|
+
language: Flags.string({
|
|
57
|
+
char: "l",
|
|
58
|
+
description: "Language code for template translations. Overwrites the one defined in front-matter and template settings."
|
|
59
|
+
}),
|
|
54
60
|
browser: Flags.string({
|
|
55
61
|
char: "b",
|
|
56
62
|
description: "Browser path that is going to be used for the PDF generation.",
|
|
@@ -81,10 +87,18 @@ var MDPrinter = class extends Command {
|
|
|
81
87
|
});
|
|
82
88
|
cs;
|
|
83
89
|
fs;
|
|
90
|
+
i18n;
|
|
84
91
|
browser;
|
|
92
|
+
register(cli) {
|
|
93
|
+
return {
|
|
94
|
+
...cli,
|
|
95
|
+
providers: [...cli.providers ?? [], I18nService]
|
|
96
|
+
};
|
|
97
|
+
}
|
|
85
98
|
async shouldRunBefore() {
|
|
86
99
|
this.cs = this.app.get(ConfigService);
|
|
87
100
|
this.fs = this.app.get(FileSystemService);
|
|
101
|
+
this.i18n = this.app.get(I18nService);
|
|
88
102
|
await this.app.get(ParserService).register(JsonParser, YamlParser);
|
|
89
103
|
this.nunjucks.addFilter("markdown_to_html", (markdown) => {
|
|
90
104
|
return new showdown.Converter().makeHtml(markdown);
|
|
@@ -160,6 +174,7 @@ var MDPrinter = class extends Command {
|
|
|
160
174
|
this.logger.debug("Tailwind CSS exists for template: %s -> %s", paths["tailwind.css"]);
|
|
161
175
|
ctx.options.css = await postcss([tailwind({ base: ctx.templates })]).process(await this.fs.read(paths["tailwind.css"]), { from: paths["tailwind.css"] }).then((result) => result.css);
|
|
162
176
|
}
|
|
177
|
+
await this.applyTranslations(ctx);
|
|
163
178
|
} }]);
|
|
164
179
|
}
|
|
165
180
|
async shouldRunAfter(ctx) {
|
|
@@ -182,6 +197,14 @@ var MDPrinter = class extends Command {
|
|
|
182
197
|
await this.runMd2Pdf(ctx);
|
|
183
198
|
if (this.browser) await this.browser.close();
|
|
184
199
|
}
|
|
200
|
+
async applyTranslations(ctx) {
|
|
201
|
+
ctx.language = this.flags.language ?? ctx.metadata?.language ?? ctx.options.i18n?.language ?? "en";
|
|
202
|
+
ctx.t = await this.i18n.load(join(ctx.templates, I18N_DIRECTORY), {
|
|
203
|
+
language: ctx.language,
|
|
204
|
+
fallback: ctx.options.i18n?.fallback
|
|
205
|
+
});
|
|
206
|
+
if (ctx.t) this.logger.info("Rendering with language: %s", ctx.language);
|
|
207
|
+
}
|
|
185
208
|
continuousBrowser(browser) {
|
|
186
209
|
return new Proxy(browser, { get: (target, property, receiver) => {
|
|
187
210
|
if (property !== "newPage") {
|
|
@@ -242,10 +265,15 @@ var MDPrinter = class extends Command {
|
|
|
242
265
|
let output;
|
|
243
266
|
if (ctx.template) {
|
|
244
267
|
this.logger.info("Rendering as template.");
|
|
245
|
-
|
|
268
|
+
const context = {
|
|
246
269
|
...ctx.metadata ?? {},
|
|
247
270
|
content: ctx.content
|
|
248
|
-
}
|
|
271
|
+
};
|
|
272
|
+
if (ctx.t) {
|
|
273
|
+
context.t = ctx.t;
|
|
274
|
+
context.language = ctx.language;
|
|
275
|
+
}
|
|
276
|
+
output = await convertMdToPdf({ content: this.nunjucks.renderString(ctx.template, context) }, options, { browser: this.browser });
|
|
249
277
|
} else {
|
|
250
278
|
this.logger.info("Rendering as plain file.");
|
|
251
279
|
output = await convertMdToPdf({ content: ctx.content }, options, { browser: this.browser });
|
package/dist/constants/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RequiredTemplateFiles, TEMPLATE_DIRECTORY, TemplateFiles } from "./template.constants.mjs";
|
|
1
|
+
import { DEFAULT_LANGUAGE, I18N_ACCEPTED_TYPES, I18N_DIRECTORY, RequiredTemplateFiles, TEMPLATE_DIRECTORY, TemplateFiles } from "./template.constants.mjs";
|
|
2
2
|
import { INPUT_FILE_ACCEPTED_TYPES, InputFileType, OUTPUT_FILE_ACCEPTED_TYPES, OutputFileType } from "./file.constants.mjs";
|
|
3
3
|
|
|
4
|
-
export { INPUT_FILE_ACCEPTED_TYPES, InputFileType, OUTPUT_FILE_ACCEPTED_TYPES, OutputFileType, RequiredTemplateFiles, TEMPLATE_DIRECTORY, TemplateFiles };
|
|
4
|
+
export { DEFAULT_LANGUAGE, I18N_ACCEPTED_TYPES, I18N_DIRECTORY, INPUT_FILE_ACCEPTED_TYPES, InputFileType, OUTPUT_FILE_ACCEPTED_TYPES, OutputFileType, RequiredTemplateFiles, TEMPLATE_DIRECTORY, TemplateFiles };
|
|
@@ -10,6 +10,13 @@ let TemplateFiles = /* @__PURE__ */ function(TemplateFiles) {
|
|
|
10
10
|
}({});
|
|
11
11
|
const RequiredTemplateFiles = ["settings.json"];
|
|
12
12
|
const TEMPLATE_DIRECTORY = "templates";
|
|
13
|
+
const I18N_DIRECTORY = "i18n";
|
|
14
|
+
const I18N_ACCEPTED_TYPES = [
|
|
15
|
+
".yaml",
|
|
16
|
+
".yml",
|
|
17
|
+
".json"
|
|
18
|
+
];
|
|
19
|
+
const DEFAULT_LANGUAGE = "en";
|
|
13
20
|
|
|
14
21
|
//#endregion
|
|
15
|
-
export { RequiredTemplateFiles, TEMPLATE_DIRECTORY, TemplateFiles };
|
|
22
|
+
export { DEFAULT_LANGUAGE, I18N_ACCEPTED_TYPES, I18N_DIRECTORY, RequiredTemplateFiles, TEMPLATE_DIRECTORY, TemplateFiles };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { DEFAULT_LANGUAGE, I18N_ACCEPTED_TYPES } from "../constants/template.constants.mjs";
|
|
2
|
+
import __decorateMetadata from "../_virtual/_@oxc-project_runtime@0.139.0/helpers/esm/decorateMetadata.mjs";
|
|
3
|
+
import __decorate from "../_virtual/_@oxc-project_runtime@0.139.0/helpers/esm/decorate.mjs";
|
|
4
|
+
import { basename, extname, join } from "path";
|
|
5
|
+
import { ConfigService, FileSystemService } from "@cenk1cenk2/oclif-common";
|
|
6
|
+
import { Injectable } from "@nestjs/common";
|
|
7
|
+
import i18next from "i18next";
|
|
8
|
+
|
|
9
|
+
//#region src/services/i18n.service.ts
|
|
10
|
+
let I18nService = class I18nService {
|
|
11
|
+
fs;
|
|
12
|
+
cs;
|
|
13
|
+
constructor(fs, cs) {
|
|
14
|
+
this.fs = fs;
|
|
15
|
+
this.cs = cs;
|
|
16
|
+
}
|
|
17
|
+
async load(directory, options) {
|
|
18
|
+
if (!this.fs.exists(directory)) return;
|
|
19
|
+
const instance = i18next.createInstance();
|
|
20
|
+
await instance.init({
|
|
21
|
+
lng: options.language,
|
|
22
|
+
fallbackLng: options.fallback ?? options.language ?? "en",
|
|
23
|
+
resources: await this.resources(directory),
|
|
24
|
+
interpolation: { escapeValue: false }
|
|
25
|
+
});
|
|
26
|
+
return instance.getFixedT(options.language);
|
|
27
|
+
}
|
|
28
|
+
async resources(directory) {
|
|
29
|
+
const files = (await this.fs.extra.readdir(directory)).filter((file) => I18N_ACCEPTED_TYPES.includes(extname(file)));
|
|
30
|
+
const resources = {};
|
|
31
|
+
await Promise.all(files.map(async (file) => {
|
|
32
|
+
resources[basename(file, extname(file))] = { translation: await this.cs.read(join(directory, file)) };
|
|
33
|
+
}));
|
|
34
|
+
return resources;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
I18nService = __decorate([Injectable(), __decorateMetadata("design:paramtypes", [typeof FileSystemService === "undefined" ? Object : FileSystemService, typeof ConfigService === "undefined" ? Object : ConfigService])], I18nService);
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
40
|
+
export { I18nService };
|
package/oclif.manifest.json
CHANGED
|
@@ -117,6 +117,14 @@
|
|
|
117
117
|
"multiple": false,
|
|
118
118
|
"type": "option"
|
|
119
119
|
},
|
|
120
|
+
"language": {
|
|
121
|
+
"char": "l",
|
|
122
|
+
"description": "Language code for template translations. Overwrites the one defined in front-matter and template settings.",
|
|
123
|
+
"name": "language",
|
|
124
|
+
"hasDynamicHelp": false,
|
|
125
|
+
"multiple": false,
|
|
126
|
+
"type": "option"
|
|
127
|
+
},
|
|
120
128
|
"browser": {
|
|
121
129
|
"char": "b",
|
|
122
130
|
"description": "Browser path that is going to be used for the PDF generation.",
|
|
@@ -157,5 +165,5 @@
|
|
|
157
165
|
"enableJsonFlag": false
|
|
158
166
|
}
|
|
159
167
|
},
|
|
160
|
-
"version": "2.
|
|
161
|
-
}
|
|
168
|
+
"version": "2.18.0"
|
|
169
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cenk1cenk2/md-printer",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.18.0",
|
|
4
4
|
"description": "A markdown printer.",
|
|
5
5
|
"module": "dist/index.mjs",
|
|
6
6
|
"type": "module",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"start": "./bin/run.js",
|
|
19
19
|
"build": "tsdown",
|
|
20
20
|
"dev:start": "tsdown --watch src/",
|
|
21
|
-
"clean": "rimraf oclif.
|
|
21
|
+
"clean": "rimraf oclif.manifest.json",
|
|
22
22
|
"format": "prettier --write src/ --log-level warn && eslint --fix",
|
|
23
23
|
"lint": "eslint",
|
|
24
24
|
"manifest": "oclif manifest",
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
"dependencies": {
|
|
73
73
|
"@cenk1cenk2/oclif-common": "^7.0.12",
|
|
74
74
|
"@listr2/manager": "^4.2.1",
|
|
75
|
+
"@nestjs/common": "11.1.16",
|
|
75
76
|
"@oclif/core": "^4.8.4",
|
|
76
77
|
"@oclif/plugin-help": "^6.2.37",
|
|
77
78
|
"@tailwindcss/forms": "^0.5.11",
|
|
@@ -81,6 +82,7 @@
|
|
|
81
82
|
"fs-extra": "^11.3.4",
|
|
82
83
|
"get-port": "^7.1.0",
|
|
83
84
|
"gray-matter": "^4.0.3",
|
|
85
|
+
"i18next": "^26.3.6",
|
|
84
86
|
"listr2": "^10.2.1",
|
|
85
87
|
"md-to-pdf": "^5.2.5",
|
|
86
88
|
"nunjucks": "^3.2.4",
|
|
@@ -119,5 +121,5 @@
|
|
|
119
121
|
"path": "./node_modules/@cenk1cenk2/cz-cc"
|
|
120
122
|
}
|
|
121
123
|
},
|
|
122
|
-
"packageManager": "pnpm@11.
|
|
124
|
+
"packageManager": "pnpm@11.15.1"
|
|
123
125
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
meta:
|
|
3
|
+
title: Rechnung
|
|
4
|
+
sections:
|
|
5
|
+
from: VON
|
|
6
|
+
to: AN
|
|
7
|
+
payment: ZAHLUNG
|
|
8
|
+
notes: NOTIZEN
|
|
9
|
+
invoice: RECHNUNG
|
|
10
|
+
signature: UNTERSCHRIFT
|
|
11
|
+
fields:
|
|
12
|
+
date: Datum
|
|
13
|
+
id: Rechnungsnr.
|
|
14
|
+
table:
|
|
15
|
+
description: Beschreibung
|
|
16
|
+
quantity: Menge
|
|
17
|
+
price: Preis
|
|
18
|
+
subtotal: Zwischensumme
|
|
19
|
+
tax: MwSt.
|
|
20
|
+
total: Gesamt
|
|
21
|
+
summary:
|
|
22
|
+
subtotal: Zwischensumme
|
|
23
|
+
tax: MwSt.
|
|
24
|
+
total: Gesamt
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
meta:
|
|
3
|
+
title: Invoice
|
|
4
|
+
sections:
|
|
5
|
+
from: FROM
|
|
6
|
+
to: TO
|
|
7
|
+
payment: PAYMENT
|
|
8
|
+
notes: NOTES
|
|
9
|
+
invoice: INVOICE
|
|
10
|
+
signature: SIGNATURE
|
|
11
|
+
fields:
|
|
12
|
+
date: Date
|
|
13
|
+
id: Invoice#
|
|
14
|
+
table:
|
|
15
|
+
description: Description
|
|
16
|
+
quantity: Qty
|
|
17
|
+
price: Price
|
|
18
|
+
subtotal: Subtotal
|
|
19
|
+
tax: Tax
|
|
20
|
+
total: Total
|
|
21
|
+
summary:
|
|
22
|
+
subtotal: Subtotal
|
|
23
|
+
tax: Tax
|
|
24
|
+
total: Total
|
|
@@ -37,6 +37,7 @@ body {
|
|
|
37
37
|
|
|
38
38
|
address {
|
|
39
39
|
@apply text-sm;
|
|
40
|
+
white-space: pre-line;
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
/* Typography styles converted from config */
|
|
@@ -134,6 +135,7 @@ table th {
|
|
|
134
135
|
|
|
135
136
|
table tr {
|
|
136
137
|
border-top: 0;
|
|
138
|
+
break-inside: avoid;
|
|
137
139
|
@apply even:bg-gray-50;
|
|
138
140
|
}
|
|
139
141
|
|
|
@@ -2,27 +2,27 @@
|
|
|
2
2
|
vim: ft=htmldjango
|
|
3
3
|
-->
|
|
4
4
|
<!DOCTYPE html>
|
|
5
|
-
<html lang="
|
|
5
|
+
<html lang="{{ language }}">
|
|
6
6
|
|
|
7
7
|
<head>
|
|
8
8
|
<meta charset="UTF-8">
|
|
9
9
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
10
10
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
11
|
-
<title>
|
|
11
|
+
<title>{{ t('meta.title') }}</title>
|
|
12
12
|
</head>
|
|
13
13
|
|
|
14
14
|
<body>
|
|
15
|
-
<
|
|
16
|
-
class="
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
<div class="max-w-full leading-tight prose grid">
|
|
16
|
+
<section id="header" class="relative grid grid-cols-12">
|
|
17
|
+
<img src="https://main.s3.kilic.dev/html/icon.png" alt="logo"
|
|
18
|
+
class="absolute h-40 top-1/2 left-1/2 -translate-x-1/2 -translate-y-[62%] drop-shadow-lg drop-shadow-gray-900 z-10">
|
|
19
19
|
<div class="col-span-1 flex flex-col justify-center text-lg font-extrabold text-gray-100">
|
|
20
|
-
<p class="text-vertical">
|
|
20
|
+
<p class="text-vertical">{{ t('sections.from') }}</p>
|
|
21
21
|
</div>
|
|
22
|
-
<div class="col-start-2 col-span-5 flex flex-col justify-
|
|
22
|
+
<div class="col-start-2 col-span-5 flex flex-col justify-start p-4 pt-10 mr-12">
|
|
23
23
|
<h1>Cenk Kılıç</h1>
|
|
24
24
|
<h3>{{ company.tax_number }}</h3>
|
|
25
|
-
<address>{{ company.address }}</address>
|
|
25
|
+
<address>{{ company.address | trim }}</address>
|
|
26
26
|
<div class="flex flex-col text-sm">
|
|
27
27
|
{% if company.phone %}
|
|
28
28
|
<a href="tel:{{ company.phone }}">{{ company.phone }}</a>
|
|
@@ -36,30 +36,30 @@
|
|
|
36
36
|
</div>
|
|
37
37
|
</div>
|
|
38
38
|
<div class="col-span-6 bg-gray-900 rounded-bl-4xl flex flex-col justify-center text-center">
|
|
39
|
-
<p class="p-4 font-bold text-white text-6xl">
|
|
39
|
+
<p class="p-4 font-bold text-white text-6xl">{{ t('invoice') }}</p>
|
|
40
40
|
</div>
|
|
41
41
|
</section>
|
|
42
42
|
<section id="client" class="grid grid-cols-12">
|
|
43
43
|
<div class="col-span-1 flex flex-col justify-center text-lg font-extrabold text-gray-100">
|
|
44
|
-
<p class="text-vertical">
|
|
44
|
+
<p class="text-vertical">{{ t('sections.to') }}</p>
|
|
45
45
|
</div>
|
|
46
|
-
<div class="col-span-5 flex flex-col justify-
|
|
46
|
+
<div class="col-span-5 flex flex-col justify-start p-4">
|
|
47
47
|
<h2>{{ client.name }}</h2>
|
|
48
48
|
{% if client.tax_number %}
|
|
49
49
|
<h3>{{ client.tax_number }}</h3>
|
|
50
50
|
{% endif %}
|
|
51
|
-
<address>{{ client.address }}</address>
|
|
51
|
+
<address>{{ client.address | trim }}</address>
|
|
52
52
|
</div>
|
|
53
53
|
<div class="col-span-6 flex items-center justify-center text-xs text-center p-4">
|
|
54
54
|
<div class="grid grid-rows-2 gap-4 w-full mr-12">
|
|
55
55
|
<div
|
|
56
|
-
class="p-2 flex flex-row justify-between
|
|
57
|
-
<p class="font-bold">
|
|
56
|
+
class="p-2 flex flex-row justify-between items-center rounded-xl bg-gray-50 border border-gray-50! inset-shadow-xs inset-shadow-gray-400">
|
|
57
|
+
<p class="font-bold">{{ t('fields.date') }}</p>
|
|
58
58
|
<p class="font-semibold">{{ date }}</p>
|
|
59
59
|
</div>
|
|
60
60
|
<div
|
|
61
|
-
class="p-2 flex flex-row justify-between
|
|
62
|
-
<p class="font-bold">
|
|
61
|
+
class="p-2 flex flex-row justify-between items-center rounded-xl bg-gray-50 border border-gray-50! inset-shadow-xs inset-shadow-gray-400">
|
|
62
|
+
<p class="font-bold">{{ t('fields.id') }}</p>
|
|
63
63
|
<p class="font-semibold">{{ id }}</p>
|
|
64
64
|
</div>
|
|
65
65
|
</div>
|
|
@@ -71,26 +71,26 @@
|
|
|
71
71
|
<thead class="border-b-1 border-b-gray-900! border-x-2 border-x-gray-900!">
|
|
72
72
|
<tr>
|
|
73
73
|
<th scope="col" class="w-md text-center">
|
|
74
|
-
|
|
74
|
+
{{ t('table.description') }}
|
|
75
75
|
</th>
|
|
76
76
|
<th scope="col" class="w-[10%] text-center">
|
|
77
|
-
|
|
77
|
+
{{ t('table.quantity') }}
|
|
78
78
|
</th>
|
|
79
79
|
<th scope="col" class="w-[10%] text-center">
|
|
80
|
-
|
|
80
|
+
{{ t('table.price') }}
|
|
81
81
|
</th>
|
|
82
82
|
<th scope="col" class="w-[10%] text-center">
|
|
83
|
-
|
|
83
|
+
{{ t('table.subtotal') }}
|
|
84
84
|
</th>
|
|
85
85
|
<th scope="col" class="w-[10%] text-center">
|
|
86
|
-
|
|
86
|
+
{{ t('table.tax') }}
|
|
87
87
|
</th>
|
|
88
88
|
<th scope="col" class="w-[14%] font-semibold text-center">
|
|
89
|
-
|
|
89
|
+
{{ t('table.total') }}
|
|
90
90
|
</th>
|
|
91
91
|
</tr>
|
|
92
92
|
</thead>
|
|
93
|
-
<tbody
|
|
93
|
+
<tbody>
|
|
94
94
|
{% set calculated_subtotal = 0 %}
|
|
95
95
|
{% set calculated_tax = 0 %}
|
|
96
96
|
{% for item in items %}
|
|
@@ -99,21 +99,21 @@
|
|
|
99
99
|
<td class="text-center align-middle">{{ item.quantity }} {{ item.unit }}</td>
|
|
100
100
|
<td class="text-center align-middle">{{ item.price }}{{ currency }}</td>
|
|
101
101
|
{% set calculated_item_subtotal = item.quantity * item.price %}
|
|
102
|
-
<td class="text-center align-middle">{{ calculated_item_subtotal }}{{ currency }}</td>
|
|
102
|
+
<td class="text-center align-middle">{{ calculated_item_subtotal | round(2) }}{{ currency }}</td>
|
|
103
103
|
{% set calculated_item_tax = calculated_item_subtotal * item.tax / 100 %}
|
|
104
104
|
{% set calculated_tax = calculated_tax + calculated_item_tax %}
|
|
105
105
|
<td class="text-center align-middle">
|
|
106
106
|
{% if calculated_item_tax > 0 %}
|
|
107
|
-
<div class="flex flex-row
|
|
108
|
-
<span class="text-[0.50rem] font-semibold mr-[2px]
|
|
109
|
-
<span>{{ calculated_item_tax }}{{ currency }}</span>
|
|
107
|
+
<div class="flex flex-row items-center">
|
|
108
|
+
<span class="text-[0.50rem] font-semibold mr-[2px]">({{ item.tax }}%)</span>
|
|
109
|
+
<span>{{ calculated_item_tax | round(2) }}{{ currency }}</span>
|
|
110
110
|
</div>
|
|
111
111
|
{% else %}
|
|
112
112
|
<span class="font-semibold">—</span>
|
|
113
113
|
{% endif %}
|
|
114
114
|
</td>
|
|
115
115
|
{% set calculated_item_total = calculated_item_subtotal + calculated_item_tax %}
|
|
116
|
-
<td class="font-semibold text-center align-middle">{{ calculated_item_total }}{{ currency }}</td>
|
|
116
|
+
<td class="font-semibold text-center align-middle">{{ calculated_item_total | round(2) }}{{ currency }}</td>
|
|
117
117
|
</tr>
|
|
118
118
|
{% set calculated_subtotal = calculated_subtotal + calculated_item_subtotal %}
|
|
119
119
|
{% endfor %}
|
|
@@ -123,12 +123,12 @@
|
|
|
123
123
|
</section>
|
|
124
124
|
<section id="payment" class="grid grid-cols-12">
|
|
125
125
|
<div class="col-span-1 flex flex-col justify-center text-lg font-extrabold text-gray-100 bg-gray-900">
|
|
126
|
-
<p class="text-vertical">
|
|
126
|
+
<p class="text-vertical">{{ t('sections.payment') }}</p>
|
|
127
127
|
</div>
|
|
128
128
|
<div
|
|
129
|
-
class="col-span-5 flex flex-col p-4 ml-[-1px] pl-5 justify-center
|
|
129
|
+
class="col-span-5 flex flex-col p-4 ml-[-1px] pl-5 justify-center font-semibold bg-gray-700 rounded-r-4xl text-white">
|
|
130
130
|
<span>{{ payment.bank }}</span>
|
|
131
|
-
<address>{{ payment.address }}</address>
|
|
131
|
+
<address>{{ payment.address | trim }}</address>
|
|
132
132
|
<span>{{ payment.bic }}</span>
|
|
133
133
|
<span>{{ payment.routing }}</span>
|
|
134
134
|
<span class="mt-4 font-semibold">{{ payment.name }}</span>
|
|
@@ -140,20 +140,20 @@
|
|
|
140
140
|
<div
|
|
141
141
|
class="flex flex-row justify-between font-semibold bg-gray-50 rounded-lg border border-gray-50! inset-shadow-xs inset-shadow-gray-400 py-1 px-2">
|
|
142
142
|
<p>
|
|
143
|
-
|
|
143
|
+
{{ t('summary.subtotal') }}
|
|
144
144
|
</p>
|
|
145
145
|
<p>
|
|
146
|
-
{{ calculated_subtotal }}{{ currency }}
|
|
146
|
+
{{ calculated_subtotal | round(2) }}{{ currency }}
|
|
147
147
|
</p>
|
|
148
148
|
</div>
|
|
149
149
|
<div
|
|
150
150
|
class="flex flex-row justify-between font-semibold bg-gray-50 rounded-lg border border-gray-50! inset-shadow-xs inset-shadow-gray-400 py-1 px-2">
|
|
151
151
|
<p>
|
|
152
|
-
|
|
152
|
+
{{ t('summary.tax') }}
|
|
153
153
|
</p>
|
|
154
154
|
<p>
|
|
155
155
|
{% if calculated_tax > 0 %}
|
|
156
|
-
{{ calculated_tax }}{{currency}}
|
|
156
|
+
{{ calculated_tax | round(2) }}{{currency}}
|
|
157
157
|
{% else %}
|
|
158
158
|
<span class="font-semibold">—</span>
|
|
159
159
|
{% endif %}
|
|
@@ -163,11 +163,11 @@
|
|
|
163
163
|
<div
|
|
164
164
|
class="flex flex-row justify-between font-bold rounded-lg text-primary-500 bg-gray-50 border border-gray-50! inset-shadow-xs inset-shadow-gray-400 py-1 px-2">
|
|
165
165
|
<p>
|
|
166
|
-
|
|
166
|
+
{{ t('summary.total') }}
|
|
167
167
|
</p>
|
|
168
168
|
<p>
|
|
169
169
|
{% set calculated_total = calculated_subtotal + calculated_tax %}
|
|
170
|
-
{{ calculated_total }}{{ currency }}
|
|
170
|
+
{{ calculated_total | round(2) }}{{ currency }}
|
|
171
171
|
</p>
|
|
172
172
|
</div>
|
|
173
173
|
</div>
|
|
@@ -175,7 +175,7 @@
|
|
|
175
175
|
</section>
|
|
176
176
|
<section id="footer" class="grid grid-cols-12">
|
|
177
177
|
<div class="col-span-1 flex flex-col justify-center text-lg font-extrabold text-gray-100">
|
|
178
|
-
<p class="text-vertical">
|
|
178
|
+
<p class="text-vertical">{{ t('sections.notes') }}</p>
|
|
179
179
|
</div>
|
|
180
180
|
<div class="col-span-5 flex flex-col p-4 text-sm leading-tight prose">
|
|
181
181
|
{{ content | safe }}<br />
|
|
@@ -183,7 +183,7 @@
|
|
|
183
183
|
<div class="col-span-1"></div>
|
|
184
184
|
<div
|
|
185
185
|
class="col-span-5 flex flex-col justify-end text-center m-8 mr-16 p-4 pb-0 border-2 border-gray-50! rounded-xl text-xs text-gray-100 h-36">
|
|
186
|
-
<p>
|
|
186
|
+
<p>{{ t('signature') }}</p>
|
|
187
187
|
</div>
|
|
188
188
|
</section>
|
|
189
189
|
</div>
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
<style>
|
|
2
|
-
footer {
|
|
3
|
-
margin: 0 auto;
|
|
4
|
-
text-align: center;
|
|
5
|
-
font-size: 8px;
|
|
6
|
-
color: #38404b;
|
|
7
|
-
width: 100%;
|
|
8
|
-
border-top: 1px solid #efefef;
|
|
9
|
-
padding-top: 8px;
|
|
10
|
-
}
|
|
11
|
-
</style>
|
|
12
|
-
<footer>
|
|
13
|
-
<div>
|
|
14
|
-
<img
|
|
15
|
-
height="8px"
|
|
16
|
-
src="data:image/png;base64,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"
|
|
17
|
-
alt="logo"
|
|
18
|
-
/>
|
|
19
|
-
|
|
20
|
-
<span>kilic.dev</span>
|
|
21
|
-
-
|
|
22
|
-
<span class="title"></span>
|
|
23
|
-
-
|
|
24
|
-
<span class="pageNumber"></span>/<span class="totalPages"></span>
|
|
25
|
-
</div>
|
|
26
|
-
</footer>
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
<style>
|
|
2
|
-
header {
|
|
3
|
-
margin: 0 auto;
|
|
4
|
-
text-align: center;
|
|
5
|
-
font-family: monospace;
|
|
6
|
-
font-size: 9px;
|
|
7
|
-
color: #242424;
|
|
8
|
-
}
|
|
9
|
-
</style>
|
|
10
|
-
<header>
|
|
11
|
-
<img
|
|
12
|
-
height="24px"
|
|
13
|
-
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJAAAACQCAYAAADnRuK4AAARB0lEQVR4Ae3BC3BdZYHA8f/3ODnnJjd94dLSqiAIKxDXJmmBFlhxZ3ahxVF3jbuuW5qmL9xVV1FoYYFCKSi+dUfX4ZE2oboKPkGlhVnXGelTgbZJd12sM9YlaNNZ25ukbe4595zv29wxnclkbtM29+TVfL8fjuM4juM4juM4juM4juM4pyNIgZSyWnveAs/zb9Baz1VKXyalnIUQlYDAGWuxtbYrSeKDSRL/Mi4Udhei8D+SJDlgrU0og6AMSumLM5WVH6nwM++TUs7BmUiiOC68lD9x4mth2Ptta22eYRAMg5TydZVV1fcEmcrVQIZBpJRIpZBCIKSkSOCMJssfWWux1mKMwSQJ1loGS5LklRPHuu+KovBpa63hLAjOgujjeRV/ka2e+qhU6mIGkFKitUZpjRACZ3wyxhDHMUkcY61lgCQMe795vKf7o8aYI5whwRkSfYJM5UeqslMeBjL0k1LieR5Ka5yJw1pLoVAgLhQYKEni9u6uo+9N4vgAZ0BxBoQQMlNZtbYqO+XTQAX9PM/D932kUjgTixACpRRKa4wxWGspklLO9P3gnYUoet4Y83+chuIMBJnKlVXZKZ8DNH2EEPi+j/Y8EAJn4hJCoLTGWos1hiIh5HSvwv/LKMw/Za09zhAUp+F5FfOmTJ3+FODTRwiB7/sorXHODUIItNZYazHGUCSlPE9pfXkU5r8HJJyCYghCiMrqqdO/K6V6I/38IEAphXPuUVpjrMUaQ5FS+lJrzO/iuPAipyAZQpCp+qDWXj39KioqUErhnLt830dKST9Rmc1ukFKdzylITkFKWZ2prPoE/ZRSaM/DOfdV+D4nCSFfl6ms/DCnIDmFCj94n5RyNv28igqcyUFKifY8TvKDyiYp5RRKkJQghJB+kPkA/bTWSClxJg/P8zhJSjnH8yreQQmSEoSQf+Jp7xr6ac/DmVyEEGit6Scq/OCdlCApQXteHUJU0UdKiZQSZ/JRWnOS9rzrKEFSgta6hn5KKZzJSUmJEIIiKdXrpZTTGURSgpTqjfSTSuFMUkIgpaRICOFLKWcyiKQEIcU0+kkpcSYvKSX9tBAyyyCSEgRC00cIgTO5CSnpJwDNIJLTEELgTF6CoUkcZyhCMBSJ45RB4jhlkDhOGSSOUwbNKJgzZw4PP7SBq6++iqL/ffVVvvDFL/Pslq04E5uiBD/INCita4QQeJ5HOWpr5/K9bz/JZZdditYarTXnzZjB4kU3kcvl2LevDWf8staSxDFFYb632ZikgwE0I2j+vHpaNj5ONptlMCklD9x/H1IqNrW04kxMkhFyySUX8+gjXyObzTKUe+++i2WNt+BMTJIRMGPGDL7yr19ixvTpnI5SivX3rWNZ4y04E48kZTNmzGBz6yauuPxyzsa6e+6maVkjzsQiSdnaOz5BzZVXcLaUUty/7h4aly7BmTgkKbvoogspx/3r7mX5skaciUEyzkgpWXfv3TQuvQVn/JOkLJ8PKZcQgvX33cvyZY0445skZY88+hhRFFEuIQT33vMvNC5dgjN+KUrwg0yD0rpGCIHneZyNVzs6iKKI66+7jnIJIXjHDTfQ1dXN3r37cEaftZYkjikK873NxiQdDKAowQ8yDUrrGiEEnudxtvbs2UtlppL6+jrScP1119LV3cXefW04o8taSxLHFIX53mZjkg4GUJTgB5kGpXWNEALP8zhb1lpe2LaNykwl8+rrKJeUknfc8Hba2vbzm4MHcUaPtZYkjikK873NxiQdDKAowQ8yDUrrGiEEnucxXNt37CQTZJhXX0cabnj79ezatZtDnZ04o8NaSxLHFIX53mZjkg4GUJTgB5kGpXWNEALP8xguay0vbNtOVWUV9fV1lCsIAm5evJht27dz+PBhnJFnrSWJY4rCfG+zMUkHAyhK8INMg9K6RgiB53mUa/uOHQR+wLx59ZTL930WL7qJXbt+zqHOTpyRZa0liWOKwnxvszFJBwMoSvCDTIPSukYIged5lMtay7bt28lWZamvq6VcQRCweNGNbN+xg87Dh3FGjrWWJI4pCvO9zcYkHQygKMEPMg1K6xohBJ7nkZYXtm0nCHzmzaunXEEQcPPiRezctZtDnZ04I8NaSxLHFIX53mZjkg4GUJTgB5kGpXWNEALP80jT9h07qaqqor6ulnIFQcCim/6K7Tt2cvjwYZz0WWtJ4piiMN/bbEzSwQCKEvwg06C0rhFC4HkeafvZC9vIBBnmzaunXEEQ8M6bb2bnzp0c6uzESZe1liSOKQrzvc3GJB0MoCjBDzINSusaIQSe5zESduzcSWWmkvr6Osrl+z6LbrqRnTt309nZiZMeay1JHFMU5nubjUk6GEBRgh9kGpTWNUIIPM9jJFhreWHbNiozlcyrr6NcQRBw8+JF7Nixi87OTpx0WGtJ4piiMN/bbEzSwQCKEvwg06C0rhFC4HkeI2n7jp288Q1v4PLL30K5fN9n0U03smvXbg51duKUz1pLEscUhfneZmOSDgaQjDFjDPfet56XXn6ZNEybNo3NrS289a01OCNPUYIfZBqU1jVCCDzPY6RFUcSWLc8xf/485syeTbl832fxopvYtevnHOrsxBk+ay1JHFMU5nubjUk6GEBRgh9kGpTWNUIIPM9jNIRRxLNbtrLwmmu44IJZlCsIAhYvupHtO3bQefgwzvBYa0nimKIw39tsTNLBAIoS/CDToLSuEULgeR6jJYoifrxlK/Pn1zNn9mzKFQQBNy9exM5duznU2Ylz9qy1JHFMUZjvbTYm6WAAyTjT09ND04rV7NmzlzRMnTqV1k2P8/o5c3DSJxmHenp6WNLYxC9efIk0TJs2jSe/9Q2mTZuGky7JOHXs2DGWr1jFSy+/TBpeP2cOrZseZ+rUqTjpUZTgB5kGpXWNEALP8xgrYRTx42e3cvVV85k9ezblmjVrFtdeu5Bnt2wlDEOc07PWksQxRWG+t9mYpIMBFCX4QaZBaV0jhMDzPMZSFEVsfe45rpo/j9mzZ1OumTPPZ8GCq9n63PPk83mcoVlrSeKYojDf22xM0sEAihL8INOgtK4RQuB5HmMtDCOe3bKVa66+itkXXEC5Zs2axXULF/KjZ58lDCOcU7PWksQxRWG+t9mYpIMBFCX4QaZBaV0jhMDzPMaDKIrYsuU55s+fx5zZsynXzJnns3DBArY+9zz5fB6nNGstSRxTFOZ7m41JOhhAMoF09/SwbPlK9uzZSxrmvu3PaNn4OM7wSSaYY8eOces/fYgDB35NGmrnvo33vPtdOMMjmYA6Ow/z0ds+Ti7XRRre8qeX4QyPxHHKIJmAZs48ny9/8QtMmzaVNPzPK7/CGR7JBJPNZnnk377KpZe+mTTs2buPHzz9DM7waCaQKdXVbGx+jNrauaRh7742li1fiTN8mgkim83Ssulx6uvqSEN7+35uaVxGd3cPzvBpJoApU6rZ1PwY9XV1pGHvvn00Nq2ku7sHpzyacS6bzbKp+THm1deThrb2/SxdtoKuri6c8mnGsSnV1bRsepz6ujrSsHffPpYuW0FXVxdOOiTjVDabZWPzY9TX1ZGGjtdeo7FpJV1dXTjp0YxD1dXVbG7ZSG3tXNKQy+X4u/f/A7lcDiddknGmurqaTc2PUls7lzR0dXXR2LSSjtdew0mfZhzJZrNsbtlIbe1c0tDV1cWSpctoa9+PMzI048SU6mo2Nj9Gbe1c0pDL5WhsWklb+36ckaMZB7LZLC2bHqe+ro40dHf3sKSxifb2/TgjSzPGpJRsWH8f9XV1pCGXy9HYtIL29v04I08zxu5ccwd/89fvIQ3d3d0sXbaCfW1tOKNDM0aklNy1dg2rV60gDblcjqXLVrCvrQ1n9EjGyNo7bmf1qhWkobu7h8amFexra8MZXZpRJoTg7rvuZNXK5aQhl8uxpLGJ9vb9OKNPMoqEENy55nZWrVxOGrq6umhsWkl7+36csaEZRXffdSerVi4nDV1dXSxZuoy29v04Y0czCqSUrL3jdlatXE4acrkcjU0raWvfjzO2NKPgrrVrWL1qBWno7u5hSWMT7e37ccaeZgRJKblzzR2sXrWCNORyORqbVtDevh9nfNCMoDvX3MGtq1eSlts+sYa9+9oYTRfMmsWFF17IuWbX7t2kQTMCpJTctXYNq1etIA1JkvCxj9/Of/70p4yW8847jy99/rMsXLgArTXnmqNHc2z+xjf4yle/RhiGDJdkBKxauZzVq1aQlg0PfYpnfvgjRsu0aVPZ3LqJP//z69Facy6aPn0a//zhD/GZhz9JOSQpW7jgGm7/+G2kwRjDuvvXs6mlldH0tw0NXHnF5UwG73n3u6id+zaGS5KyW1evoqKignJZa9nw4CdpfeLrjLZFi25kMrnkkksYLk3KgsCnXNZa7lu/gdYnNjMWAj/AOTOaccYYw4YHP0nrE5txxj9Jyg4e/C3luP+BDWxsacWZGCQp+/RnP8/+//pvzlaSJNz/wIO0PvF1nIlDkrIjR45wS2MTv/vd7zkbDzz4EJtaWnEmFskIOHLkCEublnPk6FFOJ0kS7lv/AC2tm3EmHskIOXDg16y+9R85duwYQ9nw0Kdoad3MeHLk6FGcMyMZQb948SWWNDbR09PDYMYY1t2/nk0trYw3W7ZuZbIIw4i9e/cxXIoS/CDToLSuEULgeR7lOHToEE//8Edc+uZLmDVrFkmS8JuDB7l33f1857vfYzx65VcHqLnyCt70pos4121qaeEHz/yQU7HWksQxRWG+t9mYpIMBBCVMmTr9mxV+8H4hBJnKSiYj3/e5c+0dXHPVVZyrWjd/nW89+RRDSZKEMJ+nqOvoHxYUCtEuBtA4JYVhyPoHHsQZmsRxyiBxnDJIHKcMEscpg8RxyiBxnDJIHGco1jIUieMMwTI0SQkWLP2stTiTl7WWAQyDSEqx9jh9rLVYa3EmL2sM/RJrbZ5BJCUYk/yefiZJcCYvYwz9ImvNHxhEUkISx6/QL0kSnMnJGIMxhiJrTJcxppNBJCXEceFFIKFPkiRYa3EmnyRJOCmOCy9Za2MGkZSQJMnBJIkP0C+OY5zJJy4UOCmKwucpQVKCtTaMwvD79IsLBay1OJNHHMdYa/kjeyIKw2coQXIK+fyJFiCkj7WWuFDAmRystRSiiJOiMNxqTPJbSpCcQhLHvwrD/HfoVygUMMbgnPsKUYS1ln6F3hPHP2f7UIJkCCeO9zxgrT1KvygMsdbinLviOCaOY04Kw/xTcVzYxSkohmCN+QPYfEWFfxN9rLUYY1BKIYTAObckSUIUhpxkjHn1WPfRvzfGdHMKitNI4vgXWusrldZX0MdaizEGpRRCCJxzQxLHhGHIAPme7qMfiAuFPQxBcXq2UIh+4nn+tVKpN9LHWotJEqRSCCFwJrZCoUAURQxQOH6s+7Yw3/skp6E4A9ba3ijKP629iquVUhfRx1pLHMcUSSkRQuBMLMYYwnyeJI4ZIH+8p/tj+fyJRzgDijNkre0tROH3pVSv09qrAwR9jDEkcUyRlBIhBM74ZowhiiIKUYS1lpOsNYd7unNLwnzvv3OGBGdJ9Knwg/dWZas/I6V6E4MopVBKIZVCCIEQAmfsWGvBWoy1mCQhSRKMMQwSR2H+6ePHuj+WJEkHZ0EwTFLKGUGm8oNBpupDUsoLAMFgQiBwxpq1llOIC4XoZ73Hjz1cKEQ/sdYazpKgTEKITIUfLKrwg/d6nrdASvUGQOOMS9baniSJf1mIwq1hPv+dOC60UwZBioQQgZTyPKnUxVKqWUKIDCBxxpa1sbW2K0mSg8Ykr1lrc9Zag+M4juM4juM4o+//AWCsi3ii19l6AAAAAElFTkSuQmCC"
|
|
14
|
-
alt="logo"
|
|
15
|
-
/>
|
|
16
|
-
</header>
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
const colors = require('theme-colors').getColors
|
|
2
|
-
|
|
3
|
-
/** @type {import("tailwindcss").Config} */
|
|
4
|
-
module.exports = {
|
|
5
|
-
content: ['./template.html.j2'],
|
|
6
|
-
theme: {
|
|
7
|
-
extend: {
|
|
8
|
-
fontFamily: {
|
|
9
|
-
sans: ['Montserrat'],
|
|
10
|
-
serif: ['Montserrat']
|
|
11
|
-
},
|
|
12
|
-
colors: {
|
|
13
|
-
primary: colors('#cd0043')
|
|
14
|
-
},
|
|
15
|
-
typography: (theme) => ({
|
|
16
|
-
css: {
|
|
17
|
-
a: {
|
|
18
|
-
color: theme('colors.primary.500'),
|
|
19
|
-
textDecoration: 'none'
|
|
20
|
-
},
|
|
21
|
-
h1: {
|
|
22
|
-
fontWeight: 800,
|
|
23
|
-
paddingTop: theme('padding.0.75'),
|
|
24
|
-
paddingBottom: theme('padding.0.75'),
|
|
25
|
-
marginBottom: 0,
|
|
26
|
-
marginTop: 0,
|
|
27
|
-
borderWidth: 0
|
|
28
|
-
},
|
|
29
|
-
h2: {
|
|
30
|
-
paddingTop: theme('padding.0.5'),
|
|
31
|
-
paddingBottom: theme('padding.0.5'),
|
|
32
|
-
marginBottom: 0,
|
|
33
|
-
marginTop: 0,
|
|
34
|
-
borderWidth: 0
|
|
35
|
-
},
|
|
36
|
-
h3: {
|
|
37
|
-
paddingTop: theme('padding.0.25'),
|
|
38
|
-
paddingBottom: theme('padding.0.25'),
|
|
39
|
-
marginBottom: 0,
|
|
40
|
-
marginTop: 0,
|
|
41
|
-
borderWidth: 0
|
|
42
|
-
},
|
|
43
|
-
blockquote: {
|
|
44
|
-
fontWeight: 400,
|
|
45
|
-
color: theme('colors.gray.600'),
|
|
46
|
-
fontStyle: 'normal',
|
|
47
|
-
quotes: '"\\201C""\\201D""\\2018""\\2019"'
|
|
48
|
-
},
|
|
49
|
-
'blockquote p:first-of-type::before': {
|
|
50
|
-
content: ''
|
|
51
|
-
},
|
|
52
|
-
'blockquote p:last-of-type::after': {
|
|
53
|
-
content: ''
|
|
54
|
-
},
|
|
55
|
-
'ul > li': {
|
|
56
|
-
paddingLeft: '1em',
|
|
57
|
-
textAlign: 'left'
|
|
58
|
-
},
|
|
59
|
-
'ol > li': {
|
|
60
|
-
paddingLeft: '1em',
|
|
61
|
-
textAlign: 'left'
|
|
62
|
-
},
|
|
63
|
-
'ol > li::before': {
|
|
64
|
-
top: 'calc(0.875em - 0.1em)'
|
|
65
|
-
},
|
|
66
|
-
'ul > li::before': {
|
|
67
|
-
top: 'calc(0.875em - 0.1em)'
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
})
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
plugins: [require('@tailwindcss/forms'), require('@tailwindcss/typography')]
|
|
74
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
@import url('https://fonts.bunny.net/css?family=montserrat:100,200,300,400,500,600,700,800,900&display=swap');
|
|
2
|
-
|
|
3
|
-
@import 'tailwindcss';
|
|
4
|
-
|
|
5
|
-
@config './tailwind.config.cjs';
|
|
6
|
-
|
|
7
|
-
@theme {
|
|
8
|
-
--font-weight-semibold: 700;
|
|
9
|
-
--font-weight-bold: 800;
|
|
10
|
-
--font-weight-extrabold: 900;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
body {
|
|
14
|
-
font-family: 'Montserrat';
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/*
|
|
18
|
-
The default border color has changed to `currentcolor` in Tailwind CSS v4,
|
|
19
|
-
so we've added these compatibility styles to make sure everything still
|
|
20
|
-
looks the same as it did with Tailwind CSS v3.
|
|
21
|
-
|
|
22
|
-
If we ever want to remove these styles, we need to add an explicit border
|
|
23
|
-
color utility to any element that depends on these defaults.
|
|
24
|
-
*/
|
|
25
|
-
@layer base {
|
|
26
|
-
*,
|
|
27
|
-
::after,
|
|
28
|
-
::before,
|
|
29
|
-
::backdrop,
|
|
30
|
-
::file-selector-button {
|
|
31
|
-
border-color: var(--color-gray-200, currentcolor);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
@layer base {
|
|
36
|
-
html {
|
|
37
|
-
font-size: 12px;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.page-break {
|
|
41
|
-
page-break-after: always;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
vim: ft=htmldjango
|
|
3
|
-
-->
|
|
4
|
-
<!DOCTYPE html>
|
|
5
|
-
<html lang="en">
|
|
6
|
-
<head>
|
|
7
|
-
<meta charset="UTF-8" />
|
|
8
|
-
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
9
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
10
|
-
<title>Document</title>
|
|
11
|
-
</head>
|
|
12
|
-
|
|
13
|
-
<body>
|
|
14
|
-
<div class="max-w-full leading-tight prose">
|
|
15
|
-
<h1 class="mb-2 text-center border-b-2">Privatrechnung</h1>
|
|
16
|
-
<div class="text-center">
|
|
17
|
-
<p class="m-0 font-bold">Rechnungsnummer</p>
|
|
18
|
-
<p class="m-0 font-bold">{{ id }}</p>
|
|
19
|
-
</div>
|
|
20
|
-
<div class="grid grid-cols-2" style="margin-bottom: 1em !important;">
|
|
21
|
-
<div class="grid-cols-1">
|
|
22
|
-
<div>
|
|
23
|
-
<h4 class="">Absender</h4>
|
|
24
|
-
</div>
|
|
25
|
-
<div>
|
|
26
|
-
<p class="my-2 font-semibold">{{ sender.name }}</p>
|
|
27
|
-
{% if sender.email %}
|
|
28
|
-
<p class="m-0 my-2">{{ sender.email }}</p>
|
|
29
|
-
{% endif %}
|
|
30
|
-
{% if sender.phone %}
|
|
31
|
-
<p class="m-0 my-2">{{ sender.phone }}</p>
|
|
32
|
-
{% endif %}
|
|
33
|
-
<div class="mt-4">
|
|
34
|
-
<p class="m-0">{{ sender.address }}</p>
|
|
35
|
-
<p class="m-0">{{ sender.postcode }}</p>
|
|
36
|
-
<p class="m-0">{{ sender.location }}</p>
|
|
37
|
-
</div>
|
|
38
|
-
</div>
|
|
39
|
-
</div>
|
|
40
|
-
<div class="grid-cols-1 text-right">
|
|
41
|
-
<div>
|
|
42
|
-
<h4 class="">Empfänger</h4>
|
|
43
|
-
</div>
|
|
44
|
-
<div class="leading-tight">
|
|
45
|
-
<p class="my-2 font-semibold">{{ receiver.name }}</p>
|
|
46
|
-
{% if receiver.email %}
|
|
47
|
-
<p class="m-0 my-2">{{ receiver.email }}</p>
|
|
48
|
-
{% endif %}
|
|
49
|
-
{% if receiver.phone %}
|
|
50
|
-
<p class="m-0 my-2">{{ receiver.phone }}</p>
|
|
51
|
-
{% endif %}
|
|
52
|
-
<div class="mt-4">
|
|
53
|
-
<p class="m-0">{{ receiver.address }}</p>
|
|
54
|
-
<p class="m-0">{{ receiver.postcode }}</p>
|
|
55
|
-
<p class="m-0">{{ receiver.location }}</p>
|
|
56
|
-
</div>
|
|
57
|
-
</div>
|
|
58
|
-
</div>
|
|
59
|
-
</div>
|
|
60
|
-
<div class="border-t-2">
|
|
61
|
-
<p class="font-bold">Dies ist eine Privatrechnung über eine nicht gewerbliche Tätigkeit. Umsatzsteuer wird daher nicht in Rechnung gestellt.</p>
|
|
62
|
-
<table class="w-full rounded-lg border-gray-200 table-fixed">
|
|
63
|
-
<thead class="border-b-2 border-primary-500">
|
|
64
|
-
<tr class="bg-gray-200">
|
|
65
|
-
<th class="px-2 w-full">Leistung</th>
|
|
66
|
-
<th class="px-8">Menge</th>
|
|
67
|
-
<th class="px-4">Einzelpreis</th>
|
|
68
|
-
<th class="px-4">Gesamtpreis</th>
|
|
69
|
-
</tr>
|
|
70
|
-
</thead>
|
|
71
|
-
<tbody>
|
|
72
|
-
{% set sum = 0 %}
|
|
73
|
-
{% for item in items %}
|
|
74
|
-
<tr class="even:bg-gray-50">
|
|
75
|
-
<td class="px-2">{{ item.description }}</td>
|
|
76
|
-
<td class="text-center">{{ item.quantity }} {{ item.type }}</td>
|
|
77
|
-
<td class="text-center">{{ item.price }}{{ currency }}</td>
|
|
78
|
-
<td class="font-semibold text-center">{{ item.quantity * item.price }}{{ currency }}</td>
|
|
79
|
-
</tr>
|
|
80
|
-
{% set sum = sum + item.quantity * item.price %}
|
|
81
|
-
{% endfor %}
|
|
82
|
-
</tbody>
|
|
83
|
-
<tfoot class="text-black border-t-2 border-primary-500">
|
|
84
|
-
<tr class="border-0 bg-gray-200!">
|
|
85
|
-
<td></td>
|
|
86
|
-
<td></td>
|
|
87
|
-
<th class="text-center">Gesamt</th>
|
|
88
|
-
<td class="font-bold text-center text-primary-500">{{ sum }}{{ currency }}</td>
|
|
89
|
-
</tr>
|
|
90
|
-
</tfoot>
|
|
91
|
-
</table>
|
|
92
|
-
</div>
|
|
93
|
-
<h3>Anmerkung</h3>
|
|
94
|
-
<div class="py-2 px-4 mt-0 w-full rounded-lg border-2 border-gray-200">{{ content }}</div>
|
|
95
|
-
<h3>Zahlungsdaten</h3>
|
|
96
|
-
<div>
|
|
97
|
-
<table class="mt-0 w-full rounded-lg border-gray-200 table-fixed">
|
|
98
|
-
<thead class="border-b-2 border-gray-500">
|
|
99
|
-
<tr class="text-center bg-gray-200">
|
|
100
|
-
<th class="px-24">Name</th>
|
|
101
|
-
<th class="px-24">Bank</th>
|
|
102
|
-
<th class="px-12">BIC</th>
|
|
103
|
-
<th class="w-full">IBAN</th>
|
|
104
|
-
</tr>
|
|
105
|
-
</thead>
|
|
106
|
-
<tfoot class="text-black border-t-2 border-primary-500">
|
|
107
|
-
<tr class="border-0 bg-gray-100! font-semibold text-center">
|
|
108
|
-
<td>{{ payment.name }}</td>
|
|
109
|
-
<td>{{ payment.bank }}</td>
|
|
110
|
-
<td>{{ payment.bic }}</td>
|
|
111
|
-
<td>{{ payment.iban }}</td>
|
|
112
|
-
</tr>
|
|
113
|
-
</tfoot>
|
|
114
|
-
</table>
|
|
115
|
-
</div>
|
|
116
|
-
<hr class="border-t-2 mt-0! mb-2!" style="margin-top: 0 !important; margin-bottom: 1.5em !important;" />
|
|
117
|
-
<div class="grid grid-cols-2 font-semibold">
|
|
118
|
-
<div class="flex flex-row items-center text-center">
|
|
119
|
-
<div class="w-full">
|
|
120
|
-
<p class="my-4">{{ location }}</p>
|
|
121
|
-
<p class="my-4">{{ date }}</p>
|
|
122
|
-
</div>
|
|
123
|
-
</div>
|
|
124
|
-
<div class="p-20 text-center rounded-lg border-2 border-gray-200">Unterschrift</div>
|
|
125
|
-
</div>
|
|
126
|
-
</div>
|
|
127
|
-
</body>
|
|
128
|
-
</html>
|