@page "/" @rendermode InteractiveServer @inject NavigationManager Navigation

Discover thoughtfully curated
books for every reader.

Explorations into books, reading culture, and the art of thoughtful curation from Midrand to the world.

@foreach (var category in MainCategories) { var catName = category; }
@if (ShowExpandedCategories) {
@foreach (var category in DynamicExtendedCategories) { var catName = category; }
} @if (ShowFilterMenu) {

SORT ORDER

PRICE RANGE

RELEASE AVAILABILITY

}
@if (!PaginatedBooks.Any()) {

NO PRODUCTS MATCH YOUR TARGET SELECTION SPECIFICATIONS

} else if (CurrentViewMode == ViewMode.Grid) {
@foreach (var book in PaginatedBooks) {
@if (book.IsNew) { New } else {
}
@book.Category.ToUpper()
EDITION

@book.Title

by @book.Author

R @book.Price.ToString("N0")
}
} else {
@foreach (var book in PaginatedBooks) {
@book.Title by @book.Author @book.Category.ToUpper()
@if (book.IsNew) { NEW } R @book.Price.ToString("N0")
}
} @if (HasMoreItems) {
}
@code { public enum ViewMode { Grid, List } private ViewMode CurrentViewMode = ViewMode.Grid; [CascadingParameter] public string SharedSearchQuery { get; set; } = string.Empty; private string ActiveCategory = "All"; private bool ShowExpandedCategories = false; private bool ShowFilterMenu = false; private string SelectedSortOption = "default"; private string ActivePriceFilter = "all"; private bool OnlyShowNew = false; private List MainCategories = new() { "All", "Graphic Design", "Product Design", "Architecture" }; private List DynamicExtendedCategories = new(); private int ItemsPerPage = 12; private int VisibleCount = 12; public class BookItem { public long Id { get; set; } // Refactored to hold unique record indices of type long public string Title { get; set; } = string.Empty; public string Author { get; set; } = string.Empty; public decimal Price { get; set; } public string Category { get; set; } = string.Empty; public bool IsNew { get; set; } public string Isbn { get; set; } = string.Empty; } private List BooksCollection = new(); private IEnumerable FilteredData { get { var data = BooksCollection.AsEnumerable(); if (!string.IsNullOrWhiteSpace(SharedSearchQuery)) { var q = SharedSearchQuery.Trim(); data = data.Where(b => b.Title.Contains(q, StringComparison.OrdinalIgnoreCase) || b.Author.Contains(q, StringComparison.OrdinalIgnoreCase) || b.Isbn.Contains(q, StringComparison.OrdinalIgnoreCase) ); } if (ActiveCategory != "All") { data = data.Where(b => b.Category.Equals(ActiveCategory, StringComparison.OrdinalIgnoreCase)); } if (OnlyShowNew) { data = data.Where(b => b.IsNew); } data = ActivePriceFilter switch { "under-500" => data.Where(b => b.Price < 500), "500-1000" => data.Where(b => b.Price >= 500 && b.Price <= 1000), "over-1000" => data.Where(b => b.Price > 1000), _ => data }; return data; } } private IEnumerable SortedAndFilteredBooks => SelectedSortOption switch { "price-low" => FilteredData.OrderBy(b => b.Price), "price-high" => FilteredData.OrderByDescending(b => b.Price), "title-asc" => FilteredData.OrderBy(b => b.Title), _ => FilteredData }; private IEnumerable PaginatedBooks => SortedAndFilteredBooks.Take(VisibleCount); private int TotalFilteredCount => FilteredData.Count(); private bool HasMoreItems => VisibleCount < TotalFilteredCount; protected override void OnInitialized() { var extraSourceCategories = new[] { "Fine Arts", "Science", "Photography", "Typography", "Interior Design", "Industrialism", "Fashion", "Curation Studies" }; DynamicExtendedCategories.AddRange(extraSourceCategories); // Updated mock items to supply long IDs matching your screenshot items BooksCollection.Add(new BookItem { Id = 1L, Title = "Letters from M/M (Paris)", Author = "M/M Paris", Price = 720, Category = "Graphic Design", IsNew = true, Isbn = "9782915173" }); BooksCollection.Add(new BookItem { Id = 2L, Title = "Daan Paans: Floating Signifiers", Author = "Daan Paans", Price = 540, Category = "Product Design", IsNew = true, Isbn = "9789492051" }); BooksCollection.Add(new BookItem { Id = 3L, Title = "Album Architectures, Maputo", Author = "Guedes Archive", Price = 350, Category = "Architecture", IsNew = true, Isbn = "9780620751" }); var designPrefixes = new[] { "Minimalist", "Monolithic", "Architectural", "Japanese", "Scandinavian" }; var designNouns = new[] { "Structures", "Typologies", "Forms & Spaces", "Systems Matrix", "Graphic Ephemera" }; var designers = new[] { "J. Morrison", "K. Fujita", "Studio Bouroullec", "Es Devlin", "Kenya Hara" }; var entireCategoryPool = MainCategories.Concat(DynamicExtendedCategories).Where(c => c != "All").ToArray(); var random = new Random(42); for (int i = 4; i <= 60; i++) { BooksCollection.Add(new BookItem { Id = (long)i, Title = $"{designPrefixes[random.Next(designPrefixes.Length)]} {designNouns[random.Next(designNouns.Length)]} (Vol. {random.Next(1, 4)})", Author = designers[random.Next(designers.Length)], Price = random.Next(25, 135) * 10, Category = entireCategoryPool[random.Next(entireCategoryPool.Length)], IsNew = random.NextDouble() > 0.7, Isbn = $"978000000{i}" }); } } // Handles the explicit page transition routing private void NavigateToProduct(long id) { Navigation.NavigateTo($"/product/{id}"); } private void SetViewMode(ViewMode targetMode) => CurrentViewMode = targetMode; private void SelectCategory(string categoryName) { ActiveCategory = categoryName; VisibleCount = ItemsPerPage; } private void ToggleExtraCategories() => ShowExpandedCategories = !ShowExpandedCategories; private void ToggleFilterMenu() => ShowFilterMenu = !ShowFilterMenu; private void ChangeSort(string sortOption) => SelectedSortOption = sortOption; private void ChangePriceFilter(string priceBracket) { ActivePriceFilter = priceBracket; VisibleCount = ItemsPerPage; } private void ToggleNewArrivalsOnly(ChangeEventArgs e) { OnlyShowNew = e.Value is bool b && b; VisibleCount = ItemsPerPage; } private void ResetFilters() { SelectedSortOption = "default"; ActivePriceFilter = "all"; OnlyShowNew = false; VisibleCount = ItemsPerPage; } private void LoadNextPage() { if (HasMoreItems) VisibleCount += ItemsPerPage; } }