94 lines
3.7 KiB
Plaintext
94 lines
3.7 KiB
Plaintext
@model FeatureRequestRoadmapViewModel
|
|
@using Microsoft.AspNetCore.Html
|
|
@using System.Text.Encodings.Web
|
|
@{
|
|
ViewData["Title"] = "Feature Roadmap";
|
|
}
|
|
|
|
<div class="page-heading compact">
|
|
<div>
|
|
<p class="eyebrow">Feedback</p>
|
|
<h1>Feature Roadmap</h1>
|
|
<p class="lead-text">Here are some improvements currently being considered, planned, in progress, or recently shipped. This is not a complete list of every suggestion, but it shows where PlotDirector is actively evolving.</p>
|
|
</div>
|
|
<div class="button-row">
|
|
<a class="btn btn-outline-secondary" asp-action="Index">My Requests</a>
|
|
<a class="btn btn-primary" asp-action="Create">Submit Feature Request</a>
|
|
</div>
|
|
</div>
|
|
|
|
<nav class="mb-3" aria-label="Breadcrumb">
|
|
<a asp-action="Index">Feature Requests</a>
|
|
<span class="muted"> / Roadmap</span>
|
|
</nav>
|
|
|
|
@foreach (var roadmapSection in Model.Sections)
|
|
{
|
|
<section class="edit-panel">
|
|
<h2>@roadmapSection.Heading</h2>
|
|
@if (!roadmapSection.Requests.Any())
|
|
{
|
|
<p class="muted mb-0">@EmptyMessage(roadmapSection.Status)</p>
|
|
}
|
|
else
|
|
{
|
|
<div class="d-flex flex-column gap-3">
|
|
@foreach (var request in roadmapSection.Requests)
|
|
{
|
|
<article class="border rounded p-3">
|
|
<div class="d-flex justify-content-between gap-3 flex-wrap mb-2">
|
|
<div>
|
|
<h3 class="fs-5 mb-1">@request.Title</h3>
|
|
<div class="d-flex flex-wrap gap-2">
|
|
@StatusBadge(request.Status)
|
|
@if (!string.IsNullOrWhiteSpace(request.AppArea))
|
|
{
|
|
<span class="badge text-bg-secondary">@request.AppArea</span>
|
|
}
|
|
</div>
|
|
</div>
|
|
@if (string.Equals(request.Status, FeatureRequestStatuses.Shipped, StringComparison.OrdinalIgnoreCase) && request.ShippedUtc.HasValue)
|
|
{
|
|
<span class="muted">Shipped @FormatDate(request.ShippedUtc.Value)</span>
|
|
}
|
|
</div>
|
|
<p class="mb-0">@Excerpt(request.Description)</p>
|
|
</article>
|
|
}
|
|
</div>
|
|
}
|
|
</section>
|
|
}
|
|
|
|
@functions {
|
|
private static string FormatDate(DateTime value) => value.ToLocalTime().ToString("yyyy-MM-dd");
|
|
|
|
private static string Excerpt(string value)
|
|
{
|
|
var cleaned = value.ReplaceLineEndings(" ").Trim();
|
|
return cleaned.Length <= 220 ? cleaned : $"{cleaned[..220]}...";
|
|
}
|
|
|
|
private static string EmptyMessage(string status) => status switch
|
|
{
|
|
FeatureRequestStatuses.Shipped => "No shipped roadmap items yet.",
|
|
FeatureRequestStatuses.InProgress => "No roadmap items are currently in progress.",
|
|
FeatureRequestStatuses.Planned => "No planned roadmap items yet.",
|
|
_ => "No roadmap items in this section yet."
|
|
};
|
|
|
|
private static IHtmlContent StatusBadge(string status)
|
|
{
|
|
var css = status switch
|
|
{
|
|
FeatureRequestStatuses.Candidate => "text-bg-secondary",
|
|
FeatureRequestStatuses.Planned => "text-bg-success",
|
|
FeatureRequestStatuses.InProgress => "text-bg-success",
|
|
FeatureRequestStatuses.Shipped => "text-bg-dark",
|
|
_ => "text-bg-secondary"
|
|
};
|
|
|
|
return new HtmlString($"<span class=\"badge {css}\">{HtmlEncoder.Default.Encode(status)}</span>");
|
|
}
|
|
}
|