diff --git a/frontend/src/component/common/FormTemplate/FormTemplate.tsx b/frontend/src/component/common/FormTemplate/FormTemplate.tsx index 1783b6a95d..bc681b6d40 100644 --- a/frontend/src/component/common/FormTemplate/FormTemplate.tsx +++ b/frontend/src/component/common/FormTemplate/FormTemplate.tsx @@ -14,7 +14,7 @@ import Info from '@mui/icons-material/Info'; import Loader from '../Loader/Loader'; import copy from 'copy-to-clipboard'; import useToast from 'hooks/useToast'; -import type React from 'react'; +import React from 'react'; import { type ReactNode, useState } from 'react'; import { ReactComponent as MobileGuidanceBG } from 'assets/img/mobileGuidanceBg.svg'; import { formTemplateSidebarWidth } from './FormTemplate.styles'; @@ -36,6 +36,7 @@ interface ICreateProps { footer?: ReactNode; compact?: boolean; showGuidance?: boolean; + useFixedSidebar?: boolean; } const StyledContainer = styled('section', { @@ -54,7 +55,21 @@ const StyledContainer = styled('section', { }, })); -const StyledRelativeDiv = styled('div')(({ theme }) => relative); +const StyledMobileGuidanceWrapper = styled('div', { + shouldForwardProp: (prop) => !['guidanceHeight'].includes(prop.toString()), +})<{ guidanceHeight?: string }>(({ theme, guidanceHeight }) => ({ + ...relative, + // todo: review this. We're reaching down into a nested + // component, but due to the component structure, it'd be a + // lot of work to pass this down as a prop. + ...(guidanceHeight + ? { + aside: { + height: guidanceHeight, + }, + } + : {}), +})); const StyledMain = styled('div')(({ theme }) => ({ display: 'flex', @@ -151,20 +166,32 @@ const StyledInfoIcon = styled(Info)(({ theme }) => ({ fill: theme.palette.primary.contrastText, })); -const StyledSidebar = styled('aside')(({ theme }) => ({ - backgroundColor: theme.palette.background.sidebar, - padding: theme.spacing(4), - flexGrow: 0, - flexShrink: 0, - width: formTemplateSidebarWidth, - [theme.breakpoints.down(1100)]: { - width: '100%', - color: 'red', - }, - [theme.breakpoints.down(500)]: { - padding: theme.spacing(4, 2), - }, -})); +const StyledSidebar = styled('aside', { + shouldForwardProp: (prop) => + !['sidebarWidth', 'fixedCodeHeight'].includes(prop.toString()), +})<{ sidebarWidth?: string; fixedCodeHeight?: string }>( + ({ theme, sidebarWidth, fixedCodeHeight }) => ({ + backgroundColor: theme.palette.background.sidebar, + padding: theme.spacing(4), + flexGrow: 0, + flexShrink: 0, + width: sidebarWidth || formTemplateSidebarWidth, + [theme.breakpoints.down(1100)]: { + width: '100%', + color: 'red', + }, + [theme.breakpoints.down(500)]: { + padding: theme.spacing(4, 2), + }, + ...(fixedCodeHeight + ? { + pre: { + height: fixedCodeHeight, + }, + } + : {}), + }), +); const StyledDescriptionCard = styled('article')(({ theme }) => ({ display: 'flex', @@ -218,6 +245,7 @@ const FormTemplate: React.FC = ({ footer, compact, showGuidance = true, + useFixedSidebar, }) => { const { setToastData } = useToast(); const smallScreen = useMediaQuery(`(max-width:${1099}px)`); @@ -265,19 +293,23 @@ const FormTemplate: React.FC = ({ } }; + const SidebarComponent = useFixedSidebar ? FixedGuidance : Guidance; + return ( + - + } /> @@ -312,7 +344,7 @@ const FormTemplate: React.FC = ({ = ({ formatApiCode === undefined, !(showDescription || showLink), )} - + } /> @@ -380,7 +412,11 @@ interface IGuidanceProps { showLink?: boolean; } -const Guidance: React.FC = ({ +const GuidanceContent: React.FC< + IGuidanceProps & { + fixedDocumentationHeight?: string; + } +> = ({ description, children, documentationLink, @@ -388,38 +424,79 @@ const Guidance: React.FC = ({ documentationLinkLabel = 'Learn more', showDescription = true, showLink = true, + fixedDocumentationHeight, }) => { + const StyledDocumentationIconWrapper = styled('div')(({ theme }) => ({ + height: '2rem', + display: 'grid', + placeItems: 'center', + svg: { + width: '100%', + }, + })); + + const StyledDocumentationWrapper = styled('div')({ + height: fixedDocumentationHeight, + overflowY: 'auto', + }); + + const DocsWrapper = fixedDocumentationHeight + ? StyledDocumentationWrapper + : React.Fragment; + + return ( + <> + + + + {documentationIcon} + + } + /> + {description} + + } + /> + + + + + {documentationLinkLabel} + + + } + /> + + {children} + + ); +}; + +const Guidance: React.FC = (props) => { return ( - - - {description} - - } - /> + + + ); +}; - - - - {documentationLinkLabel} - - - } - /> - {children} +const FixedGuidance: React.FC = (props) => { + return ( + + ); }; diff --git a/frontend/src/component/project/Project/CreateProject/CreateProjectDialog/CreateProjectDialog.tsx b/frontend/src/component/project/Project/CreateProject/CreateProjectDialog/CreateProjectDialog.tsx index 35f8a588f2..cc0fe3efed 100644 --- a/frontend/src/component/project/Project/CreateProject/CreateProjectDialog/CreateProjectDialog.tsx +++ b/frontend/src/component/project/Project/CreateProject/CreateProjectDialog/CreateProjectDialog.tsx @@ -143,6 +143,7 @@ export const CreateProjectDialogue = ({ documentationLink={documentation.link?.url} documentationLinkLabel={documentation.link?.label} formatApiCode={formatApiCode} + useFixedSidebar > = ({ className='description' label='Description (optional)' multiline - maxRows={20} + maxRows={3} value={projectDesc} onChange={(e) => setProjectDesc(e.target.value)} data-testid={PROJECT_DESCRIPTION_INPUT} @@ -285,6 +285,7 @@ export const NewProjectForm: React.FC = ({ button={{ label: projectMode, icon: , + labelWidth: `${`protected`.length}ch`, }} search={{ label: 'Filter project mode options', diff --git a/frontend/src/component/project/Project/CreateProject/SelectionButton.tsx b/frontend/src/component/project/Project/CreateProject/SelectionButton.tsx index 16705f9e4d..002fcfe7c6 100644 --- a/frontend/src/component/project/Project/CreateProject/SelectionButton.tsx +++ b/frontend/src/component/project/Project/CreateProject/SelectionButton.tsx @@ -1,6 +1,13 @@ import Search from '@mui/icons-material/Search'; import { v4 as uuidv4 } from 'uuid'; -import { Box, Button, InputAdornment, List, ListItemText } from '@mui/material'; +import { + Box, + Button, + InputAdornment, + List, + ListItemText, + styled, +} from '@mui/material'; import { type FC, type ReactNode, useRef, useState, useMemo } from 'react'; import { StyledCheckbox, @@ -75,7 +82,7 @@ const useSelectionManagement = ({ type CombinedSelectProps = { options: Array<{ label: string; value: string }>; onChange: (value: string) => void; - button: { label: string; icon: ReactNode }; + button: { label: string; icon: ReactNode; labelWidth?: string }; search: { label: string; placeholder: string; @@ -132,6 +139,11 @@ const CombinedSelect: FC = ({ const filteredOptions = options?.filter((option) => option.label.toLowerCase().includes(searchText.toLowerCase()), ); + + const ButtonLabel = styled('span')(() => ({ + width: button.labelWidth || 'unset', + })); + return ( <> @@ -145,7 +157,7 @@ const CombinedSelect: FC = ({ } }} > - {button.label} + {button.label}