feat: merge event rankings and attribute badges into the page printer
Interview notes can print each student's ranked events and a shared attribute legend from the same catalog as the ranking index, without leftover table markup or collapsed answer space. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
using Core.Entities;
|
||||
|
||||
namespace Core.Printing;
|
||||
|
||||
/// <summary>
|
||||
/// Ranking-index style badges: colored rank dot plus a short label.
|
||||
/// Student pages list ranked events; event pages list students who ranked them.
|
||||
/// </summary>
|
||||
public static class PrintRankBadgeHtml
|
||||
{
|
||||
public static string ForStudentEvents(IEnumerable<StudentEventRanking>? rankings)
|
||||
{
|
||||
if (rankings is null)
|
||||
return string.Empty;
|
||||
|
||||
var badges = rankings
|
||||
.Where(r => r.Rank is >= 1 and <= StudentEventRanking.MaxRank)
|
||||
.OrderBy(r => r.Rank)
|
||||
.Select(EventBadge)
|
||||
.ToList();
|
||||
|
||||
return Wrap(badges);
|
||||
}
|
||||
|
||||
public static string ForEventStudents(IEnumerable<StudentEventRanking>? rankings)
|
||||
{
|
||||
if (rankings is null)
|
||||
return string.Empty;
|
||||
|
||||
var badges = rankings
|
||||
.Where(r => r.Student is not null && r.Rank is >= 1 and <= StudentEventRanking.MaxRank)
|
||||
.OrderBy(r => r.Rank)
|
||||
.ThenByDescending(r => r.Student.Grade + r.Student.TsaYear)
|
||||
.Select(r => StudentBadge(r.Student.FirstName, r.Rank))
|
||||
.ToList();
|
||||
|
||||
return Wrap(badges);
|
||||
}
|
||||
|
||||
internal static string EventBadge(StudentEventRanking ranking)
|
||||
{
|
||||
var evt = ranking.EventDefinition;
|
||||
var label = !string.IsNullOrWhiteSpace(evt?.ShortName)
|
||||
? evt.ShortName
|
||||
: evt?.Name;
|
||||
var attributes = EventAttributeMarks.For(evt);
|
||||
var attrsHtml = string.IsNullOrEmpty(attributes)
|
||||
? string.Empty
|
||||
: $"<span class=\"print-event-attrs\">{PrintTokenMap.EscapeHtml(attributes)}</span>";
|
||||
|
||||
return Badge(ranking.Rank, PrintTokenMap.EscapeHtml(label), attrsHtml);
|
||||
}
|
||||
|
||||
internal static string StudentBadge(string? firstName, int rank) =>
|
||||
Badge(rank, PrintTokenMap.EscapeHtml(firstName), string.Empty);
|
||||
|
||||
private static string Badge(int rank, string labelHtml, string extraHtml)
|
||||
{
|
||||
var extra = string.IsNullOrEmpty(extraHtml) ? string.Empty : $" {extraHtml}";
|
||||
return
|
||||
$"<span class=\"print-rank-badge\">" +
|
||||
$"<span class=\"print-rank-dot event-rank-{rank}\"></span> " +
|
||||
$"{labelHtml}{extra}" +
|
||||
"</span>";
|
||||
}
|
||||
|
||||
public static string Legend()
|
||||
{
|
||||
var marks = EventAttributeMarks.LegendItems
|
||||
.Select(mark =>
|
||||
"<span class=\"print-legend-mark\">" +
|
||||
$"<span class=\"print-event-attrs\">{PrintTokenMap.EscapeHtml(mark.Symbol)}</span> " +
|
||||
PrintTokenMap.EscapeHtml(mark.Label) +
|
||||
"</span>");
|
||||
|
||||
return
|
||||
"<div class=\"print-badge-legend\">" +
|
||||
$"<div class=\"print-attr-legend\">{string.Join(" · ", marks)}</div>" +
|
||||
"</div>";
|
||||
}
|
||||
|
||||
private static string Wrap(IReadOnlyList<string> badges, string separator = " ")
|
||||
{
|
||||
if (badges.Count == 0)
|
||||
return string.Empty;
|
||||
|
||||
return $"<div class=\"print-rank-badges\">{string.Join(separator, badges)}</div>";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user