Home hero: replace filter dropdowns with a search-engine box (+ live typeahead)
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:
@@ -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> </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>
|
||||
|
||||
|
||||
@@ -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,30 +241,40 @@
|
||||
try { return safe.replace(new RegExp('(' + terms.join('|') + ')', 'gi'), '<mark>$1</mark>'); }
|
||||
catch (e) { return safe; }
|
||||
}
|
||||
function hide() { box.style.display = 'none'; box.innerHTML = ''; }
|
||||
input.addEventListener('input', function () {
|
||||
var q = input.value.trim();
|
||||
clearTimeout(timer);
|
||||
if (q.length < 2) { hide(); return; }
|
||||
timer = setTimeout(function () {
|
||||
fetch('/search/suggest?q=' + encodeURIComponent(q))
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (items) {
|
||||
if (!items || !items.length) { hide(); return; }
|
||||
var html = items.map(function (it) {
|
||||
var sub = it.sub ? '<span class="ns-sub">' + hi(it.sub, q) + '</span>' : '';
|
||||
return '<a href="' + it.url + '"><span class="ns-type">' + esc(it.type) +
|
||||
'</span><span class="ns-text"><span class="ns-label">' + hi(it.label, q) +
|
||||
'</span>' + sub + '</span></a>';
|
||||
}).join('');
|
||||
html += '<a class="ns-all" href="/Search?Q=' + encodeURIComponent(q) + '">همه نتایج برای «' + esc(q) + '» ←</a>';
|
||||
box.innerHTML = html;
|
||||
box.style.display = 'block';
|
||||
}).catch(function () { hide(); });
|
||||
}, 200);
|
||||
});
|
||||
document.addEventListener('click', function (e) { if (!form.contains(e.target)) hide(); });
|
||||
input.addEventListener('keydown', function (e) { if (e.key === 'Escape') hide(); });
|
||||
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();
|
||||
clearTimeout(timer);
|
||||
if (q.length < 2) { hide(); return; }
|
||||
timer = setTimeout(function () {
|
||||
fetch('/search/suggest?q=' + encodeURIComponent(q))
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (items) {
|
||||
if (!items || !items.length) { hide(); return; }
|
||||
var html = items.map(function (it) {
|
||||
var sub = it.sub ? '<span class="ns-sub">' + hi(it.sub, q) + '</span>' : '';
|
||||
return '<a href="' + it.url + '"><span class="ns-type">' + esc(it.type) +
|
||||
'</span><span class="ns-text"><span class="ns-label">' + hi(it.label, q) +
|
||||
'</span>' + sub + '</span></a>';
|
||||
}).join('');
|
||||
html += '<a class="ns-all" href="/Search?Q=' + encodeURIComponent(q) + '">همه نتایج برای «' + esc(q) + '» ←</a>';
|
||||
box.innerHTML = html;
|
||||
box.style.display = 'block';
|
||||
}).catch(function () { hide(); });
|
||||
}, 200);
|
||||
});
|
||||
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>
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user