Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions e2e/support-cta.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { expect, test } from '@playwright/test'

for (const width of [1440, 390, 320]) {
test(`homepage support links remain usable at ${String(width)}px`, async ({
page,
browserName,
}, testInfo) => {
await page.setViewportSize({ width, height: 900 })
await page.goto('/')
const support = page.getByRole('region', {
name: 'Useful in your project?',
})
await expect(support).toBeVisible()
await expect(
support.getByRole('heading', {
level: 2,
name: 'Useful in your project?',
}),
).toBeVisible()
expect(
await support.evaluate((section) =>
section.previousElementSibling?.matches('.hero'),
),
).toBe(true)

const star = support.getByRole('link', { name: 'Star on GitHub' })
const explore = support.getByRole('link', {
name: 'Explore NIPE Open Source',
})
await expect(star).toHaveAttribute(
'href',
'https://github.com/NIPE-Solutions/react-pull-to-refresh',
)
await expect(explore).toHaveAttribute(
'href',
'https://opensource.nipesolutions.com',
)
await expect(support.locator('p')).not.toBeEmpty()
await support.scrollIntoViewIfNeeded()
for (const link of [star, explore]) {
await expect(link).toBeVisible()
const box = await link.boundingBox()
expect(box).not.toBeNull()
if (!box) throw new Error('Support link is not measurable')
expect(box.height).toBeGreaterThanOrEqual(44)
expect(box.width).toBeGreaterThanOrEqual(44)
expect(box.x).toBeGreaterThanOrEqual(0)
expect(box.x + box.width).toBeLessThanOrEqual(width)
}
expect(
await support.evaluate(
(section) => section.scrollWidth <= section.clientWidth,
),
).toBe(true)

await star.focus()
const macWebKit = browserName === 'webkit' && process.platform === 'darwin'
const tab = macWebKit ? 'Alt+Tab' : 'Tab'
await page.keyboard.press(macWebKit ? 'Shift+Alt+Tab' : 'Shift+Tab')
await page.keyboard.press(tab)
await expect(star).toBeFocused()
const outline = await star.evaluate((link) => {
const style = getComputedStyle(link)
return {
width: parseFloat(style.outlineWidth),
style: style.outlineStyle,
}
})
expect(outline.width).toBeGreaterThanOrEqual(2)
expect(outline.style).not.toBe('none')
await page.keyboard.press(tab)
await expect(explore).toBeFocused()
await expect(explore).toHaveCSS('outline-style', 'solid')
expect(
await explore.evaluate((link) =>
parseFloat(getComputedStyle(link).outlineWidth),
),
).toBeGreaterThanOrEqual(2)
if (process.env.SUPPORT_CTA_SCREENSHOTS === '1')
await support.screenshot({
path: testInfo.outputPath('support-cta.png'),
})
})
}
21 changes: 21 additions & 0 deletions website/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,27 @@ function App() {
</div>
</section>

<section className="support-cta" aria-labelledby="support-heading">
<div className="support-cta__copy">
<h2 id="support-heading">Useful in your project?</h2>
<p>
If React Pull to Refresh helps you build, a GitHub star supports
the project and helps others discover it.
</p>
</div>
<div className="support-cta__actions">
<a
className="support-cta__primary"
href="https://github.com/NIPE-Solutions/react-pull-to-refresh"
>
Star on GitHub
</a>
<a href="https://opensource.nipesolutions.com">
Explore NIPE Open Source
</a>
</div>
</section>

<OwnershipFlow />
<GestureLab />

Expand Down
59 changes: 59 additions & 0 deletions website/src/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,61 @@ footer a {
font-size: 0.68rem;
}

.support-cta {
display: flex;
max-width: 1320px;
margin: 0 auto;
padding: 48px 32px;
flex-wrap: wrap;
align-items: center;
gap: 32px;
border-bottom: 1px solid var(--line);
}

.support-cta__copy {
flex: 1 1 480px;
min-width: 0;
}

.support-cta h2 {
font-size: clamp(1.85rem, 3vw, 2.5rem);
}

.support-cta p {
max-width: 64ch;
margin: 14px 0 0;
color: var(--ink-soft);
line-height: 1.6;
}

.support-cta__actions {
display: flex;
flex-wrap: wrap;
gap: 12px;
}

.support-cta__actions a {
display: inline-flex;
min-height: 44px;
align-items: center;
justify-content: center;
padding: 12px 18px;
border: 1px solid var(--line);
font-weight: 700;
text-decoration: none;
}

.support-cta__actions .support-cta__primary {
border-color: var(--ink);
color: var(--tension);
background: var(--ink);
}

.support-cta__actions a:focus-visible {
outline: 3px solid var(--ink);
outline-offset: 4px;
}

.section-shell {
max-width: 1320px;
margin: 0 auto;
Expand Down Expand Up @@ -952,6 +1007,10 @@ footer {
}

@media (max-width: 760px) {
.support-cta {
padding: 32px 22px;
}

.section-shell,
.browser-section {
padding: 82px 22px;
Expand Down