* 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
116 lines
3.9 KiB
TypeScript
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>
|
|
)
|
|
}
|