diff --git a/docusaurus.config.js b/docusaurus.config.js
index 84c9add7..e2cdf19a 100644
--- a/docusaurus.config.js
+++ b/docusaurus.config.js
@@ -121,6 +121,7 @@ const config = {
{ to: '/organisations', label: 'Adopters', position: 'left' },
{ to: '/contribute', label: 'Contribute', position: 'left' },
{ to: '/resources', label: 'Resources', position: 'left' },
+ { to: '/docs/latest/Reference/LTS', label: 'Support', position: 'left' },
{
type: 'docsVersionDropdown',
position: 'right',
diff --git a/src/theme/DocItem/Layout/index.js b/src/theme/DocItem/Layout/index.js
new file mode 100644
index 00000000..29a36b06
--- /dev/null
+++ b/src/theme/DocItem/Layout/index.js
@@ -0,0 +1,79 @@
+import React from 'react'
+import clsx from 'clsx'
+import { useWindowSize } from '@docusaurus/theme-common'
+import { useDoc } from '@docusaurus/plugin-content-docs/client'
+import DocItemPaginator from '@theme/DocItem/Paginator'
+import DocVersionBanner from '@theme/DocVersionBanner'
+import DocVersionBadge from '@theme/DocVersionBadge'
+import DocItemFooter from '@theme/DocItem/Footer'
+import DocItemTOCMobile from '@theme/DocItem/TOC/Mobile'
+import DocItemTOCDesktop from '@theme/DocItem/TOC/Desktop'
+import DocItemContent from '@theme/DocItem/Content'
+import DocBreadcrumbs from '@theme/DocBreadcrumbs'
+import ContentVisibility from '@theme/ContentVisibility'
+import styles from './styles.module.css'
+/**
+ * Decide if the toc should be rendered, on mobile or desktop viewports
+ */
+function useDocTOC() {
+ const { frontMatter, toc } = useDoc()
+ const windowSize = useWindowSize()
+ const hidden = frontMatter.hide_table_of_contents
+ const canRender = !hidden && toc.length > 0
+ const mobile = canRender ? : undefined
+ const desktop = canRender && (windowSize === 'desktop' || windowSize === 'ssr') ? : undefined
+ return {
+ hidden,
+ mobile,
+ desktop,
+ }
+}
+export default function DocItemLayout({ children }) {
+ const docTOC = useDocTOC()
+ const { metadata } = useDoc()
+
+ // Show warning only on migration guide pages.
+ const isMigrationGuide = metadata.permalink.toLowerCase().includes('migration-guide')
+ const versionNumber = parseVersion(metadata.version)
+
+ return (
+
+
+
+
+
+
+
+
+ {docTOC.mobile}
+
+ {/* Show warning only on current version of documentation pages.
+ NaN indicates the latest version */}
+ {isMigrationGuide && (isNaN(versionNumber) || versionNumber === 5) && (
+
+
Version 3 and before of Fastify are no longer maintained.
+ For information about support options for end-of-life versions, see the{' '}
+ Long Term Support page.
+
+ )}
+
+ {children}
+
+
+
+
+
+ {docTOC.desktop &&
{docTOC.desktop}
}
+
+ )
+}
+
+// Return version.
+const parseVersion = (versionString) => {
+ // Remove 'v' prefix if present
+ const cleanVersion = versionString.startsWith('v') ? versionString.slice(1) : versionString
+ // Split the version string and get the first part (major version)
+ const majorVersion = cleanVersion.split('.')[0]
+ // Parse the major version to an integer
+ return parseInt(majorVersion, 10)
+}
diff --git a/src/theme/DocItem/Layout/styles.module.css b/src/theme/DocItem/Layout/styles.module.css
new file mode 100644
index 00000000..d5aaec13
--- /dev/null
+++ b/src/theme/DocItem/Layout/styles.module.css
@@ -0,0 +1,10 @@
+.docItemContainer header + *,
+.docItemContainer article > *:first-child {
+ margin-top: 0;
+}
+
+@media (min-width: 997px) {
+ .docItemCol {
+ max-width: 75% !important;
+ }
+}
diff --git a/src/theme/DocVersionBanner/index.js b/src/theme/DocVersionBanner/index.js
new file mode 100644
index 00000000..f7261596
--- /dev/null
+++ b/src/theme/DocVersionBanner/index.js
@@ -0,0 +1,128 @@
+import React from 'react'
+import clsx from 'clsx'
+import useDocusaurusContext from '@docusaurus/useDocusaurusContext'
+import Link from '@docusaurus/Link'
+import Translate from '@docusaurus/Translate'
+import { useActivePlugin, useDocVersionSuggestions } from '@docusaurus/plugin-content-docs/client'
+import { ThemeClassNames } from '@docusaurus/theme-common'
+import { useDocsPreferredVersion, useDocsVersion } from '@docusaurus/plugin-content-docs/client'
+
+function UnreleasedVersionLabel({ siteTitle, versionMetadata }) {
+ return (
+ {versionMetadata.label},
+ }}>
+ {'This is unreleased documentation for {siteTitle} {versionLabel} version.'}
+
+ )
+}
+function UnmaintainedVersionLabel({ siteTitle, versionMetadata }) {
+ const versionNumber = parseInt(versionMetadata.label.replace(/^v/, '').split('.')[0], 10)
+
+ // Return the label only if the version number is 3 or lower.
+ if (versionNumber <= 3) {
+ return (
+ {versionMetadata.label},
+ }}>
+ {'This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.'}
+
+ )
+ }
+ return null
+}
+const BannerLabelComponents = {
+ unreleased: UnreleasedVersionLabel,
+ unmaintained: UnmaintainedVersionLabel,
+}
+function BannerLabel(props) {
+ const BannerLabelComponent = BannerLabelComponents[props.versionMetadata.banner]
+ return
+}
+function LatestVersionSuggestionLabel({ versionLabel, to, onClick }) {
+ return (
+
+
+
+ latest version
+
+
+
+ ),
+ }}>
+ {'For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).'}
+
+ )
+}
+function DocVersionBannerEnabled({ className, versionMetadata }) {
+ const {
+ siteConfig: { title: siteTitle },
+ } = useDocusaurusContext()
+ const { pluginId } = useActivePlugin({ failfast: true })
+ const getVersionMainDoc = (version) => version.docs.find((doc) => doc.id === version.mainDocId)
+ const { savePreferredVersionName } = useDocsPreferredVersion(pluginId)
+ const { latestDocSuggestion, latestVersionSuggestion } = useDocVersionSuggestions(pluginId)
+
+ // Parse the version number
+ const versionNumber = parseVersion(versionMetadata.version)
+
+ // Try to link to same doc in latest version (not always possible), falling
+ // back to main doc of latest version
+ const latestVersionSuggestedDoc = latestDocSuggestion ?? getVersionMainDoc(latestVersionSuggestion)
+ return (
+