Cleanup
This commit is contained in:
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user