-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
SiteFooter-PlaygroundSamples.tsx
151 lines (122 loc) · 5.38 KB
/
SiteFooter-PlaygroundSamples.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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import React, { useEffect } from "react"
// @ts-ignore - TODO: This could prove troublesome in the future - perhaps it could be grabbed in the GraphQL?
import english from "../../../../playground-examples/generated/en"
interface Props {
lang: string
}
interface SamplesJSON {
sections: { name: string, subtitle: string }[]
sortedSubSections: string[]
examples: { path: string, title: string, name: string, id: string, sortIndex: number, hash: string, compilerSettings: any }[]
}
type Example = SamplesJSON["examples"][0]
const sortedSectionsDictionary = (locale: SamplesJSON, sectionName: string) => {
const sectionDict = {}
locale.examples.forEach(e => {
// Allow switching a "-" to "." so that titles can have
// a dot for version numbers, this own works once.
if (e.path[0] !== sectionName.replace(".", "-")) return;
if (sectionDict[e.path[1]]) {
sectionDict[e.path[1]].push(e)
} else {
sectionDict[e.path[1]] = [e]
}
})
return sectionDict
}
const hrefForExample = (example: Example) => {
const isJS = example.name.indexOf(".js") !== -1
const prefix = isJS ? "useJavaScript=true" : ""
const hash = "example/" + example.id
const params = example.compilerSettings || {}
const queryParams = Object.keys(params).map(key => key + '=' + params[key]).join('&');
return `/play/?${prefix + queryParams}#${hash}`
}
const buttonOnClick = (e) => {
const tappedButton = e.target
const contentID = tappedButton.textContent.toLowerCase()
const allSectionTitles = document.querySelectorAll(".section-name")
for (const title of allSectionTitles) { title.classList.remove("selected") }
tappedButton.classList.add("selected")
const allSections = document.querySelectorAll<HTMLElement>(".section-content")
for (const section of allSections) {
section.style.display = "none"
section.classList.remove("selected")
}
const sectionForButton = document.getElementById(contentID)
sectionForButton.style.display = "flex"
sectionForButton.classList.add("selected")
if (e && e.stopPropagation) {
e.stopPropagation()
}
}
export const PlaygroundSamples = (props: Props) => {
const locale = english as SamplesJSON
const defaultSection = "TypeScript"
// This ensures that the popover only becomes available when JS is enabled
useEffect(() => {
// Only allow hoving on wider windows
const allowHover = window.innerWidth > 900
if (!allowHover) return
// Visually enable the popover icon
const iconSpan = document.getElementsByClassName("footer-icon")[0] as HTMLElement
iconSpan.style.display = "inline-block"
// This is all that is needed for the mouse hover
for (const element of document.getElementsByClassName("popover-container")){
element.classList.add("allow-hover")
}
// This is used to handle tabbing
const showPopover = () => {
const popover = document.getElementById("playground-samples-popover")
popover.style.visibility = "visible"
popover.style.opacity = "1"
// When the popover is up, allow tabbing through all of the items to hide the popover
popover.addEventListener("blur", (e) => {
const element = e.relatedTarget as HTMLElement
if (!element || element.tagName === "A" && !element.classList.contains("example-link")) {
popover.style.visibility = "hidden"
}
}, true);
}
const triggerAnchor = document.getElementById("popover-trigger-anchor")
triggerAnchor.onfocus = showPopover
});
return (
<div id="playground-samples-popover">
<div className="examples">
<ol>
{locale.sections.map(section => {
const startOpen = section.name === defaultSection
const selectedClass = startOpen ? " selected" : ""
return <li key={section.name}><button onClick={buttonOnClick} className={"section-name button" + selectedClass} >{section.name}</button></li>
}
)}
</ol>
{locale.sections.map(section => {
const sectionDict = sortedSectionsDictionary(locale, section.name)
const subsectionNames = Object.keys(sectionDict).sort((lhs, rhs) => locale.sortedSubSections.indexOf(lhs) - locale.sortedSubSections.indexOf(rhs))
const startOpen = section.name === defaultSection
const style = startOpen ? {} : { display: "none" }
return <div key={section.name} id={section.name.toLowerCase()} className="section-content" style={style}>
<p style={{ width: "100%" }} dangerouslySetInnerHTML={{ __html: section.subtitle}}/>
{subsectionNames.map(sectionName => {
const sectionExamples = sectionDict[sectionName].sort((lhs, rhs) => lhs.sortIndex - rhs.sortIndex) as Example[]
return <div className="section-list" key={sectionName}>
<h4>{sectionName}</h4>
<ol>
{sectionExamples.map(example => {
return (
<li key={example.id}>
<a className="example-link" title={"Open the example: " + example.title} href={hrefForExample(example)}>{example.title}</a>
<div className="example-indicator" data-id={example.title} data-hash={example.hash}></div>
</li>)
})}
</ol>
</div>
})}
</div>
})}
</div>
<div className="arrow-down" />
</div>)
}