Skip to content

Commit 56eb33f

Browse files
authored
Merge pull request #40903 from github/repo-sync
Repo sync
2 parents de242a5 + e5d1588 commit 56eb33f

File tree

6 files changed

+132
-41
lines changed

6 files changed

+132
-41
lines changed

src/fixtures/tests/playwright-rendering.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,7 +1015,7 @@ test.describe('LandingCarousel component', () => {
10151015

10161016
// Check that article cards are present
10171017
const items = page.locator('[data-testid="carousel-items"]')
1018-
const cards = items.locator('div')
1018+
const cards = items.locator('a')
10191019
await expect(cards.first()).toBeVisible()
10201020

10211021
// Verify cards have real titles (not "Unknown Article" when article not found)
@@ -1190,7 +1190,7 @@ test.describe('LandingArticleGridWithFilter component', () => {
11901190
await expect(articleCards.first()).toBeVisible()
11911191

11921192
const firstCard = articleCards.first()
1193-
const titleLink = firstCard.locator('h3 a')
1193+
const titleLink = firstCard.locator('h3 span')
11941194
await expect(titleLink).toBeVisible()
11951195

11961196
const intro = firstCard.locator('div').last() // cardIntro is the last div

src/landings/components/shared/LandingArticleGridWithFilter.module.scss

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,19 @@
2424
box-shadow:
2525
0 0.0625rem 0.1875rem 0 rgba(31, 35, 40, 0.08),
2626
0 0.0625rem 0 0 rgba(31, 35, 40, 0.06);
27+
transition: all 0.2s ease-in-out;
28+
cursor: pointer;
29+
text-decoration: none !important;
30+
color: inherit;
31+
32+
&:hover {
33+
box-shadow:
34+
0 0.25rem 0.5rem 0 rgba(31, 35, 40, 0.12),
35+
0 0.125rem 0.25rem 0 rgba(31, 35, 40, 0.08);
36+
transform: translateY(-2px);
37+
background-color: var(--bgColor-muted, var(--color-canvas-subtle));
38+
text-decoration: none !important;
39+
}
2740
}
2841

2942
.cardHeader {
@@ -40,17 +53,14 @@
4053
.cardTitleLink {
4154
color: var(--fgColor-accent);
4255
text-decoration: none;
43-
44-
&:hover {
45-
text-decoration: underline;
46-
}
4756
}
4857

4958
.cardIntro {
5059
margin: 0;
5160
color: var(--fgColor-muted);
5261
font-size: 0.9rem;
5362
line-height: 1.4;
63+
text-decoration: none !important;
5464
}
5565

5666
.tagsContainer {
@@ -145,6 +155,10 @@
145155
margin-left: 0;
146156
width: auto;
147157

158+
input {
159+
font-size: 1rem;
160+
}
161+
148162
// Medium screens: flexible width with spacing
149163
@include breakpoint(md) {
150164
flex: 0 1 25%;

src/landings/components/shared/LandingArticleGridWithFilter.tsx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export const ArticleGrid = ({ flatArticles }: ArticleGridProps) => {
5151
const articlesPerPage = useResponsiveArticlesPerPage()
5252

5353
const inputRef = useRef<HTMLInputElement>(null)
54+
const headingRef = useRef<HTMLHeadingElement>(null)
5455

5556
// Reset to first page when articlesPerPage changes (screen size changes)
5657
useEffect(() => {
@@ -112,6 +113,14 @@ export const ArticleGrid = ({ flatArticles }: ArticleGridProps) => {
112113
e.preventDefault()
113114
if (pageNumber >= 1 && pageNumber <= totalPages) {
114115
setCurrentPage(pageNumber)
116+
if (headingRef.current) {
117+
const elementPosition = headingRef.current.getBoundingClientRect().top + window.scrollY
118+
const offsetPosition = elementPosition - 140 // 140px offset from top
119+
window.scrollTo({
120+
top: offsetPosition,
121+
behavior: 'smooth',
122+
})
123+
}
115124
}
116125
}
117126

@@ -122,7 +131,7 @@ export const ArticleGrid = ({ flatArticles }: ArticleGridProps) => {
122131
{/* Title and Dropdown Row */}
123132
<div className={styles.titleAndDropdownRow}>
124133
{/* Title */}
125-
<h2 className={cx(styles.headerTitle, styles.headerTitleText)}>
134+
<h2 ref={headingRef} className={cx(styles.headerTitle, styles.headerTitleText)}>
126135
{t('article_grid.heading')}
127136
</h2>
128137

@@ -156,7 +165,6 @@ export const ArticleGrid = ({ flatArticles }: ArticleGridProps) => {
156165
<form onSubmit={(e) => e.preventDefault()}>
157166
<TextInput
158167
leadingVisual={SearchIcon}
159-
sx={{ width: '100%' }}
160168
placeholder={t('article_grid.search_articles')}
161169
ref={inputRef}
162170
autoComplete="false"
@@ -210,7 +218,8 @@ type ArticleCardProps = {
210218

211219
const ArticleCard = ({ article }: ArticleCardProps) => {
212220
return (
213-
<div
221+
<Link
222+
href={article.fullPath}
214223
className={cx(
215224
styles.articleCard,
216225
styles.articleCardBox,
@@ -226,12 +235,10 @@ const ArticleCard = ({ article }: ArticleCardProps) => {
226235
</div>
227236

228237
<h3 className={styles.cardTitle}>
229-
<Link href={article.fullPath} className={styles.cardTitleLink}>
230-
{article.title}
231-
</Link>
238+
<span className={styles.cardTitleLink}>{article.title}</span>
232239
</h3>
233240

234241
{article.intro && <div className={styles.cardIntro}>{article.intro}</div>}
235-
</div>
242+
</Link>
236243
)
237244
}

src/landings/components/shared/LandingCarousel.module.scss

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.carousel {
22
margin-top: 3rem;
3-
--carousel-transition-duration: 0.3s;
3+
--carousel-transition-duration: 0.1s;
44
}
55

66
.header {
@@ -44,7 +44,7 @@
4444
display: grid;
4545
gap: 1.5rem;
4646
grid-template-columns: 1fr;
47-
transition: opacity var(--carousel-transition-duration) ease-out;
47+
transition: opacity var(--carousel-transition-duration) ease-in-out;
4848
opacity: 1;
4949

5050
@media (min-width: 768px) {
@@ -56,7 +56,7 @@
5656
}
5757

5858
&.animating {
59-
opacity: 0;
59+
opacity: 0.3;
6060
}
6161
}
6262

@@ -68,6 +68,19 @@
6868
box-shadow:
6969
0px 1px 3px 0px rgba(31, 35, 40, 0.08),
7070
0px 1px 0px 0px rgba(31, 35, 40, 0.06);
71+
transition: all 0.2s ease-in-out;
72+
cursor: pointer;
73+
text-decoration: none !important;
74+
color: inherit;
75+
76+
&:hover {
77+
box-shadow:
78+
0 0.25rem 0.5rem 0 rgba(31, 35, 40, 0.12),
79+
0 0.125rem 0.25rem 0 rgba(31, 35, 40, 0.08);
80+
transform: translateY(-2px);
81+
background-color: var(--bgColor-muted, var(--color-canvas-subtle));
82+
text-decoration: none !important;
83+
}
7184
}
7285

7386
.articleTitle {
@@ -78,17 +91,14 @@
7891
.articleLink {
7992
color: var(--fgColor-accent);
8093
text-decoration: none;
81-
82-
&:hover {
83-
text-decoration: underline;
84-
}
8594
}
8695

8796
.articleDescription {
8897
margin: 0;
8998
color: var(--fgColor-muted);
9099
font-size: 0.9rem;
91100
line-height: 1.4;
101+
text-decoration: none !important;
92102
}
93103

94104
.pagination {

src/landings/components/shared/LandingCarousel.tsx

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { useState, useEffect, useRef } from 'react'
22
import { ChevronLeftIcon, ChevronRightIcon } from '@primer/octicons-react'
3-
import { Token } from '@primer/react'
43
import cx from 'classnames'
54
import type { ResolvedArticle } from '@/types'
65
import { useTranslation } from '@/languages/components/useTranslation'
@@ -78,11 +77,11 @@ export const LandingCarousel = ({ heading = '', recommended }: LandingCarouselPr
7877
setCurrentPage((prev) => Math.max(0, prev - 1))
7978

8079
// Set animation state to false after transition completes
81-
// Duration matches CSS custom property --carousel-transition-duration (300ms)
80+
// Duration matches CSS custom property --carousel-transition-duration (100ms)
8281
animationTimeoutRef.current = setTimeout(() => {
8382
setIsAnimating(false)
8483
animationTimeoutRef.current = null
85-
}, 300)
84+
}, 100)
8685
}
8786

8887
const goToNext = () => {
@@ -97,11 +96,11 @@ export const LandingCarousel = ({ heading = '', recommended }: LandingCarouselPr
9796
setCurrentPage((prev) => Math.min(totalPages - 1, prev + 1))
9897

9998
// Set animation state to false after transition completes
100-
// Duration matches CSS custom property --carousel-transition-duration (300ms)
99+
// Duration matches CSS custom property --carousel-transition-duration (100ms)
101100
animationTimeoutRef.current = setTimeout(() => {
102101
setIsAnimating(false)
103102
animationTimeoutRef.current = null
104-
}, 300)
103+
}, 100)
105104
}
106105

107106
// Calculate the start index based on current page
@@ -144,27 +143,21 @@ export const LandingCarousel = ({ heading = '', recommended }: LandingCarouselPr
144143
data-testid="carousel-items"
145144
>
146145
{visibleItems.map((article: ResolvedArticle, index) => (
147-
<div
146+
<a
148147
key={startIndex + index}
148+
href={article.href}
149149
className={cx(styles.articleCard, 'border', 'border-default', 'rounded-2')}
150150
>
151-
<div className="mb-2">
152-
{article.category.map((cat: string) => (
153-
<Token key={cat} text={cat} className="mr-1 mb-2" />
154-
))}
155-
</div>
156151
<h3 className={styles.articleTitle}>
157-
<a href={article.href} className={styles.articleLink}>
158-
{article.title}
159-
</a>
152+
<span className={styles.articleLink}>{article.title}</span>
160153
</h3>
161154
<div
162155
className={styles.articleDescription}
163156
dangerouslySetInnerHTML={{
164157
__html: article.intro as TrustedHTML,
165158
}}
166159
/>
167-
</div>
160+
</a>
168161
))}
169162
</div>
170163
</div>

0 commit comments

Comments
 (0)