diff --git a/src/components/AnnouncementBanner/index.scss b/src/components/AnnouncementBanner/index.scss new file mode 100644 index 000000000..bff42281f --- /dev/null +++ b/src/components/AnnouncementBanner/index.scss @@ -0,0 +1,38 @@ +.announcementBanner { + width: 100%; + border-bottom: 1px solid var(--border-color); + background: #dce5f9; + color: var(--primary-color); +} + +.announcementBanner__inner { + display: flex; + gap: 12px; + align-items: center; + justify-content: center; + padding-top: 10px; + padding-bottom: 10px; +} + +.announcementBanner__content { + font-size: 15px; + line-height: 21px; + text-align: center; + flex: 1 1 auto; + font-weight: 500; + color: #4b5563; +} + +.announcementBanner__link { + color: #1a73e8; + text-decoration: underline; + font-size: 15px; +} + +@media screen and (max-width: 767px) { + .announcementBanner__inner { + flex-direction: column; + align-items: flex-start; + } +} + diff --git a/src/components/AnnouncementBanner/index.tsx b/src/components/AnnouncementBanner/index.tsx new file mode 100644 index 000000000..e88c22e38 --- /dev/null +++ b/src/components/AnnouncementBanner/index.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import './index.scss'; + +type AnnouncementBannerProps = { + enabled?: boolean; + message: React.ReactNode; +}; + +const AnnouncementBanner = (props: AnnouncementBannerProps) => { + const { enabled = true, message } = props; + + if (!enabled) return null; + + return ( +
+
+
{message}
+
+
+ ); +}; + +export default AnnouncementBanner; + diff --git a/src/components/DevDocTemplate/index.tsx b/src/components/DevDocTemplate/index.tsx index be6ea8441..81fc0acff 100644 --- a/src/components/DevDocTemplate/index.tsx +++ b/src/components/DevDocTemplate/index.tsx @@ -23,6 +23,7 @@ import { getAlgoliaIndex } from '../../configs/algolia-search-config'; import RenderPlayGround from './playGround/RESTAPI'; import GraphQLPlayGround from './playGround/GraphQL'; import { AskDocs } from './askDocs'; +import AnnouncementBanner from '../AnnouncementBanner'; import { TS_HOST_PARAM, TS_ORIGIN_PARAM, @@ -34,6 +35,7 @@ import { DEFAULT_PREVIEW_HOST, DEFAULT_APP_ROOT, HOME_PAGE_ID, + HOME_ANNOUNCEMENT_BANNER, CUSTOM_PAGE_ID, BUILD_ENVS, VERSION_DROPDOWN, @@ -487,6 +489,36 @@ const DevDocTemplate: FC = (props) => { return cName; }; + const getCloudLatestVersion = () => { + const cloudLatest = VERSION_DROPDOWN?.find( + (v) => v?.subLabel && v.subLabel.toLowerCase().includes('cloud (latest)'), + ); + return cloudLatest?.label; + }; + + const extractVersionString = (text: string | undefined | null) => { + if (!text) return undefined; + // Matches versions like 26.2.0.cl or 10.15.0.cl / 10.10.0.sw + const match = text.match(/\b\d+\.\d+\.\d+\.(?:cl|sw)\b/i); + return match?.[0]?.toLowerCase(); + }; + + const shouldShowAnnouncementBanner = () => { + if (!isPublicSiteOpen) return false; + if (!HOME_ANNOUNCEMENT_BANNER?.enabled) return false; + + const cloudLatest = extractVersionString(getCloudLatestVersion()); + const bannerVersion = + extractVersionString(HOME_ANNOUNCEMENT_BANNER?.linkText) || + extractVersionString(HOME_ANNOUNCEMENT_BANNER?.message); + + // Only hide when we can confidently compare and they match. + if (cloudLatest && bannerVersion && cloudLatest === bannerVersion) return false; + return true; + }; + + const isExternalLink = (href?: string) => /^https?:\/\//i.test(href || ''); + return ( <> @@ -511,6 +543,44 @@ const DevDocTemplate: FC = (props) => { : { height: '0px' } } > + {shouldShowAnnouncementBanner() && ( + + {HOME_ANNOUNCEMENT_BANNER?.linkHref && + HOME_ANNOUNCEMENT_BANNER?.linkText && ( + + {HOME_ANNOUNCEMENT_BANNER.linkText} + + )} + {(HOME_ANNOUNCEMENT_BANNER?.linkHref && + HOME_ANNOUNCEMENT_BANNER?.linkText) && ' '} + {HOME_ANNOUNCEMENT_BANNER?.message || + (VERSION_DROPDOWN?.[0]?.label + ? `Version ${VERSION_DROPDOWN[0].label} is now available!` + : 'A new version is now available!')} + + } + /> + )}
} diff --git a/src/configs/doc-configs.js b/src/configs/doc-configs.js index 783645484..fddb5524d 100644 --- a/src/configs/doc-configs.js +++ b/src/configs/doc-configs.js @@ -13,6 +13,18 @@ module.exports = { NOT_FOUND_PAGE_ID: '404-error', HOME_PAGE_ID: 'introduction', NOT_FOUND_GO_HOME_PAGE_ID: 'introduction', + HOME_ANNOUNCEMENT_BANNER: { + enabled: true, + message: + 'is now available. Read about the new features and enhancements.', + // Swap this between: + // - Pre-GA: release-specific URL (full http(s) URL), ex: + // 'https://developers.thoughtspot.com/docs/26.2.0.cl?pageid=whats-new' + // - GA: ' /docs/whats-new' + //linkHref: '/docs/whats-new', + linkHref: '/docs/26.2.0.cl?pageid=whats-new', + linkText: 'Version 26.2.0.cl', + }, TYPE_DOC_PREFIX: 'typedoc', DEFAULT_HOST: 'https://try-everywhere.thoughtspot.cloud', DEFAULT_PREVIEW_HOST: 'https://try-everywhere.thoughtspot.cloud/v2', @@ -63,7 +75,12 @@ module.exports = { subLabel: 'Software', iframeUrl: 'https://visual-embed-sdk-10-1.vercel.app/docs/', }, - + { + label: '26.2.0.cl', + link: '26.2.0.cl', + subLabel: 'Coming soon', + iframeUrl: 'https://developer-docs-26-2-0-cl.vercel.app/docs/', + }, ], CUSTOM_PAGE_ID: { API_PLAYGROUND: 'restV2-playground',