Skip to content

Commit 4ff5167

Browse files
Updating name: sublanding to guides and using DropdownMenu for type/topics filter (#23290)
* updating sublanding to guides page and using DropdownMenu primer component * fix linting error * remove unnecessary import * updating translation files * move data-testid * trying to fix test * fix browser tests * Update content/README.md Co-authored-by: Francis <15894826+francisfuzz@users.noreply.github.com> Co-authored-by: Francis <15894826+francisfuzz@users.noreply.github.com>
1 parent 5983137 commit 4ff5167

File tree

48 files changed

+192
-219
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+192
-219
lines changed

components/context/ProductSubLandingContext.tsx renamed to components/context/ProductGuidesContext.tsx

+6-6
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export type ArticleGuide = {
1717
topics: Array<string>
1818
}
1919

20-
export type ProductSubLandingContextT = {
20+
export type ProductGuidesContextT = {
2121
title: string
2222
intro: string
2323
featuredTrack?: FeaturedTrack
@@ -26,21 +26,21 @@ export type ProductSubLandingContextT = {
2626
allTopics?: Array<string>
2727
}
2828

29-
export const ProductSubLandingContext = createContext<ProductSubLandingContextT | null>(null)
29+
export const ProductGuidesContext = createContext<ProductGuidesContextT | null>(null)
3030

31-
export const useProductSubLandingContext = (): ProductSubLandingContextT => {
32-
const context = useContext(ProductSubLandingContext)
31+
export const useProductGuidesContext = (): ProductGuidesContextT => {
32+
const context = useContext(ProductGuidesContext)
3333

3434
if (!context) {
3535
throw new Error(
36-
'"useProductSubLandingContext" may only be used inside "ProductSubLandingContext.Provider"'
36+
'"useProductGuidesContext" may only be used inside "ProductGuidesContext.Provider"'
3737
)
3838
}
3939

4040
return context
4141
}
4242

43-
export const getProductSubLandingContextFromRequest = (req: any): ProductSubLandingContextT => {
43+
export const getProductGuidesContextFromRequest = (req: any): ProductGuidesContextT => {
4444
const page = req.context.page
4545

4646
return {

components/sublanding/ArticleCard.tsx renamed to components/guides/ArticleCard.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ArticleGuide } from 'components/context/ProductSubLandingContext'
1+
import { ArticleGuide } from 'components/context/ProductGuidesContext'
22
import { Label } from '@primer/components'
33

44
type Props = {

components/guides/ArticleCards.tsx

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import React, { useEffect, useState } from 'react'
2+
3+
import {
4+
ArticleGuide,
5+
useProductGuidesContext,
6+
} from 'components/context/ProductGuidesContext'
7+
import { useTranslation } from 'components/hooks/useTranslation'
8+
import { ArticleCard } from './ArticleCard'
9+
import { DropdownMenu } from '@primer/components'
10+
import { ItemInput } from '@primer/components/lib/ActionList/List'
11+
12+
const PAGE_SIZE = 9
13+
export const ArticleCards = () => {
14+
const { t } = useTranslation('product_guides')
15+
const guideTypes: Record<string, string> = t('guide_types')
16+
const { allTopics, includeGuides } = useProductGuidesContext()
17+
const [numVisible, setNumVisible] = useState(PAGE_SIZE)
18+
const [typeFilter, setTypeFilter] = useState<ItemInput | undefined>()
19+
const [topicFilter, setTopicFilter] = useState<ItemInput | undefined>()
20+
const [filteredResults, setFilteredResults] = useState<Array<ArticleGuide>>([])
21+
22+
useEffect(() => {
23+
setNumVisible(PAGE_SIZE)
24+
setFilteredResults(
25+
(includeGuides || []).filter((card) => {
26+
const matchesType = card.type === typeFilter?.key
27+
const matchesTopic = card.topics.some((key) => key === topicFilter?.key)
28+
return (typeFilter?.key ? matchesType : true) && (topicFilter?.key ? matchesTopic : true)
29+
})
30+
)
31+
}, [typeFilter, topicFilter])
32+
33+
const isUserFiltering = typeFilter !== undefined || topicFilter !== undefined
34+
35+
const guides = isUserFiltering ? filteredResults : includeGuides || []
36+
37+
const types = Object.entries(guideTypes).map(([key, val]) => {
38+
return (
39+
{text: val, key: key}
40+
)
41+
}) as ItemInput[]
42+
43+
types.unshift({text: t('filters.all'), key: undefined})
44+
45+
const topics = allTopics?.map((topic) => {
46+
return (
47+
{text: topic, key: topic}
48+
)
49+
}) as ItemInput[]
50+
51+
topics.unshift({text: t('filters.all'), key: undefined})
52+
53+
return (
54+
<div>
55+
<label htmlFor="guide-filter-form">{t('filter_instructions')}</label>
56+
<form name="guide-filter-form" className="mt-2 mb-5 d-flex d-flex">
57+
<div data-testid="card-filter-types">
58+
<label htmlFor="type" className="text-uppercase f6 color-fg-muted d-block">
59+
{t('filters.type')}
60+
</label>
61+
<DropdownMenu
62+
aria-label="guide types"
63+
data-testid="types-dropdown"
64+
placeholder={t('filters.all')}
65+
items={types}
66+
selectedItem={typeFilter}
67+
onChange={setTypeFilter} />
68+
</div>
69+
70+
<div data-testid="card-filter-topics" className="mx-4">
71+
<label htmlFor="topic" className="text-uppercase f6 color-fg-muted d-block">
72+
{t('filters.topic')}
73+
</label>
74+
<DropdownMenu
75+
aria-label="guide topics"
76+
data-testid="topics-dropdown"
77+
placeholder={t('filters.all')}
78+
items={topics}
79+
selectedItem={topicFilter}
80+
onChange={setTopicFilter} />
81+
</div>
82+
</form>
83+
84+
<div role="status" className="color-fg-muted">
85+
{guides.length === 0
86+
? t('guides_found.none')
87+
: guides.length === 1
88+
? t('guides_found.one')
89+
: t('guides_found.multiple').replace('{n}', guides.length)}
90+
</div>
91+
92+
<div className="d-flex flex-wrap mr-0 mr-md-n6 mr-lg-n8">
93+
{guides.slice(0, numVisible).map((card) => {
94+
return <ArticleCard key={card.href} card={card} typeLabel={guideTypes[card.type]} />
95+
})}
96+
</div>
97+
98+
{guides.length > numVisible && (
99+
<button
100+
className="col-12 mt-5 text-center text-bold color-fg-accent btn-link"
101+
onClick={() => setNumVisible(numVisible + PAGE_SIZE)}
102+
>
103+
{t('load_more')}
104+
</button>
105+
)}
106+
</div>
107+
)
108+
}

components/sublanding/SubLandingHero.tsx renamed to components/guides/GuidesHero.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import cx from 'classnames'
2-
import { useProductSubLandingContext } from 'components/context/ProductSubLandingContext'
2+
import { useProductGuidesContext } from 'components/context/ProductGuidesContext'
33
import { ArrowRightIcon, StarFillIcon } from '@primer/octicons-react'
44
import { useTranslation } from 'components/hooks/useTranslation'
55
import { Link } from 'components/Link'
66
import { TruncateLines } from 'components/ui/TruncateLines'
77
import { Lead } from 'components/ui/Lead'
8-
import styles from './SubLandingHero.module.scss'
8+
import styles from './GuidesHero.module.scss'
99

10-
export const SubLandingHero = () => {
11-
const { title, intro, featuredTrack } = useProductSubLandingContext()
12-
const { t } = useTranslation('product_sublanding')
10+
export const GuidesHero = () => {
11+
const { title, intro, featuredTrack } = useProductGuidesContext()
12+
const { t } = useTranslation('product_guides')
1313
const cardWidth = 280
1414

1515
const guideItems = featuredTrack?.guides?.map((guide) => (

components/sublanding/LearningTrack.tsx renamed to components/guides/LearningTrack.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import cx from 'classnames'
22
import { useTranslation } from 'components/hooks/useTranslation'
33
import { ArrowRightIcon } from '@primer/octicons-react'
44
import { useState } from 'react'
5-
import { FeaturedTrack } from 'components/context/ProductSubLandingContext'
5+
import { FeaturedTrack } from 'components/context/ProductGuidesContext'
66
import { TruncateLines } from 'components/ui/TruncateLines'
77
import slugger from 'github-slugger'
88
import styles from './LearningTrack.module.scss'
@@ -17,7 +17,7 @@ export const LearningTrack = ({ track }: Props) => {
1717
const showAll = () => {
1818
setNumVisible(track?.guides?.length || 0)
1919
}
20-
const { t } = useTranslation('product_sublanding')
20+
const { t } = useTranslation('product_guides')
2121
const slug = track?.title ? slugger.slug(track?.title) : ''
2222

2323
return (

components/sublanding/LearningTracks.tsx renamed to components/guides/LearningTracks.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { useProductSubLandingContext } from 'components/context/ProductSubLandingContext'
2-
import { LearningTrack } from 'components/sublanding/LearningTrack'
1+
import { useProductGuidesContext } from 'components/context/ProductGuidesContext'
2+
import { LearningTrack } from 'components/guides/LearningTrack'
33

44
export const LearningTracks = () => {
5-
const { learningTracks } = useProductSubLandingContext()
5+
const { learningTracks } = useProductGuidesContext()
66

77
return (
88
<div className="d-flex flex-wrap flex-items-start my-5 gutter">

components/sublanding/ProductSubLanding.tsx renamed to components/guides/ProductGuides.tsx

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
import { DefaultLayout } from 'components/DefaultLayout'
2-
import { useProductSubLandingContext } from 'components/context/ProductSubLandingContext'
2+
import { useProductGuidesContext } from 'components/context/ProductGuidesContext'
33
import React from 'react'
44
import { LandingSection } from 'components/landing/LandingSection'
5-
import { SubLandingHero } from 'components/sublanding/SubLandingHero'
6-
import { LearningTracks } from 'components/sublanding/LearningTracks'
7-
import { ArticleCards } from 'components/sublanding/ArticleCards'
5+
import { GuidesHero } from 'components/guides/GuidesHero'
6+
import { LearningTracks } from 'components/guides/LearningTracks'
7+
import { ArticleCards } from 'components/guides/ArticleCards'
88
import { useTranslation } from 'components/hooks/useTranslation'
99

10-
export const ProductSubLanding = () => {
11-
const { title, learningTracks, includeGuides } = useProductSubLandingContext()
10+
export const ProductGuides = () => {
11+
const { title, learningTracks, includeGuides } = useProductGuidesContext()
1212
const { t } = useTranslation('sub_landing')
1313
return (
1414
<DefaultLayout>
1515
<LandingSection className="pt-3">
16-
<SubLandingHero />
16+
<GuidesHero />
1717
</LandingSection>
1818

1919
{learningTracks && learningTracks.length > 0 && (

components/sublanding/ArticleCards.tsx

-115
This file was deleted.

content/README.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ See the [contributing docs](/CONTRIBUTING.md) for general information about work
3939
- [Links and image paths](#links-and-image-paths)
4040
- [Preventing transformations](#preventing-transformations)
4141
- [Index pages](#index-pages)
42-
- [Creating new sublanding pages](#creating-new-sublanding-pages)
42+
- [Creating new product guides pages](#creating-new-product-guides-pages)
4343

4444
## Frontmatter
4545

@@ -243,7 +243,7 @@ defaultTool: cli
243243
**Note: the featured track is set by a specific property in the learning tracks YAML. See that [README](../data/learning-tracks/README.md) for details.*
244244

245245
### `includeGuides`
246-
- Purpose: Render a list of articles, filterable by `type` and `topics`. Only applicable when used with `layout: product-sublanding`.
246+
- Purpose: Render a list of articles, filterable by `type` and `topics`. Only applicable when used with `layout: product-guides`.
247247
- Type: `Array`
248248
- Optional.
249249

@@ -376,11 +376,11 @@ The homepage is the main Table of Contents file for the docs site. The homepage
376376

377377
`childGroups` is an array of mappings containing a `name` for the group, an optional `icon` for the group, and an array of `children`. The `children` in the array must be present in the `children` frontmatter property.
378378

379-
### Creating new sublanding pages
379+
### Creating new product guides pages
380380

381-
To create a sublanding page (e.g. [Actions' Guide page](https://docs.github.com/en/actions/guides)), create or modify an existing markdown file with these specific frontmatter values:
381+
To create a product guides page (e.g. [Actions' Guide page](https://docs.github.com/en/actions/guides)), create or modify an existing markdown file with these specific frontmatter values:
382382

383-
1. Use the sublanding page template by referencing it `layout: product-sublanding`
383+
1. Use the product guides page template by referencing it `layout: product-guides`
384384
2. (optional) Include the learning tracks in [`learningTracks`](#learningTracks)
385385
3. (optional) Define which articles to include with [`includeGuides`](#includeGuides).
386386

content/actions/guides.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: Guides for GitHub Actions
33
intro: 'These guides for {% data variables.product.prodname_actions %} include specific use cases and examples to help you configure workflows.'
44
allowTitleToDifferFromFilename: true
5-
layout: product-sublanding
5+
layout: product-guides
66
versions:
77
fpt: '*'
88
ghes: '*'

content/admin/guides.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ title: GitHub Enterprise guides
33
shortTitle: Guides
44
intro: 'Learn how to increase developer productivity and code quality with {% data variables.product.product_name %}.'
55
allowTitleToDifferFromFilename: true
6-
layout: product-sublanding
6+
layout: product-guides
77
versions:
88
ghec: '*'
99
ghes: '*'

0 commit comments

Comments
 (0)