Skip to content

Commit b18149f

Browse files
authored
fix(chat): enhance mobile responsiveness and consent UI (#408)
1 parent c475108 commit b18149f

2 files changed

Lines changed: 117 additions & 27 deletions

File tree

src/components/ChatWidget.css

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,16 @@
246246
text-align: center;
247247
}
248248

249+
/* Scrollable content area so buttons stay visible on short viewports (e.g. mobile) */
250+
.chat-consent-scroll {
251+
-webkit-overflow-scrolling: touch;
252+
}
253+
254+
/* Stick buttons at bottom with safe area for notches/home indicator */
255+
.chat-consent-actions.safe-area-bottom {
256+
padding-bottom: max(16px, env(safe-area-inset-bottom));
257+
}
258+
249259
.consent-icon-wrapper {
250260
display: flex;
251261
align-items: center;
@@ -263,17 +273,60 @@
263273
text-align: left;
264274
}
265275

276+
/* Privacy Notice: Decline (secondary) & I Agree (primary) */
266277
.consent-btn {
267278
cursor: pointer;
268279
transition: all 0.2s ease;
280+
min-height: 44px;
281+
display: inline-flex;
282+
align-items: center;
283+
justify-content: center;
284+
border-radius: 10px;
285+
font-weight: 500;
269286
}
270287

271-
.consent-btn-agree:hover {
272-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
288+
.consent-btn:focus-visible {
289+
outline: 2px solid var(--ifm-color-primary);
290+
outline-offset: 2px;
291+
}
292+
293+
/* Left: Decline — use inset box-shadow as “border” so all four edges stay visible (not clipped) */
294+
.consent-btn-decline {
295+
background: transparent;
296+
border: none;
297+
box-shadow: inset 0 0 0 1.5px var(--ifm-color-emphasis-300);
298+
box-sizing: border-box;
299+
color: var(--ifm-color-content-secondary);
273300
}
274301

275302
.consent-btn-decline:hover {
276303
background: var(--ifm-color-emphasis-100);
304+
box-shadow: inset 0 0 0 1.5px var(--ifm-color-emphasis-400);
305+
color: var(--ifm-color-content);
306+
}
307+
308+
/* Right: I Agree — use fixed dark teal so white text always has ≥4.5:1 contrast (light & dark theme) */
309+
.consent-btn-agree {
310+
background: #247077;
311+
color: #fff;
312+
border: none;
313+
}
314+
315+
html[data-theme='dark'] .consent-btn-agree,
316+
[data-theme='dark'] .consent-btn-agree {
317+
background: #247077;
318+
color: #fff;
319+
}
320+
321+
.consent-btn-agree:hover {
322+
background: #1e5c62;
323+
opacity: 1;
324+
box-shadow: 0 2px 12px rgba(36, 112, 119, 0.4);
325+
}
326+
327+
.consent-btn-agree:active,
328+
.consent-btn-decline:active {
329+
transform: scale(0.98);
277330
}
278331

279332
/* Markdown Styles Override inside Chat */
@@ -344,6 +397,17 @@
344397
width: 24px;
345398
height: 24px;
346399
}
400+
401+
/* Privacy consent: ensure buttons are visible and content scrolls on mobile */
402+
.chat-consent-scroll {
403+
padding-left: 12px;
404+
padding-right: 12px;
405+
}
406+
407+
.chat-consent-actions {
408+
padding-left: 12px;
409+
padding-right: 12px;
410+
}
347411
}
348412

349413
@media screen and (max-width: 480px) {
@@ -398,4 +462,18 @@
398462
padding: 10px;
399463
border-radius: 50%;
400464
}
465+
466+
.chat-consent-scroll {
467+
padding-left: 10px;
468+
padding-right: 10px;
469+
}
470+
471+
.chat-consent-actions {
472+
padding-left: 10px;
473+
padding-right: 10px;
474+
}
475+
476+
.chat-consent-actions.safe-area-bottom {
477+
padding-bottom: max(12px, env(safe-area-inset-bottom));
478+
}
401479
}

