* move grid to Inventory component itself
* partly enable dragging and dropping
pull/5/head
Alexis Drai 2 years ago
parent 8bdb8c882b
commit 089e8f4ee2

@ -1,12 +1,25 @@
@using blazor_lab.Components <CascadingValue Value="@this">
<div class="side-by-side"> <div class="side-by-side">
<div>
<h2>@Localizer["my_inventory"]</h2> <div class="inventory-grid">
<InventoryGrid Items="Items" /> @for (int row = 0; row < 3; row++) { <div class="inventory-row">
</div> @for (int col = 0; col < 6; col++) { <div class="inventory-slot">
<div> @if (InventoryContent != null && InventoryContent.Count > (row * 6 + col))
<h2>@Localizer["list_of_items"]</h2> {
<InventoryList Items="Items" /> <InventoryItem Position="(row * 6 + col)" IsInList="false" IsInInventory="true"/>
</div> }
</div> </div>
}
</div>
}
</div>
<div>
<h2>@Localizer["list_of_items"]</h2>
<InventoryList Items="Items" />
</div>
</div>
</CascadingValue>

@ -1,6 +1,7 @@
using blazor_lab.Models; using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization; using Microsoft.Extensions.Localization;
using Minecraft.Crafting.Api.Models;
using Item = blazor_lab.Models.Item;
namespace blazor_lab.Components namespace blazor_lab.Components
{ {
@ -10,6 +11,10 @@ namespace blazor_lab.Components
public IStringLocalizer<Inventory> Localizer { get; set; } public IStringLocalizer<Inventory> Localizer { get; set; }
[Parameter] [Parameter]
public List<Item> Items { get; set; } = new(); public List<Item> Items { get; set; }
public InventoryModel? CurrentDragItem { get; set; }
public List<InventoryModel> InventoryContent { get; set; } = Enumerable.Range(1, 18).Select(_ => new InventoryModel()).ToList();
} }
} }

@ -2,3 +2,24 @@
display: flex; display: flex;
flex-direction: row; flex-direction: row;
} }
.inventory-grid {
display: flex;
flex-direction: column;
}
.inventory-row {
display: flex;
flex-direction: row;
}
.inventory-slot {
width: 64px;
height: 64px;
border: 1px solid;
margin: 5px;
display: flex;
flex-direction: column;
align-items: center;
overflow: hidden;
}

@ -1,21 +0,0 @@
<div class="inventory-grid">
@for (int row = 0; row < 3; row++)
{
<div class="inventory-row">
@for (int col = 0; col < 6; col++)
{
<div class="inventory-slot">
@if (Inventory != null && Inventory.Count > (row * 6 + col))
{
var slot = Inventory[row * 6 + col];
@if (slot.NumberItem > 0)
{
<img src="@($"data:image/png;base64,{GetItemImageBase64(@slot.ItemName)}")" alt="@slot.ItemName" />
<div class="slot-count">@slot.NumberItem</div>
}
}
</div>
}
</div>
}
</div>

@ -1,25 +0,0 @@
using Microsoft.AspNetCore.Components;
using Minecraft.Crafting.Api.Models;
namespace blazor_lab.Components
{
public partial class InventoryGrid
{
public List<InventoryModel> Inventory { get; set; } = Enumerable.Range(1, 18).Select(_ => new InventoryModel()).ToList();
/// <summary>
/// Used by GetItemImageBase64 in this component, rather than calling our DataService every time.
/// A very basic cache, not kept up to date in any way, but event listeners could be set up in the future
/// </summary>
[Parameter]
public List<Models.Item> Items { get; set; }
public string GetItemImageBase64(string displayName)
{
var item = Items.FirstOrDefault(i => i.DisplayName == displayName);
return item?.ImageBase64;
}
}
}

@ -1,25 +0,0 @@
.inventory-grid {
display: flex;
flex-direction: column;
}
.inventory-row {
display: flex;
flex-direction: row;
}
.inventory-slot {
width: 64px;
height: 64px;
border: 1px solid;
margin: 5px;
display: flex;
flex-direction: column;
align-items: center;
overflow: hidden;
}
.item-count {
margin-top: 5px;
}

@ -0,0 +1,20 @@
<div ondragover="event.preventDefault();"
draggable="true"
@ondragstart="@OnDragStart"
@ondragend="@OnDragEnd"
@ondrop="@OnDrop">
@if (Item is not null && IsInList)
{
<div class="inventory-list-item side-by-side">
<img src="@($"data:image/png;base64,{Item.ImageBase64}")" alt="@Item.DisplayName" />
<div class="item-name">@Item.DisplayName</div>
</div>
}
@if (InventoryModel is not null && IsInInventory)
{
<div>
<img src="@($" data:image/png;base64,{GetItemImageBase64()}")" alt="@InventoryModel.ItemName" />
<div class="slot-count">@InventoryModel.NumberItem</div>
</div>
}
</div>

