Skip to content

Commit d623776

Browse files
committed
Show build snippet on build list view (Closes #1330) (#1340)
1 parent 15ff789 commit d623776

File tree

3 files changed

+86
-15
lines changed

3 files changed

+86
-15
lines changed

Daybreak/Views/BuildListView.razor

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
<div class="build-list-container">
1+
<div class="build-list-container" @onmouseenter="this.ViewModel.CloseSnippet">
22
<div class="title-bar-additional-btns-left">
33
<button class="title-bar-btn" @onclick="this.ViewModel.CreateNewSingleBuild" title="Create build">
44
<FluentIcon Value="new Microsoft.FluentUI.AspNetCore.Components.Icons.Regular.Size16.PersonAdd()" />
55
</button>
66
</div>
77
<div class="stretch-container backdrop-panel">
8-
<div class="header-section">
9-
<div class="search-container">
8+
<div class="header-section" @onmouseenter="this.ViewModel.CloseSnippet">
9+
<div class="search-container" @onmouseenter="this.ViewModel.CloseSnippet">
1010
<DebouncedTextField Style="width: 50vw; max-width: 600px; font-size: var(--font-size-medium);"
1111
Placeholder="Search builds..."
1212
OnSearch="@this.ViewModel.SearchTermChanged" />
1313
</div>
1414
</div>
1515

16-
<div class="content-section">
16+
<div class="content-section" @onmouseenter="this.ViewModel.CloseSnippet">
1717
@if (this.ViewModel.IsLoading)
1818
{
1919
<div class="loading-overlay">
@@ -22,14 +22,18 @@
2222
</div>
2323
}
2424

25-
<div class="build-list-wrapper" style="@(ViewModel.IsLoading ? "opacity: 0.3; pointer-events: none;" : "")">
25+
<div @onmouseenter="this.ViewModel.CloseSnippet"
26+
class="build-list-wrapper" style="@(ViewModel.IsLoading ? "opacity: 0.3; pointer-events: none;" : "")">
2627
@if (this.ViewModel.BuildEntries.Any())
2728
{
2829
<Virtualize Items="@this.ViewModel.BuildEntries"
2930
Context="entry"
3031
ItemSize="75">
3132
<ItemContent>
32-
<div class="build-item" tabindex="0" @onclick="@(() => this.ViewModel.BuildClicked(entry))">
33+
<div class="build-item" tabindex="0"
34+
@onclick="() => this.ViewModel.BuildClicked(entry)"
35+
@onmouseenter="(e) => this.ViewModel.OpenSnippet(entry, e)"
36+
@onmousemove="(e) => this.ViewModel.MouseMoveBuildEntry(e)">
3337
<div class="build-info">
3438
@if (entry.PrimaryProfession is not null)
3539
{
@@ -50,7 +54,7 @@
5054
{
5155
<div class="build-toolbox-marker">Toolbox build</div>
5256
}
53-
<div class="build-actions" @onclick="@(() => this.ViewModel.DeleteBuild(entry))" @onclick:stopPropagation="true">
57+
<div class="build-actions" @onclick="@(() => this.ViewModel.DeleteBuild(entry))" @onclick:stopPropagation="true" @onmouseenter="this.ViewModel.CloseSnippet">
5458
<FluentButton Appearance="Appearance.Stealth"
5559
IconOnly="true">
5660
<FluentIcon Value="@(new Microsoft.FluentUI.AspNetCore.Components.Icons.Regular.Size16.Delete())" />
@@ -59,6 +63,12 @@
5963
</div>
6064
</ItemContent>
6165
</Virtualize>
66+
@if (this.ViewModel.ShowSnippet && this.ViewModel.HoveredEntry is not null && this.ViewModel.SnippetPosition.HasValue)
67+
{
68+
<div class="build-snippet-overlay" style="top: @(this.ViewModel.SnippetPosition.Value.Y)px; left: @(this.ViewModel.SnippetPosition.Value.X)px;">
69+
<BuildSnippet BuildEntry="this.ViewModel.HoveredEntry.BuildEntry" />
70+
</div>
71+
}
6272
}
6373
else if (!this.ViewModel.IsLoading)
6474
{

Daybreak/Views/BuildListView.razor.cs

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,51 @@
11
using Daybreak.Models;
2+
using Daybreak.Shared.Extensions;
23
using Daybreak.Shared.Models.Builds;
34
using Daybreak.Shared.Models.Guildwars;
45
using Daybreak.Shared.Services.BuildTemplates;
56
using Daybreak.Shared.Services.Toolbox;
67
using Daybreak.Shared.Utils;
8+
using Microsoft.AspNetCore.Components.Web;
9+
using Microsoft.JSInterop;
710
using System.Core.Extensions;
11+
using System.Drawing;
812
using System.Extensions;
913
using TrailBlazr.Services;
1014
using TrailBlazr.ViewModels;
1115

1216
namespace Daybreak.Views;
13-
public sealed class BuildListViewModel(
14-
IViewManager viewManager,
15-
IBuildTemplateManager buildTemplateManager,
16-
IToolboxService toolboxService)
17+
public sealed class BuildListViewModel
1718
: ViewModelBase<BuildListViewModel, BuildListView>
1819
{
19-
private readonly IViewManager viewManager = viewManager.ThrowIfNull();
20-
private readonly IBuildTemplateManager buildTemplateManager = buildTemplateManager.ThrowIfNull();
21-
private readonly IToolboxService toolboxService = toolboxService.ThrowIfNull();
20+
private readonly DotNetObjectReference<BuildListViewModel> dotNetObjectReference;
21+
private readonly IViewManager viewManager;
22+
private readonly IBuildTemplateManager buildTemplateManager;
23+
private readonly IJSRuntime jsRuntime;
24+
private readonly IToolboxService toolboxService;
2225

2326
private readonly List<BuildListEntry> buildEntryCache = [];
2427

28+
public BuildListViewModel(
29+
IViewManager viewManager,
30+
IBuildTemplateManager buildTemplateManager,
31+
IJSRuntime jsRuntime,
32+
IToolboxService toolboxService)
33+
{
34+
this.dotNetObjectReference = DotNetObjectReference.Create(this);
35+
this.viewManager = viewManager;
36+
this.buildTemplateManager = buildTemplateManager;
37+
this.jsRuntime = jsRuntime;
38+
this.toolboxService = toolboxService;
39+
}
40+
2541
public List<BuildListEntry> BuildEntries { get; } = [];
2642

43+
public BuildListEntry? HoveredEntry { get; private set; }
44+
45+
public Point? SnippetPosition { get; private set; }
46+
47+
public bool ShowSnippet { get; private set; }
48+
2749
public bool IsLoading
2850
{
2951
get;
@@ -86,6 +108,7 @@ public void SearchTermChanged(string searchTerm)
86108

87109
public void BuildClicked(BuildListEntry buildListEntry)
88110
{
111+
this.CloseSnippet();
89112
this.viewManager.ShowView<BuildRoutingView>((nameof(BuildRoutingView.BuildName), buildListEntry.BuildEntry.Name ?? string.Empty));
90113
}
91114

@@ -112,6 +135,37 @@ public void CreateNewTeamBuild()
112135
this.viewManager.ShowView<BuildRoutingView>((nameof(BuildRoutingView.BuildName), build.Name ?? string.Empty));
113136
}
114137

138+
public async void OpenSnippet(BuildListEntry buildListEntry, MouseEventArgs e)
139+
{
140+
this.ShowSnippet = false;
141+
this.HoveredEntry = buildListEntry;
142+
this.SnippetPosition = new Point((int)e.ClientX, (int)e.ClientY);
143+
await this.jsRuntime.HoverDelayStart(this.dotNetObjectReference, nameof(this.HoverComplete));
144+
}
145+
146+
public async void CloseSnippet()
147+
{
148+
this.HoveredEntry = default;
149+
this.ShowSnippet = false;
150+
await this.jsRuntime.HoverDelayStop();
151+
}
152+
153+
public async void MouseMoveBuildEntry(MouseEventArgs e)
154+
{
155+
if (!this.ShowSnippet)
156+
{
157+
this.SnippetPosition = new Point((int)e.ClientX, (int)e.ClientY);
158+
}
159+
}
160+
161+
162+
[JSInvokable]
163+
public void HoverComplete()
164+
{
165+
this.ShowSnippet = true;
166+
this.RefreshView();
167+
}
168+
115169
private async ValueTask SearchByTerm(string term, CancellationToken cancellationToken)
116170
{
117171
if (string.IsNullOrWhiteSpace(term))

Daybreak/Views/BuildListView.razor.css

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,4 +127,11 @@
127127
width: 100%;
128128
height: 100%;
129129
object-fit: contain;
130-
}
130+
}
131+
132+
.build-snippet-overlay {
133+
position: absolute;
134+
bottom: 10px;
135+
left: 10px;
136+
z-index: 1000;
137+
}

0 commit comments

Comments
 (0)