Redesign header menu: separate account dropdown from dashboard nav
The profile dropdown was doing three jobs at once (account actions, the job-seeker panel menu, and the admin panel menu) and a stray inline @if for the notification badge leaked into the markup as literal text. - Profile dropdown is now account-only: identity card (avatar + name + phone), one role-aware dashboard entry, edit profile, logout. This removes the leaked @if and de-clutters the menu. - Dashboard menu is centralized in _PanelNav and auto-rendered by the layout on every logged-in panel page (/Admin, /Me, /Employer, /Preferences) instead of being duplicated in the dropdown and pages. - Drop the now-duplicate manual <partial name="_PanelNav" /> from Overview, Ingested, Me/Index, Employer/Index. - CSS: identity-card (.pd-id) styles + mobile tweaks. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -8,8 +8,6 @@
|
||||
$"<a class=\"ing-pill {(Model.Status == key || (Model.Status is null && key == "all") ? "active" : "")}\" href=\"?status={key}\">{label} ({P(count)})</a>";
|
||||
}
|
||||
|
||||
<partial name="_PanelNav" />
|
||||
|
||||
<div class="page-head">
|
||||
<div class="container">
|
||||
<h1>نتایج جمعآوری</h1>
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
string P(int n) => JalaliDate.ToPersianDigits(n.ToString());
|
||||
}
|
||||
|
||||
<partial name="_PanelNav" />
|
||||
|
||||
<div class="page-head">
|
||||
<div class="container">
|
||||
<h1>داشبورد مدیریت</h1>
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
};
|
||||
}
|
||||
|
||||
<partial name="_PanelNav" />
|
||||
|
||||
<div class="page-head">
|
||||
<div class="container">
|
||||
<h1>پنل مرکز درمانی</h1>
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
};
|
||||
}
|
||||
|
||||
<partial name="_PanelNav" />
|
||||
|
||||
<div class="page-head">
|
||||
<div class="container">
|
||||
<h1>پنل کارجو</h1>
|
||||
|
||||
@@ -6,20 +6,26 @@
|
||||
var title = ViewData["Title"] as string;
|
||||
int unreadCount = 0;
|
||||
int meId = 0;
|
||||
string? meName = null;
|
||||
string? meFullName = null;
|
||||
string? mePhone = null;
|
||||
bool meHasAvatar = false;
|
||||
if (User.Identity?.IsAuthenticated == true && int.TryParse(User.FindFirstValue(ClaimTypes.NameIdentifier), out meId))
|
||||
{
|
||||
unreadCount = await Notifications.UnreadCountAsync(meId);
|
||||
var info = await Db.Users.Where(u => u.Id == meId)
|
||||
.Select(u => new { u.FullName, u.Phone, HasAvatar = u.Avatar != null }).FirstOrDefaultAsync();
|
||||
meName = string.IsNullOrWhiteSpace(info?.FullName) ? info?.Phone : info!.FullName;
|
||||
meFullName = string.IsNullOrWhiteSpace(info?.FullName) ? null : info!.FullName!.Trim();
|
||||
mePhone = info?.Phone;
|
||||
meHasAvatar = info?.HasAvatar ?? false;
|
||||
}
|
||||
// Person glyph when there's no real name yet (avoid showing a phone digit like "0").
|
||||
var meInitial = (!string.IsNullOrWhiteSpace(meName) && !char.IsDigit(meName!.Trim()[0]))
|
||||
? meName!.Trim().Substring(0, 1) : "👤";
|
||||
var meLabel = (!string.IsNullOrWhiteSpace(meName) && !char.IsDigit(meName!.Trim()[0])) ? meName! : "حساب من";
|
||||
// Avatar glyph/label: prefer a real name; never show a bare phone digit like "0".
|
||||
var meInitial = meFullName is not null ? meFullName.Substring(0, 1) : "👤";
|
||||
var meLabel = meFullName ?? "حساب من";
|
||||
|
||||
// Single, role-aware dashboard entry — the full menu lives in the panel sub-nav (_PanelNav).
|
||||
var dashUrl = "/Me/Index"; var dashLabel = "داشبورد من"; var dashIcon = "🗂️";
|
||||
if (User.IsInRole("Admin")) { dashUrl = "/Admin/Overview"; dashLabel = "پنل مدیریت"; dashIcon = "🛠️"; }
|
||||
else if (User.IsInRole("FacilityAdmin")) { dashUrl = "/Employer/Index"; dashLabel = "پنل کارفرما"; dashIcon = "🏥"; }
|
||||
|
||||
// --- SEO context ---
|
||||
var baseUrl = $"{Context.Request.Scheme}://{Context.Request.Host}";
|
||||
@@ -33,6 +39,11 @@
|
||||
string[] noindexPrefixes = { "/Admin", "/Me", "/Employer", "/Account", "/Preferences" };
|
||||
var noIndex = (ViewData["NoIndex"] as bool? ?? false)
|
||||
|| noindexPrefixes.Any(p => path.StartsWith(p, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
// Show the centralized dashboard sub-nav on any logged-in panel page.
|
||||
string[] panelPrefixes = { "/Admin", "/Me", "/Employer", "/Preferences" };
|
||||
var showPanelNav = User.Identity?.IsAuthenticated == true
|
||||
&& panelPrefixes.Any(p => path.StartsWith(p, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
<!DOCTYPE html>
|
||||
<html lang="fa" dir="rtl">
|
||||
@@ -126,22 +137,26 @@
|
||||
<span class="avatar-caret">▾</span>
|
||||
</label>
|
||||
<nav class="profile-dropdown">
|
||||
<div class="pd-head">@meName</div>
|
||||
<a asp-page="/Me/Profile">👤 ویرایش پروفایل</a>
|
||||
<a asp-page="/Me/Index" data-tour="panel">🗂️ پنل کارجو</a>
|
||||
<a asp-page="/Me/Alerts">🔎 هشدارهای شغلی</a>
|
||||
<a asp-page="/Preferences/Index">⭐ علاقهمندیها</a>
|
||||
<a asp-page="/Me/Notifications">🔔 اعلانها@if (unreadCount > 0) {<span class="bell-badge" style="position:static; margin-inline-start:6px;">@JalaliDate.ToPersianDigits(unreadCount > 99 ? "99+" : unreadCount.ToString())</span>}</a>
|
||||
@if (User.IsInRole("FacilityAdmin"))
|
||||
<div class="pd-id">
|
||||
@if (meHasAvatar)
|
||||
{
|
||||
<a asp-page="/Employer/Index">🏥 پنل کارفرما</a>
|
||||
<img class="avatar-img" src="/avatar/@meId" alt="" />
|
||||
}
|
||||
@if (User.IsInRole("Admin"))
|
||||
else
|
||||
{
|
||||
<span class="avatar-fallback">@meInitial</span>
|
||||
}
|
||||
<div class="pd-id-text">
|
||||
<strong>@(meFullName ?? "کاربر همکادر")</strong>
|
||||
@if (mePhone is not null)
|
||||
{
|
||||
<span class="muted" dir="ltr">@mePhone</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pd-sep"></div>
|
||||
<a asp-page="/Admin/Overview">🛠️ پنل مدیریت</a>
|
||||
<a asp-page="/Admin/Settings">⚙️ تنظیمات</a>
|
||||
}
|
||||
<a href="@dashUrl" data-tour="panel">@dashIcon @dashLabel</a>
|
||||
<a asp-page="/Me/Profile">👤 ویرایش پروفایل</a>
|
||||
<div class="pd-sep"></div>
|
||||
<form method="post" asp-page="/Account/Logout">
|
||||
<button type="submit" class="pd-logout">🚪 خروج</button>
|
||||
@@ -159,6 +174,10 @@
|
||||
</header>
|
||||
|
||||
<main role="main">
|
||||
@if (showPanelNav)
|
||||
{
|
||||
<partial name="_PanelNav" />
|
||||
}
|
||||
@RenderBody()
|
||||
</main>
|
||||
|
||||
|
||||
@@ -132,6 +132,11 @@ a { color: inherit; text-decoration: none; }
|
||||
.profile-dropdown a:hover, .pd-logout:hover { background: var(--primary-soft); color: var(--primary-dark); }
|
||||
.profile-dropdown form { margin: 0; }
|
||||
.pd-head { padding: 8px 12px; font-weight: 800; color: var(--muted); font-size: 13px; }
|
||||
.pd-id { display: flex; align-items: center; gap: 10px; padding: 8px 10px 12px; }
|
||||
.pd-id .avatar-img, .pd-id .avatar-fallback { width: 42px; height: 42px; font-size: 17px; }
|
||||
.pd-id-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.45; }
|
||||
.pd-id-text strong { font-size: 14px; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.pd-id-text .muted { font-size: 12px; }
|
||||
.pd-sep { height: 1px; background: var(--line); margin: 4px 0; }
|
||||
.pd-logout { color: var(--danger); }
|
||||
|
||||
@@ -483,6 +488,7 @@ label { font-size: 13px; }
|
||||
.profile-dropdown { position: static; display: block; box-shadow: none; border: none; padding: 0; min-width: 0; }
|
||||
.profile-dropdown a, .pd-logout { padding: 12px 6px; font-size: 15px; }
|
||||
.pd-head { display: none; }
|
||||
.pd-id { padding: 10px 6px; border-bottom: 1px solid var(--line); margin-bottom: 4px; }
|
||||
.pd-sep { display: none; }
|
||||
|
||||
.cal { border-spacing: 4px; }
|
||||
|
||||
Reference in New Issue
Block a user