Skip to content

Commit

Permalink
feat: initial Roster Formatting prototype for #14
Browse files Browse the repository at this point in the history
  • Loading branch information
amis92 committed Mar 11, 2022
1 parent 27d3688 commit 7f7723c
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/Phalanx.App/Pages/Index.razor
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@

<div style="display: flex; justify-content: space-around;">
<fast-anchor appearance="accent" href="/rosteredit">Edit sample roster</fast-anchor>
<fast-anchor appearance="accent" href="/print">Format roster</fast-anchor>
</div>
8 changes: 8 additions & 0 deletions src/Phalanx.App/Pages/Printing/RosterFormat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Phalanx.App.Pages.Printing;

public class RosterFormat
{
public string? Name { get; set; }

public string? HandlebarsTemplate { get; set; }
}
46 changes: 46 additions & 0 deletions src/Phalanx.App/Pages/Printing/RosterFormatter.cs
Original file line number Diff line number Diff line change
@@ -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> options)
{
this.options = options.Value;
}

/// <summary>
/// Handlebars template can reference members of <see cref="RosterCore"/>
/// by accessing the root context's "roster" property: <code>Name: {{roster.name}}</code>.
/// </summary>
/// <param name="roster"></param>
/// <param name="format"></param>
/// <returns></returns>
public string Format(RosterNode roster, RosterFormat format)
{
var templateBuilder = Handlebars.Compile(format.HandlebarsTemplate);
var context = new
{
roster = roster.Core
};
return templateBuilder(context);
}

public IEnumerable<RosterFormat> Formats => options.Formats;

public class Options
{
public List<RosterFormat> Formats { get; } = new()
{
new()
{
Name = "Default",
HandlebarsTemplate = "Roster \"{{roster.name}}\""
}
};
}
}
106 changes: 106 additions & 0 deletions src/Phalanx.App/Pages/RosterPrinter.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
@page "/print"
@using Printing
@using SampleDataset
@using WarHub.ArmouryModel.Source
@using WarHub.ArmouryModel.Workspaces.BattleScribe

@inject Printing.RosterFormatter formatter

<h1>Format roster</h1>

<label>Select roster file</label>
<InputFile OnChange="@LoadRosterFile" accept=".ros, .rosz" />

<p>
<strong>
Loaded:
@if (RosterNode is null)
{
<span>none</span>
}
else
{
<span>@RosterNode.Name</span>
}
</strong>
</p>

<label>Select formatter</label>
<fast-select current-value="@SelectedFormatIndex" @onchange="OnFormatIndexSelected">
@foreach (var (format, index) in formatter.Formats.Select((x, i) => (x, i)))
{
<fast-option value="@index">@format.Name</fast-option>
}
</fast-select>
@if (selectedFormat is not null)
{
<section>
<h2>Handlebars template <em>@selectedFormat.Name</em>:</h2>
<fast-text-area current-value="@selectedFormat.HandlebarsTemplate"
@onchange="e => selectedFormat.HandlebarsTemplate = e.Value?.ToString()" resize="both">
</fast-text-area>
<hr />
</section>
}
<fast-button @onclick="RunFormatter" disabled="@(selectedFormat is null || RosterNode is null)">Format</fast-button>

<section>
<h2>Formatted output:</h2>
<hr />
@formattedOutput
<hr />
</section>

@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<RosterNode>();
}

void RunFormatter()
{
if (RosterNode is null || selectedFormat is null)
{
formattedOutput = null;
return;
}
formattedOutput = formatter.Format(RosterNode, selectedFormat);
}
}
2 changes: 2 additions & 0 deletions src/Phalanx.App/Phalanx.App.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Handlebars.net" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="6.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="6.0.1" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="PublishSPAforGitHubPages.Build" Version="1.3.6" />
</ItemGroup>
Expand Down
2 changes: 2 additions & 0 deletions src/Phalanx.App/Program.cs
Original file line number Diff line number Diff line change
@@ -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>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddScoped<RosterFormatter>();

await builder.Build().RunAsync();

1 comment on commit 7f7723c

@amis92
Copy link
Member Author

@amis92 amis92 commented on 7f7723c Mar 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's supposed to be for #34 - a typo on my side.

Please sign in to comment.