refactor: finish route-first shell
This commit is contained in:
BIN
RpgRoller/App_Data/rpgroller.development.db
Normal file
BIN
RpgRoller/App_Data/rpgroller.development.db
Normal file
Binary file not shown.
@@ -2,6 +2,10 @@
|
||||
@inherits AuthenticatedPageBase
|
||||
<Workspace Route="WorkspaceRoute.Admin" LoggedOut="OnLoggedOutAsync">
|
||||
<ChildContent Context="workspace">
|
||||
<AdminWorkspaceContent Workspace="workspace"/>
|
||||
<WorkspaceRouteView Workspace="workspace">
|
||||
<ChildContent Context="readyWorkspace">
|
||||
<AdminWorkspaceContent Workspace="readyWorkspace"/>
|
||||
</ChildContent>
|
||||
</WorkspaceRouteView>
|
||||
</ChildContent>
|
||||
</Workspace>
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
@inherits AuthenticatedPageBase
|
||||
<Workspace Route="WorkspaceRoute.Campaigns" LoggedOut="OnLoggedOutAsync">
|
||||
<ChildContent Context="workspace">
|
||||
<CampaignsWorkspaceContent Workspace="workspace"/>
|
||||
<WorkspaceRouteView Workspace="workspace">
|
||||
<ChildContent Context="readyWorkspace">
|
||||
<CampaignsWorkspaceContent Workspace="readyWorkspace"/>
|
||||
</ChildContent>
|
||||
</WorkspaceRouteView>
|
||||
</ChildContent>
|
||||
</Workspace>
|
||||
|
||||
@@ -82,43 +82,30 @@
|
||||
</div>
|
||||
|
||||
<section class="custom-roll-panel" aria-label="Custom roll panel">
|
||||
@if (EnableCustomRollComposer)
|
||||
{
|
||||
<form class="custom-roll-composer" @onsubmit="SubmitCustomRollAsync" @onsubmit:preventDefault>
|
||||
<div class="custom-roll-composer-head">
|
||||
<label for="custom-roll-expression" class="custom-roll-label">Custom roll</label>
|
||||
<span class="muted">@CustomRollStatusText</span>
|
||||
</div>
|
||||
<div class="custom-roll-composer-row">
|
||||
<input id="custom-roll-expression"
|
||||
@key="CustomRollInputVersion"
|
||||
@ref="CustomRollInputRef"
|
||||
class="@CustomRollInputCssClass"
|
||||
@bind="CustomRollExpression"
|
||||
@bind:event="oninput"
|
||||
placeholder="@CustomRollPlaceholder"
|
||||
title="@CustomRollInputTitle"
|
||||
aria-invalid="@HasCustomRollError"
|
||||
aria-describedby="@CustomRollInputDescribedBy"
|
||||
disabled="@IsCustomRollDisabled"/>
|
||||
<button type="submit" disabled="@IsCustomRollDisabled">Roll</button>
|
||||
</div>
|
||||
<p class="field-help">@CustomRollHelpText</p>
|
||||
@if (HasCustomRollError)
|
||||
{
|
||||
<p id="@CustomRollErrorElementId" class="field-error" role="alert">@CustomRollErrorMessage</p>
|
||||
}
|
||||
</form>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="custom-roll-composer">
|
||||
<div class="custom-roll-composer-head">
|
||||
<span class="custom-roll-label">Custom roll</span>
|
||||
<span class="muted">@CustomRollStatusText</span>
|
||||
</div>
|
||||
<p class="field-help">Loading roll composer...</p>
|
||||
<form class="custom-roll-composer" @onsubmit="SubmitCustomRollAsync" @onsubmit:preventDefault>
|
||||
<div class="custom-roll-composer-head">
|
||||
<label for="custom-roll-expression" class="custom-roll-label">Custom roll</label>
|
||||
<span class="muted">@CustomRollStatusText</span>
|
||||
</div>
|
||||
}
|
||||
<div class="custom-roll-composer-row">
|
||||
<input id="custom-roll-expression"
|
||||
@key="CustomRollInputVersion"
|
||||
@ref="CustomRollInputRef"
|
||||
class="@CustomRollInputCssClass"
|
||||
@bind="CustomRollExpression"
|
||||
@bind:event="oninput"
|
||||
placeholder="@CustomRollPlaceholder"
|
||||
title="@CustomRollInputTitle"
|
||||
aria-invalid="@HasCustomRollError"
|
||||
aria-describedby="@CustomRollInputDescribedBy"
|
||||
disabled="@IsCustomRollDisabled"/>
|
||||
<button type="submit" disabled="@IsCustomRollDisabled">Roll</button>
|
||||
</div>
|
||||
<p class="field-help">@CustomRollHelpText</p>
|
||||
@if (HasCustomRollError)
|
||||
{
|
||||
<p id="@CustomRollErrorElementId" class="field-error" role="alert">@CustomRollErrorMessage</p>
|
||||
}
|
||||
</form>
|
||||
</section>
|
||||
</aside>
|
||||
|
||||
@@ -171,8 +171,6 @@ public partial class CampaignLogPanel
|
||||
|
||||
[Parameter] public string RollVisibility { get; set; } = "public";
|
||||
|
||||
[Parameter] public bool EnableCustomRollComposer { get; set; }
|
||||
|
||||
[Parameter] public bool IsMutating { get; set; }
|
||||
|
||||
[Parameter] public EventCallback<RollResult> CustomRollCreated { get; set; }
|
||||
|
||||
@@ -49,34 +49,20 @@
|
||||
</span>
|
||||
</h3>
|
||||
<div class="skill-filter-wrap">
|
||||
@if (EnableInteractiveControls)
|
||||
{
|
||||
<label class="sr-only" for="skill-filter-input">Filter skills</label>
|
||||
<input id="skill-filter-input"
|
||||
class="skill-filter-input"
|
||||
type="search"
|
||||
placeholder="Filter skills"
|
||||
@bind="SkillFilterText"
|
||||
@bind:event="oninput"/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p class="muted">Loading skill controls...</p>
|
||||
}
|
||||
<label class="sr-only" for="skill-filter-input">Filter skills</label>
|
||||
<input id="skill-filter-input"
|
||||
class="skill-filter-input"
|
||||
type="search"
|
||||
placeholder="Filter skills"
|
||||
@bind="SkillFilterText"
|
||||
@bind:event="oninput"/>
|
||||
</div>
|
||||
<div class="chip-toolbar">
|
||||
@if (EnableInteractiveControls)
|
||||
{
|
||||
<label class="visibility-control" for="roll-visibility">Visibility</label>
|
||||
<select id="roll-visibility" value="@(RollVisibility == "private" ? "private" : "public")" @onchange="OnRollVisibilityChangedAsync">
|
||||
<option value="public">Public</option>
|
||||
<option value="private">Private</option>
|
||||
</select>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p class="muted">Visibility: @(RollVisibility == "private" ? "Private" : "Public")</p>
|
||||
}
|
||||
<label class="visibility-control" for="roll-visibility">Visibility</label>
|
||||
<select id="roll-visibility" value="@(RollVisibility == "private" ? "private" : "public")" @onchange="OnRollVisibilityChangedAsync">
|
||||
<option value="public">Public</option>
|
||||
<option value="private">Private</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@{
|
||||
|
||||
@@ -370,8 +370,6 @@ public partial class CharacterPanel
|
||||
|
||||
[Parameter] public string RollVisibility { get; set; } = "public";
|
||||
|
||||
[Parameter] public bool EnableInteractiveControls { get; set; }
|
||||
|
||||
[Parameter] public EventCallback<string> RollVisibilityChanged { get; set; }
|
||||
|
||||
[Parameter] public Func<Guid, string> OwnerLabel { get; set; } = _ => string.Empty;
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
@inherits AuthenticatedPageBase
|
||||
<Workspace Route="WorkspaceRoute.Play" LoggedOut="OnLoggedOutAsync">
|
||||
<ChildContent Context="workspace">
|
||||
<PlayWorkspaceContent Workspace="workspace"/>
|
||||
<WorkspaceRouteView Workspace="workspace">
|
||||
<ChildContent Context="readyWorkspace">
|
||||
<PlayWorkspaceContent Workspace="readyWorkspace"/>
|
||||
</ChildContent>
|
||||
</WorkspaceRouteView>
|
||||
</ChildContent>
|
||||
</Workspace>
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
SelectedCharacterSkillGroups="Workspace.State.PlaySelectedCharacterSkillGroups"
|
||||
SelectedCampaignRulesetId="@(Workspace.State.PlaySelectedCampaign?.RulesetId ?? string.Empty)"
|
||||
RollVisibility="Workspace.State.RollVisibility"
|
||||
EnableInteractiveControls="Workspace.EnableCharacterControls"
|
||||
RollVisibilityChanged="Workspace.Session.OnRollVisibilityChangedAsync"
|
||||
OwnerLabel="Workspace.State.OwnerLabel"
|
||||
SkillDefinitionLabel="Workspace.State.SkillDefinitionLabel"
|
||||
@@ -38,7 +37,6 @@
|
||||
SelectedCharacterName="@(Workspace.State.PlaySelectedCharacter?.Name)"
|
||||
SelectedCampaignRulesetId="@(Workspace.State.PlaySelectedCampaign?.RulesetId ?? string.Empty)"
|
||||
RollVisibility="Workspace.State.RollVisibility"
|
||||
EnableCustomRollComposer="Workspace.EnableCustomRollComposer"
|
||||
IsMutating="Workspace.State.IsMutating"
|
||||
ToggleRollDetailRequested="Workspace.Play.ToggleRollDetailAsync"
|
||||
ResolveRollDetail="Workspace.Play.ResolveRollDetail"
|
||||
|
||||
@@ -14,34 +14,6 @@ public partial class Workspace : IAsyncDisposable
|
||||
State.IsScreenMenuOpen = false;
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
State.HasInteractiveRenderStarted = true;
|
||||
if (firstRender)
|
||||
{
|
||||
await Session.InitializeAsync();
|
||||
HasSessionInitialized = true;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!HasSessionInitialized)
|
||||
return;
|
||||
|
||||
if (!EnableCharacterControls)
|
||||
{
|
||||
EnableCharacterControls = true;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
return;
|
||||
}
|
||||
|
||||
if (EnableCustomRollComposer)
|
||||
return;
|
||||
|
||||
EnableCustomRollComposer = true;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
[JSInvokable]
|
||||
public Task OnStateEventReceived(CampaignStateSnapshot state)
|
||||
{
|
||||
@@ -126,6 +98,22 @@ public partial class Workspace : IAsyncDisposable
|
||||
return InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
private Task InitializeRouteAsync()
|
||||
{
|
||||
return InitializationTask ??= InitializeRouteCoreAsync();
|
||||
}
|
||||
|
||||
private async Task InitializeRouteCoreAsync()
|
||||
{
|
||||
if (HasSessionInitialized)
|
||||
return;
|
||||
|
||||
State.HasInteractiveRenderStarted = true;
|
||||
await Session.InitializeAsync();
|
||||
HasSessionInitialized = true;
|
||||
await RequestRefreshAsync();
|
||||
}
|
||||
|
||||
private static bool IsStaticRenderInteropException(InvalidOperationException exception)
|
||||
{
|
||||
return exception.Message.Contains("statically rendered", StringComparison.OrdinalIgnoreCase);
|
||||
@@ -145,16 +133,14 @@ public partial class Workspace : IAsyncDisposable
|
||||
|
||||
private WorkspaceState State { get; } = new();
|
||||
private bool HasSessionInitialized { get; set; }
|
||||
private bool EnableCharacterControls { get; set; }
|
||||
private bool EnableCustomRollComposer { get; set; }
|
||||
private bool IsPlayRoute => Route == WorkspaceRoute.Play;
|
||||
private bool IsCampaignsRoute => Route == WorkspaceRoute.Campaigns;
|
||||
private bool IsAdminRoute => Route == WorkspaceRoute.Admin;
|
||||
private string AppCssClass => IsPlayRoute ? "rr-app app-play" : "rr-app";
|
||||
|
||||
private WorkspacePageContext PageContext => new(State, Play, Campaigns, Admin, Scope, Session,
|
||||
RequestRefreshAsync, EnableCharacterControls, EnableCustomRollComposer, AdminDatabaseDownloadUrl,
|
||||
HeaderMenuItems, IsPlayRoute, IsCampaignsRoute, IsAdminRoute);
|
||||
InitializeRouteAsync, HasSessionInitialized, RequestRefreshAsync, AdminDatabaseDownloadUrl, HeaderMenuItems,
|
||||
IsPlayRoute, IsCampaignsRoute, IsAdminRoute);
|
||||
|
||||
private WorkspaceCampaignScopeCoordinator Scope => m_Scope ??= new(State, Feedback, JS, WorkspaceQuery,
|
||||
() => IsPlayRoute, Play.EnsureSelectedCharacterActiveAsync, Play.RefreshSelectedCharacterSheetAsync,
|
||||
@@ -231,4 +217,5 @@ public partial class Workspace : IAsyncDisposable
|
||||
|
||||
private WorkspaceCampaignScopeCoordinator? m_Scope;
|
||||
private WorkspaceSessionCoordinator? m_Session;
|
||||
private Task? InitializationTask { get; set; }
|
||||
}
|
||||
@@ -9,9 +9,9 @@ public sealed class WorkspacePageContext(
|
||||
WorkspaceAdminCoordinator admin,
|
||||
WorkspaceCampaignScopeCoordinator scope,
|
||||
WorkspaceSessionCoordinator session,
|
||||
Func<Task> initializeRouteAsync,
|
||||
bool hasSessionInitialized,
|
||||
Func<Task> requestRefreshAsync,
|
||||
bool enableCharacterControls,
|
||||
bool enableCustomRollComposer,
|
||||
string adminDatabaseDownloadUrl,
|
||||
IReadOnlyList<AppHeaderMenuItem> headerMenuItems,
|
||||
bool isPlayRoute,
|
||||
@@ -24,9 +24,9 @@ public sealed class WorkspacePageContext(
|
||||
public WorkspaceAdminCoordinator Admin { get; } = admin;
|
||||
public WorkspaceCampaignScopeCoordinator Scope { get; } = scope;
|
||||
public WorkspaceSessionCoordinator Session { get; } = session;
|
||||
public Func<Task> InitializeRouteAsync { get; } = initializeRouteAsync;
|
||||
public bool HasSessionInitialized { get; } = hasSessionInitialized;
|
||||
public Func<Task> RequestRefreshAsync { get; } = requestRefreshAsync;
|
||||
public bool EnableCharacterControls { get; } = enableCharacterControls;
|
||||
public bool EnableCustomRollComposer { get; } = enableCustomRollComposer;
|
||||
public string AdminDatabaseDownloadUrl { get; } = adminDatabaseDownloadUrl;
|
||||
public IReadOnlyList<AppHeaderMenuItem> HeaderMenuItems { get; } = headerMenuItems;
|
||||
public bool IsPlayRoute { get; } = isPlayRoute;
|
||||
|
||||
21
RpgRoller/Components/Pages/WorkspaceRouteView.razor
Normal file
21
RpgRoller/Components/Pages/WorkspaceRouteView.razor
Normal file
@@ -0,0 +1,21 @@
|
||||
@using Microsoft.AspNetCore.Components
|
||||
|
||||
@if (Workspace.HasSessionInitialized)
|
||||
{
|
||||
@ChildContent(Workspace)
|
||||
}
|
||||
|
||||
@code {
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (!firstRender)
|
||||
return;
|
||||
|
||||
await Workspace.InitializeRouteAsync();
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
[Parameter, EditorRequired] public WorkspacePageContext Workspace { get; set; } = null!;
|
||||
|
||||
[Parameter, EditorRequired] public RenderFragment<WorkspacePageContext> ChildContent { get; set; } = null!;
|
||||
}
|
||||
Reference in New Issue
Block a user