src/components/ChatWidget.tsx

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ export default function ChatWidget() {
6868
const [isOpen, setIsOpen] = useState(false);
6969
const [isExpanded, setIsExpanded] = useState(false);
7070
const [hasUserToggledExpand, setHasUserToggledExpand] = useState(false);
71+
const openedFromHeaderRef = useRef(false);
7172
const [isApiHealthy, setIsApiHealthy] = useState<boolean>(false);
7273
const [hasConsented, setHasConsented] = useState<boolean>(() => {
7374
if (typeof window !== 'undefined') {
@@ -304,6 +305,7 @@ export default function ChatWidget() {
304305
const target = e.target as HTMLElement;
305306
if (target.closest('.header-ai-chat-link')) {
306307
e.preventDefault();
308+
openedFromHeaderRef.current = true;
307309
setIsOpen(true);
308310
setIsExpanded(true);
309311
setHasUserToggledExpand(true);
@@ -324,7 +326,9 @@ export default function ChatWidget() {
324326
const isDesktop = width >= 1024;
325327

326328
if (isSmallScreen) {
327-
setIsExpanded(false);
329+
if (!openedFromHeaderRef.current) {
330+
setIsExpanded(false);
331+
}
328332
} else if (isOpen && isDesktop && !hasUserToggledExpand) {
329333
setIsExpanded(true);
330334
}
@@ -539,13 +543,14 @@ export default function ChatWidget() {
539543
};
540544

541545
const handleDeclineConsent = () => {
542-
// Close the chat widget when the user declines
546+
openedFromHeaderRef.current = false;
543547
setIsOpen(false);
544548
setIsExpanded(false);
545549
setHasUserToggledExpand(false);
546550
};
547551

548552
const handleClose = () => {
553+
openedFromHeaderRef.current = false;
549554
abortControllerRef.current?.abort();
550555
setIsOpen(false);
551556
setIsExpanded(false);
@@ -736,29 +741,35 @@ export default function ChatWidget() {
736741

737742
{/* Privacy Consent Screen */}
738743
{!hasConsented ? (
739-
<div className="chat-consent flex-1 flex flex-col items-center justify-center p-6 bg-[var(--ifm-background-color)]">
740-
<div className="consent-icon-wrapper mb-4">
741-
<ShieldCheck className="w-12 h-12 text-[var(--ifm-color-primary)]" />
742-
</div>
743-
<h3 className="text-base font-semibold text-[var(--ifm-color-content)] mb-3 text-center">
744-
Before You Begin
745-
</h3>
746-
<div className="consent-text-box rounded-lg p-4 mb-6 text-sm leading-relaxed text-[var(--ifm-color-content-secondary)] bg-[var(--ifm-color-emphasis-100)] border border-[var(--ifm-color-emphasis-200)]">
747-
{PRIVACY_CONSENT_TEXT}
744+
<div className="chat-consent flex-1 flex flex-col min-h-0 bg-[var(--ifm-background-color)]">
745+
<div className="chat-consent-scroll flex-1 min-h-0 overflow-y-auto flex flex-col items-center p-4 pb-2">
746+
<div className="consent-icon-wrapper mb-4">
747+
<ShieldCheck className="w-12 h-12 text-[var(--ifm-color-primary)]" />
748+
</div>
749+
<h3 className="text-base font-semibold text-[var(--ifm-color-content)] mb-3 text-center">
750+
Before You Begin
751+
</h3>
752+
<div className="consent-text-box rounded-lg p-4 mb-4 text-sm leading-relaxed text-[var(--ifm-color-content-secondary)] bg-[var(--ifm-color-emphasis-100)] border border-[var(--ifm-color-emphasis-200)] w-full">
753+
{PRIVACY_CONSENT_TEXT}
754+
</div>
748755
</div>
749-
<div className="flex gap-3 w-full">
750-
<button
751-
onClick={handleDeclineConsent}
752-
className="consent-btn consent-btn-decline flex-1 px-4 py-2.5 rounded-lg text-sm font-medium border border-[var(--ifm-color-emphasis-300)] text-[var(--ifm-color-content-secondary)] bg-transparent hover:bg-[var(--ifm-color-emphasis-100)] transition-colors"
753-
>
754-
Decline
755-
</button>
756-
<button
757-
onClick={handleConsent}
758-
className="consent-btn consent-btn-agree flex-1 px-4 py-2.5 rounded-lg text-sm font-medium bg-[var(--ifm-color-primary)] text-white hover:opacity-90 transition-opacity border-none"
759-
>
760-
I Agree
761-
</button>
756+
<div className="chat-consent-actions flex-shrink-0 p-4 pt-2 safe-area-bottom">
757+
<div className="flex gap-3 w-full">
758+
<button
759+
type="button"
760+
onClick={handleDeclineConsent}
761+
className="consent-btn consent-btn-decline flex-1 px-4 py-2.5 text-sm"
762+
>
763+
Decline
764+
</button>
765+
<button
766+
type="button"
767+
onClick={handleConsent}
768+
className="consent-btn consent-btn-agree flex-1 px-4 py-2.5 text-sm"
769+
>
770+
I Agree
771+
</button>
772+
</div>
762773
</div>
763774
</div>
764775
) : (
@@ -836,11 +847,12 @@ export default function ChatWidget() {
836847
whileTap={{ scale: 0.95 }}
837848
onClick={() => {
838849
if (isOpen) {
850+
openedFromHeaderRef.current = false;
839851
setIsOpen(false);
840852
setIsExpanded(false);
841853
setHasUserToggledExpand(false);
842854
} else {
843-
setHasUserToggledExpand(true);
855+
setHasUserToggledExpand(true);
844856
setIsExpanded(false);
845857
setIsOpen(true);
846858
}

0 commit comments

Comments
 (0)