Home hero: replace filter dropdowns with a search-engine box (+ live typeahead)
CI/CD / CI · dotnet build (push) Successful in 2m32s
CI/CD / Deploy · hamkadr (push) Successful in 2m0s

The hero is now a single big search box → /Search (the rich, ranked,
highlighted search across shifts/jobs/applicants), with popular-search
chips. Typeahead is generalized to any form[data-suggest], so the hero box
shows the same instant highlighted dropdown as the header pill.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-08 22:34:31 +03:30
parent 6cf7c6b573
commit bcf90f2437
3 changed files with 70 additions and 67 deletions
+12 -33
View File
@@ -14,40 +14,19 @@
مرکز درمانی، محل و تقویم هفتگی — یک‌جا.
</p>
<form class="search-card" method="get" asp-page="/Shifts/Index">
<div class="field">
<label>شهر</label>
<select name="cityId">
<option value="">همه شهرها</option>
@foreach (var c in Model.Cities)
{
<option value="@c.Id">@c.Name</option>
}
</select>
<form class="hero-search" method="get" action="/Search" role="search" data-suggest>
<div class="hero-search-pill">
<span class="hs-ico">🔎</span>
<input type="search" name="Q" autocomplete="off"
placeholder="جستجو کن: پرستار شب تهران، mmt، دندان‌پزشک پروانه‌دار، آماده به کار…" />
<button type="submit" class="btn btn-accent btn-lg">جستجو</button>
</div>
<div class="field">
<label>نقش</label>
<select name="roleId">
<option value="">همه نقش‌ها</option>
@foreach (var r in Model.Roles)
{
<option value="@r.Id">@r.Name</option>
}
</select>
</div>
<div class="field">
<label>نوع شیفت</label>
<select name="shiftType">
<option value="">همه</option>
<option value="0">صبح</option>
<option value="1">عصر</option>
<option value="2">شب</option>
<option value="3">آنکال</option>
</select>
</div>
<div class="field">
<label>&nbsp;</label>
<button type="submit" class="btn btn-accent btn-block btn-lg">جستجوی فرصت‌ها</button>
<div class="hero-chips">
<span class="hc-label">جستجوهای پرطرفدار:</span>
<a href="/Search?Q=%D9%BE%D8%B1%D8%B3%D8%AA%D8%A7%D8%B1">پرستار</a>
<a href="/Search?Q=%D9%BE%D8%B2%D8%B4%DA%A9">پزشک</a>
<a href="/Search?Q=%D8%B4%DB%8C%D9%81%D8%AA%20%D8%B4%D8%A8">شیفت شب</a>
<a href="/Search?Q=%D8%A2%D9%85%D8%A7%D8%AF%D9%87%20%D8%A8%D9%87%20%DA%A9%D8%A7%D8%B1">آماده به کار</a>
</div>
</form>
+13 -10
View File
@@ -117,7 +117,7 @@
<a asp-page="/Facilities/Index" class="@(path.StartsWith("/Facilities") ? "active" : null)">مراکز درمانی</a>
<a asp-page="/Calendar/Index" class="@(path.StartsWith("/Calendar") ? "active" : null)">تقویم هفتگی</a>
</nav>
<form class="nav-search" method="get" action="/Search" role="search">
<form class="nav-search" method="get" action="/Search" role="search" data-suggest>
<div class="nav-search-pill">
<input type="search" name="Q" placeholder="جستجو…" aria-label="جستجو" autocomplete="off" />
<button type="submit" aria-label="جستجو">🔎</button>
@@ -228,17 +228,10 @@
});
</script>
@* Instant search suggestions (typeahead) for the header search box. *@
@* Instant search suggestions (typeahead) — attaches to every form[data-suggest]
(header pill + homepage hero). *@
<script>
(function () {
var form = document.querySelector('.nav-search');
if (!form) return;
var input = form.querySelector('input');
var box = document.createElement('div');
box.className = 'nav-search-results';
box.style.display = 'none';
form.appendChild(box);
var timer;
function esc(s) { var d = document.createElement('div'); d.textContent = s == null ? '' : s; return d.innerHTML; }
function hi(text, q) {
var safe = esc(text);
@@ -248,6 +241,14 @@
try { return safe.replace(new RegExp('(' + terms.join('|') + ')', 'gi'), '<mark>$1</mark>'); }
catch (e) { return safe; }
}
function attach(form) {
var input = form.querySelector('input[type=search], input[name=Q]');
if (!input) return;
var box = document.createElement('div');
box.className = 'nav-search-results';
box.style.display = 'none';
form.appendChild(box);
var timer;
function hide() { box.style.display = 'none'; box.innerHTML = ''; }
input.addEventListener('input', function () {
var q = input.value.trim();
@@ -272,6 +273,8 @@
});
document.addEventListener('click', function (e) { if (!form.contains(e.target)) hide(); });
input.addEventListener('keydown', function (e) { if (e.key === 'Escape') hide(); });
}
document.querySelectorAll('[data-suggest]').forEach(attach);
})();
</script>
+21
View File
@@ -302,6 +302,27 @@ mark { background: #fff3bf; color: inherit; padding: 0 2px; border-radius: 3px;
.search-snippet { font-size: 12.5px; color: var(--muted); line-height: 1.6; margin: 4px 0 2px;
background: var(--bg); border-inline-start: 3px solid var(--primary-soft); padding: 5px 9px; border-radius: 6px; }
.nav-search-results .ns-all { font-weight: 700; color: var(--primary-dark); justify-content: center; }
/* Homepage hero — search-engine box (replaces the old filter form) */
.hero-search { position: relative; max-width: 720px; margin: 10px auto 0; }
.hero-search-pill { display: flex; align-items: center; gap: 8px; background: var(--surface);
border-radius: 16px; padding: 8px; box-shadow: 0 18px 44px rgba(0,0,0,.20); }
.hero-search-pill .hs-ico { font-size: 18px; opacity: .55; flex: 0 0 auto; padding-inline-start: 10px; }
.hero-search-pill input { flex: 1; min-width: 0; border: none; background: transparent; font-family: inherit;
font-size: 16px; padding: 10px 4px; color: var(--ink); }
.hero-search-pill input:focus { outline: none; }
.hero-search-pill .btn { flex: 0 0 auto; }
.hero-search .nav-search-results { inset-inline: 0; min-width: 0; top: calc(100% + 8px); text-align: start; }
.hero-chips { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; justify-content: center; margin-top: 14px; font-size: 13px; }
.hero-chips .hc-label { color: rgba(255,255,255,.85); }
.hero-chips a { background: rgba(255,255,255,.16); color: #fff; padding: 5px 13px; border-radius: 999px; font-weight: 600; transition: background .15s; }
.hero-chips a:hover { background: rgba(255,255,255,.3); }
@media (max-width: 520px) {
.hero-search-pill { flex-wrap: wrap; }
.hero-search-pill input { flex: 1 1 100%; order: 1; }
.hero-search-pill .btn { flex: 1 1 100%; order: 2; }
.hero-search-pill .hs-ico { display: none; }
}
/* Big search box on the /Search page head */
.search-hero { display: flex; gap: 8px; max-width: 640px; margin: 6px 0 4px; }
.search-hero input { flex: 1; padding: 12px 14px; border: 1px solid var(--line); border-radius: 12px;