This commit is contained in:
Simon Gruber
2024-01-08 16:21:10 +01:00
parent f3768348e9
commit b17044f959
51 changed files with 263 additions and 274 deletions
@@ -0,0 +1,42 @@
using ReportGeneration.Abstract;
using System.IO;
using System.Text;
namespace ReportGeneration.Generators;
internal class CollapsibleHtmlTableGenerator : HtmlTableGenerator
{
public string DetailsClass { get; init; }
public string Summary { get; init; } = "Show table";
/// <inheritdoc />
public CollapsibleHtmlTableGenerator(int columns)
: base(columns) { }
/// <inheritdoc />
public CollapsibleHtmlTableGenerator(int columns, Stream stream)
: base(columns, stream) { }
/// <inheritdoc />
public CollapsibleHtmlTableGenerator(int columns, Stream stream, Encoding encoding)
: base(columns, stream, encoding) { }
#region Overrides of HtmlTableGenerator
/// <inheritdoc />
protected override void OnOpen()
{
Writer.Write($"<details class=\"{DetailsClass}\" open>");
Writer.Write(HtmlTools.Wrap("summary", Summary));
base.OnOpen();
}
/// <inheritdoc />
protected override void OnClose()
{
base.OnClose();
Writer.Write($"</details>");
}
#endregion
}
@@ -0,0 +1,116 @@
using ReportGeneration.Abstract;
using ReportGeneration.Interface;
using System.IO;
using System.Reflection;
using System.Text;
namespace ReportGeneration.Generators;
public class HtmlDocumentGenerator : DocumentGeneratorBase
{
private int _sectionLevel = 0;
public string Title { get; init; } = string.Empty;
/// <inheritdoc />
public HtmlDocumentGenerator() { }
/// <inheritdoc />
public HtmlDocumentGenerator(string filePath) : base(filePath)
{
Title = Path.GetFileNameWithoutExtension(filePath);
}
/// <inheritdoc />
public HtmlDocumentGenerator(Stream stream) : base(stream) { }
/// <inheritdoc />
public HtmlDocumentGenerator(Stream stream, Encoding encoding) : base(stream, encoding) { }
#region State
/// <inheritdoc />
protected override void OnOpen()
{
base.OnOpen();
// Init html document
Write("<!DOCTYPE html>");
Write("<html>");
// Header
Write("<head>");
Write(HtmlTools.Wrap("title", Title));
Write("<meta charset=\"utf-8\">");
Write("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
Write("<style>");
using (var stream = Resources.Get("Style.css"))
{
using var streamReader = new StreamReader(stream);
Write(streamReader);
}
Write("</style>");
Write("</head>");
// Init body
Write("<body>");
}
/// <inheritdoc />
protected override void OnClose()
{
base.OnClose();
// End document
Write("</body>");
Write("</html>");
}
#endregion
#region Writing
/// <inheritdoc cref="AppendParagraph(string)" />
public IDocumentGenerator AppendParagraph(string? text, string? @class) =>
Append(HtmlTools.Wrap("p", text, @class));
/// <inheritdoc />
public override IDocumentGenerator AppendParagraph(string? text = default) =>
AppendParagraph(text, default);
/// <inheritdoc />
public override IDocumentGenerator AppendHeading(int level, string text) =>
Append($"<h{level} id=\"{text}\">{text}</h{level}>");
/// <inheritdoc />
protected override ITableGenerator MakeTable(int columns, Stream stream) =>
new CollapsibleHtmlTableGenerator(columns, stream);
/// <inheritdoc />
public override string FormatImage(string path, IBounds? bounds = default) =>
FormatImage(path, default, bounds);
/// <inheritdoc cref="FormatImage(string,IBounds)" />
public string FormatImage(string path, string? @class, IBounds? bounds = default) =>
HtmlTools.FormatImage(path, @class, bounds);
#endregion
#region Resource Management
private static class Resources
{
private static readonly Assembly assembly = Assembly.GetExecutingAssembly();
private static readonly string basePath =
typeof(HtmlDocumentGenerator).Namespace + ".Resources.";
public static Stream Get(string fileName) =>
assembly.GetManifestResourceStream(basePath + fileName) ??
throw new FileNotFoundException("Could not get resource", fileName);
}
#endregion
}
@@ -0,0 +1,77 @@
using ReportGeneration.Abstract;
using ReportGeneration.Interface;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace ReportGeneration.Generators;
internal class HtmlTableGenerator : TableGeneratorBase
{
public string Class { get; init; }
private static readonly (string start, string end) rowFormat = ("<tr>", "</tr>");
private static readonly (string start, string end) headerFormat = ("<th>", "</th>");
private static readonly (string start, string end) columnFormat = ("<td>", "</td>");
/// <inheritdoc />
public HtmlTableGenerator(int columns) : base(columns) { }
/// <inheritdoc />
public HtmlTableGenerator(int columns, Stream stream) : base(columns, stream) { }
/// <inheritdoc />
public HtmlTableGenerator(int columns, Stream stream, Encoding encoding) : base(columns, stream,
encoding)
{ }
#region State
/// <inheritdoc />
protected override void OnOpen()
{
base.OnOpen();
Writer.Write($"<table class={Class}>");
}
/// <inheritdoc />
protected override void OnClose()
{
base.OnClose();
Writer.Write("</table>");
}
#endregion
#region Writing
/// <inheritdoc />
public override ITableGenerator AppendHeader(IEnumerable<string> row) =>
AppendRow(row, rowFormat, headerFormat);
/// <inheritdoc />
public override ITableGenerator AppendRow(IEnumerable<string> row) =>
AppendRow(row, rowFormat, columnFormat);
private ITableGenerator AppendRow(
IEnumerable<string> row,
(string, string) rowFormat,
(string, string) columnFormat
)
{
var (rowStart, rowEnd) = rowFormat;
var (colStart, colEnd) = columnFormat;
this
.Write(rowStart)
.Write(colStart)
.Write(string.Join(colEnd + colStart, row))
.Write(colEnd)
.Write(rowEnd);
return this;
}
#endregion
}
@@ -0,0 +1,59 @@
using ReportGeneration.Interface;
namespace ReportGeneration.Generators;
internal static class HtmlTools
{
public static string Wrap(string tag, string? content, string? @class = default) =>
$"<{tag} class={@class}>{content}</{tag}>";
public static string FormatImage(string path, string? @class = default, IBounds? bounds = default)
{
var style = bounds is null
? string.Empty
: GetCssStyle(bounds);
path += path.EndsWith(".png") ? string.Empty : ".png";
return $"<img src=\"{path}\" style=\"{style}\" class={@class} />";
}
private static string GetCssStyle(IBounds bounds)
{
var style = string.Empty;
// Width
if (bounds.Width.HasValue)
{
style += $"width:{bounds.Width}{bounds.Unit};";
}
if (bounds.MinWidth.HasValue)
{
style += $"min-width:{bounds.MinWidth}{bounds.Unit};";
}
if (bounds.MaxWidth.HasValue)
{
style += $"max-width:{bounds.MaxWidth}{bounds.Unit};";
}
// Height
if (bounds.Height.HasValue)
{
style += $"height:{bounds.Height}{bounds.Unit};";
}
if (bounds.MinHeight.HasValue)
{
style += $"min-height:{bounds.MinHeight}{bounds.Unit};";
}
if (bounds.MaxHeight.HasValue)
{
style += $"max-height:{bounds.MaxHeight}{bounds.Unit};";
}
return style;
}
}
@@ -0,0 +1,45 @@
using ReportGeneration.Abstract;
using ReportGeneration.Interface;
using System.IO;
using System.Text;
namespace ReportGeneration.Generators;
public class MarkdownDocumentGenerator : DocumentGeneratorBase
{
/// <inheritdoc />
public MarkdownDocumentGenerator() { }
/// <inheritdoc />
public MarkdownDocumentGenerator(string filePath) : base(filePath) { }
/// <inheritdoc />
public MarkdownDocumentGenerator(Stream stream) : base(stream) { }
/// <inheritdoc />
public MarkdownDocumentGenerator(Stream stream, Encoding encoding) : base(stream, encoding) { }
#region Writing
/// <inheritdoc />
public override IDocumentGenerator AppendHeading(int level, string text) =>
AppendParagraph(new string('#', level) + ' ' + text);
/// <inheritdoc />
protected override ITableGenerator MakeTable(int columns, Stream stream) =>
new MarkdownTableGenerator(columns, stream);
/// <inheritdoc />
public override IDocumentGenerator AppendParagraph(string? text = default)
{
AppendLine(text);
AppendLine();
return this;
}
#endregion
/// <inheritdoc />
public override string FormatImage(string path, IBounds? bounds = default) =>
HtmlTools.FormatImage(path, default, bounds);
}
@@ -0,0 +1,37 @@
using ReportGeneration.Abstract;
using ReportGeneration.Interface;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace ReportGeneration.Generators;
internal class MarkdownTableGenerator : TableGeneratorBase
{
private const string ColumnSeparator = " | ";
/// <inheritdoc />
public MarkdownTableGenerator(int columns)
: base(columns) { }
/// <inheritdoc />
public MarkdownTableGenerator(int columns, Stream stream)
: base(columns, stream) { }
/// <inheritdoc />
public MarkdownTableGenerator(int columns, Stream stream, Encoding encoding)
: base(columns, stream, encoding) { }
/// <inheritdoc />
public override ITableGenerator AppendHeader(IEnumerable<string> row) =>
this
.AppendRow(row)
.AppendRow("---");
/// <inheritdoc />
public override ITableGenerator AppendRow(IEnumerable<string> row)
{
Writer.WriteLine(ColumnSeparator + string.Join(" | ", row) + ColumnSeparator);
return this;
}
}
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<IncludeSymbols>True</IncludeSymbols>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\ReportGeneration.Abstract\ReportGeneration.Abstract.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,17 @@
td, th {
border: 1px solid #777;
padding: .5rem;
text-align: center
}
table {
border-collapse: collapse
}
tbody tr:nth-child(odd) {
background: #eee
}
caption {
font-size: .8rem
}