Skip to content

Commit ef66cbe

Browse files
csharpfritzCopilot
andcommitted
feat(samples): Phase 3 UI overhaul - Search, Homepage, Sidebar fixes
- Implemented client-side search with Fuse.js fuzzy matching - SearchBox.razor with debounced search (200ms) - Keyboard navigation (up/down/enter/escape) - Match highlighting in results - Category badges and truncated descriptions - Redesigned homepage with hero section and card-based catalog - Gradient hero with CTA buttons (Get Started, View on GitHub) - 6 category cards with component counts and links - Responsive grid (3/2/1 columns for desktop/tablet/mobile) - Fixed sidebar layout issues - Removed redundant header text - Categories expanded by default on desktop - Mobile nav collapse on link click All 147 integration tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 42af08b commit ef66cbe

8 files changed

Lines changed: 695 additions & 27 deletions

File tree

samples/AfterBlazorServerSide/Components/App.razor

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
1010
<link rel="stylesheet" href="css/brand-colors.css" />
1111
<link rel="stylesheet" href="css/site.css" />
12+
<link rel="stylesheet" href="css/search.css" />
1213
<HeadOutlet @rendermode="InteractiveServer" />
1314
</head>
1415

@@ -29,6 +30,30 @@
2930

3031
<script src="_framework/blazor.web.js"></script>
3132
<script src="_content/Fritz.BlazorWebFormsComponents/js/Basepage.js"></script>
33+
<script src="https://cdn.jsdelivr.net/npm/fuse.js@7.0.0/dist/fuse.min.js"></script>
34+
<script src="js/search.js"></script>
35+
<script>
36+
// Click outside handler for search dropdown
37+
let clickOutsideHandlers = new Map();
38+
39+
window.registerClickOutsideHandler = function(element, dotNetRef) {
40+
const handler = function(event) {
41+
if (element && !element.contains(event.target)) {
42+
dotNetRef.invokeMethodAsync('CloseDropdown');
43+
}
44+
};
45+
clickOutsideHandlers.set(element, handler);
46+
document.addEventListener('click', handler);
47+
};
48+
49+
window.unregisterClickOutsideHandler = function(element) {
50+
const handler = clickOutsideHandlers.get(element);
51+
if (handler) {
52+
document.removeEventListener('click', handler);
53+
clickOutsideHandlers.delete(element);
54+
}
55+
};
56+
</script>
3257
</body>
3358

3459
</html>

samples/AfterBlazorServerSide/Components/Layout/MainLayout.razor

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
@inherits LayoutComponentBase
2+
@using AfterBlazorServerSide.Components.Shared
23

34
<div class="layout-wrapper" data-bs-theme="light">
45
<!-- Top Navbar -->
@@ -15,9 +16,9 @@
1516
<span class="navbar-toggler-icon"></span>
1617
</button>
1718
<div class="collapse navbar-collapse" id="navbarContent">
18-
<form class="d-flex ms-auto me-3 my-2 my-lg-0" role="search">
19-
<input class="form-control search-input" type="search" placeholder="Search components..." aria-label="Search" disabled title="Search coming soon">
20-
</form>
19+
<div class="d-flex ms-auto me-3 my-2 my-lg-0">
20+
<SearchBox />
21+
</div>
2122
<ul class="navbar-nav">
2223
<li class="nav-item">
2324
<a class="nav-link" href="https://fritzandfriends.github.io/BlazorWebFormsComponents/" target="_blank">
@@ -38,7 +39,7 @@
3839
<!-- Sidebar -->
3940
<aside class="sidebar @(sidebarCollapsed ? "collapsed" : "")">
4041
<div class="sidebar-content">
41-
<NavMenu />
42+
<NavMenu OnMobileNavClick="CollapseSidebar" />
4243
</div>
4344
</aside>
4445

@@ -78,4 +79,9 @@
7879
{
7980
sidebarCollapsed = !sidebarCollapsed;
8081
}
82+
83+
private void CollapseSidebar()
84+
{
85+
sidebarCollapsed = true;
86+
}
8187
}

samples/AfterBlazorServerSide/Components/Layout/NavMenu.razor

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
@inject NavigationManager NavigationManager
2+
@inject IJSRuntime JSRuntime
23

3-
<div class="top-row ps-4 navbar navbar-dark">
4-
<a class="navbar-brand" href="">BlazorWebFormsComponents<br/>@Program.ApplicationName</a>
5-
<button class="navbar-toggler" @onclick="ToggleNavMenu">
6-
<span class="navbar-toggler-icon"></span>
7-
</button>
8-
</div>
9-
10-
<div class="verticalNav @NavMenuCssClass">
4+
<div class="verticalNav">
115
<nav class="nav flex-column p-2">
12-
<a href="/" class="nav-link component-link @GetActiveClass("/")" title="Home">
6+
<a href="/" class="nav-link component-link @GetActiveClass("/")" title="Home" @onclick="OnNavLinkClick">
137
<span class="oi oi-home me-2"></span>Home
148
</a>
159

