diff --git a/components/Breadcrumbs.tsx b/components/Breadcrumbs.tsx
new file mode 100644
index 000000000000..41b34ef8b9c6
--- /dev/null
+++ b/components/Breadcrumbs.tsx
@@ -0,0 +1,43 @@
+import cx from 'classnames'
+import Link from 'next/link'
+import { useRouter } from 'next/router'
+import { useMainContext } from './context/MainContext'
+
+export type BreadcrumbT = {
+ title: string
+ documentType?: string
+ href?: string
+}
+
+type Props = {}
+export const Breadcrumbs = (props: Props) => {
+ const router = useRouter()
+ const pathWithLocale = `/${router.locale}${router.asPath}`
+ const { breadcrumbs } = useMainContext()
+ const items = Object.entries(breadcrumbs || {})
+
+ return (
+
+ )
+}
diff --git a/components/DefaultLayout.tsx b/components/DefaultLayout.tsx
new file mode 100644
index 000000000000..44b0d11058b5
--- /dev/null
+++ b/components/DefaultLayout.tsx
@@ -0,0 +1,35 @@
+import Head from 'next/head'
+
+// import { Sidebar } from 'components/Sidebar'
+// import { SmallFooter } from 'components/SmallFooter'
+// import { ScrollButton } from 'components/ScrollButton'
+// import { SupportSection } from 'components/SupportSection'
+// import { Header } from 'components/Header'
+import { DeprecationBanner } from 'components/DeprecationBanner'
+import { useMainContext } from 'components/context/MainContext'
+
+type Props = { children?: React.ReactNode }
+export const DefaultLayout = (props: Props) => {
+ const { builtAssets, expose } = useMainContext()
+ return (
+
+
+
+
+
+
+ {/* */}
+
+
+ {/* */}
+
+
+ {props.children}
+
+ {/*
+
+ */}
+
+
+ )
+}
diff --git a/components/DeprecationBanner.tsx b/components/DeprecationBanner.tsx
new file mode 100644
index 000000000000..d181e2a7b000
--- /dev/null
+++ b/components/DeprecationBanner.tsx
@@ -0,0 +1,40 @@
+import { useMainContext } from './context/MainContext'
+import { useCurrentVersion } from './useCurrentVersion'
+
+export const DeprecationBanner = () => {
+ const { data, enterpriseServerReleases } = useMainContext()
+ const { currentVersion } = useCurrentVersion()
+
+ if (!currentVersion.includes(enterpriseServerReleases.oldestSupported)) {
+ return null
+ }
+
+ const message = enterpriseServerReleases.isOldestReleaseDeprecated
+ ? data.reusables.enterprise_deprecation.version_was_deprecated
+ : data.reusables.enterprise_deprecation.version_will_be_deprecated
+
+ return (
+
+
+
+
+ {' '}
+
+ {enterpriseServerReleases.nextDeprecationDate}
+
+ .
+
+ {' '}
+
+
+
+ )
+}
diff --git a/components/context/MainContext.tsx b/components/context/MainContext.tsx
new file mode 100644
index 000000000000..7eec6ef6d911
--- /dev/null
+++ b/components/context/MainContext.tsx
@@ -0,0 +1,72 @@
+import { createContext, useContext } from 'react'
+
+import type { BreadcrumbT } from 'components/Breadcrumbs'
+
+type ProductT = {
+ external: boolean
+ href: string
+ id: string
+ name: string
+}
+type DataT = {
+ ui: Record>
+ reusables: {
+ enterprise_deprecation: {
+ version_was_deprecated: string
+ version_will_be_deprecated: string
+ deprecation_details: string
+ isOldestReleaseDeprecated: boolean
+ }
+ }
+}
+type EnterpriseServerReleases = {
+ isOldestReleaseDeprecated: boolean
+ oldestSupported: string
+ nextDeprecationDate: string
+}
+export type MainContextT = {
+ breadcrumbs?: Record
+ builtAssets: { main: { css: string; js: string } }
+ expose: string
+ activeProducts: Array
+ currentProduct: ProductT
+ currentLayoutName: string
+ data: DataT
+ airGap?: boolean
+ currentCategory?: string
+ relativePath?: string
+ enterpriseServerReleases: EnterpriseServerReleases
+}
+
+export const getMainContextFromRequest = (req: any): MainContextT => {
+ return {
+ builtAssets: req.context.builtAssets,
+ expose: req.context.expose,
+ breadcrumbs: req.context.breadcrumbs,
+ activeProducts: req.context.activeProducts,
+ currentProduct: req.context.productMap[req.context.currentProduct],
+ currentLayoutName: req.context.currentLayoutName,
+ data: {
+ ui: req.context.site.data.ui,
+ reusables: {
+ enterprise_deprecation: req.context.site.data.reusables.enterprise_deprecation,
+ },
+ },
+ airGap: req.context.AIRGAP || false,
+ currentCategory: req.context.currentCategory || '',
+ relativePath: req.context.page.relativePath,
+ enterpriseServerReleases: req.context.enterpriseServerReleases,
+ }
+}
+
+export const MainContext = createContext(null)
+
+export const useMainContext = (): MainContextT => {
+ const context = useContext(MainContext)
+
+ if (!context) {
+ throw new Error('"useMainContext" may only be used inside "MainContext.Provider"')
+ }
+
+ return context
+}
diff --git a/components/useCurrentVersion.tsx b/components/useCurrentVersion.tsx
new file mode 100644
index 000000000000..645fc4020b4d
--- /dev/null
+++ b/components/useCurrentVersion.tsx
@@ -0,0 +1,12 @@
+import { useRouter } from 'next/router'
+
+type VersionInfo = {
+ currentVersion: string;
+ isEnterprise: boolean;
+};
+const DEFAULT_VERSION = 'free-pro-team@latest'
+export const useCurrentVersion = (): VersionInfo => {
+ const router = useRouter()
+ const currentVersion = (router.query.versionId as string) || DEFAULT_VERSION
+ return { currentVersion, isEnterprise: currentVersion.includes('enterprise') };
+};
\ No newline at end of file
diff --git a/middleware/render-page.js b/middleware/render-page.js
index 20f4356a86cf..0d0ef5ec8897 100644
--- a/middleware/render-page.js
+++ b/middleware/render-page.js
@@ -28,7 +28,9 @@ const cacheableQueries = ['learn']
const renderWithNext = FEATURE_NEXTJS
? [
- '/en/rest'
+ '/en/rest',
+ '/en/sponsors',
+ '/ja/sponsors',
]
: []
diff --git a/next.config.js b/next.config.js
index c7e4e17d3a74..c6d0e46b1373 100644
--- a/next.config.js
+++ b/next.config.js
@@ -1,16 +1,17 @@
const { productIds } = require('./lib/all-products')
+const languages = require('./lib/languages')
module.exports = {
i18n: {
- locales: ['en', 'ja'],
+ locales: Object.values(languages).map(({ code }) => code),
defaultLocale: 'en'
},
async rewrites () {
- const defaultVersionId = 'free-pro-team@latest'
+ const DEFAULT_VERSION = 'free-pro-team@latest'
return productIds.map((productId) => {
return {
source: `/${productId}/:path*`,
- destination: `/${defaultVersionId}/${productId}/:path*`
+ destination: `/${DEFAULT_VERSION}/${productId}/:path*`
}
})
}
diff --git a/package-lock.json b/package-lock.json
index 864ecc849c9e..75fecf9b5687 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4263,6 +4263,11 @@
}
}
},
+ "classnames": {
+ "version": "2.2.6",
+ "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz",
+ "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q=="
+ },
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
@@ -7641,9 +7646,9 @@
}
},
"classnames": {
- "version": "2.2.6",
- "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz",
- "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q=="
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
+ "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
},
"clean-stack": {
"version": "2.2.0",
diff --git a/package.json b/package.json
index 691f3c9edf62..4f8d2b1a43d8 100644
--- a/package.json
+++ b/package.json
@@ -31,6 +31,7 @@
"browser-date-formatter": "^3.0.3",
"change-case": "^3.1.0",
"cheerio": "^1.0.0-rc.3",
+ "classnames": "^2.3.1",
"compression": "^1.7.4",
"connect-datadog": "0.0.9",
"connect-slashes": "^1.4.0",
diff --git a/pages/[versionId]/sponsors.tsx b/pages/[versionId]/sponsors.tsx
new file mode 100644
index 000000000000..391b7a43ed06
--- /dev/null
+++ b/pages/[versionId]/sponsors.tsx
@@ -0,0 +1,31 @@
+import { GetServerSideProps } from 'next'
+
+import {
+ MainContextT,
+ MainContext,
+ getMainContextFromRequest,
+} from 'components/context/MainContext'
+import { DefaultLayout } from 'components/DefaultLayout'
+
+type Props = {
+ mainContext: MainContextT
+}
+const SponsorsPage = ({ mainContext }: Props) => {
+ return (
+
+ Sponsors page
+
+ )
+}
+
+export default SponsorsPage
+
+export const getServerSideProps: GetServerSideProps = async (context) => {
+ const req = context.req as any
+
+ return {
+ props: {
+ mainContext: getMainContextFromRequest(req),
+ },
+ }
+}