224 lines
6.1 KiB
Plaintext
224 lines
6.1 KiB
Plaintext
@layout PageLayout
|
|
@inherits BasePage
|
|
@inject TechTreeService techTreeService
|
|
@inject IEntityDialogService entityDialogService
|
|
@inject NavigationManager NavigationManager
|
|
|
|
@page "/tech-tree"
|
|
|
|
<LayoutLargeContentComponent>
|
|
<WebsiteTitleComponent>Tech Tree</WebsiteTitleComponent>
|
|
|
|
<div class="techTreeControls">
|
|
<div class="techTreeFilters">
|
|
<span class="techTreeLabel">Faction:</span>
|
|
<button class="techTreeFilter @(selectedFaction == null ? "active" : "")"
|
|
@onclick="() => SelectFaction(null)">All
|
|
</button>
|
|
@foreach (var faction in factions)
|
|
{
|
|
var factionName = GetFactionName(faction);
|
|
<button class="techTreeFilter @(selectedFaction == faction ? "active" : "")"
|
|
@onclick="() => SelectFaction(faction)">@factionName</button>
|
|
}
|
|
</div>
|
|
|
|
<div class="techTreeSearchRow">
|
|
<input class="techTreeSearch" @bind="searchText" @bind:after="OnSearchChanged"
|
|
placeholder="Search for an entity..."/>
|
|
@if (!string.IsNullOrEmpty(highlightEntityId))
|
|
{
|
|
<button class="techTreeClearBtn" @onclick="ClearHighlight">Clear Highlight</button>
|
|
}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="techTreeLegend">
|
|
<span class="legendItem"><span class="legendLine" style="background: #2ed573;"></span> Produces</span>
|
|
<span class="legendItem"><span class="legendLine"
|
|
style="background: #ffa502; border-top: 3px dashed #ffa502; height: 0;"></span> Requires Building</span>
|
|
<span class="legendItem"><span class="legendLine"
|
|
style="background: #a55eea; border-top: 3px dashed #a55eea; height: 0;"></span> Requires Research</span>
|
|
<span class="legendItem"><span class="legendLine"
|
|
style="background: #ff6b6b; border-top: 2px dotted #ff6b6b; height: 0;"></span> Morph</span>
|
|
<span class="legendItem"><span class="legendLine" style="background: #1e90ff;"></span> Upgrade</span>
|
|
</div>
|
|
|
|
@if (currentGraph != null && currentGraph.Nodes.Count > 0)
|
|
{
|
|
<TechTreeGraphComponent Graph="@currentGraph" HighlightEntityId="@highlightEntityId"
|
|
OnEntitySelected="OnEntitySelected"/>
|
|
}
|
|
else
|
|
{
|
|
<PaperComponent>
|
|
<p>No data available for the selected faction.</p>
|
|
</PaperComponent>
|
|
}
|
|
</LayoutLargeContentComponent>
|
|
|
|
<style>
|
|
.techTreeControls {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.techTreeFilters {
|
|
display: flex;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
}
|
|
|
|
.techTreeLabel {
|
|
font-weight: 700;
|
|
margin-right: 4px;
|
|
}
|
|
|
|
.techTreeFilter {
|
|
padding: 6px 14px;
|
|
border-radius: 16px;
|
|
border: 2px solid var(--primary-border);
|
|
background-color: var(--primary);
|
|
color: white;
|
|
cursor: pointer;
|
|
font-family: inherit;
|
|
font-size: 0.85rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.techTreeFilter.active {
|
|
background-color: var(--primary-hover);
|
|
border-color: var(--primary-border-hover);
|
|
}
|
|
|
|
.techTreeFilter:hover {
|
|
background-color: var(--primary-hover);
|
|
}
|
|
|
|
.techTreeSearchRow {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
}
|
|
|
|
.techTreeSearch {
|
|
padding: 10px 16px;
|
|
border-radius: 8px;
|
|
border: 2px solid var(--primary-border);
|
|
background-color: var(--primary);
|
|
color: white;
|
|
font-size: 1rem;
|
|
font-family: inherit;
|
|
flex: 1;
|
|
max-width: 400px;
|
|
}
|
|
|
|
.techTreeSearch::placeholder {
|
|
color: rgba(255, 255, 255, 0.5);
|
|
}
|
|
|
|
.techTreeClearBtn {
|
|
padding: 6px 14px;
|
|
border-radius: 8px;
|
|
border: 2px solid var(--primary-border);
|
|
background-color: transparent;
|
|
color: white;
|
|
cursor: pointer;
|
|
font-family: inherit;
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
.techTreeClearBtn:hover {
|
|
background-color: var(--primary-hover);
|
|
}
|
|
|
|
.techTreeLegend {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 16px;
|
|
margin-bottom: 16px;
|
|
padding: 12px;
|
|
background-color: var(--paper);
|
|
border: 2px solid var(--paper-border);
|
|
border-radius: 8px;
|
|
font-size: 0.8rem;
|
|
}
|
|
|
|
.legendItem {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
}
|
|
|
|
.legendLine {
|
|
display: inline-block;
|
|
width: 24px;
|
|
height: 3px;
|
|
border-radius: 2px;
|
|
}
|
|
</style>
|
|
|
|
@code {
|
|
private TechTreeGraphModel? currentGraph;
|
|
private List<string> factions = new();
|
|
private string? selectedFaction;
|
|
private string searchText = "";
|
|
private string? highlightEntityId;
|
|
|
|
protected override void OnInitialized()
|
|
{
|
|
base.OnInitialized();
|
|
LoadGraph();
|
|
}
|
|
|
|
void LoadGraph()
|
|
{
|
|
currentGraph = techTreeService.BuildGraph(selectedFaction);
|
|
factions = techTreeService.GetFactions();
|
|
}
|
|
|
|
void SelectFaction(string? faction)
|
|
{
|
|
selectedFaction = faction;
|
|
highlightEntityId = null;
|
|
LoadGraph();
|
|
}
|
|
|
|
void OnSearchChanged()
|
|
{
|
|
if (string.IsNullOrWhiteSpace(searchText))
|
|
{
|
|
highlightEntityId = null;
|
|
return;
|
|
}
|
|
|
|
var found = currentGraph?.Nodes
|
|
.FirstOrDefault(n => n.Name.Contains(searchText, StringComparison.OrdinalIgnoreCase));
|
|
|
|
highlightEntityId = found?.Id;
|
|
}
|
|
|
|
void ClearHighlight()
|
|
{
|
|
highlightEntityId = null;
|
|
searchText = "";
|
|
}
|
|
|
|
void OnEntitySelected(string entityId)
|
|
{
|
|
highlightEntityId = entityId;
|
|
}
|
|
|
|
string GetFactionName(string factionId)
|
|
{
|
|
var entities = EntityData.Get();
|
|
return entities.TryGetValue(factionId, out var entity)
|
|
? entity.Info()?.Name ?? factionId
|
|
: factionId;
|
|
}
|
|
|
|
}
|