@@ -36,7 +30,8 @@
3630
{
3731
<a href="@component.Route"
3832
class="nav-link component-link py-1 @GetActiveClass(component.Route)"
39-
title="@component.Description">
33+
title="@component.Description"
34+
@onclick="OnNavLinkClick">
4035
@component.Name
4136
</a>
4237
@if (component.SubPages?.Any() == true)
@@ -47,7 +42,8 @@
4742
var subRoute = $"{component.Route}/{subPage}";
4843
<a href="@subRoute"
4944
class="nav-link component-link py-1 small @GetActiveClass(subRoute)"
50-
title="@component.Name - @subPage">
45+
title="@component.Name - @subPage"
46+
@onclick="OnNavLinkClick">
5147
@subPage
5248
</a>
5349
}
@@ -65,16 +61,51 @@
6561
private bool collapseNavMenu = true;
6662
private HashSet<string> expandedCategories = new();
6763
private string currentUrl = "";
64+
private bool isDesktop = true;
65+
66+
[Parameter]
67+
public EventCallback OnMobileNavClick { get; set; }
6868

6969
private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;
7070

71-
protected override void OnInitialized()
71+
protected override async Task OnInitializedAsync()
7272
{
7373
currentUrl = NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
7474
NavigationManager.LocationChanged += OnLocationChanged;
7575

76-
// Expand the category containing the current page
77-
ExpandCategoryForCurrentPage();
76+
// Check if desktop and expand all categories
77+
await CheckIfDesktopAndExpandCategories();
78+
}
79+
80+
private async Task CheckIfDesktopAndExpandCategories()
81+
{
82+
try
83+
{
84+
var windowWidth = await JSRuntime.InvokeAsync<int>("eval", "window.innerWidth");
85+
isDesktop = windowWidth >= 992;
86+
87+
if (isDesktop)
88+
{
89+
// Expand all categories on desktop
90+
foreach (var category in ComponentCatalog.Categories)
91+
{
92+
expandedCategories.Add(category);
93+
}
94+
}
95+
else
96+
{
97+
// On mobile, only expand the category containing current page
98+
ExpandCategoryForCurrentPage();
99+
}
100+
}
101+
catch
102+
{
103+
// Fallback: expand all categories
104+
foreach (var category in ComponentCatalog.Categories)
105+
{
106+
expandedCategories.Add(category);
107+
}
108+
}
78109
}
79110

80111
private void OnLocationChanged(object? sender, LocationChangedEventArgs e)
@@ -112,6 +143,15 @@
112143
}
113144
}
114145

146+
private async Task OnNavLinkClick()
147+
{
148+
// On mobile, collapse the sidebar when a link is clicked
149+
if (!isDesktop)
150+
{
151+
await OnMobileNavClick.InvokeAsync();
152+
}
153+
}
154+
115155
private bool IsCategoryExpanded(string category) => expandedCategories.Contains(category);
116156

117157
private string GetActiveClass(string href)
Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,51 @@
11
@page "/"
2+
@using AfterBlazorServerSide
23

3-
<PageTitle>After Blazor - Server Side</PageTitle>
4+
<PageTitle>BlazorWebFormsComponents</PageTitle>
45

5-
<h1>After Blazor - Server Side</h1>
6+
<!-- Hero Section -->
7+
<section class="hero-section text-center py-5 mb-5">
8+
<div class="container">
9+
<h1 class="display-4 fw-bold hero-title">BlazorWebFormsComponents</h1>
10+
<p class="lead hero-tagline mb-4">Migrate your Web Forms apps to Blazor with familiar syntax</p>
11+
<div class="d-flex justify-content-center gap-3 flex-wrap">
12+
<a href="https://fritzandfriends.github.io/BlazorWebFormsComponents/" class="btn btn-primary btn-lg" target="_blank">
13+
<span class="oi oi-book me-2" aria-hidden="true"></span>Get Started
14+
</a>
15+
<a href="https://github.com/FritzAndFriends/BlazorWebFormsComponents" class="btn btn-outline-secondary btn-lg" target="_blank">
16+
<span class="oi oi-external-link me-2" aria-hidden="true"></span>View on GitHub
17+
</a>
18+
</div>
19+
</div>
20+
</section>
621

7-
<p>
8-
This is a project that contains individual pages for the BlazorWebFormsComponents developers to use
9-
to test the new components they are building and see how they behave. We will use this project to help verify
10-
that our Blazor components render appropriately.
11-
</p>
12-
13-
<ComponentList />
22+
<!-- Component Catalog Section -->
23+
<section class="component-catalog">
24+
<div class="container">
25+
<h2 class="text-center mb-4">Component Catalog</h2>
26+
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4">
27+
@foreach (var category in ComponentCatalog.Categories)
28+
{
29+
var components = ComponentCatalog.GetByCategory(category).ToList();
30+
<div class="col">
31+
<div class="card h-100 category-card">
32+
<div class="card-header d-flex justify-content-between align-items-center">
33+
<h5 class="mb-0">@category</h5>
34+
<span class="badge bg-primary rounded-pill">@components.Count</span>
35+
</div>
36+
<div class="card-body">
37+
<ul class="list-unstyled component-list mb-0">
38+
@foreach (var component in components)
39+
{
40+
<li>
41+
<a href="@component.Route" class="component-link">@component.Name</a>
42+
</li>
43+
}
44+
</ul>
45+
</div>
46+
</div>
47+
</div>
48+
}
49+
</div>
50+
</div>
51+
</section>

0 commit comments

Comments
 (0)