diff --git a/client/src/components/PDF/TripPDF.test.ts b/client/src/components/PDF/TripPDF.test.ts index 2c8417e9a..02b487a67 100644 --- a/client/src/components/PDF/TripPDF.test.ts +++ b/client/src/components/PDF/TripPDF.test.ts @@ -929,7 +929,8 @@ describe('page breaks between days (#1292)', () => { }) const toggle = () => - document.querySelector('#pdf-daybreak-toggle input') + document.querySelector('#pdf-daybreak-toggle') + const isOn = () => toggle()!.getAttribute('aria-checked') === 'true' it('FE-PDF-BREAK-001: days break onto their own page by default', async () => { await downloadTripPDF(twoDays) @@ -937,7 +938,17 @@ describe('page breaks between days (#1292)', () => { expect(html).toContain('day-section day-break') expect(html).not.toContain('class="pdf-flow"') - expect(toggle()!.checked).toBe(true) + expect(isOn()).toBe(true) + }) + + it('FE-PDF-BREAK-001b: the control is the switch from the rest of the app, not a checkbox', async () => { + await downloadTripPDF(twoDays) + const el = toggle()! + + expect(el.tagName).toBe('BUTTON') + expect(el.getAttribute('role')).toBe('switch') + expect(el.style.background).toContain('--accent') + expect(document.querySelector('#pdf-daybreak-toggle input')).toBeNull() }) it('FE-PDF-BREAK-002: the remembered flowing layout comes back on the next export', async () => { @@ -948,7 +959,9 @@ describe('page breaks between days (#1292)', () => { // The class stays on the day; the body is what decides whether it breaks. expect(html).toContain('day-section day-break') expect(html).toContain('') - expect(toggle()!.checked).toBe(false) + expect(isOn()).toBe(false) + // Off uses the neutral track, so the two states are told apart by more than the knob. + expect(toggle()!.style.background).toContain('--border-primary') }) it('FE-PDF-BREAK-003: the first day never carries a break of its own', async () => { @@ -961,10 +974,9 @@ describe('page breaks between days (#1292)', () => { it('FE-PDF-BREAK-004: turning the breaks off is remembered and shown at once', async () => { await downloadTripPDF(twoDays) - const box = toggle()! - box.checked = false - box.dispatchEvent(new Event('change')) + toggle()!.click() + expect(isOn()).toBe(false) expect(localStorage.getItem('trek_pdf_page_break_per_day')).toBe('0') const body = getIframe()!.contentDocument?.body if (body) expect(body.classList.contains('pdf-flow')).toBe(true) @@ -973,10 +985,9 @@ describe('page breaks between days (#1292)', () => { it('FE-PDF-BREAK-005: turning them back on is remembered too', async () => { localStorage.setItem('trek_pdf_page_break_per_day', '0') await downloadTripPDF(twoDays) - const box = toggle()! - box.checked = true - box.dispatchEvent(new Event('change')) + toggle()!.click() + expect(isOn()).toBe(true) expect(localStorage.getItem('trek_pdf_page_break_per_day')).toBe('1') const body = getIframe()!.contentDocument?.body if (body) expect(body.classList.contains('pdf-flow')).toBe(false) @@ -991,8 +1002,6 @@ describe('page breaks between days (#1292)', () => { expect(html).toContain('day-section day-break') expect(html).not.toContain('class="pdf-flow"') - const box = toggle()! - box.checked = false - expect(() => box.dispatchEvent(new Event('change'))).not.toThrow() + expect(() => toggle()!.click()).not.toThrow() }) }) diff --git a/client/src/components/PDF/TripPDF.tsx b/client/src/components/PDF/TripPDF.tsx index 3f29a400c..e1e019f66 100644 --- a/client/src/components/PDF/TripPDF.tsx +++ b/client/src/components/PDF/TripPDF.tsx @@ -32,6 +32,14 @@ function rememberPageBreakPerDay(on: boolean): void { } } +/* The overlay is imperative DOM, so the switch from Settings/ToggleSwitch is + rebuilt here rather than rendered — as static markup it would carry no + behaviour. Same geometry and the same tokens, so it reads as the same control. */ +const TOGGLE_TRACK = 'position:relative;width:44px;height:24px;min-width:44px;flex-shrink:0;border-radius:12px;border:none;padding:0;cursor:pointer;transition:background 0.2s;' +const TOGGLE_KNOB = 'position:absolute;top:2px;width:20px;height:20px;border-radius:50%;background:white;transition:left 0.2s;box-shadow:0 1px 3px rgba(0,0,0,0.2);' +const trackColour = (on: boolean) => (on ? 'var(--accent, #111827)' : 'var(--border-primary, #d1d5db)') +const knobOffset = (on: boolean) => (on ? '22px' : '2px') + function renderLucideIcon(icon:LucideIcon, props = {}) { if (!_renderToStaticMarkup) return '' return _renderToStaticMarkup( @@ -699,10 +707,10 @@ ${pluginSectionsHtml} header.innerHTML = ` ${escHtml(trip?.title || tr('pdf.travelPlan'))}
- + +