diff --git a/Pkmds.Web/Components/MainTabPages/BagTab.razor b/Pkmds.Web/Components/MainTabPages/BagTab.razor
new file mode 100644
index 00000000..e98a66b9
--- /dev/null
+++ b/Pkmds.Web/Components/MainTabPages/BagTab.razor
@@ -0,0 +1,173 @@
+@inherits BasePkmdsComponent
+
+@if (AppState.SaveFile is { } saveFile && Inventory is not null)
+{
+
+ @foreach (var pouch in Inventory)
+ {
+
+
+
+
+ Save
+
+
+ Sort By Name
+
+
+ Sort By Count
+
+
+ Sort By Index
+
+
+
+
+
+
+
+
+
+
+ @if (item.Value != 0)
+ {
+
+ }
+
+ @item.Text
+
+
+
+
+ @if (context.Item.Index != 0)
+ {
+ var itemText = AppService.GetItemComboItem(context.Item.Index)?.Text;
+
+ }
+
+
+
+
+
+
+
+
+ @if (HasFreeSpace)
+ {
+
+
+ @if (context.Item is IItemFreeSpace freeSpaceItem)
+ {
+
+ }
+
+
+ }
+ @if (HasFreeSpaceIndex)
+ {
+
+
+ @if (context.Item is IItemFreeSpaceIndex freeSpaceIndexItem)
+ {
+
+ }
+
+
+ }
+ @if (HasFavorite)
+ {
+
+
+ @if (context.Item is IItemFavorite favoriteItem)
+ {
+
+ }
+
+
+ }
+ @if (HasNew)
+ {
+
+
+ @if (context.Item is IItemNewFlag newFlagItem)
+ {
+
+ }
+
+
+ }
+
+
+
+
+
+
+
+
+
+ }
+
+}
diff --git a/Pkmds.Web/Components/MainTabPages/BagTab.razor.cs b/Pkmds.Web/Components/MainTabPages/BagTab.razor.cs
new file mode 100644
index 00000000..e59582d0
--- /dev/null
+++ b/Pkmds.Web/Components/MainTabPages/BagTab.razor.cs
@@ -0,0 +1,128 @@
+namespace Pkmds.Web.Components.MainTabPages;
+
+public partial class BagTab
+{
+ [Parameter, EditorRequired]
+ public IReadOnlyList? Inventory { get; set; }
+
+ private string[] ItemList { get; set; } = [];
+
+ private bool HasFreeSpace { get; set; }
+
+ private bool HasFreeSpaceIndex { get; set; }
+
+ private bool HasFavorite { get; set; }
+
+ private bool HasNew { get; set; }
+
+ private bool IsSortedByName { get; set; } = true; // Set as true so first sort is ascending
+
+ private bool IsSortedByCount { get; set; } = true; // Set as true so first sort is ascending
+
+ private bool IsSortedByIndex { get; set; } = true; // Set as true so first sort is ascending
+
+ protected override void OnParametersSet()
+ {
+ base.OnParametersSet();
+
+ if (Inventory is null || AppState is not { SaveFile: { } saveFile })
+ {
+ return;
+ }
+
+ ItemList = [.. GameInfo.Strings.GetItemStrings(saveFile.Context, saveFile.Version)];
+
+ for (var i = 0; i < ItemList.Length; i++)
+ {
+ if (string.IsNullOrEmpty(ItemList[i]))
+ {
+ ItemList[i] = $"(Item #{i:000})";
+ }
+ }
+
+ var item0 = Inventory[0].Items[0];
+
+ HasFreeSpace = item0 is IItemFreeSpace;
+ HasFreeSpaceIndex = item0 is IItemFreeSpaceIndex;
+ HasFavorite = item0 is IItemFavorite;
+ HasNew = item0 is IItemNewFlag;
+ }
+
+ private void SaveChanges()
+ {
+ if (AppState?.SaveFile is null || Inventory is null)
+ {
+ return;
+ }
+
+ foreach (var pouch in Inventory)
+ {
+ pouch.ClearCount0();
+ }
+
+ AppState.SaveFile.Inventory = Inventory;
+ }
+
+ private ComboItem GetItem(CellContext context) =>
+ AppService.GetItemComboItem(context.Item.Index);
+
+ private static void SetItem(CellContext context, ComboItem item) =>
+ context.Item.Index = item.Value;
+
+ private void DeleteItem(CellContext context, InventoryPouch pouch)
+ {
+ if (Inventory is null)
+ {
+ return;
+ }
+
+ context.Item.Clear();
+ pouch.ClearCount0();
+ }
+
+ private static string GetPouchName(InventoryPouch pouch) => pouch.Type switch
+ {
+ InventoryType.None => "None",
+ InventoryType.Items => "Items",
+ InventoryType.KeyItems => "Key Items",
+ InventoryType.TMHMs => "TMs/HMs",
+ InventoryType.Medicine => "Medicine",
+ InventoryType.Berries => "Berries",
+ InventoryType.Balls => "Balls",
+ InventoryType.BattleItems => "Battle Items",
+ InventoryType.MailItems => "Mail Items",
+ InventoryType.PCItems => "PC Items",
+ InventoryType.FreeSpace => "Free Space",
+ InventoryType.ZCrystals => "Z-Crystals",
+ InventoryType.Candy => "Candy",
+ InventoryType.Treasure => "Treasure",
+ InventoryType.Ingredients => "Ingredients",
+ _ => pouch.Type.ToString()
+ };
+
+ private string[] GetStringsForPouch(ReadOnlySpan items, bool sort = true)
+ {
+ string[] res = new string[items.Length + 1];
+ for (int i = 0; i < res.Length - 1; i++)
+ res[i] = ItemList[items[i]];
+ res[items.Length] = ItemList[0];
+ if (sort)
+ Array.Sort(res);
+ return res;
+ }
+
+ private void SortByName(InventoryPouch pouch) => pouch.SortByName(ItemList, reverse: IsSortedByName = !IsSortedByName);
+
+ private void SortByCount(InventoryPouch pouch) => pouch.SortByCount(reverse: IsSortedByCount = !IsSortedByCount);
+
+ private void SortByIndex(InventoryPouch pouch) => pouch.SortByIndex(reverse: IsSortedByIndex = !IsSortedByIndex);
+
+ private Task> SearchItemNames(InventoryPouch pouch, string searchString)
+ {
+ var itemsToSearch = GetStringsForPouch(pouch.GetAllItems());
+
+ return Task.FromResult(ItemList
+ .Select((name, index) => new ComboItem(name, index))
+ .Where(x => itemsToSearch.Contains(x.Text) && x.Text.Contains(searchString, StringComparison.OrdinalIgnoreCase)));
+ }
+}
diff --git a/Pkmds.Web/Components/SaveFileComponent.razor b/Pkmds.Web/Components/SaveFileComponent.razor
index 3950c4f1..00a0409b 100644
--- a/Pkmds.Web/Components/SaveFileComponent.razor
+++ b/Pkmds.Web/Components/SaveFileComponent.razor
@@ -38,7 +38,15 @@ else
-
+
+
+
+
+
+
+
+
+
diff --git a/Pkmds.Web/wwwroot/css/app.css b/Pkmds.Web/wwwroot/css/app.css
index 6d4b08b9..536e6e64 100644
--- a/Pkmds.Web/wwwroot/css/app.css
+++ b/Pkmds.Web/wwwroot/css/app.css
@@ -4,6 +4,9 @@ pkm-sprite {
align-self: center;
}
+item-sprite {
+}
+
.slot-fill :hover {
transform-origin: center;
animation: bounce 500ms linear infinite;