fix mobile screen responsive

This commit is contained in:
2026-08-10 14:47:19 +05:30
parent 7b1af5a8ef
commit 312d2d9f4c
3 changed files with 66 additions and 11 deletions

View File

@@ -10,6 +10,16 @@ const EXPANDED_WIDTH = 620;
const GUTTER = 24;
/** Expanded must never dominate: the dashboard stays the primary experience. */
const MAX_VIEWPORT_SHARE = 0.42;
/**
* Below this width there is no room for a column *beside* the dashboard — a
* 380px track on a 375px phone collapses `main` to nothing — so the panel
* becomes a bottom sheet over the page instead of an inline column.
*
* Deliberately Tailwind's `md` (768px), not `lg`: tablets already lay the
* inline column out acceptably, so they keep the existing behaviour and only
* phones switch to the sheet.
*/
const OVERLAY_BREAKPOINT = 768;
/** Tracks viewport width so the expanded panel can be clamped on smaller screens. */
function useViewportWidth() {
@@ -58,6 +68,45 @@ export function AssistantPanel({ stickyClassName, panelHeightClassName }) {
const trackWidth = panelWidth + GUTTER;
const easing = [0.65, 0, 0.35, 1];
// Phone/small-tablet: a sheet over the dashboard rather than a column beside
// it. Same assistant, same props — only the container differs.
if (viewportWidth < OVERLAY_BREAKPOINT) {
return (
<AnimatePresence initial={false}>
{isOpen && context && (
<>
<motion.div
className="fixed inset-0 z-40 bg-black/40"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.25, ease: easing }}
onClick={close}
/>
<motion.aside
key="assistant-sheet"
aria-label="Krow AI Assistant"
className="fixed inset-x-0 bottom-0 z-50 max-h-[85dvh] overflow-y-auto overscroll-contain rounded-t-2xl bg-white shadow-2xl"
initial={{ y: '100%' }}
animate={{ y: 0 }}
exit={{ y: '100%' }}
transition={{ duration: 0.3, ease: easing }}
>
<KrowAssistant
key={context.id}
context={context}
expanded={false}
onClose={close}
onExpand={expand}
onRestore={restore}
/>
</motion.aside>
</>
)}
</AnimatePresence>
);
}
return (
<AnimatePresence initial={false}>
{isOpen && context && (

View File

@@ -123,7 +123,7 @@ export default function Layout() {
<div className="min-h-screen gradient-mesh bg-[#F8FAFC]">
{/* Header */}
<header className="sticky top-0 z-40 glass border-b border-white/40">
<div className="mx-auto max-w-container-wide px-6 h-16 flex items-center justify-between gap-4">
<div className="mx-auto max-w-container-wide px-4 sm:px-6 h-16 flex items-center justify-between gap-4">
{/* Brand */}
<button onClick={() => navigate(ROLE_HOME[activeRole])} className="flex items-center gap-2 text-left shrink-0 group">
<Image src={KROW_LOGO_URL} alt="KROW" fittingType="fit" className="h-7 w-[86px] rounded-lg shadow-lg shadow-blue-500/20 group-hover:scale-105 transition-transform" />
@@ -243,8 +243,13 @@ export default function Layout() {
{/* Control bar (Employer / Admin only) */}
{!isTalent && (
<div className="sticky top-16 z-30 glass border-b border-white/40">
<div className="mx-auto max-w-container-wide px-6 h-14 flex items-center gap-3">
<form onSubmit={handleSearch} className="relative flex-1 max-w-md">
{/* Below `sm` this wraps to two rows: search gets a full-width row of
its own, the filter + action share the next. On one row the search
field was being crushed to ~90px by the status select's intrinsic
width, clipping its own placeholder. From `sm` up it is the
original single 56px-tall row. */}
<div className="mx-auto max-w-container-wide px-4 sm:px-6 py-2.5 sm:py-0 sm:h-14 flex flex-wrap sm:flex-nowrap items-center gap-2 sm:gap-3">
<form onSubmit={handleSearch} className="relative w-full sm:w-auto sm:flex-1 sm:max-w-md">
<Search className="absolute left-3.5 top-1/2 -translate-y-1/2 w-4 h-4 text-[#9CA3AF]" />
<input
value={searchQuery}
@@ -255,12 +260,12 @@ export default function Layout() {
/>
</form>
<div className="flex items-center gap-2 ml-auto">
<div className="relative">
<div className="flex items-center gap-2 w-full sm:w-auto ml-auto">
<div className="relative flex-1 sm:flex-none min-w-0">
<select
value={statusFilter}
onChange={(e) => handleStatusChange(e.target.value)}
className="appearance-none h-9 pl-3 pr-8 text-[13px] font-medium rounded-full border border-white/60 bg-white/70 backdrop-blur-sm focus:border-[#0A39DF] focus:outline-none cursor-pointer"
className="appearance-none w-full sm:w-auto h-9 pl-3 pr-8 text-[13px] font-medium rounded-full border border-white/60 bg-white/70 backdrop-blur-sm focus:border-[#0A39DF] focus:outline-none cursor-pointer"
>
{STATUS_OPTIONS.map((s) => (
<option key={s} value={s}>{s}</option>
@@ -273,7 +278,8 @@ export default function Layout() {
className="inline-flex items-center gap-1.5 bg-[#0A39DF] hover:bg-[#082EB4] text-white text-[13px] font-semibold px-4 py-2 rounded-full transition-all shrink-0 hover:scale-[1.02] shadow-sm"
>
<Plus className="w-4 h-4" />
<span className="hidden sm:inline">New Position</span>
{/* The second row leaves room for the label on mobile too */}
<span>New Position</span>
</button>
</div>
</div>
@@ -372,7 +378,7 @@ export default function Layout() {
layout is identical to the original. Opening the assistant animates a
track open beside it; `main` is a flex child, so it reflows smoothly
rather than jumping, and closing restores the original layout exactly. */}
<div className="mx-auto flex max-w-container-wide px-6 py-8">
<div className="mx-auto flex max-w-container-wide px-4 sm:px-6 py-6 sm:py-8">
<main className="min-w-0 w-full max-w-7xl flex-1 mx-auto">
<Outlet />
</main>

View File

@@ -78,11 +78,11 @@ export default function Overview() {
transition={{ duration: 0.5 }}
className="flex items-center justify-between flex-wrap gap-4"
>
<div>
<h1 className="text-3xl font-heading font-bold text-[#111827]">
<div className="min-w-0">
<h1 className="text-2xl sm:text-3xl font-heading font-bold text-[#111827]">
Good day. <span className="gradient-text">Let's hire smarter.</span>
</h1>
<p className="text-[14px] text-[#6B7280] mt-1">AI-powered hiring · No quizzes · Real readiness</p>
<p className="text-[13px] sm:text-[14px] text-[#6B7280] mt-1">AI-powered hiring · No quizzes · Real readiness</p>
</div>
<AssistantTrigger />
</motion.div>