feat: add a Tools page printer for note merge and print presets

Chapter officers can merge a markdown note onto filtered students, teams, or events and save the recipe. Extra student-note columns are additional fields (any ## … fields heading) so they work as print tokens whether imported or typed by hand.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-30 15:38:43 -04:00
co-authored by Cursor
parent 4cfd85b902
commit 3f50d6e635
39 changed files with 2199 additions and 69 deletions
@@ -3,28 +3,26 @@
@inject IDialogService DialogService
@implements IAsyncDisposable
<div @ref="_anchorElement"
@onmouseenter="@(() => { if (_hasContent) _popoverOpen = true; })"
<div @onmouseenter="@(() => { if (_hasContent) _popoverOpen = true; })"
@onmouseleave="@(() => _popoverOpen = false)"
style="display: inline-block;">
<MudButton StartIcon="@IconValue"
OnClick="OpenDialog"
Variant="@Variant"
Size="@Size"
Color="@ButtonColor"
Tooltip="@TooltipText"
Class="@MarkdownHelper.GetNoteColorClass(_noteId)">
@if (!string.IsNullOrEmpty(ButtonText))
{
@ButtonText
}
</MudButton>
</div>
<MudPopover @bind-Open="_popoverOpen"
AnchorOrigin="Origin.BottomCenter"
TransformOrigin="Origin.TopCenter"
Elevation="8"
Anchor="@_anchorElement">
style="display: inline-block; position: relative;">
<MudTooltip Text="@TooltipText">
<MudButton StartIcon="@IconValue"
OnClick="OpenDialog"
Variant="@Variant"
Size="@Size"
Color="@ButtonColor"
Class="@MarkdownHelper.GetNoteColorClass(_noteId)">
@if (!string.IsNullOrEmpty(ButtonText))
{
@ButtonText
}
</MudButton>
</MudTooltip>
<MudPopover Open="_popoverOpen"
AnchorOrigin="Origin.BottomCenter"
TransformOrigin="Origin.TopCenter"
Elevation="8">
<ChildContent>
@if (_hasContent && !string.IsNullOrWhiteSpace(_noteContent))
{
@@ -41,7 +39,8 @@
</MudPaper>
}
</ChildContent>
</MudPopover>
</MudPopover>
</div>
@code {
[Parameter]
@@ -68,7 +67,6 @@
private int _noteId = 0;
private string _noteContent = string.Empty;
private bool _popoverOpen = false;
private ElementReference _anchorElement;
private Color ButtonColor => _hasContent ? Color.Success : (Variant == Variant.Filled ? Color.Primary : Color.Default);
private CancellationTokenSource? _cancellationTokenSource;
private bool _isDisposed = false;
@@ -30,6 +30,7 @@
<MudNavGroup Title="Tools" Icon="@Icons.Material.Filled.Build" Expanded="false">
<MudNavLink Href="/notes" Icon="@Icons.Material.Filled.Note">Notes</MudNavLink>
<MudNavLink Href="/print" Icon="@Icons.Material.Filled.Print">Page printer</MudNavLink>
</MudNavGroup>
<AuthorizeView Roles="Administrator">