diff --git a/src/Phalanx.App/Pages/Index.razor b/src/Phalanx.App/Pages/Index.razor index 5faed24c3..6e83ce936 100644 --- a/src/Phalanx.App/Pages/Index.razor +++ b/src/Phalanx.App/Pages/Index.razor @@ -4,4 +4,5 @@
Edit sample roster + Format roster
\ No newline at end of file diff --git a/src/Phalanx.App/Pages/Printing/RosterFormat.cs b/src/Phalanx.App/Pages/Printing/RosterFormat.cs new file mode 100644 index 000000000..11181a5e5 --- /dev/null +++ b/src/Phalanx.App/Pages/Printing/RosterFormat.cs @@ -0,0 +1,8 @@ +namespace Phalanx.App.Pages.Printing; + +public class RosterFormat +{ + public string? Name { get; set; } + + public string? HandlebarsTemplate { get; set; } +} diff --git a/src/Phalanx.App/Pages/Printing/RosterFormatter.cs b/src/Phalanx.App/Pages/Printing/RosterFormatter.cs new file mode 100644 index 000000000..de30477e0 --- /dev/null +++ b/src/Phalanx.App/Pages/Printing/RosterFormatter.cs @@ -0,0 +1,46 @@ +using HandlebarsDotNet; +using Microsoft.Extensions.Options; +using WarHub.ArmouryModel.Source; + +namespace Phalanx.App.Pages.Printing; + +public class RosterFormatter +{ + private readonly Options options; + + public RosterFormatter(IOptions options) + { + this.options = options.Value; + } + + /// + /// Handlebars template can reference members of + /// by accessing the root context's "roster" property: Name: {{roster.name}}. + /// + /// + /// + /// + public string Format(RosterNode roster, RosterFormat format) + { + var templateBuilder = Handlebars.Compile(format.HandlebarsTemplate); + var context = new + { + roster = roster.Core + }; + return templateBuilder(context); + } + + public IEnumerable Formats => options.Formats; + + public class Options + { + public List Formats { get; } = new() + { + new() + { + Name = "Default", + HandlebarsTemplate = "Roster \"{{roster.name}}\"" + } + }; + } +} diff --git a/src/Phalanx.App/Pages/RosterPrinter.razor b/src/Phalanx.App/Pages/RosterPrinter.razor new file mode 100644 index 000000000..1d0eb4081 --- /dev/null +++ b/src/Phalanx.App/Pages/RosterPrinter.razor @@ -0,0 +1,106 @@ +@page "/print" +@using Printing +@using SampleDataset +@using WarHub.ArmouryModel.Source +@using WarHub.ArmouryModel.Workspaces.BattleScribe + +@inject Printing.RosterFormatter formatter + +

Format roster

+ + + + +

+ + Loaded: + @if (RosterNode is null) + { + none + } + else + { + @RosterNode.Name + } + +

+ + + + @foreach (var (format, index) in formatter.Formats.Select((x, i) => (x, i))) + { + @format.Name + } + +@if (selectedFormat is not null) +{ +
+

Handlebars template @selectedFormat.Name:

+ + +
+
+} +Format + +
+

Formatted output:

+
+ @formattedOutput +
+
+ +@code { + private RosterNode? RosterNode; + private string? formattedOutput; + private RosterFormat? selectedFormat; + private string? selectedFormatIndex; + private string? SelectedFormatIndex + { + get => selectedFormatIndex; + set + { + selectedFormatIndex = value; + selectedFormat = int.TryParse(value, out var i) + ? formatter.Formats.ElementAtOrDefault(i) + : null; + } + } + + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + selectedFormat = formatter.Formats.FirstOrDefault(); + var rosterFile = SampleDataResources.CreateXmlWorkspace().DocumentsByKind[XmlDocumentKind.Roster][0]; + RosterNode = (RosterNode?)(await rosterFile.GetRootAsync()); + } + + void OnFormatIndexSelected(ChangeEventArgs e) + { + SelectedFormatIndex = e.Value?.ToString(); + } + + async Task LoadRosterFile(InputFileChangeEventArgs eventArgs) + { + // 10MB + const long maxSize = 10 << 10 << 10; + using var stream = eventArgs.File.OpenReadStream(maxAllowedSize: maxSize); + // it's bad but WHAM doesn't support async reading currently :( + // TODO fix when wham gains async support, consider migrating? + using var memStream = new MemoryStream(); + await stream.CopyToAsync(memStream); + memStream.Position = 0; + RosterNode = (RosterNode)await memStream.LoadSourceAuto(eventArgs.File.Name).GetDataOrThrowAsync(); + } + + void RunFormatter() + { + if (RosterNode is null || selectedFormat is null) + { + formattedOutput = null; + return; + } + formattedOutput = formatter.Format(RosterNode, selectedFormat); + } +} diff --git a/src/Phalanx.App/Phalanx.App.csproj b/src/Phalanx.App/Phalanx.App.csproj index df9393d58..674aa8be7 100644 --- a/src/Phalanx.App/Phalanx.App.csproj +++ b/src/Phalanx.App/Phalanx.App.csproj @@ -6,8 +6,10 @@ + + diff --git a/src/Phalanx.App/Program.cs b/src/Phalanx.App/Program.cs index 0852df0f4..218e95473 100644 --- a/src/Phalanx.App/Program.cs +++ b/src/Phalanx.App/Program.cs @@ -1,11 +1,13 @@ using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using Phalanx.App; +using Phalanx.App.Pages.Printing; var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.RootComponents.Add("#app"); builder.RootComponents.Add("head::after"); builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); +builder.Services.AddScoped(); await builder.Build().RunAsync();