From 2170ba250c68f87065ac74c2da33058ea385ca6c Mon Sep 17 00:00:00 2001 From: "soroush.asadi" Date: Thu, 4 Jun 2026 19:12:34 +0330 Subject: [PATCH] [UI] Mobile sticky action bar on shift/job details (native-app feel) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On mobile the action panel (CTA + map) stacked at the very bottom, so users had to scroll the whole page to act. Add a fixed bottom action bar (<=860px) with the primary «اعلام تمایل» button + a quick save, always reachable like a native app; when contact is revealed it becomes a «تماس با مرکز» tel: button. The in-aside primary CTA is hidden on mobile (.aside-apply) to avoid duplication, and pages get bottom padding (.has-action-bar) so the bar never covers content. Desktop layout unchanged (bar hidden, sidebar CTA shown). Co-Authored-By: Claude Opus 4.8 --- src/JobsMedical.Web/Pages/Jobs/Details.cshtml | 36 +++++++++++++++--- .../Pages/Shifts/Details.cshtml | 38 ++++++++++++++++--- src/JobsMedical.Web/wwwroot/css/site.css | 19 ++++++++++ 3 files changed, 82 insertions(+), 11 deletions(-) diff --git a/src/JobsMedical.Web/Pages/Jobs/Details.cshtml b/src/JobsMedical.Web/Pages/Jobs/Details.cshtml index 6dadbcc..74b3a67 100644 --- a/src/JobsMedical.Web/Pages/Jobs/Details.cshtml +++ b/src/JobsMedical.Web/Pages/Jobs/Details.cshtml @@ -30,7 +30,7 @@ -
+
@if (Model.ShowContact) @@ -77,10 +77,12 @@
@salary

@empLabel

-
- -
+
+
+ +
+
@@ -147,6 +149,30 @@
+@* Sticky bottom action bar — mobile only. *@ +
+ @if (Model.ShowContact) + { + @if (!string.IsNullOrEmpty(f.Phone)) + { + 📞 تماس با مرکز + } + else + { + اطلاعات تماس در بالای صفحه + } + } + else + { + + + +
+ +
+ } +
+ @if (!string.IsNullOrEmpty(Model.MapKey) && Model.Job?.Facility?.Lat is not null) { diff --git a/src/JobsMedical.Web/Pages/Shifts/Details.cshtml b/src/JobsMedical.Web/Pages/Shifts/Details.cshtml index e81efc0..8369da2 100644 --- a/src/JobsMedical.Web/Pages/Shifts/Details.cshtml +++ b/src/JobsMedical.Web/Pages/Shifts/Details.cshtml @@ -28,7 +28,7 @@
-
+
@if (Model.ShowContact) @@ -93,11 +93,13 @@ {
✓ این فرصت ذخیره شد و در پیشنهادهای شما لحاظ می‌شود.
} -
- -
-

با اعلام تمایل، اطلاعات تماس مرکز نمایش داده می‌شود.

+
+
+ +
+

با اعلام تمایل، اطلاعات تماس مرکز نمایش داده می‌شود.

+
+@* Sticky bottom action bar — mobile only. Always-reachable primary action (native-app feel). *@ +
+ @if (Model.ShowContact) + { + @if (!string.IsNullOrEmpty(f.Phone)) + { + 📞 تماس با مرکز + } + else + { + اطلاعات تماس در بالای صفحه + } + } + else + { + + + +
+ +
+ } +
+ @if (!string.IsNullOrEmpty(Model.MapKey) && Model.Shift?.Facility?.Lat is not null) { diff --git a/src/JobsMedical.Web/wwwroot/css/site.css b/src/JobsMedical.Web/wwwroot/css/site.css index 47fc642..bbcae90 100644 --- a/src/JobsMedical.Web/wwwroot/css/site.css +++ b/src/JobsMedical.Web/wwwroot/css/site.css @@ -256,6 +256,25 @@ label { font-size: 13px; } .tour-count { font-size: 12px; color: var(--muted); } .tour-btns { display: flex; gap: 6px; } +/* ---------- Mobile sticky action bar (detail pages feel like a native app) ---------- */ +.mobile-action-bar { display: none; } +@media (max-width: 860px) { + .mobile-action-bar { + display: flex; gap: 8px; align-items: stretch; + position: fixed; inset-inline: 0; bottom: 0; z-index: 95; + padding: 10px 14px; padding-bottom: calc(10px + env(safe-area-inset-bottom, 0px)); + background: var(--surface); border-top: 1px solid var(--line); + box-shadow: 0 -8px 24px rgba(0,0,0,.10); + } + .mobile-action-bar form { margin: 0; } + .mobile-action-bar .cta-main { flex: 1; } + .mobile-action-bar .btn { margin: 0; } + /* breathing room so the fixed bar never covers page content */ + .has-action-bar { padding-bottom: 92px; } + /* the in-aside primary CTA is redundant on mobile — the sticky bar replaces it */ + .aside-apply { display: none; } +} + /* ---------- Admin settings: sidebar tabs ---------- */ .settings-layout { display: grid; grid-template-columns: 220px 1fr; gap: 18px; align-items: start; } .settings-tabs {