From 296a6b722fd37b210d897e203bdcecb70ab7b0c3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pawe=C5=82=20Zieli=C5=84ski?=
Date: Wed, 11 Sep 2024 15:16:35 +0200
Subject: [PATCH 1/2] [TASK]: Add all-documentation-menu WebComponent
---
.../assets/js/all-documentations-menu.js | 239 ++++++++++++++++++
.../components/_allDocumentationMenu.scss | 125 +++++++++
.../assets/sass/layout/_structure.scss | 14 +
.../typo3-docs-theme/assets/sass/theme.scss | 1 +
.../resources/public/css/theme.css | 125 +++++++++
.../resources/public/js/theme.min.js | 10 +-
.../layoutParts/pageHeader.html.twig | 31 ++-
7 files changed, 526 insertions(+), 19 deletions(-)
create mode 100644 packages/typo3-docs-theme/assets/js/all-documentations-menu.js
create mode 100644 packages/typo3-docs-theme/assets/sass/components/_allDocumentationMenu.scss
diff --git a/packages/typo3-docs-theme/assets/js/all-documentations-menu.js b/packages/typo3-docs-theme/assets/js/all-documentations-menu.js
new file mode 100644
index 000000000..ebf5f0b2b
--- /dev/null
+++ b/packages/typo3-docs-theme/assets/js/all-documentations-menu.js
@@ -0,0 +1,239 @@
+// mock up for presentation purposes - should be replaced with real data
+const exampleDocumentationsJson = JSON.stringify([
+ {
+ name: 'References',
+ href: '#',
+ children: [
+ { name: 'Changelog', href: '#', versions: [ { name: 'main', href: '#' }, { name: '12.4', href: '#' }, { name: '11.5', href: '#' } ] },
+ { name: 'TYPO3 Explained', href: '#', versions: [ { name: 'main', href: '#' }, { name: '12.4', href: '#' }, { name: '11.5', href: '#' } ] },
+ { name: 'TCA Reference', href: '#', versions: [ { name: 'main', href: '#' }, { name: '12.4', href: '#' }, { name: '11.5', href: '#' } ] },
+ { name: 'TypoScript Reference', href: '#', versions: [ { name: 'main', href: '#' }, { name: '12.4', href: '#' }, { name: '11.5', href: '#' } ] },
+ { name: 'TSConfig Reference', href: '#', versions: [ { name: 'main', href: '#' }, { name: '12.4', href: '#' }, { name: '11.5', href: '#' } ] },
+ { name: 'ViewHelper Reference', href: '#', versions: [ { name: 'main', href: '#' }, { name: '12.4', href: '#' }, { name: '11.5', href: '#' } ] },
+ ]
+ },
+ {
+ name: 'Guides',
+ href: '#',
+ children: [
+ { name: 'Getting started', href: '#', versions: [ { name: 'main', href: '#' }, { name: '12.4', href: '#' }, { name: '11.5', href: '#' } ] },
+ { name: 'Localization', href: '#', versions: [ { name: 'main', href: '#' }, { name: '12.4', href: '#' }, { name: '11.5', href: '#' } ] },
+ { name: 'Upgrade Guide', href: '#', versions: [ { name: 'main', href: '#' }, { name: '12.4', href: '#' }, { name: '11.5', href: '#' } ] },
+ { name: 'Editors Guide', href: '#', versions: [ { name: 'main', href: '#' }, { name: '12.4', href: '#' }, { name: '11.5', href: '#' } ] },
+ { name: 'Exceptions', href: '#', versions: [ { name: 'main', href: '#' }, { name: '12.4', href: '#' }, { name: '11.5', href: '#' } ] },
+ ]
+ },
+ {
+ name: 'Tutorials',
+ href: '#',
+ children: [
+ { name: 'Sitepackage Tutorial', href: '#', versions: [ { name: 'main', href: '#' }, { name: '12.4', href: '#' }, { name: '11.5', href: '#' } ] },
+ { name: 'TypoScript Tutorial', href: '#', versions: [ { name: 'main', href: '#' }, { name: '12.4', href: '#' }, { name: '11.5', href: '#' } ] },
+ ]
+ },
+ {
+ name: 'System Extensions',
+ href: '#',
+ children: [
+ { name: 'Adminpanel', href: '#', versions: [ { name: 'main', href: '#' }, { name: '12.4', href: '#' }, { name: '11.5', href: '#' } ] },
+ { name: 'SEO', href: '#', versions: [ { name: 'main', href: '#' }, { name: '12.4', href: '#' }, { name: '11.5', href: '#' } ] },
+ ]
+ },
+ {
+ name: 'Third Party Extensions',
+ href: '#',
+ },
+ {
+ name: 'Contribution',
+ href: '#',
+ children: [
+ { name: 'Core', href: '#' },
+ { name: 'Documentation', href: '#' },
+ { name: 'typo3.org', href: '#' },
+ ]
+ },
+])
+
+class AllDocumentationMenu extends HTMLElement {
+ constructor() {
+ super();
+ this.data = this.initializeDocumentationsData();
+
+ this.classList.add('all-documentations-menu')
+
+ this.mainButton = this.createMainButton('All documentations');
+ this.tooltip = this.createTooltip();
+
+ this.appendChild(this.mainButton);
+ this.appendChild(this.tooltip);
+
+ this.popperInstance = null;
+
+ this.mainButton.addEventListener('click', (event) => {
+ event.stopPropagation();
+ this.toggleTooltip();
+ });
+
+ // hide popup on outside click
+ document.addEventListener('click', (event) => {
+ if (!this.tooltip.hasAttribute('data-show')) {
+ return;
+ }
+
+ if (event.target?.closest('.all-documentations-menu-tooltip')) {
+ return
+ }
+
+ this.hideTooltip();
+ })
+ }
+
+ initializeDocumentationsData() {
+ // replace with real data
+ return JSON.parse(exampleDocumentationsJson)
+ }
+
+ createClassName(name) {
+ return `all-documentations-menu-${name}`;
+ }
+
+ /** Button */
+
+ createMainButton(text) {
+ const element = document.createElement('button')
+ element.classList.add(
+ 'btn', 'btn-light',
+ this.createClassName('button'),
+ );
+ element.innerHTML = text;
+
+ const icon = document.createElement('i');
+ icon.classList.add('fa-solid', 'fa-bars');
+ element.prepend(icon);
+
+ return element;
+ }
+
+ /** Documentations popup */
+
+ createDocumentationCategoryHeader(text, href) {
+ let headerElement;
+ if (href) {
+ headerElement = document.createElement('a');
+ headerElement.setAttribute('href', href)
+ } else {
+ headerElement = document.createElement('div')
+ }
+
+ headerElement.classList.add(this.createClassName('category-header'))
+ headerElement.innerHTML = text;
+
+ return headerElement;
+ }
+
+ createDocumentationVersionBadge(version) {
+ const element = document.createElement('a');
+ element.setAttribute('href', version.href)
+ element.innerHTML = version.name;
+ return element;
+ }
+
+ createDocumentationLink(documentation) {
+ const listItemElement = document.createElement('li');
+ const anchorElement = document.createElement('a');
+ anchorElement.setAttribute('href', documentation.href);
+ anchorElement.innerHTML = documentation.name;
+
+ listItemElement.appendChild(anchorElement);
+
+ if (!documentation.versions || !documentation.versions.length) {
+ return listItemElement;
+ }
+
+ const versionsElement = document.createElement('div');
+ versionsElement.classList.add(this.createClassName('versions'));
+
+ for (const version of documentation.versions) {
+ versionsElement.appendChild(this.createDocumentationVersionBadge(version))
+ }
+
+ listItemElement.appendChild(versionsElement);
+
+ return listItemElement;
+ }
+
+ createDocumentationCategory(category) {
+ const section = document.createElement('div');
+ section.classList.add('category');
+
+ const header = this.createDocumentationCategoryHeader(category.name, category.href);
+ section.appendChild(header);
+
+ if (!category.children || !category.children.length) {
+ return section;
+ }
+
+ const docsListElement = document.createElement('ul');
+ docsListElement.classList.add(this.createClassName('documentations'))
+
+ for (const child of category.children) {
+ docsListElement.appendChild(this.createDocumentationLink(child));
+ }
+
+ section.appendChild(docsListElement);
+
+ return section;
+ }
+
+ createTooltip() {
+ const element = document.createElement('div');
+ element.classList.add(this.createClassName('tooltip'));
+ element.setAttribute('role', 'topoltip');
+
+ const arrowElement = document.createElement('div');
+ arrowElement.classList.add(this.createClassName('tooltip-arrow'));
+ arrowElement.setAttribute('data-popper-arrow', '')
+ element.appendChild(arrowElement);
+
+ const categoriesElement = document.createElement('div');
+ categoriesElement.classList.add(this.createClassName('categories'));
+
+ for (const category of this.data) {
+ categoriesElement.appendChild(this.createDocumentationCategory(category));
+ }
+
+ element.appendChild(categoriesElement);
+
+ return element;
+ }
+
+ toggleTooltip() {
+ if (this.tooltip.hasAttribute('data-show')) {
+ this.hideTooltip();
+ } else {
+ this.showTooltip();
+ }
+ }
+
+ showTooltip() {
+ this.tooltip.setAttribute('data-show', '');
+
+ this.popperInstance = Popper.createPopper(this.mainButton, this.tooltip, {
+ placement: 'bottom',
+ modifiers: [
+ { name: 'arrow' },
+ { name: 'offset', options: { offset: [0, 10] } }
+ ],
+ });
+ }
+
+ hideTooltip() {
+ this.tooltip.removeAttribute('data-show');
+ if (this.popperInstance) {
+ this.popperInstance.destroy();
+ this.popperInstance = null;
+ }
+ }
+}
+
+customElements.define('all-documentations-menu', AllDocumentationMenu)
diff --git a/packages/typo3-docs-theme/assets/sass/components/_allDocumentationMenu.scss b/packages/typo3-docs-theme/assets/sass/components/_allDocumentationMenu.scss
new file mode 100644
index 000000000..ac05fd206
--- /dev/null
+++ b/packages/typo3-docs-theme/assets/sass/components/_allDocumentationMenu.scss
@@ -0,0 +1,125 @@
+.all-documentations-menu {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ white-space: nowrap;
+
+ &-button {
+ display: flex;
+ align-items: center;
+ gap: 0.4em;
+ }
+
+ &-tooltip {
+ display: none;
+ border-radius: 0.6em;
+ background: white;
+ box-shadow: 0 6px 24px rgba(0, 0, 0, 0.25);
+ padding: 1.5em 2.5em;
+ border: 1px solid #eaeaea;
+ z-index: 50;
+
+ &[data-show] {
+ display: block;
+ }
+
+ &-arrow {
+ width: 1.2em;
+ height: 1.2em;
+ top: -0.2em;
+
+ &:before {
+ display: block;
+ content: '';
+ width: 100%;
+ height: 100%;
+ transform: rotateZ(45deg);
+ background-color: white;
+ }
+ }
+
+ @media screen and (max-width: 768px) {
+ padding: 1.5em;
+ }
+ }
+
+ &-categories {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 1em 2em;
+
+ @media screen and (max-width: 1200px) {
+ grid-template-columns: repeat(2, 1fr)
+ }
+
+ @media screen and (max-width: 768px) {
+ grid-template-columns: 1fr;
+ }
+ }
+
+ &-category {
+ &-header {
+ font-size: 1.1em;
+ font-weight: 700;
+ color: #333;
+ position: relative;
+ text-decoration: none;
+
+ &:before {
+ display: block;
+ content: '';
+ width: 0.2em;
+ height: 100%;
+ background: $primary;
+ position: absolute;
+ top: 0;
+ left: -0.6em;
+ }
+ }
+ }
+
+ a.all-documentations-menu-category-header {
+ &:hover, &:focus {
+ text-decoration: .1em underline;
+ }
+ }
+
+ &-documentations {
+ display: flex;
+ flex-direction: column;
+ gap: 0.2em;
+ list-style-type: none;
+ padding: 0.4em 0 0 0;
+
+ li {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ gap: 0.4em;
+
+ a:not(:hover):not(:focus) {
+ text-decoration: none;
+ }
+ }
+ }
+
+ &-versions {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 0.3em;
+
+ a {
+ background-color: $light;
+ padding: 0 5px;
+ font-size: 0.8em;
+ border-radius: 0.4em;
+ display: flex;
+ align-items: center;
+
+ &:first-child {
+ background-color: lighten($primary, 40%);
+ }
+ }
+ }
+}
diff --git a/packages/typo3-docs-theme/assets/sass/layout/_structure.scss b/packages/typo3-docs-theme/assets/sass/layout/_structure.scss
index 45fc850ce..e15562830 100644
--- a/packages/typo3-docs-theme/assets/sass/layout/_structure.scss
+++ b/packages/typo3-docs-theme/assets/sass/layout/_structure.scss
@@ -26,6 +26,20 @@
margin: 0 auto;
padding: 0 calc(#{$grid-gutter-width} / 2);
}
+.menu-search-wrapper {
+ display: flex;
+ align-items: center;
+ gap: 0.4em;
+
+ search {
+ flex-grow: 1;
+ }
+
+ @media screen and (max-width: 576px) {
+ flex-direction: column;
+ align-items: start;
+ }
+}
/**
* Main
diff --git a/packages/typo3-docs-theme/assets/sass/theme.scss b/packages/typo3-docs-theme/assets/sass/theme.scss
index 3c7f7e269..0f608c9a8 100644
--- a/packages/typo3-docs-theme/assets/sass/theme.scss
+++ b/packages/typo3-docs-theme/assets/sass/theme.scss
@@ -41,6 +41,7 @@
@import 'components/tabs';
@import 'components/textroles';
@import 'components/uml';
+@import 'components/allDocumentationMenu';
// Additional classes that can be applied by .. rst-class::
@import 'components/customClasses/bignums';
diff --git a/packages/typo3-docs-theme/resources/public/css/theme.css b/packages/typo3-docs-theme/resources/public/css/theme.css
index f0fd741f0..92eb68466 100644
--- a/packages/typo3-docs-theme/resources/public/css/theme.css
+++ b/packages/typo3-docs-theme/resources/public/css/theme.css
@@ -24800,6 +24800,116 @@ figure.uml-diagram {
overflow: scroll;
}
+.all-documentations-menu {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ white-space: nowrap;
+}
+.all-documentations-menu-button {
+ display: flex;
+ align-items: center;
+ gap: 0.4em;
+}
+.all-documentations-menu-tooltip {
+ display: none;
+ border-radius: 0.6em;
+ background: white;
+ box-shadow: 0 6px 24px rgba(0, 0, 0, 0.25);
+ padding: 1.5em 2.5em;
+ border: 1px solid #eaeaea;
+ z-index: 50;
+}
+.all-documentations-menu-tooltip[data-show] {
+ display: block;
+}
+.all-documentations-menu-tooltip-arrow {
+ width: 1.2em;
+ height: 1.2em;
+ top: -0.2em;
+}
+.all-documentations-menu-tooltip-arrow:before {
+ display: block;
+ content: "";
+ width: 100%;
+ height: 100%;
+ transform: rotateZ(45deg);
+ background-color: white;
+}
+@media screen and (max-width: 768px) {
+ .all-documentations-menu-tooltip {
+ padding: 1.5em;
+ }
+}
+.all-documentations-menu-categories {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 1em 2em;
+}
+@media screen and (max-width: 1200px) {
+ .all-documentations-menu-categories {
+ grid-template-columns: repeat(2, 1fr);
+ }
+}
+@media screen and (max-width: 768px) {
+ .all-documentations-menu-categories {
+ grid-template-columns: 1fr;
+ }
+}
+.all-documentations-menu-category-header {
+ font-size: 1.1em;
+ font-weight: 700;
+ color: #333;
+ position: relative;
+ text-decoration: none;
+}
+.all-documentations-menu-category-header:before {
+ display: block;
+ content: "";
+ width: 0.2em;
+ height: 100%;
+ background: #ff8700;
+ position: absolute;
+ top: 0;
+ left: -0.6em;
+}
+.all-documentations-menu a.all-documentations-menu-category-header:hover, .all-documentations-menu a.all-documentations-menu-category-header:focus {
+ text-decoration: 0.1em underline;
+}
+.all-documentations-menu-documentations {
+ display: flex;
+ flex-direction: column;
+ gap: 0.2em;
+ list-style-type: none;
+ padding: 0.4em 0 0 0;
+}
+.all-documentations-menu-documentations li {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ gap: 0.4em;
+}
+.all-documentations-menu-documentations li a:not(:hover):not(:focus) {
+ text-decoration: none;
+}
+.all-documentations-menu-versions {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 0.3em;
+}
+.all-documentations-menu-versions a {
+ background-color: #f2f2f2;
+ padding: 0 5px;
+ font-size: 0.8em;
+ border-radius: 0.4em;
+ display: flex;
+ align-items: center;
+}
+.all-documentations-menu-versions a:first-child {
+ background-color: #ffe7cc;
+}
+
/**
* Bignums
*/
@@ -25744,6 +25854,21 @@ a.toc-title-project:hover {
padding: 0 calc(40px / 2);
}
+.menu-search-wrapper {
+ display: flex;
+ align-items: center;
+ gap: 0.4em;
+}
+.menu-search-wrapper search {
+ flex-grow: 1;
+}
+@media screen and (max-width: 576px) {
+ .menu-search-wrapper {
+ flex-direction: column;
+ align-items: start;
+ }
+}
+
/**
* Main
*/
diff --git a/packages/typo3-docs-theme/resources/public/js/theme.min.js b/packages/typo3-docs-theme/resources/public/js/theme.min.js
index b5b9da2f9..30378054a 100644
--- a/packages/typo3-docs-theme/resources/public/js/theme.min.js
+++ b/packages/typo3-docs-theme/resources/public/js/theme.min.js
@@ -1,18 +1,18 @@
-(()=>{const a="code-block-hide";if(navigator.clipboard||navigator.clipboard.writeText){const o=e=>{var t=e.querySelector(".code-block-copy-icon"),o=e.querySelector(".code-block-check-icon"),e=e.querySelector(".code-block-check-tooltip");t.classList.toggle(a),o.classList.toggle(a),e.classList.toggle(a)};[...document.querySelectorAll(".code-block-copy")].forEach(e=>{e.addEventListener("click",e=>{const t=e.target.closest(".code-block-wrapper");e=t.querySelector(".code-block");e?(navigator.clipboard.writeText(e.textContent),o(t),setTimeout(()=>{o(t)},3e3)):console.warn("Cannot copy code as no code block is available!")})})}else console.info('"navigator.clipboard.writeText" is not available. Update to a modern browser to copy code to the system\'s clipboard')})(),[].slice.call(document.querySelectorAll(".code-inline[aria-description]")).map(function(e){var t=e.getAttribute("aria-description"),o=e.getAttribute("aria-details");return new bootstrap.Popover(e,{title:o?t:"",content:o||t,trigger:"hover",placement:"bottom"})}),(()=>{function n(a){const r=a.querySelector("#general-alert-success");var e=a.querySelectorAll(".copy-button");navigator.clipboard&&navigator.clipboard.writeText?e.forEach(e=>{e.addEventListener("click",function(){var e,t,o=this.getAttribute("data-target"),o=a.querySelector("#"+o);o?(r.classList.remove("d-none"),r.innerHTML=`Snippet ${e=o.value,t=document.createElement("div"),t.textContent=e,t.innerHTML}
was copied to your clipboard.`,navigator.clipboard.writeText(o.value)):console.warn("Cannot copy link as no input is available!")})}):(console.info('"navigator.clipboard.writeText" is not available. Update to a modern browser to copy code to the system\'s clipboard'),e.forEach(e=>e.disabled=!0))}const i=document.querySelector("#generalModal");i.addEventListener("show.bs.modal",function(e){var t,o,a,r,e=e.relatedTarget;e.dataset.composername&&(o=i.querySelector("#generalModalLabel"),t=i.querySelector("#generalModalContent"),o.innerText=e.dataset.composername,n(i),t.innerHTML=`
+const exampleDocumentationsJson=JSON.stringify([{name:"References",href:"#",children:[{name:"Changelog",href:"#",versions:[{name:"main",href:"#"},{name:"12.4",href:"#"},{name:"11.5",href:"#"}]},{name:"TYPO3 Explained",href:"#",versions:[{name:"main",href:"#"},{name:"12.4",href:"#"},{name:"11.5",href:"#"}]},{name:"TCA Reference",href:"#",versions:[{name:"main",href:"#"},{name:"12.4",href:"#"},{name:"11.5",href:"#"}]},{name:"TypoScript Reference",href:"#",versions:[{name:"main",href:"#"},{name:"12.4",href:"#"},{name:"11.5",href:"#"}]},{name:"TSConfig Reference",href:"#",versions:[{name:"main",href:"#"},{name:"12.4",href:"#"},{name:"11.5",href:"#"}]},{name:"ViewHelper Reference",href:"#",versions:[{name:"main",href:"#"},{name:"12.4",href:"#"},{name:"11.5",href:"#"}]}]},{name:"Guides",href:"#",children:[{name:"Getting started",href:"#",versions:[{name:"main",href:"#"},{name:"12.4",href:"#"},{name:"11.5",href:"#"}]},{name:"Localization",href:"#",versions:[{name:"main",href:"#"},{name:"12.4",href:"#"},{name:"11.5",href:"#"}]},{name:"Upgrade Guide",href:"#",versions:[{name:"main",href:"#"},{name:"12.4",href:"#"},{name:"11.5",href:"#"}]},{name:"Editors Guide",href:"#",versions:[{name:"main",href:"#"},{name:"12.4",href:"#"},{name:"11.5",href:"#"}]},{name:"Exceptions",href:"#",versions:[{name:"main",href:"#"},{name:"12.4",href:"#"},{name:"11.5",href:"#"}]}]},{name:"Tutorials",href:"#",children:[{name:"Sitepackage Tutorial",href:"#",versions:[{name:"main",href:"#"},{name:"12.4",href:"#"},{name:"11.5",href:"#"}]},{name:"TypoScript Tutorial",href:"#",versions:[{name:"main",href:"#"},{name:"12.4",href:"#"},{name:"11.5",href:"#"}]}]},{name:"System Extensions",href:"#",children:[{name:"Adminpanel",href:"#",versions:[{name:"main",href:"#"},{name:"12.4",href:"#"},{name:"11.5",href:"#"}]},{name:"SEO",href:"#",versions:[{name:"main",href:"#"},{name:"12.4",href:"#"},{name:"11.5",href:"#"}]}]},{name:"Third Party Extensions",href:"#"},{name:"Contribution",href:"#",children:[{name:"Core",href:"#"},{name:"Documentation",href:"#"},{name:"typo3.org",href:"#"}]}]);class AllDocumentationMenu extends HTMLElement{constructor(){super(),this.data=this.initializeDocumentationsData(),this.classList.add("all-documentations-menu"),this.mainButton=this.createMainButton("All documentations"),this.tooltip=this.createTooltip(),this.appendChild(this.mainButton),this.appendChild(this.tooltip),this.popperInstance=null,this.mainButton.addEventListener("click",e=>{e.stopPropagation(),this.toggleTooltip()}),document.addEventListener("click",e=>{!this.tooltip.hasAttribute("data-show")||e.target?.closest(".all-documentations-menu-tooltip")||this.hideTooltip()})}initializeDocumentationsData(){return JSON.parse(exampleDocumentationsJson)}createClassName(e){return"all-documentations-menu-"+e}createMainButton(e){var t=document.createElement("button"),e=(t.classList.add("btn","btn-light",this.createClassName("button")),t.innerHTML=e,document.createElement("i"));return e.classList.add("fa-solid","fa-bars"),t.prepend(e),t}createDocumentationCategoryHeader(e,t){let a;return t?(a=document.createElement("a")).setAttribute("href",t):a=document.createElement("div"),a.classList.add(this.createClassName("category-header")),a.innerHTML=e,a}createDocumentationVersionBadge(e){var t=document.createElement("a");return t.setAttribute("href",e.href),t.innerHTML=e.name,t}createDocumentationLink(e){var t=document.createElement("li"),a=document.createElement("a");if(a.setAttribute("href",e.href),a.innerHTML=e.name,t.appendChild(a),e.versions&&e.versions.length){var n=document.createElement("div");n.classList.add(this.createClassName("versions"));for(const r of e.versions)n.appendChild(this.createDocumentationVersionBadge(r));t.appendChild(n)}return t}createDocumentationCategory(e){var t=document.createElement("div"),a=(t.classList.add("category"),this.createDocumentationCategoryHeader(e.name,e.href));if(t.appendChild(a),e.children&&e.children.length){var n=document.createElement("ul");n.classList.add(this.createClassName("documentations"));for(const r of e.children)n.appendChild(this.createDocumentationLink(r));t.appendChild(n)}return t}createTooltip(){var e=document.createElement("div"),t=(e.classList.add(this.createClassName("tooltip")),e.setAttribute("role","topoltip"),document.createElement("div")),a=(t.classList.add(this.createClassName("tooltip-arrow")),t.setAttribute("data-popper-arrow",""),e.appendChild(t),document.createElement("div"));a.classList.add(this.createClassName("categories"));for(const n of this.data)a.appendChild(this.createDocumentationCategory(n));return e.appendChild(a),e}toggleTooltip(){this.tooltip.hasAttribute("data-show")?this.hideTooltip():this.showTooltip()}showTooltip(){this.tooltip.setAttribute("data-show",""),this.popperInstance=Popper.createPopper(this.mainButton,this.tooltip,{placement:"bottom",modifiers:[{name:"arrow"},{name:"offset",options:{offset:[0,10]}}]})}hideTooltip(){this.tooltip.removeAttribute("data-show"),this.popperInstance&&(this.popperInstance.destroy(),this.popperInstance=null)}}customElements.define("all-documentations-menu",AllDocumentationMenu),(()=>{const n="code-block-hide";if(navigator.clipboard||navigator.clipboard.writeText){const a=e=>{var t=e.querySelector(".code-block-copy-icon"),a=e.querySelector(".code-block-check-icon"),e=e.querySelector(".code-block-check-tooltip");t.classList.toggle(n),a.classList.toggle(n),e.classList.toggle(n)};[...document.querySelectorAll(".code-block-copy")].forEach(e=>{e.addEventListener("click",e=>{const t=e.target.closest(".code-block-wrapper");e=t.querySelector(".code-block");e?(navigator.clipboard.writeText(e.textContent),a(t),setTimeout(()=>{a(t)},3e3)):console.warn("Cannot copy code as no code block is available!")})})}else console.info('"navigator.clipboard.writeText" is not available. Update to a modern browser to copy code to the system\'s clipboard')})(),[].slice.call(document.querySelectorAll(".code-inline[aria-description]")).map(function(e){var t=e.getAttribute("aria-description"),a=e.getAttribute("aria-details");return new bootstrap.Popover(e,{title:a?t:"",content:a||t,trigger:"hover",placement:"bottom"})}),(()=>{function o(n){const r=n.querySelector("#general-alert-success");var e=n.querySelectorAll(".copy-button");navigator.clipboard&&navigator.clipboard.writeText?e.forEach(e=>{e.addEventListener("click",function(){var e,t,a=this.getAttribute("data-target"),a=n.querySelector("#"+a);a?(r.classList.remove("d-none"),r.innerHTML=`Snippet ${e=a.value,t=document.createElement("div"),t.textContent=e,t.innerHTML}
was copied to your clipboard.`,navigator.clipboard.writeText(a.value)):console.warn("Cannot copy link as no input is available!")})}):(console.info('"navigator.clipboard.writeText" is not available. Update to a modern browser to copy code to the system\'s clipboard'),e.forEach(e=>e.disabled=!0))}const i=document.querySelector("#generalModal");i.addEventListener("show.bs.modal",function(e){var t,a,n,r,e=e.relatedTarget;e.dataset.composername&&(a=i.querySelector("#generalModalLabel"),t=i.querySelector("#generalModalContent"),a.innerText=e.dataset.composername,o(i),t.innerHTML=`
${e.dataset.description}
Install the package using Composer:
- `,o="",e.dataset.source&&(r="Source","github.com"===(a=new URL(e.dataset.source)).hostname&&(r="GitHub"),"gitlab.com"===a.hostname&&(r="GitLab"),o+=`${r} `),e.dataset.issues&&(o+=`Report issue `),o&&(t.innerHTML+=`${o}
`),(a=i.querySelector("#generalModalCustomButtons")).innerHTML=`
+ `,a="",e.dataset.source&&(r="Source","github.com"===(n=new URL(e.dataset.source)).hostname&&(r="GitHub"),"gitlab.com"===n.hostname&&(r="GitLab"),a+=`${r} `),e.dataset.issues&&(a+=`Report issue `),a&&(t.innerHTML+=`${a}
`),(n=i.querySelector("#generalModalCustomButtons")).innerHTML=`
Packagist
- `,e.dataset.documentation&&(r="docs.typo3.org"!==new URL(e.dataset.documentation).hostname,a.innerHTML+=`
+ `,e.dataset.documentation&&(r="docs.typo3.org"!==new URL(e.dataset.documentation).hostname,n.innerHTML+=`
Documentation ${r?"(external)":""}
- `),e.dataset.homepage&&"extensions.typo3.org"===new URL(e.dataset.homepage).hostname&&(a.innerHTML+=`
+ `),e.dataset.homepage&&"extensions.typo3.org"===new URL(e.dataset.homepage).hostname&&(n.innerHTML+=`
TER
- `),n(i))})})(),(()=>{const s="#permalink-uri",c="#permalink-html";function d(a){const r=a.querySelector("#permalink-alert-success");var e=a.querySelectorAll(".copy-button");navigator.clipboard&&navigator.clipboard.writeText?e.forEach(e=>{e.addEventListener("click",function(){var e,t,o=this.getAttribute("data-target"),o=a.querySelector("#"+o);o?(r.classList.remove("d-none"),r.innerHTML=`Snippet ${e=o.value,t=document.createElement("div"),t.textContent=e,t.innerHTML}
was copied to your clipboard.`,navigator.clipboard.writeText(o.value)):console.warn("Cannot copy link as no input is available!")})}):(console.info('"navigator.clipboard.writeText" is not available. Update to a modern browser to copy code to the system\'s clipboard'),e.forEach(e=>e.disabled=!0))}const u=document.querySelector("#linkReferenceModal");u.addEventListener("show.bs.modal",function(e){var t,e=e.relatedTarget,o=e.closest("section"),a=e.dataset.id||(o?o.dataset.rstAnchor:null),r=e.closest("h1, h2, h3, h4, h5, h6, dt"),r=r?r.innerText:"",n=e.dataset.rstcode,e=e.title,i=(i=u,l=a||n,i=i.querySelector(".alert-permalink-rst"),l?i.classList.add("d-none"):i.classList.remove("d-none"),l=o,i=a,"null"===window.location.origin||"file://"===window.location.origin?null:i?""+window.location.origin+window.location.pathname+"#"+i:""+window.location.origin+window.location.pathname+"#"+(l?.id||"")),l=u.dataset.currentFilename,a=n||(n=u,o=o,t=r,a=a,l=l,n=n.dataset.interlinkShortcode||"somemanual",a?`:ref:\`${t} <${n}:${a}>\``:""===l?"":`:doc:\`${t} <${n}:${l}#${o?.id||""}>\``);t=u,n=r,l=i,o=a,(r=e)&&(t.querySelector("h5").innerHTML=r),null===l?(t.querySelector(s).value="",t.querySelector(c).value=""):(t.querySelector(s).value=l,t.querySelector(c).value=`${n} `),r=t.querySelector("#permalink-rst"),l=r.closest("div"),""===o?l.classList.add("d-none"):(l.classList.remove("d-none"),r.value=o),d(u)})})(),(()=>{"use strict";function o(e){e.preventDefault();const t=e.currentTarget.parentElement.parentElement;e=t.parentElement.parentElement.querySelectorAll("li.active");Array.from(e).forEach(e=>{e!==t&&e.classList.remove("active")}),t.classList.toggle("active")}var e;e=document.getElementsByClassName("main_menu"),Array.from(e).forEach(e=>{e=e.getElementsByTagName("a");Array.from(e).forEach(e=>{var t;e.nextSibling&&((t=document.createElement("span")).classList.add("toctree-expand"),t.addEventListener("click",o,!0),e.prepend(t))})})})(),window.addEventListener("load",()=>{var e,t,o=window.location.pathname.match(/^\/(c|m|p|h|other)\/[A-Za-z0-9\-_]+\/[A-Za-z0-9\-_]+\/[A-Za-z0-9\-.]+\/[A-Za-z0-9\-]+\/(Changelog\/[A-Za-z0-9\-.]+\/)?/),o=o?o[0]:null;o&&(e=document.getElementById("searchscope"),(t=document.createElement("option")).value=o,t.text="Search current",e.add(t))}),(()=>{"use strict";const e=Array.from(document.querySelectorAll('.nav-item > [role="tab"]'));function n(e){return e.innerHTML.trim()}document.addEventListener("shown.bs.tab",function(a){const r=n(a.target);e.filter(e=>{var t=n(e)===r,o=e===a.target,e="true"===e.getAttribute("aria-selected");return t&&!o&&!e}).forEach(e=>{new bootstrap.Tab(e).show()})})})(),(()=>{"use strict";const u="A_Default",m=1e5,r=document.getElementById("toc-version");function o(e,a){var t=document.createElement("dl"),r={"de-de":"German","de-at":"German (Austria)","de-ch":"German (Switzerland)","en-gb":"English","fr-fr":"French","ru-ru":"Russian"};if(r["en-us"]=u,"object"!=typeof a)console.log("AJAX version selector API: Request failed, no JSON returned."),e.innerHTML="Versions unavailable.
";else{var n,i={currentfile:{},singlefile:{}};for(n in a){var l=a[n];let e=l.language,t=l.version;var s,c=r[e.toLocaleLowerCase()];c&&(e=c);let o="3_named";"main"===t?o="1_main":(c=t.trim(),s=parseFloat(c),isNaN(s)||Number(c)!==s||(t=t.split(".").map(e=>+e+m).join("."),o="2_numeric")),i.currentfile[e]||(i.currentfile[e]={},i.singlefile[e]={}),i.singlefile[e][o]||(i.currentfile[e][o]={},i.singlefile[e][o]={}),i.singlefile[e][o][t]||(i.currentfile[e][o][t]={},i.singlefile[e][o][t]={}),i.currentfile[e][o][t]=l.url,i.singlefile[e][o][t]=l.singleUrl}var o=function t(o){{if(null===o||"object"!=typeof o||Array.isArray(o))return o;{const a={},e=Object.keys(o).filter(e=>!isNaN(e)).sort((e,t)=>t-e),r=Object.keys(o).filter(e=>isNaN(e)).sort(),n=[...e,...r];return n.forEach(e=>{a[e]=t(o[e])}),a}}}(i),d="",d=(d+=p("currentfile",o))+p("singlefile",o);t.innerHTML=d,e.innerHTML="",e.appendChild(t)}}function p(t,o){let a="";for(var r in"singlefile"===t&&(a+="In one file: "),o[t]){var e,n,i;for(i in r!=u&&(e=Object.keys(o[t][r])[0],n=Object.keys(o[t][r][e])[0],a+=''+r+" "),o[t][r])for(var l in o[t][r][i]){let e=l;"2_numeric"===i&&(e=l.split(".").map(e=>+e-m).join(".")),a+=''+e+" "}}return"singlefile"===t&&(a+="
"),a}r&&r.addEventListener("click",function(){var e=document.getElementById("toc-version-wrapper");const t=document.getElementById("toc-version-options");e.classList.toggle("toc-version-wrapper-active"),t.dataset.ready||async function(){let e=document.URL,t="https://docs.typo3.org/services/versionsJson.php?url=";r.getAttribute("data-override-url-self")&&(e=r.getAttribute("data-override-url-self"),t=r.getAttribute("data-override-url-proxy"),console.log("AJAX version selector API: Developer mode enabled. Adjust data-override-url-self to simulate different menus. More information: https://docs.typo3.org/other/t3docs/render-guides/main/en-us/Developer/AjaxVersions.html"),console.log("Currently: "+e),console.log("The API PROXY is currently served from: "+t));var o=t+encodeURI(e);try{var a=await fetch(o);return a.ok?a.json():(console.log("AJAX version selector API: Request failure or empty response."),"")}catch(e){return console.log("AJAX version selector API: Request failed, likely CORS issue. Read the documentation to configure a proxy."),""}}().then(e=>{""===e&&(e="No data available.
"),o(t,e),t.dataset.ready="true"})})})();
\ No newline at end of file
+ `),o(i))})})(),(()=>{const l="#permalink-uri",c="#permalink-html";function d(n){const r=n.querySelector("#permalink-alert-success");var e=n.querySelectorAll(".copy-button");navigator.clipboard&&navigator.clipboard.writeText?e.forEach(e=>{e.addEventListener("click",function(){var e,t,a=this.getAttribute("data-target"),a=n.querySelector("#"+a);a?(r.classList.remove("d-none"),r.innerHTML=`Snippet ${e=a.value,t=document.createElement("div"),t.textContent=e,t.innerHTML}
was copied to your clipboard.`,navigator.clipboard.writeText(a.value)):console.warn("Cannot copy link as no input is available!")})}):(console.info('"navigator.clipboard.writeText" is not available. Update to a modern browser to copy code to the system\'s clipboard'),e.forEach(e=>e.disabled=!0))}const m=document.querySelector("#linkReferenceModal");m.addEventListener("show.bs.modal",function(e){var t,e=e.relatedTarget,a=e.closest("section"),n=e.dataset.id||(a?a.dataset.rstAnchor:null),r=e.closest("h1, h2, h3, h4, h5, h6, dt"),r=r?r.innerText:"",o=e.dataset.rstcode,e=e.title,i=(i=m,s=n||o,i=i.querySelector(".alert-permalink-rst"),s?i.classList.add("d-none"):i.classList.remove("d-none"),s=a,i=n,"null"===window.location.origin||"file://"===window.location.origin?null:i?""+window.location.origin+window.location.pathname+"#"+i:""+window.location.origin+window.location.pathname+"#"+(s?.id||"")),s=m.dataset.currentFilename,n=o||(o=m,a=a,t=r,n=n,s=s,o=o.dataset.interlinkShortcode||"somemanual",n?`:ref:\`${t} <${o}:${n}>\``:""===s?"":`:doc:\`${t} <${o}:${s}#${a?.id||""}>\``);t=m,o=r,s=i,a=n,(r=e)&&(t.querySelector("h5").innerHTML=r),null===s?(t.querySelector(l).value="",t.querySelector(c).value=""):(t.querySelector(l).value=s,t.querySelector(c).value=`${o} `),r=t.querySelector("#permalink-rst"),s=r.closest("div"),""===a?s.classList.add("d-none"):(s.classList.remove("d-none"),r.value=a),d(m)})})(),(()=>{"use strict";function a(e){e.preventDefault();const t=e.currentTarget.parentElement.parentElement;e=t.parentElement.parentElement.querySelectorAll("li.active");Array.from(e).forEach(e=>{e!==t&&e.classList.remove("active")}),t.classList.toggle("active")}var e;e=document.getElementsByClassName("main_menu"),Array.from(e).forEach(e=>{e=e.getElementsByTagName("a");Array.from(e).forEach(e=>{var t;e.nextSibling&&((t=document.createElement("span")).classList.add("toctree-expand"),t.addEventListener("click",a,!0),e.prepend(t))})})})(),window.addEventListener("load",()=>{var e,t,a=window.location.pathname.match(/^\/(c|m|p|h|other)\/[A-Za-z0-9\-_]+\/[A-Za-z0-9\-_]+\/[A-Za-z0-9\-.]+\/[A-Za-z0-9\-]+\/(Changelog\/[A-Za-z0-9\-.]+\/)?/),a=a?a[0]:null;a&&(e=document.getElementById("searchscope"),(t=document.createElement("option")).value=a,t.text="Search current",e.add(t))}),(()=>{"use strict";const e=Array.from(document.querySelectorAll('.nav-item > [role="tab"]'));function o(e){return e.innerHTML.trim()}document.addEventListener("shown.bs.tab",function(n){const r=o(n.target);e.filter(e=>{var t=o(e)===r,a=e===n.target,e="true"===e.getAttribute("aria-selected");return t&&!a&&!e}).forEach(e=>{new bootstrap.Tab(e).show()})})})(),(()=>{"use strict";const m="A_Default",u=1e5,r=document.getElementById("toc-version");function a(e,n){var t=document.createElement("dl"),r={"de-de":"German","de-at":"German (Austria)","de-ch":"German (Switzerland)","en-gb":"English","fr-fr":"French","ru-ru":"Russian"};if(r["en-us"]=m,"object"!=typeof n)console.log("AJAX version selector API: Request failed, no JSON returned."),e.innerHTML="Versions unavailable.
";else{var o,i={currentfile:{},singlefile:{}};for(o in n){var s=n[o];let e=s.language,t=s.version;var l,c=r[e.toLocaleLowerCase()];c&&(e=c);let a="3_named";"main"===t?a="1_main":(c=t.trim(),l=parseFloat(c),isNaN(l)||Number(c)!==l||(t=t.split(".").map(e=>+e+u).join("."),a="2_numeric")),i.currentfile[e]||(i.currentfile[e]={},i.singlefile[e]={}),i.singlefile[e][a]||(i.currentfile[e][a]={},i.singlefile[e][a]={}),i.singlefile[e][a][t]||(i.currentfile[e][a][t]={},i.singlefile[e][a][t]={}),i.currentfile[e][a][t]=s.url,i.singlefile[e][a][t]=s.singleUrl}var a=function t(a){{if(null===a||"object"!=typeof a||Array.isArray(a))return a;{const n={},e=Object.keys(a).filter(e=>!isNaN(e)).sort((e,t)=>t-e),r=Object.keys(a).filter(e=>isNaN(e)).sort(),o=[...e,...r];return o.forEach(e=>{n[e]=t(a[e])}),n}}}(i),d="",d=(d+=h("currentfile",a))+h("singlefile",a);t.innerHTML=d,e.innerHTML="",e.appendChild(t)}}function h(t,a){let n="";for(var r in"singlefile"===t&&(n+="In one file: "),a[t]){var e,o,i;for(i in r!=m&&(e=Object.keys(a[t][r])[0],o=Object.keys(a[t][r][e])[0],n+=''+r+" "),a[t][r])for(var s in a[t][r][i]){let e=s;"2_numeric"===i&&(e=s.split(".").map(e=>+e-u).join(".")),n+=''+e+" "}}return"singlefile"===t&&(n+="
"),n}r&&r.addEventListener("click",function(){var e=document.getElementById("toc-version-wrapper");const t=document.getElementById("toc-version-options");e.classList.toggle("toc-version-wrapper-active"),t.dataset.ready||async function(){let e=document.URL,t="https://docs.typo3.org/services/versionsJson.php?url=";r.getAttribute("data-override-url-self")&&(e=r.getAttribute("data-override-url-self"),t=r.getAttribute("data-override-url-proxy"),console.log("AJAX version selector API: Developer mode enabled. Adjust data-override-url-self to simulate different menus. More information: https://docs.typo3.org/other/t3docs/render-guides/main/en-us/Developer/AjaxVersions.html"),console.log("Currently: "+e),console.log("The API PROXY is currently served from: "+t));var a=t+encodeURI(e);try{var n=await fetch(a);return n.ok?n.json():(console.log("AJAX version selector API: Request failure or empty response."),"")}catch(e){return console.log("AJAX version selector API: Request failed, likely CORS issue. Read the documentation to configure a proxy."),""}}().then(e=>{""===e&&(e="No data available.
"),a(t,e),t.dataset.ready="true"})})})();
\ No newline at end of file
diff --git a/packages/typo3-docs-theme/resources/template/structure/layoutParts/pageHeader.html.twig b/packages/typo3-docs-theme/resources/template/structure/layoutParts/pageHeader.html.twig
index 10eb9fe4e..54dd81657 100644
--- a/packages/typo3-docs-theme/resources/template/structure/layoutParts/pageHeader.html.twig
+++ b/packages/typo3-docs-theme/resources/template/structure/layoutParts/pageHeader.html.twig
@@ -10,24 +10,27 @@