mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-29 06:33:40 -05:00
Merge pull request #19126 from overleaf/td-bs5-contact-modal-react
React version of Contact Us modal GitOrigin-RevId: 0bef3095f36daa88afdc6172a5531ed11e892047
This commit is contained in:
parent
fb114a7c44
commit
34fc43d59a
33 changed files with 484 additions and 210 deletions
|
@ -555,6 +555,7 @@
|
||||||
"have_more_days_to_try": "",
|
"have_more_days_to_try": "",
|
||||||
"headers": "",
|
"headers": "",
|
||||||
"help": "",
|
"help": "",
|
||||||
|
"help_articles_matching": "",
|
||||||
"help_improve_overleaf_fill_out_this_survey": "",
|
"help_improve_overleaf_fill_out_this_survey": "",
|
||||||
"help_improve_screen_reader_fill_out_this_survey": "",
|
"help_improve_screen_reader_fill_out_this_survey": "",
|
||||||
"hide_configuration": "",
|
"hide_configuration": "",
|
||||||
|
@ -686,10 +687,12 @@
|
||||||
"joined_team": "",
|
"joined_team": "",
|
||||||
"joining": "",
|
"joining": "",
|
||||||
"justify": "",
|
"justify": "",
|
||||||
|
"kb_suggestions_enquiry": "",
|
||||||
"keep_current_plan": "",
|
"keep_current_plan": "",
|
||||||
"keep_personal_projects_separate": "",
|
"keep_personal_projects_separate": "",
|
||||||
"keep_your_account_safe_add_another_email": "",
|
"keep_your_account_safe_add_another_email": "",
|
||||||
"keybindings": "",
|
"keybindings": "",
|
||||||
|
"knowledge_base": "",
|
||||||
"labels_help_you_to_easily_reference_your_figures": "",
|
"labels_help_you_to_easily_reference_your_figures": "",
|
||||||
"labels_help_you_to_reference_your_tables": "",
|
"labels_help_you_to_reference_your_tables": "",
|
||||||
"language_feedback": "",
|
"language_feedback": "",
|
||||||
|
@ -976,6 +979,8 @@
|
||||||
"please_enter_confirmation_code": "",
|
"please_enter_confirmation_code": "",
|
||||||
"please_get_in_touch": "",
|
"please_get_in_touch": "",
|
||||||
"please_link_before_making_primary": "",
|
"please_link_before_making_primary": "",
|
||||||
|
"please_provide_a_message": "",
|
||||||
|
"please_provide_a_subject": "",
|
||||||
"please_reconfirm_institutional_email": "",
|
"please_reconfirm_institutional_email": "",
|
||||||
"please_reconfirm_your_affiliation_before_making_this_primary": "",
|
"please_reconfirm_your_affiliation_before_making_this_primary": "",
|
||||||
"please_refresh": "",
|
"please_refresh": "",
|
||||||
|
|
|
@ -24,10 +24,12 @@ export function formatWikiHit(hit) {
|
||||||
const pagePath = hit.kb ? 'how-to' : 'latex'
|
const pagePath = hit.kb ? 'how-to' : 'latex'
|
||||||
|
|
||||||
let pageAnchor = ''
|
let pageAnchor = ''
|
||||||
let pageName = hit._highlightResult.pageName.value
|
const rawPageName = hit._highlightResult.pageName.value
|
||||||
if (hit.sectionName) {
|
const sectionName = hit.sectionName
|
||||||
pageAnchor = `#${hit.sectionName.replace(/\s/g, '_')}`
|
let pageName = rawPageName
|
||||||
pageName += ' - ' + hit.sectionName
|
if (sectionName) {
|
||||||
|
pageAnchor = `#${sectionName.replace(/\s/g, '_')}`
|
||||||
|
pageName += ' - ' + sectionName
|
||||||
}
|
}
|
||||||
|
|
||||||
const body = hit._highlightResult.content.value
|
const body = hit._highlightResult.content.value
|
||||||
|
@ -37,5 +39,5 @@ export function formatWikiHit(hit) {
|
||||||
.join('\n...\n')
|
.join('\n...\n')
|
||||||
|
|
||||||
const url = `/learn/${pagePath}/${pageSlug}${pageAnchor}`
|
const url = `/learn/${pagePath}/${pageSlug}${pageAnchor}`
|
||||||
return { url, pageName, content }
|
return { url, pageName, rawPageName, sectionName, content }
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ export function setupSearch(formEl) {
|
||||||
const iconEl = document.createElement('i')
|
const iconEl = document.createElement('i')
|
||||||
iconEl.className = 'fa fa-angle-right'
|
iconEl.className = 'fa fa-angle-right'
|
||||||
iconEl.setAttribute('aria-hidden', 'true')
|
iconEl.setAttribute('aria-hidden', 'true')
|
||||||
linkEl.append(contentEl)
|
linkEl.append(iconEl)
|
||||||
|
|
||||||
resultsEl.append(liEl)
|
resultsEl.append(liEl)
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,18 +118,20 @@ function AccountInfoSection() {
|
||||||
</OLFormGroup>
|
</OLFormGroup>
|
||||||
) : null}
|
) : null}
|
||||||
{canUpdateEmail || canUpdateNames ? (
|
{canUpdateEmail || canUpdateNames ? (
|
||||||
<OLButton
|
<OLFormGroup>
|
||||||
type="submit"
|
<OLButton
|
||||||
variant="primary"
|
type="submit"
|
||||||
form="account-info-form"
|
variant="primary"
|
||||||
disabled={!isFormValid}
|
form="account-info-form"
|
||||||
isLoading={isLoading}
|
disabled={!isFormValid}
|
||||||
bs3Props={{
|
isLoading={isLoading}
|
||||||
loading: isLoading ? `${t('saving')}…` : t('update'),
|
bs3Props={{
|
||||||
}}
|
loading: isLoading ? `${t('saving')}…` : t('update'),
|
||||||
>
|
}}
|
||||||
{t('update')}
|
>
|
||||||
</OLButton>
|
{t('update')}
|
||||||
|
</OLButton>
|
||||||
|
</OLFormGroup>
|
||||||
) : null}
|
) : null}
|
||||||
</form>
|
</form>
|
||||||
</>
|
</>
|
||||||
|
@ -188,7 +190,9 @@ function ReadOrWriteFormGroup({
|
||||||
onChange={handleChangeAndValidity}
|
onChange={handleChangeAndValidity}
|
||||||
onInvalid={handleInvalid}
|
onInvalid={handleInvalid}
|
||||||
/>
|
/>
|
||||||
{validationMessage && <FormText isError>{validationMessage}</FormText>}
|
{validationMessage && (
|
||||||
|
<FormText type="error">{validationMessage}</FormText>
|
||||||
|
)}
|
||||||
</OLFormGroup>
|
</OLFormGroup>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,18 +196,20 @@ function PasswordForm() {
|
||||||
/>
|
/>
|
||||||
</OLFormGroup>
|
</OLFormGroup>
|
||||||
) : null}
|
) : null}
|
||||||
<OLButton
|
<OLFormGroup>
|
||||||
form="password-change-form"
|
<OLButton
|
||||||
type="submit"
|
form="password-change-form"
|
||||||
variant="primary"
|
type="submit"
|
||||||
disabled={!isFormValid}
|
variant="primary"
|
||||||
isLoading={isLoading}
|
disabled={!isFormValid}
|
||||||
bs3Props={{
|
isLoading={isLoading}
|
||||||
loading: isLoading ? `${t('saving')}…` : t('change'),
|
bs3Props={{
|
||||||
}}
|
loading: isLoading ? `${t('saving')}…` : t('change'),
|
||||||
>
|
}}
|
||||||
{t('change')}
|
>
|
||||||
</OLButton>
|
{t('change')}
|
||||||
|
</OLButton>
|
||||||
|
</OLFormGroup>
|
||||||
</form>
|
</form>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,9 +91,13 @@ export function DropdownToggle({ ...props }: DropdownToggleProps) {
|
||||||
return <BS5DropdownToggle {...props} />
|
return <BS5DropdownToggle {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DropdownMenu({ as = 'ul', ...props }: DropdownMenuProps) {
|
export const DropdownMenu = forwardRef<
|
||||||
return <BS5DropdownMenu as={as} role="menu" {...props} />
|
typeof BS5DropdownMenu,
|
||||||
}
|
DropdownMenuProps
|
||||||
|
>(({ as = 'ul', ...props }, ref) => {
|
||||||
|
return <BS5DropdownMenu as={as} role="menu" {...props} ref={ref} />
|
||||||
|
})
|
||||||
|
DropdownMenu.displayName = 'DropdownMenu'
|
||||||
|
|
||||||
export function DropdownDivider({ as = 'li' }: DropdownDividerProps) {
|
export function DropdownDivider({ as = 'li' }: DropdownDividerProps) {
|
||||||
return <BS5DropdownDivider as={as} />
|
return <BS5DropdownDivider as={as} />
|
||||||
|
|
|
@ -36,7 +36,7 @@ const FormControl = forwardRef<HTMLInputElement, OLFormControlProps>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Form.Control className={className} {...props} />
|
return <Form.Control ref={ref} className={className} {...props} />
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
FormControl.displayName = 'FormControl'
|
FormControl.displayName = 'FormControl'
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { Form } from 'react-bootstrap-5'
|
||||||
|
import FormText from '@/features/ui/components/bootstrap-5/form/form-text'
|
||||||
|
import { ComponentProps } from 'react'
|
||||||
|
|
||||||
|
export type FormFeedbackProps = Pick<
|
||||||
|
ComponentProps<typeof Form.Control.Feedback>,
|
||||||
|
'type' | 'className' | 'children'
|
||||||
|
>
|
||||||
|
|
||||||
|
function FormFeedback(props: FormFeedbackProps) {
|
||||||
|
return (
|
||||||
|
<Form.Control.Feedback {...props}>
|
||||||
|
<FormText type={props.type === 'invalid' ? 'error' : 'success'}>
|
||||||
|
{props.children}
|
||||||
|
</FormText>
|
||||||
|
</Form.Control.Feedback>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FormFeedback
|
|
@ -1,71 +1,49 @@
|
||||||
import { Form } from 'react-bootstrap-5'
|
import { Form } from 'react-bootstrap-5'
|
||||||
import { MergeAndOverride } from '../../../../../../../types/utils'
|
|
||||||
import MaterialIcon from '@/shared/components/material-icon'
|
import MaterialIcon from '@/shared/components/material-icon'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
|
|
||||||
type FormTextProps = MergeAndOverride<
|
type TextType = 'default' | 'info' | 'success' | 'warning' | 'error'
|
||||||
React.ComponentProps<(typeof Form)['Text']>,
|
|
||||||
| {
|
|
||||||
isInfo?: boolean
|
|
||||||
isError?: never
|
|
||||||
isWarning?: never
|
|
||||||
isSuccess?: never
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
isInfo?: never
|
|
||||||
isError?: boolean
|
|
||||||
isWarning?: never
|
|
||||||
isSuccess?: never
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
isInfo?: never
|
|
||||||
isError?: never
|
|
||||||
isWarning?: boolean
|
|
||||||
isSuccess?: never
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
isInfo?: never
|
|
||||||
isError?: never
|
|
||||||
isWarning?: never
|
|
||||||
isSuccess?: boolean
|
|
||||||
}
|
|
||||||
>
|
|
||||||
|
|
||||||
export const getFormTextColor = ({
|
export type FormTextProps = React.ComponentProps<typeof Form.Text> & {
|
||||||
isError,
|
type?: TextType
|
||||||
isSuccess,
|
}
|
||||||
isWarning,
|
|
||||||
}: {
|
const typeClassMap: Partial<Record<TextType, string>> = {
|
||||||
isError?: boolean
|
error: 'text-danger',
|
||||||
isSuccess?: boolean
|
success: 'text-success',
|
||||||
isWarning?: boolean
|
warning: 'text-warning',
|
||||||
}) => ({
|
}
|
||||||
'text-danger': isError,
|
|
||||||
'text-success': isSuccess,
|
export const getFormTextClass = (type?: TextType) =>
|
||||||
'text-warning': isWarning,
|
typeClassMap[type || 'default']
|
||||||
})
|
|
||||||
|
function FormTextIcon({ type }: { type?: TextType }) {
|
||||||
|
switch (type) {
|
||||||
|
case 'info':
|
||||||
|
return <MaterialIcon type="info" className="text-info" />
|
||||||
|
case 'success':
|
||||||
|
return <MaterialIcon type="check_circle" />
|
||||||
|
case 'warning':
|
||||||
|
return <MaterialIcon type="warning" />
|
||||||
|
case 'error':
|
||||||
|
return <MaterialIcon type="error" />
|
||||||
|
default:
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function FormText({
|
function FormText({
|
||||||
isInfo,
|
type = 'default',
|
||||||
isError,
|
|
||||||
isWarning,
|
|
||||||
isSuccess,
|
|
||||||
children,
|
children,
|
||||||
className,
|
className,
|
||||||
...rest
|
...rest
|
||||||
}: FormTextProps) {
|
}: FormTextProps) {
|
||||||
return (
|
return (
|
||||||
<Form.Text
|
<Form.Text
|
||||||
className={classnames(
|
className={classnames(className, getFormTextClass(type))}
|
||||||
className,
|
|
||||||
getFormTextColor({ isError, isSuccess, isWarning })
|
|
||||||
)}
|
|
||||||
{...rest}
|
{...rest}
|
||||||
>
|
>
|
||||||
{isInfo && <MaterialIcon type="info" className="text-info" />}
|
<FormTextIcon type={type} />
|
||||||
{isError && <MaterialIcon type="error" />}
|
|
||||||
{isWarning && <MaterialIcon type="warning" />}
|
|
||||||
{isSuccess && <MaterialIcon type="check_circle" />}
|
|
||||||
{children}
|
{children}
|
||||||
</Form.Text>
|
</Form.Text>
|
||||||
)
|
)
|
||||||
|
|
|
@ -11,7 +11,7 @@ type OLFormCheckboxProps = React.ComponentProps<(typeof Form)['Check']> & {
|
||||||
function OLFormCheckbox(props: OLFormCheckboxProps) {
|
function OLFormCheckbox(props: OLFormCheckboxProps) {
|
||||||
const { bs3Props, inputRef, ...rest } = props
|
const { bs3Props, inputRef, ...rest } = props
|
||||||
|
|
||||||
const bs3FormLabelProps: React.ComponentProps<typeof BS3Checkbox> = {
|
const bs3FormCheckboxProps: React.ComponentProps<typeof BS3Checkbox> = {
|
||||||
children: rest.label,
|
children: rest.label,
|
||||||
checked: rest.checked,
|
checked: rest.checked,
|
||||||
required: rest.required,
|
required: rest.required,
|
||||||
|
@ -34,9 +34,9 @@ function OLFormCheckbox(props: OLFormCheckboxProps) {
|
||||||
<BootstrapVersionSwitcher
|
<BootstrapVersionSwitcher
|
||||||
bs3={
|
bs3={
|
||||||
rest.type === 'radio' ? (
|
rest.type === 'radio' ? (
|
||||||
<BS3Radio {...bs3FormLabelProps} />
|
<BS3Radio {...bs3FormCheckboxProps} />
|
||||||
) : (
|
) : (
|
||||||
<BS3Checkbox {...bs3FormLabelProps} />
|
<BS3Checkbox {...bs3FormCheckboxProps} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
bs5={<Form.Check ref={inputRef} {...rest} />}
|
bs5={<Form.Check ref={inputRef} {...rest} />}
|
||||||
|
|
|
@ -1,25 +1,29 @@
|
||||||
import { forwardRef } from 'react'
|
import { forwardRef, ComponentProps } from 'react'
|
||||||
import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
|
import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
|
||||||
import BS3FormControl from '@/features/ui/components/bootstrap-3/form/form-control'
|
|
||||||
import FormControl from '@/features/ui/components/bootstrap-5/form/form-control'
|
import FormControl from '@/features/ui/components/bootstrap-5/form/form-control'
|
||||||
|
import BS3FormControl from '@/features/ui/components/bootstrap-3/form/form-control'
|
||||||
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
|
|
||||||
type OLFormControlProps = React.ComponentProps<typeof FormControl> & {
|
type OLFormControlProps = ComponentProps<typeof FormControl> & {
|
||||||
bs3Props?: Record<string, unknown>
|
bs3Props?: Record<string, unknown>
|
||||||
'data-ol-dirty'?: unknown
|
'data-ol-dirty'?: unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BS3FormControlProps = ComponentProps<typeof BS3FormControl>
|
||||||
|
|
||||||
const OLFormControl = forwardRef<HTMLInputElement, OLFormControlProps>(
|
const OLFormControl = forwardRef<HTMLInputElement, OLFormControlProps>(
|
||||||
(props, ref) => {
|
(props, ref) => {
|
||||||
const { bs3Props, ...rest } = props
|
const { bs3Props, ...rest } = props
|
||||||
|
|
||||||
let bs3FormControlProps: React.ComponentProps<typeof BS3FormControl> = {
|
let bs3FormControlProps: BS3FormControlProps = {
|
||||||
|
componentClass: rest.as,
|
||||||
id: rest.id,
|
id: rest.id,
|
||||||
name: rest.name,
|
name: rest.name,
|
||||||
className: rest.className,
|
className: rest.className,
|
||||||
style: rest.style,
|
style: rest.style,
|
||||||
type: rest.type,
|
type: rest.type,
|
||||||
value: rest.value,
|
value: rest.value,
|
||||||
|
defaultValue: rest.defaultValue,
|
||||||
required: rest.required,
|
required: rest.required,
|
||||||
disabled: rest.disabled,
|
disabled: rest.disabled,
|
||||||
placeholder: rest.placeholder,
|
placeholder: rest.placeholder,
|
||||||
|
@ -28,10 +32,10 @@ const OLFormControl = forwardRef<HTMLInputElement, OLFormControlProps>(
|
||||||
autoFocus: rest.autoFocus,
|
autoFocus: rest.autoFocus,
|
||||||
minLength: rest.minLength,
|
minLength: rest.minLength,
|
||||||
maxLength: rest.maxLength,
|
maxLength: rest.maxLength,
|
||||||
onChange: rest.onChange as (e: React.ChangeEvent<unknown>) => void,
|
onChange: rest.onChange as BS3FormControlProps['onChange'],
|
||||||
onKeyDown: rest.onKeyDown as (e: React.KeyboardEvent<unknown>) => void,
|
onKeyDown: rest.onKeyDown as BS3FormControlProps['onKeyDown'],
|
||||||
onFocus: rest.onFocus as (e: React.FocusEvent<unknown>) => void,
|
onFocus: rest.onFocus as BS3FormControlProps['onFocus'],
|
||||||
onInvalid: rest.onInvalid as (e: React.InvalidEvent<unknown>) => void,
|
onInvalid: rest.onInvalid as BS3FormControlProps['onInvalid'],
|
||||||
inputRef: (inputElement: HTMLInputElement) => {
|
inputRef: (inputElement: HTMLInputElement) => {
|
||||||
if (typeof ref === 'function') {
|
if (typeof ref === 'function') {
|
||||||
ref(inputElement)
|
ref(inputElement)
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { Form } from 'react-bootstrap-5'
|
||||||
|
import {
|
||||||
|
HelpBlock as BS3HelpBlock,
|
||||||
|
HelpBlockProps as BS3HelpBlockProps,
|
||||||
|
} from 'react-bootstrap'
|
||||||
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
|
import { ComponentProps } from 'react'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
import FormFeedback from '@/features/ui/components/bootstrap-5/form/form-feedback'
|
||||||
|
|
||||||
|
type OLFormFeedbackProps = Pick<
|
||||||
|
ComponentProps<typeof Form.Control.Feedback>,
|
||||||
|
'type' | 'className' | 'children'
|
||||||
|
> & {
|
||||||
|
bs3Props?: Record<string, unknown>
|
||||||
|
}
|
||||||
|
|
||||||
|
function OLFormFeedback(props: OLFormFeedbackProps) {
|
||||||
|
const { bs3Props, children, ...bs5Props } = props
|
||||||
|
|
||||||
|
const bs3HelpBlockProps: BS3HelpBlockProps = {
|
||||||
|
className: classnames(
|
||||||
|
bs5Props.className,
|
||||||
|
bs5Props.type === 'invalid' ? 'invalid-only' : null
|
||||||
|
),
|
||||||
|
children,
|
||||||
|
...bs3Props,
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<BS3HelpBlock {...bs3HelpBlockProps} />}
|
||||||
|
bs5={<FormFeedback {...bs5Props}>{children}</FormFeedback>}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OLFormFeedback
|
|
@ -1,5 +1,8 @@
|
||||||
import { FormGroupProps } from 'react-bootstrap-5'
|
import { FormGroupProps } from 'react-bootstrap-5'
|
||||||
import { FormGroup as BS3FormGroup } from 'react-bootstrap'
|
import {
|
||||||
|
FormGroup as BS3FormGroup,
|
||||||
|
FormGroupProps as BS3FormGroupProps,
|
||||||
|
} from 'react-bootstrap'
|
||||||
import FormGroup from '@/features/ui/components/bootstrap-5/form/form-group'
|
import FormGroup from '@/features/ui/components/bootstrap-5/form/form-group'
|
||||||
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
|
|
||||||
|
@ -8,19 +11,19 @@ type OLFormGroupProps = FormGroupProps & {
|
||||||
}
|
}
|
||||||
|
|
||||||
function OLFormGroup(props: OLFormGroupProps) {
|
function OLFormGroup(props: OLFormGroupProps) {
|
||||||
const { bs3Props, ...rest } = props
|
const { bs3Props, className, ...rest } = props
|
||||||
|
|
||||||
const bs3FormGroupProps: React.ComponentProps<typeof BS3FormGroup> = {
|
const bs3FormGroupProps: BS3FormGroupProps = {
|
||||||
children: rest.children,
|
children: rest.children,
|
||||||
controlId: rest.controlId,
|
controlId: rest.controlId,
|
||||||
className: rest.className,
|
className,
|
||||||
...bs3Props,
|
...bs3Props,
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BootstrapVersionSwitcher
|
<BootstrapVersionSwitcher
|
||||||
bs3={<BS3FormGroup {...bs3FormGroupProps} />}
|
bs3={<BS3FormGroup {...bs3FormGroupProps} />}
|
||||||
bs5={<FormGroup {...rest} />}
|
bs5={<FormGroup className={className} {...rest} />}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { Form, FormSelectProps } from 'react-bootstrap-5'
|
||||||
|
import {
|
||||||
|
FormControl as BS3FormControl,
|
||||||
|
FormControlProps as BS3FormControlProps,
|
||||||
|
} from 'react-bootstrap'
|
||||||
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
|
import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
|
||||||
|
|
||||||
|
type OLFormSelectProps = FormSelectProps & {
|
||||||
|
bs3Props?: Record<string, unknown>
|
||||||
|
}
|
||||||
|
|
||||||
|
function OLFormSelect(props: OLFormSelectProps) {
|
||||||
|
const { bs3Props, ...bs5Props } = props
|
||||||
|
|
||||||
|
const bs3FormSelectProps: BS3FormControlProps = {
|
||||||
|
bsSize: bs5Props.size,
|
||||||
|
name: bs5Props.name,
|
||||||
|
value: bs5Props.value,
|
||||||
|
disabled: bs5Props.disabled,
|
||||||
|
onChange: bs5Props.onChange as BS3FormControlProps['onChange'],
|
||||||
|
required: bs5Props.required,
|
||||||
|
placeholder: bs5Props.placeholder,
|
||||||
|
className: bs5Props.className,
|
||||||
|
...bs3Props,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all `aria-*` and `data-*` attributes
|
||||||
|
const extraProps = getAriaAndDataProps(bs5Props)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={
|
||||||
|
<BS3FormControl
|
||||||
|
componentClass="select"
|
||||||
|
{...bs3FormSelectProps}
|
||||||
|
{...extraProps}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
bs5={<Form.Select {...bs5Props} />}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OLFormSelect
|
|
@ -1,11 +1,12 @@
|
||||||
import FormText, {
|
import FormText, {
|
||||||
getFormTextColor,
|
FormTextProps,
|
||||||
|
getFormTextClass,
|
||||||
} from '@/features/ui/components/bootstrap-5/form/form-text'
|
} from '@/features/ui/components/bootstrap-5/form/form-text'
|
||||||
import PolymorphicComponent from '@/shared/components/polymorphic-component'
|
import PolymorphicComponent from '@/shared/components/polymorphic-component'
|
||||||
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
|
|
||||||
type OLFormTextProps = React.ComponentProps<typeof FormText> & {
|
type OLFormTextProps = FormTextProps & {
|
||||||
bs3Props?: Record<string, unknown>
|
bs3Props?: Record<string, unknown>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,15 +15,7 @@ function OLFormText(props: OLFormTextProps) {
|
||||||
|
|
||||||
const bs3HelpBlockProps = {
|
const bs3HelpBlockProps = {
|
||||||
children: rest.children,
|
children: rest.children,
|
||||||
className: classnames(
|
className: classnames('small', rest.className, getFormTextClass(rest.type)),
|
||||||
'small',
|
|
||||||
rest.className,
|
|
||||||
getFormTextColor({
|
|
||||||
isError: rest.isError,
|
|
||||||
isSuccess: rest.isSuccess,
|
|
||||||
isWarning: rest.isWarning,
|
|
||||||
})
|
|
||||||
),
|
|
||||||
as: 'span',
|
as: 'span',
|
||||||
...bs3Props,
|
...bs3Props,
|
||||||
} as const satisfies React.ComponentProps<typeof PolymorphicComponent>
|
} as const satisfies React.ComponentProps<typeof PolymorphicComponent>
|
||||||
|
|
|
@ -1,27 +1,42 @@
|
||||||
import { Form } from 'react-bootstrap-5'
|
import { Form } from 'react-bootstrap-5'
|
||||||
import { Form as BS3Form } from 'react-bootstrap'
|
import { Form as BS3Form, FormProps as BS3FormProps } from 'react-bootstrap'
|
||||||
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
|
import { ComponentProps } from 'react'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
|
||||||
|
|
||||||
type OLFormProps = React.ComponentProps<typeof Form> & {
|
type OLFormProps = ComponentProps<typeof Form> & {
|
||||||
bs3Props?: React.ComponentProps<typeof BS3Form>
|
bs3Props?: ComponentProps<typeof BS3Form>
|
||||||
}
|
}
|
||||||
|
|
||||||
function OLForm(props: OLFormProps) {
|
function OLForm(props: OLFormProps) {
|
||||||
const { bs3Props, ...rest } = props
|
const { bs3Props, ...rest } = props
|
||||||
|
|
||||||
const bs3FormProps: React.ComponentProps<typeof BS3Form> = {
|
const bs3FormProps: BS3FormProps = {
|
||||||
componentClass: rest.as,
|
componentClass: rest.as,
|
||||||
children: rest.children,
|
children: rest.children,
|
||||||
id: rest.id,
|
id: rest.id,
|
||||||
onSubmit: rest.onSubmit as React.FormEventHandler<BS3Form> | undefined,
|
onSubmit: rest.onSubmit as BS3FormProps['onSubmit'],
|
||||||
className: rest.className,
|
onClick: rest.onClick as BS3FormProps['onClick'],
|
||||||
|
name: rest.name,
|
||||||
|
noValidate: rest.noValidate,
|
||||||
role: rest.role,
|
role: rest.role,
|
||||||
...bs3Props,
|
...bs3Props,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bs3ClassName = classnames(
|
||||||
|
rest.className,
|
||||||
|
rest.validated ? 'was-validated' : null
|
||||||
|
)
|
||||||
|
|
||||||
|
// Get all `aria-*` and `data-*` attributes
|
||||||
|
const extraProps = getAriaAndDataProps(rest)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BootstrapVersionSwitcher
|
<BootstrapVersionSwitcher
|
||||||
bs3={<BS3Form {...bs3FormProps} />}
|
bs3={
|
||||||
|
<BS3Form className={bs3ClassName} {...bs3FormProps} {...extraProps} />
|
||||||
|
}
|
||||||
bs5={<Form {...rest} />}
|
bs5={<Form {...rest} />}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
|
@ -102,7 +102,7 @@ export function OLModalBody({ children, ...props }: OLModalBodyProps) {
|
||||||
|
|
||||||
const bs3ModalProps: BS3ModalBodyProps = {
|
const bs3ModalProps: BS3ModalBodyProps = {
|
||||||
componentClass: bs5Props.as,
|
componentClass: bs5Props.as,
|
||||||
bsClass: bs5Props.className,
|
className: bs5Props.className,
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -118,7 +118,7 @@ export function OLModalFooter({ children, ...props }: OLModalFooterProps) {
|
||||||
|
|
||||||
const bs3ModalProps: BS3ModalFooterProps = {
|
const bs3ModalProps: BS3ModalFooterProps = {
|
||||||
componentClass: bs5Props.as,
|
componentClass: bs5Props.as,
|
||||||
bsClass: bs5Props.className,
|
className: bs5Props.className,
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -21,7 +21,7 @@ export type DropdownProps = {
|
||||||
export type DropdownItemProps = PropsWithChildren<{
|
export type DropdownItemProps = PropsWithChildren<{
|
||||||
active?: boolean
|
active?: boolean
|
||||||
as?: ElementType
|
as?: ElementType
|
||||||
description?: string
|
description?: ReactNode
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
eventKey?: string | number
|
eventKey?: string | number
|
||||||
href?: string
|
href?: string
|
||||||
|
@ -32,6 +32,7 @@ export type DropdownItemProps = PropsWithChildren<{
|
||||||
className?: string
|
className?: string
|
||||||
role?: string
|
role?: string
|
||||||
tabIndex?: number
|
tabIndex?: number
|
||||||
|
target?: string
|
||||||
}>
|
}>
|
||||||
|
|
||||||
export type DropdownToggleProps = PropsWithChildren<{
|
export type DropdownToggleProps = PropsWithChildren<{
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
import importOverleafModules from '../../../macros/import-overleaf-module.macro'
|
import importOverleafModules from '../../../macros/import-overleaf-module.macro'
|
||||||
import { JSXElementConstructor, useCallback, useState } from 'react'
|
import { JSXElementConstructor, useCallback, useState } from 'react'
|
||||||
|
import { HelpSuggestionSearchProvider } from '../../../../modules/support/frontend/js/context/help-suggestion-search-context'
|
||||||
|
|
||||||
const [contactUsModalModules] = importOverleafModules('contactUsModal')
|
const [contactUsModalModules] = importOverleafModules('contactUsModal')
|
||||||
const ContactUsModal: JSXElementConstructor<{
|
const ContactUsModal: JSXElementConstructor<{
|
||||||
show: boolean
|
show: boolean
|
||||||
handleHide: () => void
|
handleHide: () => void
|
||||||
|
autofillProjectUrl: boolean
|
||||||
}> = contactUsModalModules?.import.default
|
}> = contactUsModalModules?.import.default
|
||||||
|
|
||||||
export const useContactUsModal = () => {
|
export const useContactUsModal = (options = { autofillProjectUrl: true }) => {
|
||||||
const [show, setShow] = useState(false)
|
const [show, setShow] = useState(false)
|
||||||
|
|
||||||
const hideModal = useCallback((event?: Event) => {
|
const hideModal = useCallback((event?: Event) => {
|
||||||
|
@ -21,7 +23,13 @@ export const useContactUsModal = () => {
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const modal = ContactUsModal && (
|
const modal = ContactUsModal && (
|
||||||
<ContactUsModal show={show} handleHide={hideModal} />
|
<HelpSuggestionSearchProvider>
|
||||||
|
<ContactUsModal
|
||||||
|
show={show}
|
||||||
|
handleHide={hideModal}
|
||||||
|
autofillProjectUrl={options.autofillProjectUrl}
|
||||||
|
/>
|
||||||
|
</HelpSuggestionSearchProvider>
|
||||||
)
|
)
|
||||||
|
|
||||||
return { modal, hideModal, showModal }
|
return { modal, hideModal, showModal }
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
import { useState } from 'react'
|
|
||||||
import useFetchMock from './hooks/use-fetch-mock'
|
|
||||||
import ContactUsModal from '../../modules/support/frontend/js/components/contact-us-modal'
|
|
||||||
import { ScopeDecorator } from './decorators/scope'
|
|
||||||
|
|
||||||
export const Generic = () => {
|
|
||||||
const [show, setShow] = useState(true)
|
|
||||||
|
|
||||||
const handleHide = () => setShow(false)
|
|
||||||
|
|
||||||
useFetchMock(fetchMock => {
|
|
||||||
fetchMock.post('/support', { status: 200 }, { delay: 1000 })
|
|
||||||
})
|
|
||||||
|
|
||||||
return <ContactUsModal show={show} handleHide={handleHide} />
|
|
||||||
}
|
|
||||||
|
|
||||||
export const RequestError = args => {
|
|
||||||
useFetchMock(fetchMock => {
|
|
||||||
fetchMock.post('/support', { status: 404 }, { delay: 250 })
|
|
||||||
})
|
|
||||||
|
|
||||||
return <ContactUsModal {...args} />
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
title: 'Shared / Modals / Contact Us',
|
|
||||||
component: ContactUsModal,
|
|
||||||
args: {
|
|
||||||
show: true,
|
|
||||||
handleHide: () => {},
|
|
||||||
},
|
|
||||||
argTypes: {
|
|
||||||
handleHide: { action: 'close modal' },
|
|
||||||
},
|
|
||||||
decorators: [ScopeDecorator],
|
|
||||||
}
|
|
93
services/web/frontend/stories/contact-us-modal.stories.tsx
Normal file
93
services/web/frontend/stories/contact-us-modal.stories.tsx
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
import { ComponentProps } from 'react'
|
||||||
|
import useFetchMock from './hooks/use-fetch-mock'
|
||||||
|
import ContactUsModal from '../../modules/support/frontend/js/components/contact-us-modal'
|
||||||
|
import { ScopeDecorator } from './decorators/scope'
|
||||||
|
import { StoryObj } from '@storybook/react'
|
||||||
|
import { FixedHelpSuggestionSearchProvider } from '../../modules/support/test/frontend/helpers/contact-us-modal-base-tests'
|
||||||
|
|
||||||
|
type Story = StoryObj<typeof ContactUsModal>
|
||||||
|
type ContactUsModalProps = ComponentProps<typeof ContactUsModal>
|
||||||
|
|
||||||
|
function bootstrap3Story(render: Story['render']): Story {
|
||||||
|
return {
|
||||||
|
render,
|
||||||
|
decorators: [
|
||||||
|
story => {
|
||||||
|
return ScopeDecorator(story)
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function bootstrap5Story(render: Story['render']): Story {
|
||||||
|
return {
|
||||||
|
render,
|
||||||
|
decorators: [
|
||||||
|
story => {
|
||||||
|
return ScopeDecorator(story, undefined, {
|
||||||
|
'ol-bootstrapVersion': 5,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
],
|
||||||
|
parameters: {
|
||||||
|
bootstrap5: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function GenericContactUsModal(args: ContactUsModalProps) {
|
||||||
|
useFetchMock(fetchMock => {
|
||||||
|
fetchMock.post('/support', { status: 200 }, { delay: 1000 })
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FixedHelpSuggestionSearchProvider>
|
||||||
|
<ContactUsModal {...args} />
|
||||||
|
</FixedHelpSuggestionSearchProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Generic: Story = bootstrap3Story(args => (
|
||||||
|
<GenericContactUsModal {...args} />
|
||||||
|
))
|
||||||
|
|
||||||
|
export const GenericBootstrap5: Story = bootstrap5Story(args => (
|
||||||
|
<GenericContactUsModal {...args} />
|
||||||
|
))
|
||||||
|
|
||||||
|
const ContactUsModalWithRequestError = (args: ContactUsModalProps) => {
|
||||||
|
useFetchMock(fetchMock => {
|
||||||
|
fetchMock.post('/support', { status: 404 }, { delay: 250 })
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FixedHelpSuggestionSearchProvider>
|
||||||
|
<ContactUsModal {...args} />
|
||||||
|
</FixedHelpSuggestionSearchProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderContactUsModalWithRequestError = (args: ContactUsModalProps) => (
|
||||||
|
<ContactUsModalWithRequestError {...args} />
|
||||||
|
)
|
||||||
|
|
||||||
|
export const RequestError: Story = bootstrap3Story(
|
||||||
|
renderContactUsModalWithRequestError
|
||||||
|
)
|
||||||
|
|
||||||
|
export const RequestErrorBootstrap5: Story = bootstrap5Story(
|
||||||
|
renderContactUsModalWithRequestError
|
||||||
|
)
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Shared / Modals / Contact Us',
|
||||||
|
component: ContactUsModal,
|
||||||
|
args: {
|
||||||
|
show: true,
|
||||||
|
handleHide: () => {},
|
||||||
|
autofillProjectUrl: true,
|
||||||
|
},
|
||||||
|
argTypes: {
|
||||||
|
handleHide: { action: 'close modal' },
|
||||||
|
},
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import FormGroup from '@/features/ui/components/bootstrap-5/form/form-group'
|
||||||
import FormText from '@/features/ui/components/bootstrap-5/form/form-text'
|
import FormText from '@/features/ui/components/bootstrap-5/form/form-text'
|
||||||
import FormControl from '@/features/ui/components/bootstrap-5/form/form-control'
|
import FormControl from '@/features/ui/components/bootstrap-5/form/form-control'
|
||||||
import MaterialIcon from '@/shared/components/material-icon'
|
import MaterialIcon from '@/shared/components/material-icon'
|
||||||
|
import FormFeedback from '@/features/ui/components/bootstrap-5/form/form-feedback'
|
||||||
|
|
||||||
const meta: Meta<React.ComponentProps<typeof FormControl>> = {
|
const meta: Meta<React.ComponentProps<typeof FormControl>> = {
|
||||||
title: 'Shared / Components / Bootstrap 5 / Form / Input',
|
title: 'Shared / Components / Bootstrap 5 / Form / Input',
|
||||||
|
@ -57,7 +58,7 @@ export const Info: Story = {
|
||||||
size="lg"
|
size="lg"
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isInfo>Info</FormText>
|
<FormText type="info">Info</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-2">
|
<FormGroup controlId="id-2">
|
||||||
|
@ -67,7 +68,7 @@ export const Info: Story = {
|
||||||
defaultValue="Regular input"
|
defaultValue="Regular input"
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isInfo>Info</FormText>
|
<FormText type="info">Info</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-3">
|
<FormGroup controlId="id-3">
|
||||||
|
@ -78,7 +79,7 @@ export const Info: Story = {
|
||||||
size="sm"
|
size="sm"
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isInfo>Info</FormText>
|
<FormText type="info">Info</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -98,7 +99,7 @@ export const Error: Story = {
|
||||||
isInvalid
|
isInvalid
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isError>Error</FormText>
|
<FormFeedback type="invalid">Error</FormFeedback>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-2">
|
<FormGroup controlId="id-2">
|
||||||
|
@ -109,7 +110,7 @@ export const Error: Story = {
|
||||||
isInvalid
|
isInvalid
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isError>Error</FormText>
|
<FormFeedback type="invalid">Error</FormFeedback>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-3">
|
<FormGroup controlId="id-3">
|
||||||
|
@ -121,7 +122,7 @@ export const Error: Story = {
|
||||||
isInvalid
|
isInvalid
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isError>Error</FormText>
|
<FormFeedback type="invalid">Error</FormFeedback>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -140,7 +141,7 @@ export const Warning: Story = {
|
||||||
size="lg"
|
size="lg"
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isWarning>Warning</FormText>
|
<FormText type="warning">Warning</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-2">
|
<FormGroup controlId="id-2">
|
||||||
|
@ -150,7 +151,7 @@ export const Warning: Story = {
|
||||||
defaultValue="Regular input"
|
defaultValue="Regular input"
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isWarning>Warning</FormText>
|
<FormText type="warning">Warning</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-3">
|
<FormGroup controlId="id-3">
|
||||||
|
@ -161,7 +162,7 @@ export const Warning: Story = {
|
||||||
size="sm"
|
size="sm"
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isWarning>Warning</FormText>
|
<FormText type="warning">Warning</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -180,7 +181,7 @@ export const Success: Story = {
|
||||||
size="lg"
|
size="lg"
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isSuccess>Success</FormText>
|
<FormText type="success">Success</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-2">
|
<FormGroup controlId="id-2">
|
||||||
|
@ -190,7 +191,7 @@ export const Success: Story = {
|
||||||
defaultValue="Regular input"
|
defaultValue="Regular input"
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isSuccess>Success</FormText>
|
<FormText type="success">Success</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-3">
|
<FormGroup controlId="id-3">
|
||||||
|
@ -201,7 +202,7 @@ export const Success: Story = {
|
||||||
size="sm"
|
size="sm"
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isSuccess>Success</FormText>
|
<FormText type="success">Success</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
@ -70,7 +70,7 @@ export const Info: Story = {
|
||||||
<option value="2">Two</option>
|
<option value="2">Two</option>
|
||||||
<option value="3">Three</option>
|
<option value="3">Three</option>
|
||||||
</Form.Select>
|
</Form.Select>
|
||||||
<FormText isInfo>Info</FormText>
|
<FormText type="info">Info</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-2">
|
<FormGroup controlId="id-2">
|
||||||
|
@ -81,7 +81,7 @@ export const Info: Story = {
|
||||||
<option value="2">Two</option>
|
<option value="2">Two</option>
|
||||||
<option value="3">Three</option>
|
<option value="3">Three</option>
|
||||||
</Form.Select>
|
</Form.Select>
|
||||||
<FormText isInfo>Info</FormText>
|
<FormText type="info">Info</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-3">
|
<FormGroup controlId="id-3">
|
||||||
|
@ -92,7 +92,7 @@ export const Info: Story = {
|
||||||
<option value="2">Two</option>
|
<option value="2">Two</option>
|
||||||
<option value="3">Three</option>
|
<option value="3">Three</option>
|
||||||
</Form.Select>
|
</Form.Select>
|
||||||
<FormText isInfo>Info</FormText>
|
<FormText type="info">Info</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -111,7 +111,7 @@ export const Error: Story = {
|
||||||
<option value="2">Two</option>
|
<option value="2">Two</option>
|
||||||
<option value="3">Three</option>
|
<option value="3">Three</option>
|
||||||
</Form.Select>
|
</Form.Select>
|
||||||
<FormText isError>Error</FormText>
|
<FormText type="error">Error</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-2">
|
<FormGroup controlId="id-2">
|
||||||
|
@ -122,7 +122,7 @@ export const Error: Story = {
|
||||||
<option value="2">Two</option>
|
<option value="2">Two</option>
|
||||||
<option value="3">Three</option>
|
<option value="3">Three</option>
|
||||||
</Form.Select>
|
</Form.Select>
|
||||||
<FormText isError>Error</FormText>
|
<FormText type="error">Error</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-3">
|
<FormGroup controlId="id-3">
|
||||||
|
@ -133,7 +133,7 @@ export const Error: Story = {
|
||||||
<option value="2">Two</option>
|
<option value="2">Two</option>
|
||||||
<option value="3">Three</option>
|
<option value="3">Three</option>
|
||||||
</Form.Select>
|
</Form.Select>
|
||||||
<FormText isError>Error</FormText>
|
<FormText type="error">Error</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -152,7 +152,7 @@ export const Warning: Story = {
|
||||||
<option value="2">Two</option>
|
<option value="2">Two</option>
|
||||||
<option value="3">Three</option>
|
<option value="3">Three</option>
|
||||||
</Form.Select>
|
</Form.Select>
|
||||||
<FormText isWarning>Warning</FormText>
|
<FormText type="warning">Warning</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-2">
|
<FormGroup controlId="id-2">
|
||||||
|
@ -163,7 +163,7 @@ export const Warning: Story = {
|
||||||
<option value="2">Two</option>
|
<option value="2">Two</option>
|
||||||
<option value="3">Three</option>
|
<option value="3">Three</option>
|
||||||
</Form.Select>
|
</Form.Select>
|
||||||
<FormText isWarning>Warning</FormText>
|
<FormText type="warning">Warning</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-3">
|
<FormGroup controlId="id-3">
|
||||||
|
@ -174,7 +174,7 @@ export const Warning: Story = {
|
||||||
<option value="2">Two</option>
|
<option value="2">Two</option>
|
||||||
<option value="3">Three</option>
|
<option value="3">Three</option>
|
||||||
</Form.Select>
|
</Form.Select>
|
||||||
<FormText isWarning>Warning</FormText>
|
<FormText type="warning">Warning</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -193,7 +193,7 @@ export const Success: Story = {
|
||||||
<option value="2">Two</option>
|
<option value="2">Two</option>
|
||||||
<option value="3">Three</option>
|
<option value="3">Three</option>
|
||||||
</Form.Select>
|
</Form.Select>
|
||||||
<FormText isSuccess>Success</FormText>
|
<FormText type="success">Success</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-2">
|
<FormGroup controlId="id-2">
|
||||||
|
@ -204,7 +204,7 @@ export const Success: Story = {
|
||||||
<option value="2">Two</option>
|
<option value="2">Two</option>
|
||||||
<option value="3">Three</option>
|
<option value="3">Three</option>
|
||||||
</Form.Select>
|
</Form.Select>
|
||||||
<FormText isSuccess>Success</FormText>
|
<FormText type="success">Success</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-3">
|
<FormGroup controlId="id-3">
|
||||||
|
@ -215,7 +215,7 @@ export const Success: Story = {
|
||||||
<option value="2">Two</option>
|
<option value="2">Two</option>
|
||||||
<option value="3">Three</option>
|
<option value="3">Three</option>
|
||||||
</Form.Select>
|
</Form.Select>
|
||||||
<FormText isSuccess>Success</FormText>
|
<FormText type="success">Success</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
@ -67,7 +67,7 @@ export const Info: Story = {
|
||||||
size="lg"
|
size="lg"
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isInfo>Info</FormText>
|
<FormText type="info">Info</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-2">
|
<FormGroup controlId="id-2">
|
||||||
|
@ -78,7 +78,7 @@ export const Info: Story = {
|
||||||
defaultValue="Regular input"
|
defaultValue="Regular input"
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isInfo>Info</FormText>
|
<FormText type="info">Info</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-3">
|
<FormGroup controlId="id-3">
|
||||||
|
@ -90,7 +90,7 @@ export const Info: Story = {
|
||||||
size="sm"
|
size="sm"
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isInfo>Info</FormText>
|
<FormText type="info">Info</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -111,7 +111,7 @@ export const Error: Story = {
|
||||||
isInvalid
|
isInvalid
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isError>Error</FormText>
|
<FormText type="error">Error</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-2">
|
<FormGroup controlId="id-2">
|
||||||
|
@ -123,7 +123,7 @@ export const Error: Story = {
|
||||||
isInvalid
|
isInvalid
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isError>Error</FormText>
|
<FormText type="error">Error</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-3">
|
<FormGroup controlId="id-3">
|
||||||
|
@ -136,7 +136,7 @@ export const Error: Story = {
|
||||||
isInvalid
|
isInvalid
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isError>Error</FormText>
|
<FormText type="error">Error</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -156,7 +156,7 @@ export const Warning: Story = {
|
||||||
size="lg"
|
size="lg"
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isWarning>Warning</FormText>
|
<FormText type="warning">Warning</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-2">
|
<FormGroup controlId="id-2">
|
||||||
|
@ -167,7 +167,7 @@ export const Warning: Story = {
|
||||||
defaultValue="Regular input"
|
defaultValue="Regular input"
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isWarning>Warning</FormText>
|
<FormText type="warning">Warning</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-3">
|
<FormGroup controlId="id-3">
|
||||||
|
@ -179,7 +179,7 @@ export const Warning: Story = {
|
||||||
size="sm"
|
size="sm"
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isWarning>Warning</FormText>
|
<FormText type="warning">Warning</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -199,7 +199,7 @@ export const Success: Story = {
|
||||||
size="lg"
|
size="lg"
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isSuccess>Success</FormText>
|
<FormText type="success">Success</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-2">
|
<FormGroup controlId="id-2">
|
||||||
|
@ -210,7 +210,7 @@ export const Success: Story = {
|
||||||
defaultValue="Regular input"
|
defaultValue="Regular input"
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isSuccess>Success</FormText>
|
<FormText type="success">Success</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<hr />
|
<hr />
|
||||||
<FormGroup controlId="id-3">
|
<FormGroup controlId="id-3">
|
||||||
|
@ -222,7 +222,7 @@ export const Success: Story = {
|
||||||
size="sm"
|
size="sm"
|
||||||
{...args}
|
{...args}
|
||||||
/>
|
/>
|
||||||
<FormText isSuccess>Success</FormText>
|
<FormText type="success">Success</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
@ -120,6 +120,7 @@ $form-check-input-disabled-opacity: 1;
|
||||||
// form-feedback-variables
|
// form-feedback-variables
|
||||||
$form-feedback-invalid-color: $bg-danger-01;
|
$form-feedback-invalid-color: $bg-danger-01;
|
||||||
$form-feedback-icon-invalid: null;
|
$form-feedback-icon-invalid: null;
|
||||||
|
$form-feedback-margin-top: 0; // Our feedback component wraps Form.Text, which takes care of top margin
|
||||||
|
|
||||||
// form-validation-colors
|
// form-validation-colors
|
||||||
$form-invalid-color: $form-feedback-invalid-color;
|
$form-invalid-color: $form-feedback-invalid-color;
|
||||||
|
|
|
@ -3,3 +3,6 @@ $footer-height: 50px;
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
$header-height: 68px;
|
$header-height: 68px;
|
||||||
|
|
||||||
|
// Forms
|
||||||
|
$form-group-margin-bottom: $spacing-06;
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-group {
|
.form-group {
|
||||||
margin-bottom: var(--spacing-06);
|
margin-bottom: $form-group-margin-bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-control-wrapper {
|
.form-control-wrapper {
|
||||||
|
|
|
@ -85,12 +85,3 @@
|
||||||
.git-bridge-optional-tokens-actions {
|
.git-bridge-optional-tokens-actions {
|
||||||
margin-top: var(--spacing-05);
|
margin-top: var(--spacing-05);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Contact us modal
|
|
||||||
.contact-us-modal-textarea {
|
|
||||||
height: 120px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-form-messages .notification {
|
|
||||||
margin-bottom: var(--spacing-05);
|
|
||||||
}
|
|
||||||
|
|
|
@ -32,3 +32,9 @@ $is-overleaf-light: false;
|
||||||
|
|
||||||
// Page layout that isn't related to a particular component or page
|
// Page layout that isn't related to a particular component or page
|
||||||
@import 'base/layout';
|
@import 'base/layout';
|
||||||
|
|
||||||
|
// Modals
|
||||||
|
@import 'modals/all';
|
||||||
|
|
||||||
|
// Pages custom style
|
||||||
|
@import 'pages/all';
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
@import 'contact-us-modal';
|
|
@ -0,0 +1,82 @@
|
||||||
|
.contact-us-modal-textarea {
|
||||||
|
height: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-form-messages .notification {
|
||||||
|
margin-bottom: var(--spacing-05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-suggestions {
|
||||||
|
@include body-sm;
|
||||||
|
|
||||||
|
margin: 0 calc(-1 * var(--bs-modal-padding)) var(--spacing-05);
|
||||||
|
padding: var(--spacing-05) 0;
|
||||||
|
color: var(--content-secondary);
|
||||||
|
background-color: var(--bg-light-secondary);
|
||||||
|
border-top: solid 1px var(--border-primary-dark);
|
||||||
|
border-bottom: solid 1px var(--border-primary-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-suggestion-label {
|
||||||
|
margin-bottom: var(--spacing-05);
|
||||||
|
padding: 0 var(--spacing-07);
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-suggestion-list {
|
||||||
|
padding-left: 0;
|
||||||
|
list-style: none;
|
||||||
|
background-color: var(--white);
|
||||||
|
border-top: solid 1px var(--border-primary-dark);
|
||||||
|
border-bottom: solid 1px var(--border-primary-dark);
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
li:last-child .contact-suggestion-list-item {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-suggestion-list-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
color: var(--content-secondary);
|
||||||
|
padding: var(--spacing-05) var(--spacing-07);
|
||||||
|
border-bottom: solid 1px var(--border-divider);
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
background-color: var(--bg-light-secondary);
|
||||||
|
|
||||||
|
span {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa {
|
||||||
|
color: var(--neutral-30);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-suggestions-dropdown {
|
||||||
|
width: calc(100% - 2 * var(--bs-modal-padding));
|
||||||
|
|
||||||
|
.dropdown-header {
|
||||||
|
@include body-sm;
|
||||||
|
|
||||||
|
padding: var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item {
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group + & {
|
||||||
|
margin-top: $spacing-02 - $form-group-margin-bottom;
|
||||||
|
}
|
||||||
|
}
|
|
@ -357,6 +357,15 @@ input[type='checkbox'],
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
color: lighten(@text-color, 25%); // lighten the text some for contrast
|
color: lighten(@text-color, 25%); // lighten the text some for contrast
|
||||||
|
|
||||||
|
// Hide help blocks used as validation messages by default
|
||||||
|
&.invalid-only {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
.has-error & {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline forms
|
// Inline forms
|
||||||
|
|
|
@ -1455,6 +1455,8 @@
|
||||||
"please_enter_email": "Please enter your email address",
|
"please_enter_email": "Please enter your email address",
|
||||||
"please_get_in_touch": "Please get in touch",
|
"please_get_in_touch": "Please get in touch",
|
||||||
"please_link_before_making_primary": "Please confirm your email by linking to your institutional account before making it the primary email.",
|
"please_link_before_making_primary": "Please confirm your email by linking to your institutional account before making it the primary email.",
|
||||||
|
"please_provide_a_message": "Please provide a message",
|
||||||
|
"please_provide_a_subject": "Please provide a subject",
|
||||||
"please_reconfirm_institutional_email": "Please take a moment to confirm your institutional email address or <0>remove it</0> from your account.",
|
"please_reconfirm_institutional_email": "Please take a moment to confirm your institutional email address or <0>remove it</0> from your account.",
|
||||||
"please_reconfirm_your_affiliation_before_making_this_primary": "Please confirm your affiliation before making this the primary.",
|
"please_reconfirm_your_affiliation_before_making_this_primary": "Please confirm your affiliation before making this the primary.",
|
||||||
"please_refresh": "Please refresh the page to continue.",
|
"please_refresh": "Please refresh the page to continue.",
|
||||||
|
|
Loading…
Reference in a new issue