Skip to content

Commit 686cf1c

Browse files
Ekwunolauragift21Cherry
authored
[Doc site]: Add tab switcher shortcode (#4861)
* Create shortcode for code switcher with initial slides * add tab switcher * update code sample * update components * update components and fix scrolling issue * update tabs component to remove SVG * update tags * Update static/style.css Co-authored-by: Gift Egwuenu <[email protected]> * fix hover issue * update * format tabs component * Fix responsiveness for tab labels * fix tab-label-wrapper hover effect * Call tabs higher up * Remove unnecessary overflow on code * add on load * update tab code * rename tabs wrapper * Fix extra padding under tabs-wrapper * add active tab styling * add active tab for dark mood * update lightmood colour * add upstream changes * add upstream changes * add svgs to tab labels * fix svg width * remove rounded corners code block * remove padding bottom from codeblock * fix hover color in light mood * add defult block with no js * switch default value to * remove outline from tab-headers * remove padding in media query * add responsiveness for smaller screens. * make svg clickable * add titles to SVG * remove shortcode from tutorial * Apply suggestions from code review Co-authored-by: James Ross <[email protected]> Co-authored-by: Gift Egwuenu <[email protected]> Co-authored-by: James Ross <[email protected]>
1 parent 07770ef commit 686cf1c

File tree

7 files changed

+1234
-457
lines changed

7 files changed

+1234
-457
lines changed

assets/events.ts

Lines changed: 95 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,26 @@ function $clickaway(ev: MouseEvent) {
88
}
99

1010
export function $focus(elem: HTMLElement, bool: boolean) {
11-
elem.toggleAttribute('is-focus-visible', bool);
11+
elem.toggleAttribute("is-focus-visible", bool);
1212
if (bool) elem.focus();
1313

1414
// if is topbar search input
1515
if (SEARCH_ID && SEARCH_ID.test(elem.id)) {
1616
SEARCH_INPUT = elem;
1717

18-
elem.parentElement.parentElement.toggleAttribute('is-focused', bool);
19-
elem.setAttribute('aria-expanded', '' + bool);
18+
elem.parentElement.parentElement.toggleAttribute("is-focused", bool);
19+
elem.setAttribute("aria-expanded", "" + bool);
2020

21-
if (bool) addEventListener('click', $clickaway);
22-
else removeEventListener('click', $clickaway);
21+
if (bool) addEventListener("click", $clickaway);
22+
else removeEventListener("click", $clickaway);
2323
}
2424
}
2525

2626
export function $tabbable(links: NodeListOf<Element>, bool: boolean) {
2727
for (let i = 0; i < links.length; i++) {
28-
bool ? links[i].removeAttribute('tabindex') : links[i].setAttribute('tabindex', '-1');
28+
bool
29+
? links[i].removeAttribute("tabindex")
30+
: links[i].setAttribute("tabindex", "-1");
2931
}
3032
}
3133

@@ -34,38 +36,43 @@ export function $tabbable(links: NodeListOf<Element>, bool: boolean) {
3436
export function load() {
3537
let hash = location.hash.substring(1);
3638
let item = hash && document.getElementById(hash);
37-
let timer = item && setInterval(() => {
38-
if (document.readyState !== 'complete') return;
39-
clearInterval(timer);
40-
setTimeout(() => {
41-
item.scrollIntoView({ behavior: 'smooth'});
42-
}, 250);
43-
}, 10);
39+
let timer =
40+
item &&
41+
setInterval(() => {
42+
if (document.readyState !== "complete") return;
43+
clearInterval(timer);
44+
setTimeout(() => {
45+
item.scrollIntoView({ behavior: "smooth" });
46+
}, 250);
47+
}, 10);
4448
}
4549

4650
// mobile sidebar toggle
4751
export function mobile() {
4852
let root = document.documentElement;
49-
let btn = document.querySelector('.DocsMobileTitleHeader--sidebar-toggle-button');
53+
let btn = document.querySelector(
54+
".DocsMobileTitleHeader--sidebar-toggle-button"
55+
);
5056
if (btn)
51-
btn.addEventListener('click', () => {
52-
root.toggleAttribute('is-mobile-sidebar-open');
57+
btn.addEventListener("click", () => {
58+
root.toggleAttribute("is-mobile-sidebar-open");
5359
});
5460

5561
// clicking on mobile search icon
5662
let input: HTMLInputElement =
57-
document.querySelector('#DocsSearch--input') || document.querySelector('#SiteSearch--input');
63+
document.querySelector("#DocsSearch--input") ||
64+
document.querySelector("#SiteSearch--input");
5865

5966
// register init handler
6067
if (input)
61-
input.addEventListener('click', () => {
68+
input.addEventListener("click", () => {
6269
$focus(input, true);
6370
});
6471
}
6572

6673
function $copy(ev: MouseEvent) {
67-
let btn = (ev.target as HTMLElement).closest('button');
68-
let txt = btn.getAttribute('data-clipboard');
74+
let btn = (ev.target as HTMLElement).closest("button");
75+
let txt = btn.getAttribute("data-clipboard");
6976
if (txt) {
7077
try {
7178
navigator.clipboard.writeText(txt);
@@ -76,32 +83,79 @@ function $copy(ev: MouseEvent) {
7683
}
7784

7885
export function copy() {
79-
let btns = document.querySelectorAll('button[data-clipboard]');
80-
for (let i = 0; i < btns.length; i++) btns[i].addEventListener('click', $copy);
86+
let btns = document.querySelectorAll("button[data-clipboard]");
87+
for (let i = 0; i < btns.length; i++)
88+
btns[i].addEventListener("click", $copy);
8189
}
8290

8391
// add focus attribute to activeElement if keyboard trigger
8492
export function focus() {
8593
let isTAB = false;
86-
addEventListener('keydown', ev => {
94+
addEventListener("keydown", (ev) => {
8795
isTAB = ev.which === 9;
8896
});
8997

90-
addEventListener('focusin', ev => {
98+
addEventListener("focusin", (ev) => {
9199
if (isTAB) $focus(ev.target as HTMLElement, true);
92100
});
93101

94-
addEventListener('focusout', ev => {
102+
addEventListener("focusout", (ev) => {
95103
$focus(ev.target as HTMLElement, false);
96104
});
97105
}
98106

107+
function $tab(ev: MouseEvent) {
108+
ev.preventDefault();
109+
110+
let tabs = document.querySelectorAll(".tab");
111+
112+
for (let i = 0; i < tabs.length; i++) {
113+
(tabs[i] as HTMLElement).style.display = "none";
114+
}
115+
116+
let target = ev.target;
117+
let link = (target as HTMLElement).getAttribute("data-link");
118+
119+
document.getElementById(link).style.display = "block";
120+
}
121+
122+
export function tabs() {
123+
// Find all tab wrappers
124+
let wrappers = document.querySelectorAll(".tabs-wrapper");
125+
126+
addEventListener("load", () => {
127+
for (let i = 0; i < wrappers.length; i++) {
128+
const labels = wrappers[i].querySelectorAll(".tab-label");
129+
const tabs = wrappers[i].querySelectorAll(".tab");
130+
131+
if (tabs.length > 0) {
132+
// Set the first tab in a group to display
133+
(tabs[0] as HTMLElement).style.display = "block";
134+
for (let i = 0; i < labels.length; i++)
135+
labels[i].addEventListener("click", $tab);
136+
}
137+
}
138+
});
139+
}
140+
141+
export function activeTab() {
142+
var header = document.getElementById("tab-active");
143+
var tabs = header.getElementsByClassName("tab-label");
144+
for (var i = 0; i < tabs.length; i++) {
145+
(tabs[i] as HTMLElement).addEventListener("click", function name() {
146+
let current = document.getElementsByClassName("active");
147+
current[0].className = current[0].className.replace(" active", "");
148+
this.className += " active";
149+
});
150+
}
151+
}
152+
99153
export function dropdowns() {
100-
let attr = 'data-expanded';
154+
let attr = "data-expanded";
101155

102-
document.querySelectorAll('.Dropdown').forEach(div => {
103-
let btn = div.querySelector('button');
104-
let links = div.querySelectorAll<HTMLAnchorElement>('li>a');
156+
document.querySelectorAll(".Dropdown").forEach((div) => {
157+
let btn = div.querySelector("button");
158+
let links = div.querySelectorAll<HTMLAnchorElement>("li>a");
105159
let focused = 0; // index
106160

107161
if (btn && links.length > 0) {
@@ -125,37 +179,37 @@ export function dropdowns() {
125179
$focus(links[focused], true);
126180
};
127181

128-
let close: EventListener = ev => {
182+
let close: EventListener = (ev) => {
129183
ev.stopPropagation();
130-
removeEventListener('click', close);
184+
removeEventListener("click", close);
131185

132186
// tab-inactive sublinks
133187
$tabbable(links, false);
134188

135-
div.setAttribute(attr, 'false');
136-
btn.setAttribute(attr, 'false');
189+
div.setAttribute(attr, "false");
190+
btn.setAttribute(attr, "false");
137191

138-
div.removeEventListener('keydown', arrows);
192+
div.removeEventListener("keydown", arrows);
139193
};
140194

141-
let open: EventListener = ev => {
195+
let open: EventListener = (ev) => {
142196
ev.stopPropagation();
143-
addEventListener('click', close);
197+
addEventListener("click", close);
144198

145199
// tab-friendly sublinks
146200
$tabbable(links, true);
147201

148-
div.setAttribute(attr, 'true');
149-
btn.setAttribute(attr, 'true');
202+
div.setAttribute(attr, "true");
203+
btn.setAttribute(attr, "true");
150204

151205
// focus the first link
152206
$focus(links[(focused = 0)], true);
153207

154-
div.addEventListener('keydown', arrows);
208+
div.addEventListener("keydown", arrows);
155209
};
156210

157-
btn.addEventListener('click', ev => {
158-
if (div.getAttribute(attr) === 'true') {
211+
btn.addEventListener("click", (ev) => {
212+
if (div.getAttribute(attr) === "true") {
159213
close(ev);
160214
} else {
161215
open(ev);

assets/main.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import * as events from './events';
2-
import * as contents from './contents';
3-
import * as timeago from './timeago';
4-
import * as navs from './navlinks';
1+
import * as events from "./events";
2+
import * as contents from "./contents";
3+
import * as timeago from "./timeago";
4+
import * as navs from "./navlinks";
55

66
declare global {
77
interface Window {
@@ -14,12 +14,12 @@ declare global {
1414
(function () {
1515
navs.init();
1616
timeago.init();
17-
1817
events.load();
1918
events.focus();
2019
events.mobile();
2120
events.dropdowns();
2221
events.copy();
23-
22+
events.activeTab();
2423
contents.toc();
24+
events.tabs();
2525
})();

content/pages/tutorials/forms/index.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,6 @@ Technically, only the `<form>` and its child elements are necessary. The `<head>
195195
The HTML page is also completely unstyled at this point, relying on the browsers' default UI and color palettes. Styling the page is entirely optional and not necessary for the form to function. If you would like to attach a CSS stylesheet, you may [add a `<link>` element](https://developer.mozilla.org/en-US/docs/Learn/CSS/First_steps/Getting_started#adding_css_to_our_document). Refer to the finished tutorial's [source code](https://github.com/cloudflare/submit.pages.dev/blob/8c0594f48681935c268987f2f08bcf3726a74c57/public/index.html#L11) for an example or any inspiration – the only requirement is that your CSS stylesheet also resides within the `public` directory.
196196

197197
{{</Aside>}}
198-
199198
### Worker
200199

201200
The HTML form is complete and ready for deployment. When the user submits this form, all data will be sent in a `POST` request to the `/api/submit` URL. This is due to the form's `method` and `action` attributes. However, there is currently no request handler at the `/api/submit` address. You will now create it.

layouts/shortcodes/tab.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{{- $label := replace (.Get "label") "/" "-"}}
2+
{{- $default := .Get "default"
3+
-}}
4+
5+
{{ if eq $default "true"}}
6+
<div class="tab tab-default" id="tab-js-sw">{{ $.Inner | markdownify }}</div>
7+
{{ else }}
8+
<div class="tab" id="tab-{{$label}}">{{ $.Inner | markdownify }}</div>
9+
{{ end }}

layouts/shortcodes/tabs.html

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{{- $text := .Get "labels" -}} {{- $labels := split $text " | " -}}
2+
3+
<div class="tabs-wrapper">
4+
<nav role="navigation" class="tabs">
5+
<ul id="tab-active">
6+
{{ range $idx, $txt := $labels }} {{- $link := replace $txt "/" "-"}}
7+
<li class="tab-label-wrapper " >
8+
{{ if or (eq $link "js-sw") }}
9+
<a class="tab-label active" href="#" data-link="tab-{{$link}}">
10+
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" height="1em" width="1em"
11+
xmlns="http://www.w3.org/2000/svg" data-link="tab-{{$link}}">
12+
<title>JavaScript</title>
13+
<path
14+
d="M32 32v448h448V32zm240 348c0 43.61-25.76 64.87-63.05 64.87-33.68 0-53.23-17.44-63.15-38.49l34.28-20.75c6.61 11.73 11.63 21.65 26.06 21.65 12 0 21.86-5.41 21.86-26.46V240h44zm99.35 63.87c-39.09 0-64.35-17.64-76.68-42L329 382c9 14.74 20.75 24.56 41.5 24.56 17.44 0 27.57-7.72 27.57-19.75 0-14.43-10.43-19.54-29.68-28l-10.52-4.52c-30.38-12.92-50.52-29.16-50.52-63.45 0-31.57 24.05-54.63 61.64-54.63 26.77 0 46 8.32 59.85 32.68L396 290c-7.22-12.93-15-18-27.06-18-12.33 0-20.15 7.82-20.15 18 0 12.63 7.82 17.74 25.86 25.56l10.52 4.51c35.79 15.34 55.94 31 55.94 66.16.01 37.9-29.76 57.64-69.76 57.64z" data-link="tab-{{$link}}">
15+
</path>
16+
</svg> Service Workers</a
17+
>
18+
19+
{{ else if (eq $link "ts-sw") }}
20+
<a class="tab-label" href="#" data-link="tab-{{$link}}">
21+
<svg stroke="currentColor" fill="currentColor" stroke-width="0" role="img" viewBox="0 0 24 24" height="1em" width="1em"
22+
xmlns="http://www.w3.org/2000/svg" data-link="tab-{{$link}}">
23+
<title>TypeScript</title>
24+
<path
25+
d="M1.125 0C.502 0 0 .502 0 1.125v21.75C0 23.498.502 24 1.125 24h21.75c.623 0 1.125-.502 1.125-1.125V1.125C24 .502 23.498 0 22.875 0zm17.363 9.75c.612 0 1.154.037 1.627.111a6.38 6.38 0 0 1 1.306.34v2.458a3.95 3.95 0 0 0-.643-.361 5.093 5.093 0 0 0-.717-.26 5.453 5.453 0 0 0-1.426-.2c-.3 0-.573.028-.819.086a2.1 2.1 0 0 0-.623.242c-.17.104-.3.229-.393.374a.888.888 0 0 0-.14.49c0 .196.053.373.156.529.104.156.252.304.443.444s.423.276.696.41c.273.135.582.274.926.416.47.197.892.407 1.266.628.374.222.695.473.963.753.268.279.472.598.614.957.142.359.214.776.214 1.253 0 .657-.125 1.21-.373 1.656a3.033 3.033 0 0 1-1.012 1.085 4.38 4.38 0 0 1-1.487.596c-.566.12-1.163.18-1.79.18a9.916 9.916 0 0 1-1.84-.164 5.544 5.544 0 0 1-1.512-.493v-2.63a5.033 5.033 0 0 0 3.237 1.2c.333 0 .624-.03.872-.09.249-.06.456-.144.623-.25.166-.108.29-.234.373-.38a1.023 1.023 0 0 0-.074-1.089 2.12 2.12 0 0 0-.537-.5 5.597 5.597 0 0 0-.807-.444 27.72 27.72 0 0 0-1.007-.436c-.918-.383-1.602-.852-2.053-1.405-.45-.553-.676-1.222-.676-2.005 0-.614.123-1.141.369-1.582.246-.441.58-.804 1.004-1.089a4.494 4.494 0 0 1 1.47-.629 7.536 7.536 0 0 1 1.77-.201zm-15.113.188h9.563v2.166H9.506v9.646H6.789v-9.646H3.375z" data-link="tab-{{$link}}">
26+
</path>
27+
28+
</svg>Service Workers</a
29+
>
30+
31+
{{ end }} {{ if or (eq $link "js-esm") }}
32+
<a class="tab-label " href="#" data-link="tab-{{$link}}">
33+
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" height="1em" width="1em"
34+
xmlns="http://www.w3.org/2000/svg" data-link="tab-{{$link}}">
35+
<title>JavaScript</title>
36+
<path
37+
d="M32 32v448h448V32zm240 348c0 43.61-25.76 64.87-63.05 64.87-33.68 0-53.23-17.44-63.15-38.49l34.28-20.75c6.61 11.73 11.63 21.65 26.06 21.65 12 0 21.86-5.41 21.86-26.46V240h44zm99.35 63.87c-39.09 0-64.35-17.64-76.68-42L329 382c9 14.74 20.75 24.56 41.5 24.56 17.44 0 27.57-7.72 27.57-19.75 0-14.43-10.43-19.54-29.68-28l-10.52-4.52c-30.38-12.92-50.52-29.16-50.52-63.45 0-31.57 24.05-54.63 61.64-54.63 26.77 0 46 8.32 59.85 32.68L396 290c-7.22-12.93-15-18-27.06-18-12.33 0-20.15 7.82-20.15 18 0 12.63 7.82 17.74 25.86 25.56l10.52 4.51c35.79 15.34 55.94 31 55.94 66.16.01 37.9-29.76 57.64-69.76 57.64z" data-link="tab-{{$link}}">
38+
</path>
39+
40+
</svg> ES Modules</a
41+
>
42+
43+
{{ else if (eq $link "ts-esm") }}
44+
<a class="tab-label" href="#" data-link="tab-{{$link}}">
45+
<svg stroke="currentColor" fill="currentColor" stroke-width="0" role="img" viewBox="0 0 24 24" height="1em" width="1em"
46+
xmlns="http://www.w3.org/2000/svg" data-link="tab-{{$link}}">
47+
<title>TypeScript</title>
48+
<path
49+
d="M1.125 0C.502 0 0 .502 0 1.125v21.75C0 23.498.502 24 1.125 24h21.75c.623 0 1.125-.502 1.125-1.125V1.125C24 .502 23.498 0 22.875 0zm17.363 9.75c.612 0 1.154.037 1.627.111a6.38 6.38 0 0 1 1.306.34v2.458a3.95 3.95 0 0 0-.643-.361 5.093 5.093 0 0 0-.717-.26 5.453 5.453 0 0 0-1.426-.2c-.3 0-.573.028-.819.086a2.1 2.1 0 0 0-.623.242c-.17.104-.3.229-.393.374a.888.888 0 0 0-.14.49c0 .196.053.373.156.529.104.156.252.304.443.444s.423.276.696.41c.273.135.582.274.926.416.47.197.892.407 1.266.628.374.222.695.473.963.753.268.279.472.598.614.957.142.359.214.776.214 1.253 0 .657-.125 1.21-.373 1.656a3.033 3.033 0 0 1-1.012 1.085 4.38 4.38 0 0 1-1.487.596c-.566.12-1.163.18-1.79.18a9.916 9.916 0 0 1-1.84-.164 5.544 5.544 0 0 1-1.512-.493v-2.63a5.033 5.033 0 0 0 3.237 1.2c.333 0 .624-.03.872-.09.249-.06.456-.144.623-.25.166-.108.29-.234.373-.38a1.023 1.023 0 0 0-.074-1.089 2.12 2.12 0 0 0-.537-.5 5.597 5.597 0 0 0-.807-.444 27.72 27.72 0 0 0-1.007-.436c-.918-.383-1.602-.852-2.053-1.405-.45-.553-.676-1.222-.676-2.005 0-.614.123-1.141.369-1.582.246-.441.58-.804 1.004-1.089a4.494 4.494 0 0 1 1.47-.629 7.536 7.536 0 0 1 1.77-.201zm-15.113.188h9.563v2.166H9.506v9.646H6.789v-9.646H3.375z" data-link="tab-{{$link}}">
50+
</path>
51+
</svg>ES Modules</a
52+
>
53+
54+
{{ end }}
55+
</li>
56+
{{ end }}
57+
</ul>
58+
</nav>
59+
60+
{{ .Inner }}
61+
</div>

static/javascript.svg

Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)