diff --git a/docusaurus.config.ts b/docusaurus.config.ts index 149b2de0..cb9a09ab 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -1,6 +1,7 @@ import { themes as prismThemes } from 'prism-react-renderer'; import type { Config } from '@docusaurus/types'; import type * as Preset from '@docusaurus/preset-classic'; +import path from 'path'; // This runs in Node.js - Don't use client-side code here (browser APIs, JSX...) @@ -135,6 +136,10 @@ const config: Config = { ], + clientModules: [ + path.join(__dirname, 'src/clientModules/gtagGuard.ts'), + ], + themeConfig: { announcementBar: { id: 'release_v1_0_0', @@ -168,6 +173,7 @@ const config: Config = { }, { to: '/modules', label: 'Modules', position: 'left' }, { to: '/blog', label: 'Blog', position: 'left' }, + { to: '/enterprise', label: 'Enterprise', position: 'left' }, { type: 'docsVersionDropdown', position: 'right', diff --git a/src/clientModules/gtagGuard.ts b/src/clientModules/gtagGuard.ts new file mode 100644 index 00000000..04e95e40 --- /dev/null +++ b/src/clientModules/gtagGuard.ts @@ -0,0 +1,10 @@ +/** + * Defines a no-op window.gtag if the Google Analytics script was blocked + * (e.g. by an ad blocker), preventing "window.gtag is not a function" errors + * thrown by @docusaurus/plugin-google-gtag on route changes. + */ +if (typeof window !== 'undefined' && typeof window.gtag !== 'function') { + (window as typeof window & { gtag: (...args: unknown[]) => void }).gtag = () => {}; +} + +export {}; diff --git a/src/pages/enterprise.module.css b/src/pages/enterprise.module.css new file mode 100644 index 00000000..047a2378 --- /dev/null +++ b/src/pages/enterprise.module.css @@ -0,0 +1,157 @@ +.root { + padding-top: 2rem; + padding-bottom: 2rem; +} + +.root section.margin-bottom--lg { + padding-bottom: 3rem; +} + +/* ============================ + OFFERING CARD + ============================ */ +.offeringCard { + background: var(--ifm-color-gray-100); + border-radius: 12px; + padding: 2.5rem; + max-width: 820px; + margin: 0 auto; +} + +[data-theme='dark'] .offeringCard { + background: var(--ifm-background-color); +} + +.offeringHeader { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 0.5rem; + margin-bottom: 1.25rem; +} + +.providerLogo { + height: 32px; + width: auto; + flex-shrink: 0; +} + +.offeringHeaderText { + font-size: 1.25rem; + font-weight: 700; + color: var(--ifm-heading-color); + line-height: 1.3; +} + +.offeringTagline { + font-size: 1rem; + color: var(--ifm-color-emphasis-700); + margin-bottom: 2rem; + line-height: 1.6; +} + +.featureList { + list-style: none; + padding: 0; + margin: 0 0 2rem; + display: flex; + flex-direction: column; + gap: 0.875rem; +} + +.featureItem { + display: flex; + align-items: flex-start; + gap: 0.75rem; + font-size: 0.975rem; + color: var(--ifm-font-color-base); + line-height: 1.6; +} + +.featureIcon { + flex-shrink: 0; + width: 20px; + height: 20px; + border-radius: 50%; + background: var(--ifm-color-primary-lightest); + color: var(--ifm-color-primary-darkest); + display: flex; + align-items: center; + justify-content: center; + font-size: 0.75rem; + font-weight: 700; + margin-top: 2px; +} + +[data-theme='dark'] .featureIcon { + background: rgba(43, 140, 247, 0.2); + color: var(--ifm-color-primary-light); +} + +.featureLabel { + font-weight: 600; + color: var(--ifm-heading-color); +} + +/* ============================ + BUTTONS — same as marketplace + ============================ */ +.buttonGroup { + display: flex; + justify-content: center; + align-items: center; + gap: 0.75rem; + margin-top: 2rem; + flex-wrap: wrap; +} + +.cButton { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.75rem 2rem; + font-size: 1rem; + line-height: 1; + font-weight: 600; + border-radius: 6px; + border: 2px solid var(--ifm-color-primary); + background: var(--ifm-color-primary); + color: #fff; + text-decoration: none; + cursor: pointer; + box-sizing: border-box; + transition: + background-color 0.2s ease, + color 0.2s ease, + border-color 0.2s ease, + box-shadow 0.2s ease, + transform 0.1s ease; +} + +.cButton:hover { + color: #fff; + opacity: 0.9; + transform: translateY(-1px); +} + +.cButton:focus { + outline: none; +} + +/* ============================ + RESPONSIVE + ============================ */ +@media (max-width: 768px) { + .offeringCard { + padding: 1.75rem 1.25rem; + } + + + .buttonGroup { + flex-direction: column; + } + + .cButton { + width: 100%; + } +} diff --git a/src/pages/enterprise.tsx b/src/pages/enterprise.tsx new file mode 100644 index 00000000..d3dc632d --- /dev/null +++ b/src/pages/enterprise.tsx @@ -0,0 +1,98 @@ +import type {ReactNode} from 'react'; +import React from 'react'; +import Layout from '@theme/Layout'; +import useBaseUrl from '@docusaurus/useBaseUrl'; +import SectionHeader from '@site/src/components/common/SectionHeader'; +import styles from './enterprise.module.css'; + +const features = [ + { + label: '24/7 incident support.', + detail: 'Global, round-the-clock support with aggressive SLAs for production-stopping issues.', + }, + { + label: 'Proactive security monitoring.', + detail: '', + }, + { + label: 'Dedicated onboarding support', + detail: 'to help you move from legacy CI/CD to a modern IDP.', + }, + { + label: "Direct access to OpenChoreo's core engineers and WSO2's customer success team", + detail: 'for architectural advice, tuning, and best practices.', + }, +]; + +/** + * Enterprise page (/enterprise) + * + * Lists enterprise support offerings for OpenChoreo. + * Currently features the WSO2 Developer Platform for OpenChoreo offering, + * including a feature list and a CTA linking to the WSO2 product page. + */ +export default function Enterprise(): ReactNode { + return ( + +
+
+ + {/* HERO */} +
+ +

+ OpenChoreo was originally created by WSO2 and is a CNCF Sandbox Project.
+ You can find enterprise support options for the project below. +

+
+
+ + {/* OFFERING CARD */} +
+
+
+ WSO2 +Developer Platform for OpenChoreo +
+

+ Get open source flexibility with enterprise platform reliability. Direct access to + architects and developers from the creators of OpenChoreo. +

+ +
    + {features.map((f, i) => ( +
  • + + + {f.label} + {f.detail && ` ${f.detail}`} + +
  • + ))} +
+ + +
+
+ +
+
+
+ ); +}