Fix search dropdown: use Blazor conditional rendering instead of details element to fix double button issue

This commit is contained in:
Saidamin Kattan
2026-08-11 01:35:10 +03:00
parent 87e2a02c28
commit f2abe57557
12 changed files with 36 additions and 62 deletions
+31 -57
View File
@@ -1,10 +1,7 @@
@using Microsoft.Extensions.Localization @using Microsoft.Extensions.Localization
@using Microsoft.JSInterop
@using Common @using Common
@inject IStringLocalizer<SharedRes> Loc @inject IStringLocalizer<SharedRes> Loc
@inject NavigationManager Navigation @inject NavigationManager Navigation
@inject IJSRuntime JSRuntime
@implements IAsyncDisposable
<header class="navbar w-full bg-transparent absolute z-30"> <header class="navbar w-full bg-transparent absolute z-30">
<nav class="navbar-start bg-transparent"> <nav class="navbar-start bg-transparent">
@@ -53,27 +50,30 @@
<!-- Search Dropdown using DaisyUI's native CSS focus behavior --> <!-- Search Dropdown using DaisyUI's native CSS focus behavior -->
<li class="search-item"> <li class="search-item">
<details @ref="searchDetails"> <button type="button" class="nav-link flex items-center gap-1"
<summary class="nav-link flex items-center gap-1 list-none cursor-pointer"> @onclick="ToggleSearchMenu"
@Loc["Search"] @onblur="HandleBlur">
<svg xmlns="http://www.w3.org/2000/svg" @Loc["Search"]
class="h-3 w-3 transition-transform duration-200 details-chevron" <svg xmlns="http://www.w3.org/2000/svg"
fill="none" viewBox="0 0 24 24" stroke="currentColor"> class="h-3 w-3 transition-transform duration-200 @(IsSearchOpen ? "rotate-180" : "")"
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M19 9l-7 7-7-7" /> fill="none" viewBox="0 0 24 24" stroke="currentColor">
</svg> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M19 9l-7 7-7-7" />
</summary> </svg>
<ul class="search-dropdown-menu" data-search-menu> </button>
@if (IsSearchOpen)
{
<ul class="search-dropdown-menu" data-search-menu @onmousedown:preventDefault>
<li> <li>
<a class="nav-link block w-full" href="/categories" data-close-dropdown>@Loc["Categories"]</a> <a class="nav-link block w-full" href="/categories" @onclick="CloseSearchMenu">@Loc["Categories"]</a>
</li> </li>
<li> <li>
<a class="nav-link block w-full" href="/shop?IsBundle=true" data-close-dropdown>@Loc["Bundles"]</a> <a class="nav-link block w-full" href="/shop?IsBundle=true" @onclick="CloseSearchMenu">@Loc["Bundles"]</a>
</li> </li>
<li> <li>
<a class="nav-link block w-full" href="/shop?IsBundle=false" data-close-dropdown>@Loc["Products"]</a> <a class="nav-link block w-full" href="/shop?IsBundle=false" @onclick="CloseSearchMenu">@Loc["Products"]</a>
</li> </li>
</ul> </ul>
</details> }
</li> </li>
<li> <li>
@@ -122,25 +122,6 @@
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
} }
.search-item details {
position: relative;
display: inline-block;
}
.search-item details > summary {
display: inline-flex;
align-items: center;
list-style: none;
}
.search-item details > summary::-webkit-details-marker {
display: none;
}
.search-item details[open] > summary .details-chevron {
transform: rotate(180deg);
}
/* Hide the content when not open */
.search-item details:not([open]) > ul {
display: none;
}
.search-dropdown-menu { .search-dropdown-menu {
position: absolute; position: absolute;
top: calc(100% + 0.5rem); top: calc(100% + 0.5rem);
@@ -162,31 +143,24 @@
</style> </style>
@code { @code {
private ElementReference searchDetails; private bool IsSearchOpen = false;
protected override async Task OnAfterRenderAsync(bool firstRender) private void ToggleSearchMenu()
{ {
if (firstRender) IsSearchOpen = !IsSearchOpen;
{
// Attach click handler to all [data-close-dropdown] elements
// When clicked, remove the 'open' attribute from parent <details>
await JSRuntime.InvokeVoidAsync("eval", @"
document.addEventListener('click', function(e) {
var target = e.target.closest('[data-close-dropdown]');
if (target) {
var details = target.closest('details');
if (details) {
details.removeAttribute('open');
}
}
});
");
}
} }
public async ValueTask DisposeAsync() private void CloseSearchMenu()
{ {
// Cleanup if needed IsSearchOpen = false;
await Task.CompletedTask; }
private async Task HandleBlur(FocusEventArgs e)
{
// Wait a tick - if user clicked a link, the click handler runs first
// If they clicked outside, this closes the menu
await Task.Delay(150);
IsSearchOpen = false;
StateHasChanged();
} }
} }
Binary file not shown.
Binary file not shown.
@@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("LayoutLib.Layout")] [assembly: System.Reflection.AssemblyCompanyAttribute("LayoutLib.Layout")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+f60a818bfb0166641551296a497028c6df42c321")] [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+87e2a02c2844ace28a27a7d82c4fe49a40332cd5")]
[assembly: System.Reflection.AssemblyProductAttribute("LayoutLib.Layout")] [assembly: System.Reflection.AssemblyProductAttribute("LayoutLib.Layout")]
[assembly: System.Reflection.AssemblyTitleAttribute("LayoutLib.Layout")] [assembly: System.Reflection.AssemblyTitleAttribute("LayoutLib.Layout")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
@@ -1 +1 @@
1abdae089eab332962428ae4afadad4205bcedd1614519f57a8795ba197c6e51 7c329c03621aa70eb2c40c927e3c0d5852a83176bb82cae7291b10797023588c
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
{"GlobalPropertiesHash":"sPqc4Sg6QmuYzPcoi06ylJfNLqqU6BZ36g8HacPs4NQ=","FingerprintPatternsHash":"gq3WsqcKBUGTSNle7RKKyXRIwh7M8ccEqOqYvIzoM04=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["QxoAEi32sV90j1gOewnGlq68ZmINHD3g4IrVYLMcDGU=","cYRQaZ0Ky5MA4GLjUiViTE//NFXlRkH0DkdNEuFPD1s=","2FlIYAueYgO9MktfmLizXJ65RTr/rFinjMf2LHHud9A=","Le\u002BCN12a9Jbmis2zmQIovtxW1CuzMq/3750f8xxJVy0=","w9tDaDUnIhU5zj73g2saRixeTDhOK02Vo8bX3b0DpUg=","B1FHfq6JXWEoiqTnP9QBnybI4MQI5yj3q2\u002BWjcCO3zI=","T5H7JXFKwqAY2N\u002BJpeEci\u002BW\u002Be8BGpXfVSmgEIzdlRWY=","fRm1FniQu/w7kKDGs2gDOEieToe8U\u002BIvfd3fNayoIK4=","WrwJu7DXL\u002BPuNc1GKfi\u002B\u002BdCInAD3ja6T7VcsM6fdM2M=","\u002BWURRLeaTnrPmMEsYaNMDjD1RNdAjMeewUE4E8wwBMs=","NDVcq/sXlwzrWgCosvfQW7ZN3QxeknuD4lNDJVT4js8=","aEyPjuyDGmes7Rlp5CTOfqHNHMX\u002BYoCu0kOPwa\u002BWP/o=","S1wXokP6LBK7k4q1Rdmz7A49GqtNe/YNN5LK8EjWV\u002BY=","psimpoporwXVbXvmndjDuxXA7\u002Bp7cqHKB4u22N4cpYc=","MzsPbiUNcTwpdfJjIUwcb\u002B6PTkONRHzti7W1PFSlVX0=","wdvZbQwEEjNZZTXYlxRk4IKvcFfC95QR2Lp7hf4V0Ew=","cL5YzfS0T8mPElQAee4xHUrnfHtMTacbuNjiaswt540="],"CachedAssets":{},"CachedCopyCandidates":{}} {"GlobalPropertiesHash":"sPqc4Sg6QmuYzPcoi06ylJfNLqqU6BZ36g8HacPs4NQ=","FingerprintPatternsHash":"gq3WsqcKBUGTSNle7RKKyXRIwh7M8ccEqOqYvIzoM04=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["QxoAEi32sV90j1gOewnGlq68ZmINHD3g4IrVYLMcDGU=","cYRQaZ0Ky5MA4GLjUiViTE//NFXlRkH0DkdNEuFPD1s=","2FlIYAueYgO9MktfmLizXJ65RTr/rFinjMf2LHHud9A=","Le\u002BCN12a9Jbmis2zmQIovtxW1CuzMq/3750f8xxJVy0=","w9tDaDUnIhU5zj73g2saRixeTDhOK02Vo8bX3b0DpUg=","B1FHfq6JXWEoiqTnP9QBnybI4MQI5yj3q2\u002BWjcCO3zI=","T5H7JXFKwqAY2N\u002BJpeEci\u002BW\u002Be8BGpXfVSmgEIzdlRWY=","fRm1FniQu/w7kKDGs2gDOEieToe8U\u002BIvfd3fNayoIK4=","WrwJu7DXL\u002BPuNc1GKfi\u002B\u002BdCInAD3ja6T7VcsM6fdM2M=","\u002BWURRLeaTnrPmMEsYaNMDjD1RNdAjMeewUE4E8wwBMs=","NDVcq/sXlwzrWgCosvfQW7ZN3QxeknuD4lNDJVT4js8=","aEyPjuyDGmes7Rlp5CTOfqHNHMX\u002BYoCu0kOPwa\u002BWP/o=","S1wXokP6LBK7k4q1Rdmz7A49GqtNe/YNN5LK8EjWV\u002BY=","psimpoporwXVbXvmndjDuxXA7\u002Bp7cqHKB4u22N4cpYc=","zqMm63afhtl2Yi8AdSw/sKgx2y8LAh82gDM4S8lYmNI=","wdvZbQwEEjNZZTXYlxRk4IKvcFfC95QR2Lp7hf4V0Ew=","cL5YzfS0T8mPElQAee4xHUrnfHtMTacbuNjiaswt540="],"CachedAssets":{},"CachedCopyCandidates":{}}
+1 -1
View File
@@ -1 +1 @@
{"GlobalPropertiesHash":"aZS2WwHIge+vJQBMZUoYsR3fpM8ZhaFvLVITjJjH6TM=","FingerprintPatternsHash":"gq3WsqcKBUGTSNle7RKKyXRIwh7M8ccEqOqYvIzoM04=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["QxoAEi32sV90j1gOewnGlq68ZmINHD3g4IrVYLMcDGU=","cYRQaZ0Ky5MA4GLjUiViTE//NFXlRkH0DkdNEuFPD1s=","2FlIYAueYgO9MktfmLizXJ65RTr/rFinjMf2LHHud9A=","Le\u002BCN12a9Jbmis2zmQIovtxW1CuzMq/3750f8xxJVy0=","w9tDaDUnIhU5zj73g2saRixeTDhOK02Vo8bX3b0DpUg=","B1FHfq6JXWEoiqTnP9QBnybI4MQI5yj3q2\u002BWjcCO3zI=","T5H7JXFKwqAY2N\u002BJpeEci\u002BW\u002Be8BGpXfVSmgEIzdlRWY=","fRm1FniQu/w7kKDGs2gDOEieToe8U\u002BIvfd3fNayoIK4=","WrwJu7DXL\u002BPuNc1GKfi\u002B\u002BdCInAD3ja6T7VcsM6fdM2M=","\u002BWURRLeaTnrPmMEsYaNMDjD1RNdAjMeewUE4E8wwBMs=","NDVcq/sXlwzrWgCosvfQW7ZN3QxeknuD4lNDJVT4js8=","aEyPjuyDGmes7Rlp5CTOfqHNHMX\u002BYoCu0kOPwa\u002BWP/o=","S1wXokP6LBK7k4q1Rdmz7A49GqtNe/YNN5LK8EjWV\u002BY=","psimpoporwXVbXvmndjDuxXA7\u002Bp7cqHKB4u22N4cpYc=","MzsPbiUNcTwpdfJjIUwcb\u002B6PTkONRHzti7W1PFSlVX0=","wdvZbQwEEjNZZTXYlxRk4IKvcFfC95QR2Lp7hf4V0Ew=","cL5YzfS0T8mPElQAee4xHUrnfHtMTacbuNjiaswt540="],"CachedAssets":{},"CachedCopyCandidates":{}} {"GlobalPropertiesHash":"aZS2WwHIge+vJQBMZUoYsR3fpM8ZhaFvLVITjJjH6TM=","FingerprintPatternsHash":"gq3WsqcKBUGTSNle7RKKyXRIwh7M8ccEqOqYvIzoM04=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["QxoAEi32sV90j1gOewnGlq68ZmINHD3g4IrVYLMcDGU=","cYRQaZ0Ky5MA4GLjUiViTE//NFXlRkH0DkdNEuFPD1s=","2FlIYAueYgO9MktfmLizXJ65RTr/rFinjMf2LHHud9A=","Le\u002BCN12a9Jbmis2zmQIovtxW1CuzMq/3750f8xxJVy0=","w9tDaDUnIhU5zj73g2saRixeTDhOK02Vo8bX3b0DpUg=","B1FHfq6JXWEoiqTnP9QBnybI4MQI5yj3q2\u002BWjcCO3zI=","T5H7JXFKwqAY2N\u002BJpeEci\u002BW\u002Be8BGpXfVSmgEIzdlRWY=","fRm1FniQu/w7kKDGs2gDOEieToe8U\u002BIvfd3fNayoIK4=","WrwJu7DXL\u002BPuNc1GKfi\u002B\u002BdCInAD3ja6T7VcsM6fdM2M=","\u002BWURRLeaTnrPmMEsYaNMDjD1RNdAjMeewUE4E8wwBMs=","NDVcq/sXlwzrWgCosvfQW7ZN3QxeknuD4lNDJVT4js8=","aEyPjuyDGmes7Rlp5CTOfqHNHMX\u002BYoCu0kOPwa\u002BWP/o=","S1wXokP6LBK7k4q1Rdmz7A49GqtNe/YNN5LK8EjWV\u002BY=","psimpoporwXVbXvmndjDuxXA7\u002Bp7cqHKB4u22N4cpYc=","zqMm63afhtl2Yi8AdSw/sKgx2y8LAh82gDM4S8lYmNI=","wdvZbQwEEjNZZTXYlxRk4IKvcFfC95QR2Lp7hf4V0Ew=","cL5YzfS0T8mPElQAee4xHUrnfHtMTacbuNjiaswt540="],"CachedAssets":{},"CachedCopyCandidates":{}}
File diff suppressed because one or more lines are too long