From 8a93af0c180adcef03f8b781718524529cfe3797 Mon Sep 17 00:00:00 2001 From: VyPr-Red Date: Sun, 5 Jul 2026 22:24:12 -0500 Subject: [PATCH 1/7] Add level info sidebar for guide pages --- src/Downpatch.Web/Components/App.razor | 2 + .../Components/Guide/LevelInfoCard.razor | 165 ++++++++++++ .../Components/Guide/LevelInfoCard.razor.css | 244 ++++++++++++++++++ .../Components/Guide/Models/GoalInfo.cs | 14 + .../Components/Guide/Models/LevelInfo.cs | 24 ++ .../Components/Pages/Guide.razor | 115 ++++++++- src/Downpatch.Web/Downpatch.Web.csproj | 1 + src/Downpatch.Web/Program.cs | 7 +- src/Downpatch.Web/content | 1 + src/Downpatch.Web/wwwroot/css/site.css | 53 +++- src/Downpatch.Web/wwwroot/js/guide.js | 44 ++++ 11 files changed, 657 insertions(+), 13 deletions(-) create mode 100644 src/Downpatch.Web/Components/Guide/LevelInfoCard.razor create mode 100644 src/Downpatch.Web/Components/Guide/LevelInfoCard.razor.css create mode 100644 src/Downpatch.Web/Components/Guide/Models/GoalInfo.cs create mode 100644 src/Downpatch.Web/Components/Guide/Models/LevelInfo.cs create mode 160000 src/Downpatch.Web/content create mode 100644 src/Downpatch.Web/wwwroot/js/guide.js diff --git a/src/Downpatch.Web/Components/App.razor b/src/Downpatch.Web/Components/App.razor index c3672f8..e7cc8d8 100644 --- a/src/Downpatch.Web/Components/App.razor +++ b/src/Downpatch.Web/Components/App.razor @@ -19,7 +19,9 @@ + + diff --git a/src/Downpatch.Web/Components/Guide/LevelInfoCard.razor b/src/Downpatch.Web/Components/Guide/LevelInfoCard.razor new file mode 100644 index 0000000..b1655b5 --- /dev/null +++ b/src/Downpatch.Web/Components/Guide/LevelInfoCard.razor @@ -0,0 +1,165 @@ +@using Downpatch.Web.Components.Guide.Models +@using Microsoft.AspNetCore.Components.Web + +
+ +
+ +
+ + @if (!string.IsNullOrWhiteSpace(Info.Game)) + { +
@Info.Game
+ } + +

@Info.Title

