forked from github/docs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathToolPicker.tsx
124 lines (108 loc) · 4.38 KB
/
ToolPicker.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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import { useEffect, useState } from 'react'
import { useRouter } from 'next/router'
import Cookies from 'js-cookie'
import { UnderlineNav } from '@primer/react'
import { sendEvent, EventType } from 'components/lib/events'
import { preserveAnchorNodePosition } from 'scroll-anchoring'
import { useArticleContext } from 'components/context/ArticleContext'
// example: http://localhost:4000/en/codespaces/developing-in-codespaces/creating-a-codespace
// Nota bene: tool === application
// Nota bene: picker === switcher
// Imperatively modify article content to show only the selected tool
// find all platform-specific *block* elements and hide or show as appropriate
// example: {% webui %} block content {% endwebui %}
function showToolSpecificContent(tool: string, supportedTools: Array<string>) {
const markdowns = Array.from(document.querySelectorAll<HTMLElement>('.extended-markdown'))
markdowns
.filter((el) => supportedTools.some((tool) => el.classList.contains(tool)))
.forEach((el) => {
el.style.display = el.classList.contains(tool) ? '' : 'none'
})
// find all tool-specific *inline* elements and hide or show as appropriate
// example: <span class="tool-webui">inline content</span>
const toolEls = Array.from(
document.querySelectorAll<HTMLElement>(supportedTools.map((tool) => `.tool-${tool}`).join(', '))
)
toolEls.forEach((el) => {
el.style.display = el.classList.contains(`tool-${tool}`) ? '' : 'none'
})
}
function getDefaultTool(defaultTool: string | undefined, detectedTools: Array<string>): string {
// If there is a default tool and the tool is present on this page
if (defaultTool && detectedTools.includes(defaultTool)) return defaultTool
// Default to webui if present (this is generally the case where we show UI/CLI/Desktop info)
if (detectedTools.includes('webui')) return 'webui'
// Default to cli if present (this is generally the case where we show curl/CLI info)
if (detectedTools.includes('cli')) return 'cli'
// Otherwise, just choose the first detected tool
return detectedTools[0]
}
type Props = {
variant?: 'subnav' | 'tabnav' | 'underlinenav'
}
export const ToolPicker = ({ variant = 'subnav' }: Props) => {
const { asPath } = useRouter()
// allTools comes from the ArticleContext which contains the list of tools available
const { defaultTool, detectedTools, allTools } = useArticleContext()
const [currentTool, setCurrentTool] = useState(getDefaultTool(defaultTool, detectedTools))
const sharedContainerProps = {
'data-testid': 'tool-picker',
'aria-label': 'Tool picker',
'data-default-tool': defaultTool,
className: 'mb-4',
}
// Run on mount for client-side only features
useEffect(() => {
// If the user selected a tool preference and the tool is present on this page
// Has to be client-side only for cookie reading
const cookieValue = Cookies.get('toolPreferred')
if (cookieValue && detectedTools.includes(cookieValue)) {
setCurrentTool(cookieValue)
}
}, [])
// Whenever the currentTool is changed, update the article content
useEffect(() => {
preserveAnchorNodePosition(document, () => {
showToolSpecificContent(currentTool, Object.keys(allTools))
})
}, [currentTool, asPath])
function onClickTool(tool: string) {
setCurrentTool(tool)
sendEvent({
type: EventType.preference,
preference_name: 'application',
preference_value: tool,
})
Cookies.set('toolPreferred', tool, { sameSite: 'strict', secure: true })
}
if (variant === 'underlinenav') {
return (
<UnderlineNav {...sharedContainerProps}>
{detectedTools.map((tool) => (
<UnderlineNav.Link
key={tool}
data-tool={tool}
as="button"
selected={tool === currentTool}
// Temporary fix: This should be removed when this merges: PR 24123
sx={{
color: 'var(--color-fg-default)',
'&.selected': { color: 'var(--color-fg-default)' },
':hover': { color: 'var(--color-fg-default)' },
':focus': {
color: 'var(--color-fg-default)',
outline: '-webkit-focus-ring-color auto 1px;',
},
}}
onClick={() => {
onClickTool(tool)
}}
>
{allTools[tool]}
</UnderlineNav.Link>
))}
</UnderlineNav>
)
}
return null
}