1
0
mirror of synced 2025-12-21 10:57:10 -05:00
Files
docs/components/sublanding/ArticleCards.tsx
Kevin Heis 567652b0e3 Primer 18 b (#22462)
* Create migrate-colors-primer-18.js

* Update colors round 1

* upgrade primer packages

* Update index.scss

* Replace auto colors

* remove btn-primary-matte

* Turns out the class names and variables names DONT LINE UP... ugh....

* Check for allowed var colors
2021-10-28 19:17:23 +00:00

116 lines
3.9 KiB
TypeScript

import { useEffect, useState } from 'react'
import {
ArticleGuide,
useProductSubLandingContext,
} from 'components/context/ProductSubLandingContext'
import { useTranslation } from 'components/hooks/useTranslation'
import { ArticleCard } from './ArticleCard'
const PAGE_SIZE = 9
export const ArticleCards = () => {
const { t } = useTranslation('product_sublanding')
const guideTypes: Record<string, string> = t('guide_types')
const { allTopics, includeGuides } = useProductSubLandingContext()
const [numVisible, setNumVisible] = useState(PAGE_SIZE)
const [typeFilter, setTypeFilter] = useState('')
const [topicFilter, setTopicFilter] = useState('')
const [filteredResults, setFilteredResults] = useState<Array<ArticleGuide>>([])
useEffect(() => {
setNumVisible(PAGE_SIZE)
setFilteredResults(
(includeGuides || []).filter((card) => {
const matchesType = card.type === typeFilter
const matchesTopic = card.topics.some((key) => key === topicFilter)
return (typeFilter ? matchesType : true) && (topicFilter ? matchesTopic : true)
})
)
}, [typeFilter, topicFilter])
const isUserFiltering = typeFilter !== '' || topicFilter !== ''
const onChangeTypeFilter = (e: React.ChangeEvent<HTMLSelectElement>) => {
setTypeFilter(e.target.value)
}
const onChangeTopicFilter = (e: React.ChangeEvent<HTMLSelectElement>) => {
setTopicFilter(e.target.value)
}
const guides = isUserFiltering ? filteredResults : includeGuides || []
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>
<label htmlFor="type" className="text-uppercase f6 color-fg-muted d-block">
{t('filters.type')}
</label>
<select
value={typeFilter}
className="form-select f4 text-bold border-0 rounded-0 border-top box-shadow-none pl-0"
name="type"
aria-label="guide types"
data-testid="card-filter-dropdown"
onChange={onChangeTypeFilter}
>
<option value="">{t('filters.all')}</option>
{Object.entries(guideTypes).map(([key, val]) => {
return (
<option key={key} value={key}>
{val}
</option>
)
})}
</select>
</div>
<div className="mx-4">
<label htmlFor="topic" className="text-uppercase f6 color-fg-muted d-block">
{t('filters.topic')}
</label>
<select
value={topicFilter}
className="form-select f4 text-bold border-0 rounded-0 border-top box-shadow-none pl-0"
name="topics"
data-testid="card-filter-dropdown"
aria-label="guide topics"
onChange={onChangeTopicFilter}
>
<option value="">{t('filters.all')}</option>
{allTopics?.map((topic) => {
return (
<option key={topic} value={topic}>
{topic}
</option>
)
})}
</select>
</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>
)
}