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