diff --git a/package-lock.json b/package-lock.json index 9fa56de14..081f250f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4727,10 +4727,9 @@ } }, "node_modules/@leafygreen-ui/icon": { - "version": "12.7.0", - "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/@leafygreen-ui/icon/-/icon-12.7.0.tgz", - "integrity": "sha512-RM+ohvFLF9JCj1WumiqiKUSF7bvYNV4uNWgHCWeXFpydJC+j6wqGXpclIXMHYeP2/bl54aHOgmaY/1FKq7QvRA==", - "license": "Apache-2.0", + "version": "12.8.0", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/@leafygreen-ui/icon/-/icon-12.8.0.tgz", + "integrity": "sha512-LDYSFtdn+dX3/hyBJJw722grz98To+X9Nw/97F6MUk+D9eNdufzPFYQCd8iDsgUbfeSVJ/uw1PVr20QEJ7Xtcw==", "dependencies": { "@leafygreen-ui/emotion": "^4.0.8", "lodash": "^4.17.21" @@ -34783,9 +34782,9 @@ } }, "@leafygreen-ui/icon": { - "version": "12.7.0", - "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/@leafygreen-ui/icon/-/icon-12.7.0.tgz", - "integrity": "sha512-RM+ohvFLF9JCj1WumiqiKUSF7bvYNV4uNWgHCWeXFpydJC+j6wqGXpclIXMHYeP2/bl54aHOgmaY/1FKq7QvRA==", + "version": "12.8.0", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/@leafygreen-ui/icon/-/icon-12.8.0.tgz", + "integrity": "sha512-LDYSFtdn+dX3/hyBJJw722grz98To+X9Nw/97F6MUk+D9eNdufzPFYQCd8iDsgUbfeSVJ/uw1PVr20QEJ7Xtcw==", "requires": { "@leafygreen-ui/emotion": "^4.0.8", "lodash": "^4.17.21" diff --git a/src/components/ActionBar/ActionBar.js b/src/components/ActionBar/ActionBar.js index 636043f55..baeb161dd 100644 --- a/src/components/ActionBar/ActionBar.js +++ b/src/components/ActionBar/ActionBar.js @@ -1,12 +1,18 @@ -import React, { useContext } from 'react'; +import React, { lazy, useState, useContext } from 'react'; import PropTypes from 'prop-types'; +import Button from '@leafygreen-ui/button'; import { cx } from '@leafygreen-ui/emotion'; import Icon from '@leafygreen-ui/icon'; import { Overline } from '@leafygreen-ui/typography'; +import { useDarkMode } from '@leafygreen-ui/leafygreen-provider'; +import IconButton from '@leafygreen-ui/icon-button'; +import { useSiteMetadata } from '../../hooks/use-site-metadata'; import { isBrowser } from '../../utils/is-browser'; import { getPlaintext } from '../../utils/get-plaintext'; import { getNestedValue } from '../../utils/get-nested-value'; import { isOfflineDocsBuild } from '../../utils/is-offline-docs-build'; +import { getCurrLocale } from '../../utils/locale'; +import { reportAnalytics } from '../../utils/report-analytics'; import useSnootyMetadata from '../../utils/use-snooty-metadata'; import { SidenavContext } from '../Sidenav'; import { @@ -16,6 +22,7 @@ import { useFeedbackData, FeedbackContainer, } from '../Widgets/FeedbackWidget'; +import { SuspenseHelper } from '../SuspenseHelper'; import DarkModeDropdown from './DarkModeDropdown'; import SearchInput from './SearchInput'; import { @@ -25,13 +32,21 @@ import { getContainerStyling, offlineStyling, overlineStyling, + chatbotButtonStyling, + chatbotMobileButtonStyling, } from './styles'; +const Chatbot = lazy(() => import('mongodb-chatbot-ui')); +const ChatbotModal = lazy(() => import('./ChatbotModal')); + export const DEPRECATED_PROJECTS = ['atlas-app-services', 'datalake', 'realm']; +const CHATBOT_TEXT = 'Ask MongoDB AI'; const ActionBar = ({ template, slug, sidenav, ...props }) => { const url = isBrowser ? window.location.href : null; const metadata = useSnootyMetadata(); + const [chatbotClicked, setChatbotClicked] = useState(false); + const locale = getCurrLocale(); const feedbackData = useFeedbackData({ slug, url, @@ -43,6 +58,16 @@ const ActionBar = ({ template, slug, sidenav, ...props }) => { const { hideMobile, setHideMobile } = useContext(SidenavContext); + const openChatbot = () => { + reportAnalytics('Chatbot button clicked'); + setChatbotClicked((currVal) => !currVal); + }; + const { snootyEnv } = useSiteMetadata(); + const { darkMode } = useDarkMode(); + const CHATBOT_SERVER_BASE_URL = ['dotcomprd', 'production'].includes(snootyEnv) + ? 'https://knowledge.mongodb.com/api/v1' + : 'https://knowledge.staging.corp.mongodb.com/api/v1'; + return (
{ {!isOfflineDocsBuild && ( - {template !== 'openapi' && } + + + + + {locale === 'en-us' && ( + + + + + + )} + {template !== 'errorpage' && !DEPRECATED_PROJECTS.includes(metadata.project) && ( @@ -68,6 +112,7 @@ const ActionBar = ({ template, slug, sidenav, ...props }) => { )} + {template !== 'openapi' && } )}
diff --git a/src/components/ActionBar/ChatbotControls.js b/src/components/ActionBar/ChatbotControls.js deleted file mode 100644 index 9ae07352a..000000000 --- a/src/components/ActionBar/ChatbotControls.js +++ /dev/null @@ -1,28 +0,0 @@ -import { forwardRef, useCallback, useImperativeHandle } from 'react'; -import { useChatbotContext } from 'mongodb-chatbot-ui'; -import PropTypes from 'prop-types'; - -// Using a forward ref and imperative handle -// to expose lazy loaded child (chatbot) behaviors to parent (SearchInput) -// https://react.dev/reference/react/useImperativeHandle -const ChatbotControls = forwardRef(function ChatbotControls({ searchValue }, ref) { - const { setInputText, handleSubmit, openChat } = useChatbotContext(); - - const onClick = useCallback(async () => { - await openChat(); - setInputText(searchValue); - handleSubmit(searchValue); - }, [handleSubmit, openChat, searchValue, setInputText]); - - useImperativeHandle(ref, () => { - return { - onClick, - }; - }); -}); - -export default ChatbotControls; - -ChatbotControls.propTypes = { - searchValue: PropTypes.string.isRequired, -}; diff --git a/src/components/ActionBar/ChatbotModal.js b/src/components/ActionBar/ChatbotModal.js new file mode 100644 index 000000000..420c07ed6 --- /dev/null +++ b/src/components/ActionBar/ChatbotModal.js @@ -0,0 +1,37 @@ +import React, { useEffect } from 'react'; +import { useChatbotContext, ModalView, MongoDbLegalDisclosure, PoweredByAtlasVectorSearch } from 'mongodb-chatbot-ui'; +import { css } from '@leafygreen-ui/emotion'; +import { defaultSuggestedPrompts } from '../ChatbotUi'; + +const ChatbotModal = ({ chatbotClicked, setChatbotClicked }) => { + const { openChat } = useChatbotContext(); + useEffect(() => { + if (chatbotClicked) { + openChat(); + setChatbotClicked(false); + } + }, [chatbotClicked, openChat, setChatbotClicked]); + + return ( + + + + + } + initialMessageText={'Welcome to MongoDB AI'} + initialMessageSuggestedPrompts={defaultSuggestedPrompts} + /> + ); +}; + +export default ChatbotModal; diff --git a/src/components/ActionBar/SearchInput.js b/src/components/ActionBar/SearchInput.js index 358f960d7..c5de7c917 100644 --- a/src/components/ActionBar/SearchInput.js +++ b/src/components/ActionBar/SearchInput.js @@ -1,112 +1,44 @@ -import React, { lazy, useCallback, useEffect, useRef, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { navigate } from 'gatsby'; import PropTypes from 'prop-types'; import { useLocation } from '@gatsbyjs/reach-router'; import { css, cx } from '@leafygreen-ui/emotion'; import IconButton from '@leafygreen-ui/icon-button'; import Icon from '@leafygreen-ui/icon'; -import { useBackdropClick } from '@leafygreen-ui/hooks'; -import { useDarkMode } from '@leafygreen-ui/leafygreen-provider'; import { SearchInput as LGSearchInput } from '@leafygreen-ui/search-input'; import { Link } from '@leafygreen-ui/typography'; +import { useAllDocsets } from '../../hooks/useAllDocsets'; import useScreenSize from '../../hooks/useScreenSize'; import { useSiteMetadata } from '../../hooks/use-site-metadata'; import { theme } from '../../theme/docsTheme'; -import debounce from '../../utils/debounce'; +import { assertTrailingSlash } from '../../utils/assert-trailing-slash'; import { isBrowser } from '../../utils/is-browser'; -import { SuspenseHelper } from '../SuspenseHelper'; -import { getCurrLocale } from '../../utils/locale'; +import { localizePath } from '../../utils/locale'; +import { reportAnalytics } from '../../utils/report-analytics'; import { searchIconStyling, searchInputStyling, StyledInputContainer, StyledSearchBoxRef } from './styles'; -import { ShortcutIcon, SparkleIcon } from './SparkIcon'; -const Chatbot = lazy(() => import('mongodb-chatbot-ui')); -const SearchMenu = lazy(() => import('./SearchMenu')); -export const PLACEHOLDER_TEXT = `Search MongoDB Docs or Ask MongoDB AI`; -const PLACEHOLDER_TEXT_MOBILE = 'Search or AI'; - -// taken from LG/lib - our library is out of date -// https://github.com/mongodb/leafygreen-ui/blob/main/packages/lib/src/index.ts#L102 -const keyMap = { - ArrowUp: 'ArrowUp', - ArrowDown: 'ArrowDown', - ArrowLeft: 'ArrowLeft', - ArrowRight: 'ArrowRight', - Backspace: 'Backspace', - BracketLeft: '[', - Delete: 'Delete', - Enter: 'Enter', - Escape: 'Escape', - Space: ' ', - Tab: 'Tab', -}; - -export const SEARCH_SUGGESTIONS = [ - { - copy: 'Search', - }, - { - copy: 'Ask MongoDB AI', - icon: , - shortcutIcon: , - }, -]; +export const PLACEHOLDER_TEXT = `Search MongoDB Docs`; +const PLACEHOLDER_TEXT_MOBILE = 'Search'; const SearchInput = ({ className, slug }) => { const [searchValue, setSearchValue] = useState(''); - const [isOpen, setIsOpen] = useState(false); - const [isFocused, setIsFocused] = useState(false); - const [selectedResult, setSelectedResult] = useState(); const searchBoxRef = useRef(); const inputRef = useRef(); - const menuRef = useRef(); - const metadata = useSiteMetadata(); - const { darkMode } = useDarkMode(); - const [selectedOption, setSelectedOption] = useState(0); + const { project, snootyEnv } = useSiteMetadata(); const [mobileSearchActive, setMobileSearchActive] = useState(false); const { search } = useLocation(); - const locale = getCurrLocale(); - const [isChatbotAvail, setChatbotAvail] = useState(false); - const isEnglish = locale === 'en-us'; - - useBackdropClick( - () => { - setIsOpen(false); - inputRef.current?.blur(); - }, - [searchBoxRef, menuRef], - isOpen - ); - - useEffect(() => { - if (!searchValue.length) { - return setIsOpen(false); + const docsets = useAllDocsets(); + + const keyPressHandler = useCallback(async (event) => { + // cmd+k or ctrl+k focuses search bar, + // unless already focused on an input field + const holdingCtrlCmd = (navigator.userAgent.includes('Mac') && event.metaKey) || event.ctrlKey; + if (holdingCtrlCmd && event.key === 'k' && document.activeElement.tagName.toLowerCase() !== 'input') { + event.preventDefault(); + inputRef.current?.focus(); + return; } - const debounced = debounce(() => { - setIsOpen(!!searchValue.length && document?.activeElement === inputRef.current); - }, 500); - return () => debounced(); - }, [searchValue]); - - const keyPressHandler = useCallback( - async (event) => { - // cmd+k or ctrl+k focuses search bar, - // unless already focused on an input field - const holdingCtrlCmd = (navigator.userAgent.includes('Mac') && event.metaKey) || event.ctrlKey; - if (holdingCtrlCmd && event.key === 'k' && document.activeElement.tagName.toLowerCase() !== 'input') { - event.preventDefault(); - inputRef.current?.focus(); - return; - } - - // if currently focused on search input and on English site (therefore, chatbot is an option), - // activates the chatbot modal - if (event.target.isSameNode(inputRef.current) && event.key === '/' && isEnglish) { - event.preventDefault(); - setIsOpen(false); - setSelectedResult(1); - } - }, - [isEnglish] - ); + }, []); // adding keyboard shortcuts document wide useEffect(() => { @@ -141,99 +73,48 @@ const SearchInput = ({ className, slug }) => { } }, [search]); - // close menu when changing screen size - useEffect(() => { - function handleResize() { - setIsOpen(false); - } - window.addEventListener('resize', handleResize); - // Remove event listener on cleanup - return () => window.removeEventListener('resize', handleResize); - }, [isMobile, mobileSearchActive]); - - const handleSearchBoxKeyDown = (e) => { - const isFocusInMenu = menuRef.current?.contains?.(document.activeElement); - const isFocusOnSearchBox = searchBoxRef.current?.contains?.(document.activeElement); - const isFocusInComponent = isFocusOnSearchBox || isFocusInMenu; - const optionsCount = isChatbotAvail ? 2 : 1; - - if (!isFocusInComponent) { - return; - } - switch (e.key) { - case keyMap.Enter: { - setSelectedResult(selectedOption); - setIsOpen(false); - break; - } - - case keyMap.Escape: { - setIsOpen(false); - inputRef.current?.focus(); - break; - } - - case keyMap.ArrowDown: { - if (isOpen && isEnglish && isChatbotAvail) { - setSelectedOption((selectedOption + 1) % optionsCount); - inputRef.current?.focus(); - } - e.preventDefault(); - break; - } - - case keyMap.ArrowUp: { - if (isOpen && isEnglish && isChatbotAvail) { - setSelectedOption(Math.abs(selectedOption - (1 % optionsCount))); - inputRef.current?.focus(); - } - e.preventDefault(); - break; - } - - case keyMap.Tab: { - if (isOpen) { - setIsOpen(false); - } - break; - } - - default: { - break; - } + // get search url for staging and prod environments + // all other environments will fall back to prod + // considers localization as well + const fullSearchUrl = useMemo(() => { + const ENVS_WITH_SEARCH = ['dotcomstg', 'dotcomprd']; + const targetEnv = ENVS_WITH_SEARCH.includes(snootyEnv) ? snootyEnv : ENVS_WITH_SEARCH[1]; + const landingDocset = docsets.find((d) => d.project === 'landing'); + return ( + assertTrailingSlash(landingDocset.url[targetEnv]) + + localizePath(assertTrailingSlash(landingDocset.prefix[targetEnv]) + 'search') + ); + }, [docsets, snootyEnv]); + + const onSubmit = () => { + reportAnalytics('Search bar used', { + type: 'docs-search', + query: searchValue, + }); + inputRef.current?.blur(); + if (project === 'landing' && slug === 'search') { + const newSearch = new URLSearchParams(); + newSearch.set('q', searchValue); + return navigate(`?${newSearch.toString()}`, { state: { searchValue } }); } + return (window.location.href = `${fullSearchUrl}/?q=${searchValue}`); }; - const CHATBOT_SERVER_BASE_URL = ['dotcomprd', 'production'].includes(metadata?.snootyEnv) - ? 'https://knowledge.mongodb.com/api/v1' - : 'https://knowledge.staging.corp.mongodb.com/api/v1'; - return ( - + { - setIsFocused(true); setSearchValue(e.target.value); }} - onClick={() => { - setIsOpen(!!searchValue.length); - }} - onSubmit={(e) => { - inputRef.current?.blur(); - setIsOpen(false); - }} onFocus={() => { - setIsFocused(true); + reportAnalytics('Search bar focused'); }} + onSubmit={onSubmit} ref={inputRef} /> @@ -253,28 +134,11 @@ const SearchInput = ({ className, slug }) => { Cancel )} - - - - - {!mobileSearchActive && ( { - setIsOpen(false); setMobileSearchActive((state) => !state); }} > diff --git a/src/components/ActionBar/SearchMenu.js b/src/components/ActionBar/SearchMenu.js deleted file mode 100644 index a3e366fbd..000000000 --- a/src/components/ActionBar/SearchMenu.js +++ /dev/null @@ -1,155 +0,0 @@ -import React, { forwardRef, useEffect, useMemo, useState } from 'react'; -import { navigate } from 'gatsby'; -import { SearchResultsMenu, SearchResult } from '@leafygreen-ui/search-input'; -import { css, cx } from '@leafygreen-ui/emotion'; -import { ModalView, MongoDbLegalDisclosure, PoweredByAtlasVectorSearch, useChatbotContext } from 'mongodb-chatbot-ui'; -import PropTypes from 'prop-types'; -import { useAllDocsets } from '../../hooks/useAllDocsets'; -import { useSiteMetadata } from '../../hooks/use-site-metadata'; -import { assertTrailingSlash } from '../../utils/assert-trailing-slash'; -import { getCurrLocale, localizePath } from '../../utils/locale'; -import { reportAnalytics } from '../../utils/report-analytics'; -import useSnootyMetadata from '../../utils/use-snooty-metadata'; -import { suggestionStyling } from './styles'; -import { SEARCH_SUGGESTIONS } from './SearchInput'; - -const SearchMenu = forwardRef(function SearchMenu( - { - searchValue, - searchBoxRef, - isOpen, - selectedOption, - slug, - selectedResult, - setSelectedResult, - isFocused, - setChatbotAvail, - }, - ref -) { - const { handleSubmit, conversation } = useChatbotContext(); - const { project } = useSnootyMetadata(); - const docsets = useAllDocsets(); - const { snootyEnv } = useSiteMetadata(); - const locale = getCurrLocale(); - const [conversationInit, setConversationInit] = useState(false); - - // get search url for staging and prod environments - // all other environments will fall back to prod - // considers localization as well - const fullSearchUrl = useMemo(() => { - const ENVS_WITH_SEARCH = ['dotcomstg', 'dotcomprd']; - const targetEnv = ENVS_WITH_SEARCH.includes(snootyEnv) ? snootyEnv : ENVS_WITH_SEARCH[1]; - const landingDocset = docsets.find((d) => d.project === 'landing'); - return ( - assertTrailingSlash(landingDocset.url[targetEnv]) + - localizePath(assertTrailingSlash(landingDocset.prefix[targetEnv]) + 'search') - ); - }, [docsets, snootyEnv]); - - const handleSearchResultClick = async (isChatbotRes) => { - reportAnalytics('Search bar used', { - type: isChatbotRes ? 'chatbot' : 'docs-search', - query: searchValue, - }); - setSelectedResult(undefined); - if (isChatbotRes) { - return handleSubmit(searchValue).catch((e) => console.error(e)); - } - if (project === 'landing' && slug === 'search') { - const newSearch = new URLSearchParams(); - newSearch.set('q', searchValue); - return navigate(`?${newSearch.toString()}`, { state: { searchValue } }); - } - return (window.location.href = `${fullSearchUrl}/?q=${searchValue}`); - }; - - useEffect(() => { - if (!Number.isInteger(selectedResult)) { - return; - } - handleSearchResultClick(selectedResult > 0); - // NOTE: this effect should only run when selected result is changed - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [selectedResult]); - - // NOTE: conversation is updated in effect below - useEffect(() => { - if (!conversation.conversationId) { - return; - } - setChatbotAvail(!conversation.error && !!conversation.conversationId); - }, [conversation, setChatbotAvail]); - - useEffect(() => { - if (!isFocused || conversationInit || conversation.conversationId) { - return; - } - setConversationInit(true); - // NOTE: createConversation does not resolve / throw errors. - // updates conversation from useChatbotContext instead - // https://github.com/mongodb/chatbot/blob/mongodb-chatbot-ui-v0.8.1/packages/mongodb-chatbot-ui/src/useConversation.tsx#L409 - conversation.createConversation().finally((e) => setConversationInit(false)); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isFocused]); - - const searchOptions = useMemo(() => { - const useChatbot = !!conversation.conversationId && locale === 'en-us'; - return SEARCH_SUGGESTIONS.slice(0, useChatbot ? SEARCH_SUGGESTIONS.length : 1); - }, [conversation, locale]); - - return ( - <> - - {searchOptions.map((suggestion, i) => { - const { copy } = suggestion; - const isChatbot = i === 1; - return ( - setSelectedResult(i)} - highlighted={selectedOption === i} - > - {!isChatbot && <>{searchValue}} - {isChatbot && ( - <> - {suggestion.icon} - {searchValue} - {suggestion.shortcutIcon} - - )} - - ); - })} - - - - - - } - /> - - ); -}); - -export default SearchMenu; - -SearchMenu.propTypes = { - searchValue: PropTypes.string.isRequired, - searchBoxRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({ current: PropTypes.instanceOf(Element) })]), - isOpen: PropTypes.bool, - selectedOption: PropTypes.number, - slug: PropTypes.string, -}; diff --git a/src/components/ActionBar/styles.js b/src/components/ActionBar/styles.js index 9486004ad..bd693169a 100644 --- a/src/components/ActionBar/styles.js +++ b/src/components/ActionBar/styles.js @@ -1,12 +1,11 @@ import styled from '@emotion/styled'; import { palette } from '@leafygreen-ui/palette'; import { css } from '@leafygreen-ui/emotion'; +import { gridStyling as landingTemplateGridStyling } from '../../templates/landing'; +import { gridStyling as centerGridStyling } from '../../templates/NotFound'; import { theme } from '../../theme/docsTheme'; -import { CONTENT_MAX_WIDTH } from '../../templates/product-landing'; import { displayNone } from '../../utils/display-none'; -const DESKTOP_DARK_MODE_AND_FEEDBACK_BUTTONS_WIDTH = '236px'; - // default styling for all Action Bars export const actionBarStyling = css` display: flex; @@ -41,10 +40,7 @@ export const actionBarStyling = css` // used for :template: options - 'product-landing', 'changelog' const gridStyling = css` display: grid; - grid-template-columns: minmax(${theme.size.xlarge}, 1fr) minmax(0, ${CONTENT_MAX_WIDTH}px) minmax( - ${DESKTOP_DARK_MODE_AND_FEEDBACK_BUTTONS_WIDTH}, - 1fr - ); + grid-template-columns: minmax(${theme.size.xlarge}, 1fr) repeat(2, minmax(0, 600px)) minmax(${theme.size.xlarge}, 1fr); @media ${theme.screenSize.upToLarge} { grid-template-columns: ${theme.size.medium} 1fr fit-content(100%); @@ -54,10 +50,7 @@ const gridStyling = css` // use strictly for :template: landing const landingGridStyling = css` display: grid; - grid-template-columns: minmax(${theme.size.xlarge}, 1fr) minmax(0, ${theme.breakpoints.xxLarge}px) minmax( - ${DESKTOP_DARK_MODE_AND_FEEDBACK_BUTTONS_WIDTH}, - 1fr - ); + ${landingTemplateGridStyling} @media ${theme.screenSize.upToLarge} { grid-template-columns: ${theme.size.medium} 1fr fit-content(100%); } @@ -76,20 +69,40 @@ const flexStyling = css` const middleAlignment = css` display: grid; - grid-template-columns: ${theme.size.xlarge} repeat(12, minmax(0, 1fr)) ${theme.size.xlarge}; + ${centerGridStyling} + + @media ${theme.screenSize.upToMedium} { + grid-template-columns: repeat(12, 1fr); + } `; -const centerInGrid = css` +const leftInGrid = css` grid-column: 2/-2; @media ${theme.screenSize.upToLarge} { - grid-column: 3/-3; + grid-column: 2/-3; + padding-right: 0; } @media ${theme.screenSize.largeAndUp} { - grid-column: 4/-4; + grid-column: 2/-8; } @media ${theme.screenSize.xLargeAndUp} { - grid-column: 6/-5; + grid-column: 2/-7; + } +`; + +const centerInGrid = css` + grid-column: 6/-5; + + @media ${theme.screenSize.upToXLarge} { + grid-column: 4/-6; + } + + @media ${theme.screenSize.upToLarge} { + grid-column: 3/-8; + } + @media ${theme.screenSize.upToMedium} { + grid-column: 3/-2; } `; @@ -97,6 +110,7 @@ export const getContainerStyling = (template) => { let containerClassname, searchContainerClassname, fakeColumns = false; + switch (template) { case 'product-landing': containerClassname = gridStyling; @@ -104,6 +118,7 @@ export const getContainerStyling = (template) => { break; case 'landing': containerClassname = landingGridStyling; + searchContainerClassname = leftInGrid; fakeColumns = true; break; case 'changelog': @@ -134,6 +149,10 @@ export const ActionBarSearchContainer = styled.div` width: 100%; background: inherit; + @media ${theme.screenSize.mediumAndUp} { + padding-right: ${theme.size.default}; + } + @media ${theme.screenSize.upToLarge} { max-width: unset; justify-content: space-between; @@ -221,12 +240,13 @@ export const ActionsBox = styled('div')` grid-column: -2/-1; @media ${theme.screenSize.upToLarge} { + column-gap: 6px; margin-right: ${theme.size.medium}; + margin-left: ${theme.size.small}; } @media ${theme.screenSize.upToMedium} { - margin-left: ${theme.size.small}; - column-gap: ${theme.size.small}; + margin-left: 1px; } `; @@ -254,34 +274,33 @@ export const overlineStyling = css` export const searchIconStyling = css` ${displayNone.onLargerThanMedium}; float: right; + justify-content: right; `; -// using content before/after to prevent event bubbling up from lg/search-input/search-result -// package above gets all text inside node, and sets the value of Input node of all text within search result: -// https://github.com/mongodb/leafygreen-ui/blob/%40leafygreen-ui/search-input%402.1.4/packages/search-input/src/SearchInput/SearchInput.tsx#L149-L155 -export const suggestionStyling = ({ copy }) => css` - & > div:before { - content: '${copy} "'; - } - - & > div:after { - content: '"'; +export const offlineStyling = css` + @media ${theme.screenSize.largeAndUp} { + display: none; } +`; - svg:first-of-type { - float: left; - margin-right: ${theme.size.tiny}; +const hideOnEnLang = ` + &:not(:lang(EN)) { + display: none; } +`; - padding: ${theme.fontSize.tiny} ${theme.size.medium}; - - svg:last-of-type { - float: right; - } +export const chatbotButtonStyling = css` + text-wrap-mode: nowrap; + ${displayNone.onMobileAndTablet}; + ${hideOnEnLang} `; -export const offlineStyling = css` - @media ${theme.screenSize.largeAndUp} { - display: none; +export const chatbotMobileButtonStyling = css` + ${displayNone.onLargerThanTablet} + ${hideOnEnLang} + color: ${palette.green.dark2}; + + .dark-theme & { + color: ${palette.green.dark1}; } `; diff --git a/src/components/Widgets/FeedbackWidget/FeedbackButton.js b/src/components/Widgets/FeedbackWidget/FeedbackButton.js index 9a26fc141..850538ca6 100644 --- a/src/components/Widgets/FeedbackWidget/FeedbackButton.js +++ b/src/components/Widgets/FeedbackWidget/FeedbackButton.js @@ -10,19 +10,12 @@ import { useFeedbackContext } from './context'; import { FEEDBACK_BUTTON_TEXT } from './constants'; const darkModePrestyling = css` - color: ${palette.green.dark2}; - border-color: ${palette.green.dark2}; - - svg { - color: ${palette.green.dark2}; - } - .dark-theme & { - color: ${palette.green.base}; - border-color: ${palette.green.base}; + color: ${palette.white}; + border-color: ${palette.gray.base}; svg { - color: ${palette.green.base}; + color: ${palette.white}; } } `; @@ -47,7 +40,7 @@ const FeedbackButton = () => { ` )} onClick={() => (!feedback ? initializeFeedback() : abandon())} - variant={Variant.PrimaryOutline} + variant={Variant.Default} leftGlyph={} > {FEEDBACK_BUTTON_TEXT} diff --git a/src/templates/NotFound.js b/src/templates/NotFound.js index 655064764..e59bb6388 100644 --- a/src/templates/NotFound.js +++ b/src/templates/NotFound.js @@ -135,8 +135,7 @@ export const NotFoundContainer = styled.div` } `; -export const Wrapper = styled('main')` - display: grid; +export const gridStyling = ` @media ${theme.screenSize.mediumAndUp} { grid-template-columns: ${`${theme.size.xlarge} repeat(12, minmax(0, 1fr)) ${theme.size.xlarge};`}; } @@ -154,6 +153,11 @@ export const Wrapper = styled('main')` } `; +export const Wrapper = styled('main')` + display: grid; + ${gridStyling} +`; + const NotFound = () => { return ( diff --git a/src/templates/landing.js b/src/templates/landing.js index 95802ccfb..b4b461f47 100644 --- a/src/templates/landing.js +++ b/src/templates/landing.js @@ -4,9 +4,34 @@ import { useTheme, Global, css } from '@emotion/react'; import { useDarkMode } from '@leafygreen-ui/leafygreen-provider'; import { palette } from '@leafygreen-ui/palette'; import PropTypes from 'prop-types'; +import { theme } from '../theme/docsTheme'; const CONTENT_MAX_WIDTH = 1440; +export const gridStyling = ` + +// Use leftmost and rightmost grid columns as "margins" to allow the hero image +// to span across the page while remaining as part of the document flow +@media ${theme.screenSize.mediumAndUp} { + grid-template-columns: ${`minmax(${theme.size.xlarge}, 1fr) repeat(12, minmax(0, ${ + CONTENT_MAX_WIDTH / 12 + }px)) minmax(${theme.size.xlarge}, 1fr);`}; +} + +@media ${theme.screenSize.upToMedium} { + grid-template-columns: 48px repeat(12, 1fr) 48px; +} + +@media ${theme.screenSize.upToSmall} { + grid-template-columns: ${theme.size.large} 1fr ${theme.size.large}; +} + +@media ${theme.screenSize.upToXSmall} { + grid-template-columns: ${theme.size.medium} 1fr ${theme.size.medium}; +} + +`; + const Wrapper = styled('main')` margin: 0 auto; width: 100%; @@ -16,26 +41,7 @@ const Wrapper = styled('main')` display: grid; grid-column: 1 / -1; - // Use leftmost and rightmost grid columns as "margins" to allow the hero image - // to span across the page while remaining as part of the document flow - @media ${({ theme }) => theme.screenSize.mediumAndUp} { - grid-template-columns: ${({ theme }) => - `minmax(${theme.size.xlarge}, 1fr) repeat(12, minmax(0, ${CONTENT_MAX_WIDTH / 12}px)) minmax(${ - theme.size.xlarge - }, 1fr);`}; - } - - @media ${({ theme }) => theme.screenSize.upToMedium} { - grid-template-columns: 48px repeat(12, 1fr) 48px; - } - - @media ${({ theme }) => theme.screenSize.upToSmall} { - grid-template-columns: ${({ theme }) => theme.size.large} 1fr ${({ theme }) => theme.size.large}; - } - - @media ${({ theme }) => theme.screenSize.upToXSmall} { - grid-template-columns: ${({ theme }) => theme.size.medium} 1fr ${({ theme }) => theme.size.medium}; - } + ${gridStyling}; & > .card-group { @media ${({ theme }) => theme.screenSize.mediumAndUp} {