From 961953511892aef1eb9b7d6f0e461a055e47bdb8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 8 Mar 2026 20:09:48 +0000 Subject: [PATCH 1/6] Initial plan From 11b40ed0dd8be81c9f0054ed715169ebff64b8de Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 8 Mar 2026 20:16:43 +0000 Subject: [PATCH 2/6] Fix clipboard copy on Safari/iPad OS using execCommand fallback Replace navigator.clipboard.writeText() with a textarea + execCommand approach that works reliably on Safari/iPad OS. The Clipboard API silently resolves without writing to the clipboard on Safari iPad OS. Also fix description text extraction to use innerText instead of textContent to preserve line breaks from
tags. Co-authored-by: benbalter <282759+benbalter@users.noreply.github.com> --- src/pages/resume/linkedin.astro | 45 +++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/src/pages/resume/linkedin.astro b/src/pages/resume/linkedin.astro index 33498623f..8c6b845d9 100644 --- a/src/pages/resume/linkedin.astro +++ b/src/pages/resume/linkedin.astro @@ -224,21 +224,51 @@ const educationData: EducationData[] = degrees?.map((degree: { school: string; d diff --git a/src/scripts/linkedin-copy.ts b/src/scripts/linkedin-copy.ts new file mode 100644 index 000000000..06e2b9836 --- /dev/null +++ b/src/scripts/linkedin-copy.ts @@ -0,0 +1,73 @@ +/** + * Copy text to clipboard with fallback for Safari/iPad OS. + * Safari silently resolves navigator.clipboard.writeText() without actually + * writing to the clipboard (the promise succeeds but content is blank), so we + * cannot use the modern Clipboard API with a catch fallback. Instead, we use + * textarea + execCommand('copy') which works reliably across all browsers. + */ +function copyToClipboard(text: string, triggerElement?: Element): boolean { + const textarea = document.createElement('textarea'); + textarea.value = text; + textarea.setAttribute('readonly', ''); + textarea.style.position = 'fixed'; + textarea.style.left = '-9999px'; + textarea.style.top = '-9999px'; + textarea.style.opacity = '0'; + document.body.appendChild(textarea); + + // iOS/iPad Safari requires both selection methods + textarea.select(); + textarea.setSelectionRange(0, textarea.value.length); + + let success = false; + try { + success = document.execCommand('copy'); + } catch { + success = false; + } + document.body.removeChild(textarea); + + // Restore focus to the trigger element after textarea removal + if (triggerElement instanceof HTMLElement) { + triggerElement.focus(); + } + + return success; +} + +function initCopyButtons() { + document.querySelectorAll('.copy-btn').forEach(btn => { + btn.addEventListener('click', () => { + let textToCopy = ''; + + if (btn.classList.contains('copy-description')) { + const descriptionElement = btn.parentElement?.querySelector('[data-description]') as HTMLElement | null; + textToCopy = descriptionElement?.innerText?.trim() || ''; + } else { + textToCopy = btn.getAttribute('data-copy') || ''; + } + + const success = copyToClipboard(textToCopy, btn); + + if (success) { + const original = btn.textContent; + btn.textContent = '✓'; + btn.classList.add('!bg-green-600'); + + setTimeout(() => { + btn.textContent = original; + btn.classList.remove('!bg-green-600'); + }, 1500); + } else { + const original = btn.textContent; + btn.textContent = '✗'; + setTimeout(() => { + btn.textContent = original; + }, 1500); + } + }); + }); +} + +// Re-initialize after Astro view transitions +document.addEventListener('astro:page-load', initCopyButtons); From ea735fda55fc5d9af3c45a8b242e164ce33c5c3b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 04:27:55 +0000 Subject: [PATCH 6/6] Changes before error encountered Co-authored-by: benbalter <282759+benbalter@users.noreply.github.com> Agent-Logs-Url: https://github.com/benbalter/benbalter.github.com/sessions/735cc370-3cc9-4263-98b5-030f6179504b --- e2e/accessibility-astro.spec.ts | 2 +- e2e/tldr-mobile.spec.ts | 12 ++++++------ e2e/tldr-navigation-ios.spec.ts | 6 +++--- e2e/tldr-tooltip.spec.ts | 18 +++++++++--------- src/pages/404.astro | 2 +- src/pages/talks.astro | 2 +- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/e2e/accessibility-astro.spec.ts b/e2e/accessibility-astro.spec.ts index 81003bc94..ef9147b70 100644 --- a/e2e/accessibility-astro.spec.ts +++ b/e2e/accessibility-astro.spec.ts @@ -107,7 +107,7 @@ test.describe('Accessibility - Blog Post', () => { // Check for article element - use specific selector for the main post article // (related posts also use
elements but are nested inside the main article) - const article = page.locator('.col-md-10 > article'); + const article = page.locator('article[data-pagefind-body]'); await expect(article).toHaveCount(1); // Check for header within article diff --git a/e2e/tldr-mobile.spec.ts b/e2e/tldr-mobile.spec.ts index a18fc4d5f..c71adb90c 100644 --- a/e2e/tldr-mobile.spec.ts +++ b/e2e/tldr-mobile.spec.ts @@ -22,7 +22,7 @@ test.describe('TLDR Tooltip - Mobile/iOS', () => { const astro = await isAstroBuild(page); if (astro) { - const tldrElement = page.locator('.lead strong abbr.initialism'); + const tldrElement = page.locator('.tldr-content strong abbr.initialism'); await expect(tldrElement).toBeVisible(); // Verify iOS-specific CSS properties are applied @@ -69,7 +69,7 @@ test.describe('TLDR Tooltip - Mobile/iOS', () => { const astro = await isAstroBuild(page); if (astro) { - const tldrElement = page.locator('.lead strong abbr.initialism'); + const tldrElement = page.locator('.tldr-content strong abbr.initialism'); await expect(tldrElement).toBeVisible(); // Tap the element to show tooltip @@ -103,7 +103,7 @@ test.describe('TLDR Tooltip - Mobile/iOS', () => { const astro = await isAstroBuild(page); if (astro) { - const tldrElement = page.locator('.lead strong abbr.initialism'); + const tldrElement = page.locator('.tldr-content strong abbr.initialism'); await expect(tldrElement).toBeVisible(); // Try to hover (should not work on mobile) @@ -130,7 +130,7 @@ test.describe('TLDR Tooltip - Mobile/iOS', () => { const astro = await isAstroBuild(page); if (astro) { - const tldrElement = page.locator('.lead strong abbr.initialism'); + const tldrElement = page.locator('.tldr-content strong abbr.initialism'); await expect(tldrElement).toBeVisible(); // Check that cursor is pointer on touch devices @@ -160,7 +160,7 @@ test.describe('TLDR Tooltip - Mobile/iOS', () => { const astro = await isAstroBuild(page); if (astro) { - const tldrElement = page.locator('.lead strong abbr.initialism'); + const tldrElement = page.locator('.tldr-content strong abbr.initialism'); await expect(tldrElement).toBeVisible(); // Verify touch-action is set for proper iPadOS handling @@ -205,7 +205,7 @@ test.describe('TLDR Tooltip - Mobile/iOS', () => { const astro = await isAstroBuild(page); if (astro) { - const tldrElement = page.locator('.lead strong abbr.initialism'); + const tldrElement = page.locator('.tldr-content strong abbr.initialism'); await expect(tldrElement).toBeVisible(); // Verify -webkit-tap-highlight-color is set diff --git a/e2e/tldr-navigation-ios.spec.ts b/e2e/tldr-navigation-ios.spec.ts index 8575750dd..ba8733b75 100644 --- a/e2e/tldr-navigation-ios.spec.ts +++ b/e2e/tldr-navigation-ios.spec.ts @@ -29,7 +29,7 @@ test.describe('TLDR Tooltip - iOS/iPadOS Navigation', () => { await page.waitForTimeout(500); // Check TLDR component is visible on load - const tldrElement = page.locator('.lead strong abbr.initialism'); + const tldrElement = page.locator('.tldr-content strong abbr.initialism'); await expect(tldrElement).toBeVisible(); await expect(tldrElement).toHaveText('TL;DR'); @@ -53,7 +53,7 @@ test.describe('TLDR Tooltip - iOS/iPadOS Navigation', () => { await page.waitForTimeout(500); // Verify tooltip still works after re-navigation - const tldrElement2 = page.locator('.lead strong abbr.initialism'); + const tldrElement2 = page.locator('.tldr-content strong abbr.initialism'); await expect(tldrElement2).toBeVisible(); await tldrElement2.tap(); @@ -84,7 +84,7 @@ test.describe('TLDR Tooltip - iOS/iPadOS Navigation', () => { await page.waitForTimeout(500); // Check TLDR component is visible on load - const tldrElement = page.locator('.lead strong abbr.initialism'); + const tldrElement = page.locator('.tldr-content strong abbr.initialism'); await expect(tldrElement).toBeVisible(); await expect(tldrElement).toHaveText('TL;DR'); diff --git a/e2e/tldr-tooltip.spec.ts b/e2e/tldr-tooltip.spec.ts index a811e01d9..9b7217e3c 100644 --- a/e2e/tldr-tooltip.spec.ts +++ b/e2e/tldr-tooltip.spec.ts @@ -13,7 +13,7 @@ test.describe('TLDR Tooltip', () => { if (astro) { // Check TLDR component is visible - const tldr = page.locator('.lead strong abbr.initialism'); + const tldr = page.locator('.tldr-content strong abbr.initialism'); await expect(tldr).toBeVisible(); await expect(tldr).toHaveText('TL;DR'); @@ -35,7 +35,7 @@ test.describe('TLDR Tooltip', () => { const astro = await isAstroBuild(page); if (astro) { - const tldrElement = page.locator('.lead strong abbr.initialism'); + const tldrElement = page.locator('.tldr-content strong abbr.initialism'); await expect(tldrElement).toBeVisible(); // Hover over the TLDR element @@ -61,7 +61,7 @@ test.describe('TLDR Tooltip', () => { const astro = await isAstroBuild(page); if (astro) { - const tldrElement = page.locator('.lead strong abbr.initialism'); + const tldrElement = page.locator('.tldr-content strong abbr.initialism'); await expect(tldrElement).toBeVisible(); // Dispatch click event to simulate pure tap without mouse events @@ -88,7 +88,7 @@ test.describe('TLDR Tooltip', () => { const astro = await isAstroBuild(page); if (astro) { - const tldrElement = page.locator('.lead strong abbr.initialism'); + const tldrElement = page.locator('.tldr-content strong abbr.initialism'); await expect(tldrElement).toBeVisible(); // Click to show tooltip @@ -114,7 +114,7 @@ test.describe('TLDR Tooltip', () => { const astro = await isAstroBuild(page); if (astro) { - const tldrElement = page.locator('.lead strong abbr.initialism'); + const tldrElement = page.locator('.tldr-content strong abbr.initialism'); await expect(tldrElement).toBeVisible(); // Click to show tooltip @@ -140,7 +140,7 @@ test.describe('TLDR Tooltip', () => { const astro = await isAstroBuild(page); if (astro) { - const tldrElement = page.locator('.lead strong abbr.initialism'); + const tldrElement = page.locator('.tldr-content strong abbr.initialism'); await expect(tldrElement).toBeVisible(); // Check for help cursor style @@ -167,7 +167,7 @@ test.describe('TLDR Tooltip', () => { const astro = await isAstroBuild(page); if (astro) { - const tldrElement = page.locator('.lead strong abbr.initialism'); + const tldrElement = page.locator('.tldr-content strong abbr.initialism'); await expect(tldrElement).toBeVisible(); // Focus the element @@ -198,7 +198,7 @@ test.describe('TLDR Tooltip', () => { const astro = await isAstroBuild(page); if (astro) { - const tldrElement = page.locator('.lead strong abbr.initialism'); + const tldrElement = page.locator('.tldr-content strong abbr.initialism'); await expect(tldrElement).toBeVisible(); // Focus the element @@ -238,7 +238,7 @@ test.describe('TLDR Tooltip', () => { await page.waitForTimeout(500); // Check TLDR component is visible after navigation - const tldrElement = page.locator('.lead strong abbr.initialism'); + const tldrElement = page.locator('.tldr-content strong abbr.initialism'); await expect(tldrElement).toBeVisible(); await expect(tldrElement).toHaveText('TL;DR'); diff --git a/src/pages/404.astro b/src/pages/404.astro index d19522bae..bd489d7c2 100644 --- a/src/pages/404.astro +++ b/src/pages/404.astro @@ -32,7 +32,7 @@ const posts: CollectionEntry<'posts'>[] = allPosts
-