@ -0,0 +1,109 @@
using blazor_lab.Services;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Minecraft.Crafting.Api.Models;
using System.Diagnostics;
using Item = blazor_lab.Models.Item;
namespace blazor_lab.Components
{
public partial class InventoryItem
{
[Parameter]
public Item? Item { get; set; }
[Parameter]
public int Position { get; set; } = -1;
[Parameter]
public bool IsInList { get; set; }
[Parameter]
public bool IsInInventory { get; set; }
[CascadingParameter]
public InventoryList? ListParent { get; set; }
[CascadingParameter]
public Inventory? InventoryParent { get; set; }
[Inject]
public IDataService DataService { get; set; }
public InventoryModel InventoryModel { get; set; } = new InventoryModel();
public InventoryItem()
{
if (Item is not null && IsInList)
{
InventoryModel.ItemName = Item.DisplayName;
InventoryModel.NumberItem = 1;
}
}
internal void OnDrop()
{
if (IsInList)
{
return;
}
if (IsInInventory)
{
if (InventoryModel.Position == -1) // new inventoryModel
{
InventoryModel = InventoryParent!.CurrentDragItem!;
InventoryModel.Position = Position;
InventoryParent.InventoryContent.Add(InventoryModel);
}
else
{
if (InventoryModel.ItemName == InventoryParent!.CurrentDragItem!.ItemName) // adding to an existing stack
{
InventoryModel.NumberItem += 1;
}
}
}
}
internal void OnDragEnd()
{
if (IsInList)
{
ListParent!.Parent.CurrentDragItem = null;
}
else if (IsInInventory)
{
InventoryParent!.CurrentDragItem = null;
}
}
private void OnDragStart()
{
if (InventoryModel is not null)
{
if (IsInList)
{
ListParent!.Parent.CurrentDragItem = InventoryModel;
}
else if (IsInInventory)
{
InventoryParent!.CurrentDragItem = InventoryModel;
}
}
}
public async Task<string?> GetItemImageBase64()
{
// FIXME probably not great to inject a service in each item and query the whole database everytime we display it
if (InventoryParent is not null)
{
return (await DataService.List(0, await DataService.Count()))
.FirstOrDefault(i => i.DisplayName == InventoryModel.ItemName)?
.ImageBase64;
}
else return null;
}
}
}

@ -0,0 +1,22 @@
.inventory-list-item {
margin-bottom: 10px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
.inventory-list-item img {
max-width: 64px;
max-height: 64px;
margin-right: 10px;
}
.item-name {
font-weight: bold;
}
.side-by-side {
display: flex;
flex-direction: row;
}

@ -1,4 +1,6 @@
<div class="inventory-list"> <CascadingValue Value="@this">
<div class="inventory-list">
<div class="search-container"> <div class="search-container">
<input type="text" value="@searchQuery" @oninput="OnInputChange" placeholder="@Localizer["search_label"]" /> <input type="text" value="@searchQuery" @oninput="OnInputChange" placeholder="@Localizer["search_label"]" />
</div> </div>
@ -12,32 +14,31 @@
</div> </div>
<div class="inventory-list-items"> <div class="inventory-list-items">
@foreach (var item in VisibleItems) @foreach (var item in VisibleItems)
{ {
<div class="inventory-list-item side-by-side"> <InventoryItem Item=item IsInList="true" IsInInventory="false"></InventoryItem>
<img src="@($"data:image/png;base64,{item.ImageBase64}")" alt="@item.DisplayName" /> }
<div class="item-name">@item.DisplayName</div>
</div>
}
</div> </div>
<div class="pagination-container"> <div class="pagination-container">
@for (var i = 1; i <= TotalPages; i++) @for (var i = 1; i <= TotalPages; i++)
{ {
var pageNumber = i; // copy the loop variable to avoid closure issues var pageNumber = i; // copy the loop variable to avoid closure issues
<button @onclick="() => GoToPage(pageNumber)">@pageNumber</button> <button @onclick="() => GoToPage(pageNumber)">@pageNumber</button>
} }
</div> </div>
<div class="item-count"> <div class="item-count">
@if (VisibleItems.Any()) @if (VisibleItems.Any())
{ {
var firstItem = (currentPage - 1) * pageSize + 1; var firstItem = (currentPage - 1) * pageSize + 1;
var lastItem = Math.Min(currentPage * pageSize, TotalItems); var lastItem = Math.Min(currentPage * pageSize, TotalItems);
<span>@firstItem - @lastItem @Localizer["out_of"] @TotalItems</span> <span>@firstItem - @lastItem @Localizer["out_of"] @TotalItems</span>
} }
else else
{ {
<span>@Localizer["no_items_found"]</span> <span>@Localizer["no_items_found"]</span>
} }
</div> </div>
</div> </div>
</CascadingValue>

@ -11,6 +11,9 @@ namespace blazor_lab.Components
} }
public partial class InventoryList public partial class InventoryList
{ {
[CascadingParameter]
public Inventory Parent { get; set; }
[Inject] [Inject]
public IStringLocalizer<InventoryList> Localizer { get; set; } public IStringLocalizer<InventoryList> Localizer { get; set; }

@ -5,31 +5,3 @@
.search-container { .search-container {
margin-bottom: 20px; margin-bottom: 20px;
} }
.inventory-list-item {
margin-bottom: 10px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
.inventory-list-item img {
max-width: 64px;
max-height: 64px;
margin-right: 10px;
}
.item-name {
font-weight: bold;
}
.side-by-side {
display: flex;
flex-direction: row;
}
button[disabled] {
opacity: 0.5;
cursor: default;
}
Loading…
Cancel
Save