1
0
mirror of synced 2025-12-22 11:26:57 -05:00
Files
docs/components/article/PlatformPicker.tsx
Grace Park 822fe2926b Megabranch: Upgrade primer/react (#28458)
* upgrade primer/react

* upgrade

* using deprecated

* remove lib"

* Upgrade primer/react: Upgrade Label (#28502)

update Label to primer/react 35.2.2

* fix merge conflicts

* primer/react v35: update ActionList (#28467)

* Update to v35 ActionList for LearningTrack

* Update to v35 ActionList for ArticleList

* Update to v35 ActionList for ProductArticleList

* Update to v35 ActionList for TableOfContents

* Update to v35 ActionList for ProductCollapsibleSection

* Update to v35 ActionList for RestCollapsibleSection

* Update to v35 ActionList for SidebarHomepage

* Update to v35 ActionList for MiniTocs

* Update to v35 ActionList for Search

* Extra div for rendering test

* One less div for rendering test

* All the style updates for v35 ActionList

* Works without setting as an li which is already the default (didn't before for some reason)

* Use deprecated ItemInput for now

* Picker update for primer/react (#28485)

* update picker

* inline picker for mobile

* set width to auto

* Update components/ui/Picker/Picker.tsx

Co-authored-by: Kevin Heis <heiskr@users.noreply.github.com>

* update

* Update Picker.tsx

* update onselect

* checking language code

* move language cookie setting to language picker

Co-authored-by: Kevin Heis <heiskr@users.noreply.github.com>

* Resolve package merge conflicts

* fresh npm install

* Primer update UnderlineNav (#28582)

* update underlinenav for primer/react update

* update tests

* update switches test

* update one last label

* update header test"

* remove href in underlinenav

* update rendering tests

* update cursor

* primer/react v35: update DropDownMenu to ActionMenu (#28576)

* Update to v35 ActionMenu for ArticleCards

* Update to v35 ActionMenu for Search

* Set button to inline-block

* Put the props on the overlay

* Update test for ActionMenu markup

* update package

* update package lock

* primer/react v35: CodeLanguagePicker update from SelectMenu to ActionMenu (#28625)

* Use octicon for menu down arrow

* Update to v35 ActionMenu for CodeLanguagePicker

* update to SubNav

Co-authored-by: Grace Park <gracepark@github.com>

* update package-lock

Co-authored-by: Robert Sese <734194+rsese@users.noreply.github.com>
Co-authored-by: Kevin Heis <heiskr@users.noreply.github.com>
2022-07-11 11:51:18 -07:00

171 lines
5.2 KiB
TypeScript

import { useEffect, useState } from 'react'
import Cookies from 'js-cookie'
import { SubNav, TabNav, UnderlineNav } from '@primer/react'
import { sendEvent, EventType } from 'components/lib/events'
import { useRouter } from 'next/router'
import { useArticleContext } from 'components/context/ArticleContext'
import parseUserAgent from 'components/lib/user-agent'
const platforms = [
{ id: 'mac', label: 'Mac' },
{ id: 'windows', label: 'Windows' },
{ id: 'linux', label: 'Linux' },
]
// Nota bene: platform === os
// Imperatively modify article content to show only the selected platform
// find all platform-specific *block* elements and hide or show as appropriate
// example: {% mac %} block content {% endmac %}
function showPlatformSpecificContent(platform: string) {
const markdowns = Array.from(document.querySelectorAll<HTMLElement>('.extended-markdown'))
markdowns
.filter((el) => platforms.some((platform) => el.classList.contains(platform.id)))
.forEach((el) => {
el.style.display = el.classList.contains(platform) ? '' : 'none'
})
// find all platform-specific *inline* elements and hide or show as appropriate
// example: <span class="platform-mac">inline content</span>
const platformEls = Array.from(
document.querySelectorAll<HTMLElement>(
platforms.map((platform) => `.platform-${platform.id}`).join(', ')
)
)
platformEls.forEach((el) => {
el.style.display = el.classList.contains(`platform-${platform}`) ? '' : 'none'
})
}
// uses the order of the supportedPlatforms array to
// determine the default platform
const getFallbackPlatform = (detectedPlatforms: Array<string>): string => {
const foundPlatform = platforms.find((platform) => detectedPlatforms.includes(platform.id))
return foundPlatform?.id || 'linux'
}
type Props = {
variant?: 'subnav' | 'tabnav' | 'underlinenav'
}
export const PlatformPicker = ({ variant = 'subnav' }: Props) => {
const { defaultPlatform, detectedPlatforms } = useArticleContext()
const [currentPlatform, setCurrentPlatform] = useState(defaultPlatform || '')
const { asPath } = useRouter()
// Run on mount for client-side only features
useEffect(() => {
let userAgent = parseUserAgent().os
if (userAgent === 'ios') {
userAgent = 'mac'
}
const platform = defaultPlatform || Cookies.get('osPreferred') || userAgent || 'linux'
setCurrentPlatform(platform)
// always trigger this on initial render. if the default doesn't change the other useEffect won't fire
showPlatformSpecificContent(platform)
}, [asPath])
// Make sure we've always selected a platform that exists in the article
useEffect(() => {
// Only check *after* current platform has been determined
if (currentPlatform && !detectedPlatforms.includes(currentPlatform)) {
setCurrentPlatform(getFallbackPlatform(detectedPlatforms))
}
}, [currentPlatform, detectedPlatforms.join(',')])
const onClickPlatform = (platform: string) => {
setCurrentPlatform(platform)
// imperatively modify the article content
showPlatformSpecificContent(platform)
sendEvent({
type: EventType.preference,
preference_name: 'os',
preference_value: platform,
})
Cookies.set('osPreferred', platform, {
sameSite: 'strict',
secure: true,
})
}
// only show platforms that are in the current article
const platformOptions = platforms.filter((platform) => detectedPlatforms.includes(platform.id))
const sharedContainerProps = {
'data-testid': 'platform-picker',
'aria-label': 'Platform picker',
'data-default-platform': defaultPlatform,
className: 'mb-4',
}
if (variant === 'subnav') {
return (
<SubNav {...sharedContainerProps}>
<SubNav.Links>
{platformOptions.map((option) => {
return (
<SubNav.Link
key={option.id}
data-platform={option.id}
as="button"
selected={option.id === currentPlatform}
onClick={() => {
onClickPlatform(option.id)
}}
>
{option.label}
</SubNav.Link>
)
})}
</SubNav.Links>
</SubNav>
)
}
if (variant === 'underlinenav') {
return (
<UnderlineNav {...sharedContainerProps}>
{platformOptions.map((option) => {
return (
<UnderlineNav.Link
key={option.id}
data-platform={option.id}
selected={option.id === currentPlatform}
onClick={() => {
onClickPlatform(option.id)
}}
>
{option.label}
</UnderlineNav.Link>
)
})}
</UnderlineNav>
)
}
return (
<TabNav {...sharedContainerProps}>
{platformOptions.map((option) => {
return (
<TabNav.Link
key={option.id}
data-platform={option.id}
as="button"
selected={option.id === currentPlatform}
onClick={() => {
onClickPlatform(option.id)
}}
>
{option.label}
</TabNav.Link>
)
})}
</TabNav>
)
}