+ +
+ + @if (!string.IsNullOrWhiteSpace(Info.MissionNumber)) + { +
+ @Info.MissionNumber +
+ } + +
+ + @if (!string.IsNullOrWhiteSpace(Info.HeroImage)) + { + @Info.Title + } + + @if (!string.IsNullOrWhiteSpace(Info.MapName)) + { +
+ +
+ Map +
+ +
+ @Info.MapName?.ToUpperInvariant() +
+ +
+ } + + @if (Info.Goals.Any()) + { +
+ +
+ Goals +
+ +
+ + + + + + + +
+ + @foreach (var goal in Info.Goals) + { +
+ +
+ + + @goal.Label +
+ +
+ + + + @(difficulty switch + { + "Easy" => goal.Easy, + "Legendary" => goal.Legendary, + "LASO" => goal.Laso, + _ => goal.Easy + }) + + + +
+ +
+ } + +
+ } + +
+ +
+ Navigation +
+ +
+ + @if (!string.IsNullOrWhiteSpace(Info.PreviousName)) + { + + ← @Info.PreviousName + + } + + + + @if (!string.IsNullOrWhiteSpace(Info.NextName)) + { + + @Info.NextName → + + } + +
+ +
+ +
+ +@code +{ + [Parameter] + public required LevelInfo Info { get; set; } + + private void ShowEasy() => difficulty = "Easy"; + + private void ShowLegendary() => difficulty = "Legendary"; + + private void ShowLASO() => difficulty = "LASO"; + + private string difficulty = "Easy"; + + private void SetDifficulty(string value) + { + difficulty = value; + } +} diff --git a/src/Downpatch.Web/Components/Guide/LevelInfoCard.razor.css b/src/Downpatch.Web/Components/Guide/LevelInfoCard.razor.css new file mode 100644 index 0000000..0458714 --- /dev/null +++ b/src/Downpatch.Web/Components/Guide/LevelInfoCard.razor.css @@ -0,0 +1,244 @@ +.level-card { + display: flex; + flex-direction: column; + gap: 1.5rem; + + padding: 1.5rem; + + border-radius: 22px; + + background: rgba(18,22,28,.82); + backdrop-filter: blur(18px); + + border: 1px solid rgba(255,255,255,.08); + + box-shadow: 0 18px 50px rgba(0,0,0,.35); +} + +.level-header { + + display: flex; + + justify-content: space-between; + + align-items: flex-start; + + gap: 1rem; + +} + +.level-game { + + text-transform: uppercase; + + letter-spacing: .12em; + + font-size: .72rem; + + color: #8b9097; + + margin-bottom: .35rem; + +} + +.level-title { + + margin: 0; + + font-size: 1.6rem; + + line-height: 1.15; + +} + +.level-mission-number { + + white-space: nowrap; + + padding: .45rem .9rem; + + border-radius: 999px; + + background: rgba(246,182,76,.12); + + color: #F6B64C; + + font-weight: 600; + + font-size: .82rem; + +} + +.level-image { + + width: 100%; + + border-radius: 16px; + + display: block; + + aspect-ratio: 16 / 9; + + object-fit: cover; + +} + +.level-section { + + display: flex; + + flex-direction: column; + + gap: .85rem; + +} + +.section-title { + + text-transform: uppercase; + + letter-spacing: .12em; + + font-size: .72rem; + + color: #8b9097; + +} + +.goal-row { + + display: flex; + + align-items: center; + + justify-content: space-between; + + padding: .45rem 0; + +} + +.goal-name { + display: flex; + align-items: center; + gap: .75rem; + + font-size: .92rem; + font-weight: 500; + + min-width: 0; +} + +.goal-dot { + width: 10px; + height: 10px; + border-radius: 999px; + flex-shrink: 0; +} + +.goal-time { + display: flex; + justify-content: flex-end; + flex-shrink: 0; +} + +.goal-time strong { + font-size: .92rem; + font-weight: 600; +} + +.difficulty-toggle { + + display: flex; + + gap: .5rem; + +} + +.difficulty-toggle button { + + background: transparent; + + color: #9ca3af; + + border: 1px solid rgba(255,255,255,.10); + + transition: .18s; + +} + +.difficulty-toggle button.active { + + background: #F6B64C; + + color: #111; + + border-color: #F6B64C; + + font-weight: 600; + + box-shadow: + 0 0 0 1px rgba(246,182,76,.35), + 0 8px 24px rgba(246,182,76,.18); + +} + +.level-map-id { + display: inline-block; + width: fit-content; + + padding: .35rem .7rem; + + border-radius: 8px; + + background: rgba(255,255,255,.05); + + border: 1px solid rgba(255,255,255,.08); + + font-family: ui-monospace, + SFMono-Regular, + Menlo, + Consolas, + monospace; + + font-size: .9rem; + + font-weight: 600; + + letter-spacing: .08em; + + color: #e5e7eb; +} + +.level-navigation { + + display: flex; + + flex-direction: column; + + gap: .85rem; + +} + +.nav-link { + + color: #d7b16a; + + text-decoration: none; + + transition: color .15s ease; + +} + +.nav-link:hover { + + color: white; + +} + +.nav-current { + + font-weight: 700; + + color: #f3f4f6; + +} diff --git a/src/Downpatch.Web/Components/Guide/Models/GoalInfo.cs b/src/Downpatch.Web/Components/Guide/Models/GoalInfo.cs new file mode 100644 index 0000000..2c88f69 --- /dev/null +++ b/src/Downpatch.Web/Components/Guide/Models/GoalInfo.cs @@ -0,0 +1,14 @@ +namespace Downpatch.Web.Components.Guide.Models; + +public class GoalInfo +{ + public string Label { get; set; } = ""; + + public string Easy { get; set; } = ""; + + public string Legendary { get; set; } = ""; + + public string? Laso { get; set; } + + public string Accent { get; set; } = "#F6B64C"; +} diff --git a/src/Downpatch.Web/Components/Guide/Models/LevelInfo.cs b/src/Downpatch.Web/Components/Guide/Models/LevelInfo.cs new file mode 100644 index 0000000..0e033c4 --- /dev/null +++ b/src/Downpatch.Web/Components/Guide/Models/LevelInfo.cs @@ -0,0 +1,24 @@ +namespace Downpatch.Web.Components.Guide.Models; + +public class LevelInfo +{ + public string Title { get; set; } = ""; + + public string Game { get; set; } = ""; + + public string? MissionNumber { get; set; } + + public string HeroImage { get; set; } = ""; + + public string MapName { get; set; } = ""; + + public string PreviousName { get; set; } = ""; + + public string PreviousUrl { get; set; } = ""; + + public string NextName { get; set; } = ""; + + public string NextUrl { get; set; } = ""; + + public List Goals { get; set; } = []; +} diff --git a/src/Downpatch.Web/Components/Pages/Guide.razor b/src/Downpatch.Web/Components/Pages/Guide.razor index 1b7bf83..cc8481f 100644 --- a/src/Downpatch.Web/Components/Pages/Guide.razor +++ b/src/Downpatch.Web/Components/Pages/Guide.razor @@ -1,6 +1,9 @@ @page "/guide/{**slug}" @using Downpatch.Web.Services @using Microsoft.AspNetCore.Components +@using Downpatch.Web.Components.Guide +@using Downpatch.Web.Components.Guide.Models +@rendermode InteractiveServer @inject MarkdownPageService Pages @inject NavStore Nav @inject IHttpContextAccessor HttpContextAccessor @@ -96,20 +99,48 @@ else -