diff --git a/WGneu/Documents/BusinessDocument.cshtml b/WGneu/Documents/BusinessDocument.cshtml new file mode 100644 index 0000000..ac7b169 --- /dev/null +++ b/WGneu/Documents/BusinessDocument.cshtml @@ -0,0 +1,18 @@ +@using RazorLight +@inherits TemplatePage<WGneu.Documents.BusinessDocument> +@model WGneu.Documents.BusinessDocument +@{ Layout = "Document"; } + +<div class="info-wrapper"> + <div class="address-wrapper"> + <div class="sender"> + <div>WG Matzen | Schloßstraße 6 | 2243 Matzen</div> + <div>E Österreichische Post AG Eco Brief</div> + </div> + <address>@Model.Address</address> + </div> + <aside></aside> +</div> +<main> + @RenderBody() +</main> diff --git a/WGneu/Documents/BusinessDocument.cshtml.cs b/WGneu/Documents/BusinessDocument.cshtml.cs new file mode 100644 index 0000000..322b5d7 --- /dev/null +++ b/WGneu/Documents/BusinessDocument.cshtml.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WGneu.Models; + +namespace WGneu.Documents { + public class BusinessDocument : Document { + + public BusinessDocument(string title, Member m) : base(title) { + Member = m; + } + + public Member Member { get; set; } + + public string Address { + get { + // TODO Name/Rechnungsadresse + return $"{Member.GivenName} {Member.FamilyName}\n{Member.Address}"; + } + } + } +} diff --git a/WGneu/Documents/BusinessLetter.cshtml b/WGneu/Documents/BusinessLetter.cshtml new file mode 100644 index 0000000..760eccd --- /dev/null +++ b/WGneu/Documents/BusinessLetter.cshtml @@ -0,0 +1,8 @@ +@using RazorLight +@inherits TemplatePage<WGneu.Documents.BusinessLetter> +@model WGneu.Documents.BusinessLetter +@{ Layout = "BusinessDocument"; } + +<p>Sehr geehrtes Mitglied,</p> +<p>nein.</p> +<p>Mit freundlichen Grüßen<br/>Ihre Winzergenossenschaft</p> diff --git a/WGneu/Documents/BusinessLetter.cshtml.cs b/WGneu/Documents/BusinessLetter.cshtml.cs new file mode 100644 index 0000000..6a9ea3d --- /dev/null +++ b/WGneu/Documents/BusinessLetter.cshtml.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WGneu.Models; + +namespace WGneu.Documents { + public class BusinessLetter : BusinessDocument { + public BusinessLetter(string title, Member m) : base(title, m) { + + } + } +} diff --git a/WGneu/Documents/Document.cshtml b/WGneu/Documents/Document.cshtml new file mode 100644 index 0000000..0521e05 --- /dev/null +++ b/WGneu/Documents/Document.cshtml @@ -0,0 +1,44 @@ +@using RazorLight +@inherits TemplatePage<WGneu.Documents.Document> +@model WGneu.Documents.Document + +<!DOCTYPE html> +<html lang="de-AT"> +<head> + <title>@Model.Title</title> + <meta charset="UTF-8"/> + <script> + window.finished = false; + window.PagedConfig = { auto: navigator.webdriver }; + if (!navigator.webdriver) { + window.addEventListener("beforeprint", async () => { + await window.PagedPolyfill.preview(); + window.finished = true; + }); + window.addEventListener("afterprint", () => { + location.reload(); + }); + } + </script> + <!-- TODO store paged.js locally to avoid using the internet --> + <script src="https://unpkg.com/pagedjs/dist/paged.polyfill.js"></script> + <link rel="stylesheet" href="style.css" type="text/css"/> +</head> +<body> + <div class="m1"></div> + <div class="m2"></div> + <div class="m3"></div> + <header>@Model.Header</header> + <div class="footer-wrapper"> + <div class="pre-footer"> + <span class="date">@Model.FullDateString</span> + <span class="page"></span> + </div> + <footer>@Model.Footer</footer> + </div> + <div class="spacing"></div> + <div class="main-wrapper"> + @RenderBody() + </div> +</body> +</html> diff --git a/WGneu/Documents/Document.cshtml.cs b/WGneu/Documents/Document.cshtml.cs new file mode 100644 index 0000000..e0a1237 --- /dev/null +++ b/WGneu/Documents/Document.cshtml.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.IO; + +namespace WGneu.Documents { + public class Document { + + public Document(string title) { + Title = title; + Header = "Winzergenossenschaft Matzen"; + Footer = "Winzergenossenschaft für Matzen und Umgebung reg. Gen.m.b.H."; + Date = DateTime.Today; + } + + public string Title { get; set; } + + public string Header { get; set; } + + public string Footer { get; set; } + + public string FullDateString { + get { + return Date.ToString("dddd, d. MMMM yyyy"); + } + } + + public DateTime Date { get; set; } + + private async Task<string> Render() { + if (this is BusinessLetter bl) { + return await Pdf.CompileRenderAsync("BusinessLetter.cshtml", bl); + } else if (this is BusinessDocument bd) { + return await Pdf.CompileRenderAsync("BusinessDocument.cshtml", bd); + } else { + return await Pdf.CompileRenderAsync("Document.cshtml", this); + } + } + + private async Task<string> SaveHtml() { + await File.WriteAllTextAsync("razor_test.html", await Render()); + return ""; + } + + public async Task<string> Save() { + await SaveHtml(); + return ""; + } + } +} diff --git a/WGneu/Documents/Pdf.cs b/WGneu/Documents/Pdf.cs index 178a571..5151698 100644 --- a/WGneu/Documents/Pdf.cs +++ b/WGneu/Documents/Pdf.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using PdfSharp.Pdf.IO; using PuppeteerSharp; using PuppeteerSharp.Media; +using RazorLight; using WGneu.Windows; namespace WGneu.Documents { @@ -16,9 +17,11 @@ namespace WGneu.Documents { private static readonly string CHROMIUM = @"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"; private static IBrowser? _Browser = null; + private static RazorLightEngine? _Engine = null; public static void Init() { var b = Browser; + var e = Engine; } private static IBrowser Browser { @@ -31,6 +34,16 @@ namespace WGneu.Documents { } } + private static RazorLightEngine Engine { + get { + _Engine ??= new RazorLightEngineBuilder() + .UseFileSystemProject(@"C:\Users\Lorenz\source\repos\WGneu\WGneu\Documents") + .UseMemoryCachingProvider() + .Build(); + return _Engine; + } + } + public static async Task Convert(string path_html, string path_pdf) { using var page = await Browser.NewPageAsync(); await page.GoToAsync("file://" + path_html); @@ -59,5 +72,9 @@ namespace WGneu.Documents { var w = new DocumentViewerWindow(title, path); w.Show(); } + + public static async Task<string> CompileRenderAsync(string key, object model) { + return await Engine.CompileRenderAsync(key, model); + } } } diff --git a/WGneu/Documents/Template.cs b/WGneu/Documents/Template.cs index d22b0c4..f0ffb7a 100644 --- a/WGneu/Documents/Template.cs +++ b/WGneu/Documents/Template.cs @@ -20,16 +20,8 @@ namespace WGneu.Documents { } public static async void Generate(WgContext c) { - var engine = new RazorLightEngineBuilder() - .UseFileSystemProject(@"C:\Users\tom\source\repos\wgneu-cs\WGneu\Documents") - .UseMemoryCachingProvider() - .Build(); - - var model = new TestTemplateModel(c); - - string result = await engine.CompileRenderAsync("TestTemplate.cshtml", model); - - await File.WriteAllTextAsync(ROOT + "razor_test.html", result); + var letter = new BusinessLetter("Test Dokument", c.Members.First()); + var pdf_path = await letter.Save(); } } } diff --git a/WGneu/Documents/TestTemplate.cshtml b/WGneu/Documents/TestTemplate.cshtml deleted file mode 100644 index c59b0a8..0000000 --- a/WGneu/Documents/TestTemplate.cshtml +++ /dev/null @@ -1,249 +0,0 @@ -@using RazorLight -@inherits TemplatePage<WGneu.Documents.TestTemplateModel> -@model IQueryable<WGneu.Documents.TestTemplateModel> - -<!DOCTYPE html> -<html lang="de-AT"> -<head> - <title>%SUBJECT%</title> - <!-- TODO store paged.js locally to avoid using the internet --> - <script> - window.finished = false; - window.PagedConfig = {auto: navigator.webdriver, after: () => { window.finished = true; }}; - if (!navigator.webdriver) window.addEventListener("beforeprint", () => { window.PagedPolyfill.preview(); }); - </script> - <script src="https://unpkg.com/pagedjs/dist/paged.polyfill.js"></script> - <style> - :root { - font-family: "Times New Roman", serif; - line-height: 1; - } - * {box-sizing: border-box;} - body {margin: 0;} - .m1, .m2, .m3 { - height: 0; - width: 1cm; - position: fixed; - left: 0; - border-top: 1pt solid black; - } - .m1 {top: 105mm;} - .m2 {top: 148.5mm;} - .m3 {top: 210mm;} - header { - height: 45mm; - padding: 5mm; - position: absolute; - top: -25mm; - left: 0; - right: 0; - text-align: center; - } - .spacing {height: 20mm;} - .info-wrapper { - width: 100%; - height:45mm; - margin: 0 0 8.46mm 0; - position: relative; - } - .address-wrapper { - height: 45mm; - width: 85mm; - margin: 0; - padding: 5mm; - position: absolute; - left: 20mm; - top: 0; - display: flex; - flex-direction: column; - justify-content: flex-end; - } - .address-wrapper .sender { - flex: 17.7mm 1 1; - font-size: 8pt; - display: flex; - flex-direction: column; - justify-content: flex-end; - padding-bottom: 2mm; - } - - address { - flex: 27.3mm 1 1; - white-space: pre-line; - font-size: 12pt; - font-style: normal; - } - - aside { - height: 40mm; - width: 75mm; - margin: 0; - position: absolute; - left: 125mm; - top: 5mm; - } - main { - margin: 8.46mm 20mm 4.23mm 25mm; - } - main :first-child { - margin-top: 0; - } - main h1, main p { - font-size: 12pt; - margin: 1em 0; - text-align: justify; - widows: 3; - orphans: 3; - } - main .date { - margin-bottom: 2em; - text-align: right; - } - main h1 { - margin-bottom: 2em; - } - .footer-wrapper { - padding: 0 20mm 0 25mm; - position: running(page-footer); - bottom: 0; - left: 0; - right: 0; - } - .pre-footer { - margin: 4.23mm 0; - font-size: 10pt; - display: flex; - } - .pre-footer .date, .pre-footer .page { - flex: 100px 1 1; - } - .pre-footer .date {text-align: left;} - .pre-footer .page {text-align: right;} - .page::after { - content: "Seite 1 von 1"; - } - footer { - font-size: 10pt; - border-top: 1pt solid black; - height: 25mm; - padding-top: 1mm; - text-align: center; - } - - @@page { - size: A4; - margin: 25mm 0 35mm 0; - @@bottom-center { - content: element(page-footer); - } - } - @@media screen { - body, header, .footer-wrapper { - width: 210mm; - } - header, .address-wrapper, aside, main { - border: 1px solid lightgray; - } - .m1, .m2, .m3 {display: none;} - header {top: 0;} - .spacing {height: 45mm;} - .main-wrapper { - margin-bottom: 40mm; - } - .footer-wrapper { - position: fixed; - bottom: 0; - left: 0; - right: 0; - background: white; - } - } - @@media print { - .page::after { - content: "Seite " counter(page) " von " counter(pages); - } - .footer-wrapper { - display: none; - } - } - </style> -</head> -<body> -<div class="m1"></div> -<div class="m2"></div> -<div class="m3"></div> -<header> - <h1>Winzergenossenschaft Matzen</h1> -</header> -<div class="footer-wrapper"> - <div class="pre-footer"> - <span class="date">Samstag, 4. März 2023</span> - <span class="page"></span> - </div> - <footer> - Winzergenossenschaft für Matzen und Umgebung reg. Gen.m.b.H. - </footer> -</div> -<div class="spacing"></div> -<div class="main-wrapper"> - <div class="info-wrapper"> - <div class="address-wrapper"> - <div class="sender"> - <div>WG Matzen | Schloßstraße 6 | 2243 Matzen</div> - <div>E Österreichische Post AG Eco Brief</div> - </div> - <address>Maximilian Mustermann - Musterstraße 123 - 2222 Musterort - Österreich</address> - </div> - <aside></aside> - </div> - <main> - <div class="date">Matzen, am 04.03.2023</div> - <h1>%SUBJECT%</h1> - <p>Sehr geehrtes Mitglied,</p> - - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - <p>Ich bin ein langer Paragraph.</p> - - @foreach (var country in Model.Countries) { - <h1>Land:</h1> - <p>@Raw(country.Name)</p> - <p>@country.Alpha2</p> - <p>@country.Alpha3</p> - } - - - - <p> - Mit freundlichen Grüßen<br/> - Ihre Winzergenossenschaft Matzen - </p> - </main> -</div> -</body> -</html> diff --git a/WGneu/Documents/TestTemplateModel.cshtml.cs b/WGneu/Documents/TestTemplateModel.cshtml.cs deleted file mode 100644 index a033d85..0000000 --- a/WGneu/Documents/TestTemplateModel.cshtml.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.AspNetCore.Mvc.RazorPages; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WGneu.Models; - -namespace WGneu.Documents { - public class TestTemplateModel { - - public IQueryable<Country> Countries { get; set; } - - public TestTemplateModel(WgContext c) { - Countries = c.Countries; - } - - } -} diff --git a/WGneu/Documents/style.css b/WGneu/Documents/style.css new file mode 100644 index 0000000..7e09e11 --- /dev/null +++ b/WGneu/Documents/style.css @@ -0,0 +1,176 @@ + +:root { + font-family: "Times New Roman", serif; + line-height: 1; +} + +* { + box-sizing: border-box; +} + +body { + margin: 0; +} + +.m1, .m2, .m3 { + height: 0; + width: 1cm; + position: fixed; + left: 0; + border-top: 1pt solid black; +} + +.m1 {top: 105mm;} +.m2 {top: 148.5mm;} +.m3 {top: 210mm;} + +header { + height: 45mm; + padding: 5mm; + position: absolute; + top: -25mm; + left: 0; + right: 0; + text-align: center; +} +.spacing {height: 20mm;} +.info-wrapper { + width: 100%; + height:45mm; + margin: 0 0 8.46mm 0; + position: relative; +} + +.address-wrapper { + height: 45mm; + width: 85mm; + margin: 0; + padding: 5mm; + position: absolute; + left: 20mm; + top: 0; + display: flex; + flex-direction: column; + justify-content: flex-end; +} + +.address-wrapper .sender { + flex: 17.7mm 1 1; + font-size: 8pt; + display: flex; + flex-direction: column; + justify-content: flex-end; + padding-bottom: 2mm; +} + +address { + flex: 27.3mm 1 1; + white-space: pre-line; + font-size: 12pt; + font-style: normal; +} + +aside { + height: 40mm; + width: 75mm; + margin: 0; + position: absolute; + left: 125mm; + top: 5mm; +} + +main { + margin: 8.46mm 20mm 4.23mm 25mm; +} + +main :first-child { + margin-top: 0; +} + +main h1, main p { + font-size: 12pt; + margin: 1em 0; + text-align: justify; + widows: 3; + orphans: 3; +} + +main .date { + margin-bottom: 2em; + text-align: right; +} + +main h1 { + margin-bottom: 2em; +} + +.footer-wrapper { + padding: 0 20mm 0 25mm; + position: running(page-footer); + bottom: 0; + left: 0; + right: 0; +} + +.pre-footer { + margin: 4.23mm 0; + font-size: 10pt; + display: flex; +} + +.pre-footer .date, .pre-footer .page { + flex: 100px 1 1; +} + +.pre-footer .date {text-align: left;} +.pre-footer .page {text-align: right;} +.page::after { + content: "Seite 1 von 1"; +} + +footer { + font-size: 10pt; + border-top: 1pt solid black; + height: 25mm; + padding-top: 1mm; + text-align: center; +} + +@page { + size: A4; + margin: 25mm 0 35mm 0; + @bottom-center { + content: element(page-footer); + } +} + +@media screen { + body, header, .footer-wrapper { + width: 210mm; + } + header, .address-wrapper, aside, main { + border: 1px solid lightgray; + } + .m1, .m2, .m3 {display: none;} + header {top: 0;} + .spacing {height: 45mm;} + .main-wrapper { + margin-bottom: 40mm; + } + .footer-wrapper { + position: fixed; + bottom: 0; + left: 0; + right: 0; + background: white; + } +} + +@media print { + .page::after { + content: "Seite " counter(page) " von " counter(pages); + } + .footer-wrapper { + display: none; + } +}