diff --git a/src/app/messages/setup/page.tsx b/src/app/messages/setup/page.tsx index 3c4e167f..487d2e62 100644 --- a/src/app/messages/setup/page.tsx +++ b/src/app/messages/setup/page.tsx @@ -6,6 +6,7 @@ import { useAuth } from '@/contexts/AuthContext'; import { isOAuthUser, getOAuthProvider } from '@/lib/auth/oauth-utils'; import { sendWelcomeMessageOnSetup } from '@/lib/messaging/welcome/send-welcome-message'; import { createLogger } from '@/lib/logger/logger'; +import Icon from '@/components/atomic/Icon'; const logger = createLogger('app:messages:setup'); @@ -264,7 +265,10 @@ export default function MessagingSetupPage() { className="btn btn-ghost btn-sm absolute top-1/2 right-1 -translate-y-1/2" aria-label={showPassword ? 'Hide password' : 'Show password'} > - {showPassword ? '👁️' : '👁️‍🗨️'} + {/* Decorative (#385): the button's aria-label already + says Show/Hide password, and the two emoji were nearly + indistinguishable at button size. */} + diff --git a/src/app/schedule/page.tsx b/src/app/schedule/page.tsx index c1607d6f..8ea5e256 100644 --- a/src/app/schedule/page.tsx +++ b/src/app/schedule/page.tsx @@ -1,6 +1,7 @@ 'use client'; import dynamic from 'next/dynamic'; +import Icon from '@/components/atomic/Icon'; const CalendarEmbed = dynamic( () => import('@/components/atomic/CalendarEmbed'), @@ -59,7 +60,10 @@ export default function SchedulePage() {

- 💡 + {/* Decorative (#385): "Prepare for the meeting:" follows. */} + + + Prepare for the meeting:

diff --git a/src/components/GlobalNav.tsx b/src/components/GlobalNav.tsx index 952cf362..b3d2a7e6 100644 --- a/src/components/GlobalNav.tsx +++ b/src/components/GlobalNav.tsx @@ -350,8 +350,13 @@ export function GlobalNav() { )}

  • + {/* min-h-11: DaisyUI's menu default renders this at 26px, + 18px under the 44px standard. It sits inside a closed + dropdown, so the touch-target gate never measured it + until that gate was taught to open the menu (#378). */}
  • )}
  • + {/* Same 26px default as the desktop menu above. */} + >${iconSvg('copy')}${iconSvg('check', 'display:none')}Copy code
    ${code}
  • `; diff --git a/src/components/molecular/SEOAnalysisPanel/SEOAnalysisPanel.tsx b/src/components/molecular/SEOAnalysisPanel/SEOAnalysisPanel.tsx index b949e4d3..d8e11d0c 100644 --- a/src/components/molecular/SEOAnalysisPanel/SEOAnalysisPanel.tsx +++ b/src/components/molecular/SEOAnalysisPanel/SEOAnalysisPanel.tsx @@ -3,6 +3,7 @@ import React, { useState, useMemo } from 'react'; import type { BlogPost } from '@/types/blog'; import { seoAnalyzer } from '@/lib/blog/seo-analyzer'; +import Icon from '@/components/atomic/Icon'; export interface SEOAnalysisPanelProps { post: BlogPost; @@ -64,7 +65,9 @@ export default function SEOAnalysisPanel({ className="btn btn-xs sm:btn-sm btn-ghost" title="Copy SEO feedback" > - {copied ? '✓ Copied' : '📋 Copy'} + {/* Decorative (#385): the word beside it changes too. */} + + {copied ? 'Copied' : 'Copy'}
    - + {/* Decorative: the

    above reads "Strengths (N)", so + the marker is not the only non-colour signal (#385). */} + + + {strength} ))} @@ -165,7 +172,10 @@ export default function SEOAnalysisPanel({ key={i} className="flex items-start gap-2 text-xs sm:text-sm" > - + {/* Decorative: the

    above reads "Weaknesses (N)". */} + + + {weakness} ))} diff --git a/src/components/organisms/A11yDevOverlay/A11yDevOverlay.tsx b/src/components/organisms/A11yDevOverlay/A11yDevOverlay.tsx index 271eb700..9a74160f 100644 --- a/src/components/organisms/A11yDevOverlay/A11yDevOverlay.tsx +++ b/src/components/organisms/A11yDevOverlay/A11yDevOverlay.tsx @@ -3,6 +3,7 @@ import React, { useMemo, useRef, useState } from 'react'; import type { ImpactValue, Result } from 'axe-core'; import { useA11yScan } from './useA11yScan'; +import Icon from '@/components/atomic/Icon'; export interface A11yDevOverlayProps { /** @@ -167,9 +168,9 @@ export default function A11yDevOverlay({ aria-label={`Accessibility violations: ${violations.length}. Open panel.`} className={`badge ${badgeColor} fixed right-4 bottom-20 z-[90] flex min-h-11 min-w-11 cursor-pointer items-center gap-1 rounded-full px-3 shadow-lg ${className}`} > - + {/* Decorative (#385): the button's aria-label already reads + "Accessibility violations: N. Open panel." */} + {violations.length} ); @@ -184,9 +185,7 @@ export default function A11yDevOverlay({ >

    - + A11y {violations.length} @@ -208,7 +207,8 @@ export default function A11yDevOverlay({ aria-label="Collapse accessibility panel" className="btn btn-ghost btn-xs min-h-11 min-w-11" > - ✕ + {/* The button carries aria-label="Collapse accessibility panel". */} +

    diff --git a/src/components/privacy/CookieConsent/CookieConsent.tsx b/src/components/privacy/CookieConsent/CookieConsent.tsx index 305f1b73..97686902 100644 --- a/src/components/privacy/CookieConsent/CookieConsent.tsx +++ b/src/components/privacy/CookieConsent/CookieConsent.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { useConsent } from '../../../contexts/ConsentContext'; +import Icon from '../../atomic/Icon'; export interface CookieConsentProps { position?: 'top' | 'bottom'; @@ -71,8 +72,12 @@ export function CookieConsent({
    {/* Message Section - Compact */}
    - - 🍪 + {/* Decorative (#385): the sentence beside it already says + "We use cookies". The emoji carried aria-label="Cookie", so + a screen reader announced "Cookie, We use cookies to enhance + your experience" — the name repeated the copy. */} + + {customContent || (

    diff --git a/tests/e2e/tests/mobile-touch-targets.spec.ts b/tests/e2e/tests/mobile-touch-targets.spec.ts index 7ae0cda9..07d7c8a8 100644 --- a/tests/e2e/tests/mobile-touch-targets.spec.ts +++ b/tests/e2e/tests/mobile-touch-targets.spec.ts @@ -53,6 +53,24 @@ test.describe('Touch Target Standards', () => { await dismissCookieBanner(page); await waitForLayoutStability(page); + // OPEN THE MOBILE MENU FIRST. Without this the gate is very nearly inert: + // measured on a clean page at 390px, the selector below matched 58 + // elements and exactly ONE was visible — the hamburger itself. The other + // 57 sit inside the closed dropdown, `isVisible()` skips them, and the + // test reports green having checked a single 44px button. + // + // The nav is a DaisyUI `dropdown` held open by `:focus-within`, so + // focusing the trigger opens it (#378 will add more of these). + const menuTrigger = page.locator('[aria-label="Navigation menu"]'); + if (await menuTrigger.count()) { + // click(), not focus(): a DaisyUI dropdown is held open by + // :focus-within, and a programmatic focus on the