mirror of
https://github.com/overleaf/overleaf.git
synced 2024-09-16 02:52:31 -04:00
Merge pull request #17990 from overleaf/rd-button-links
[web] Migrating buttons to Bootstrap 5 on the Account Settings page GitOrigin-RevId: c9dfa9b1dee50f4c0b30abf8ac464e53cf98db95
This commit is contained in:
parent
06f34c71bc
commit
898acab307
25 changed files with 277 additions and 146 deletions
|
@ -124,7 +124,8 @@ function AccountInfoSection() {
|
||||||
type="submit"
|
type="submit"
|
||||||
variant="primary"
|
variant="primary"
|
||||||
form="account-info-form"
|
form="account-info-form"
|
||||||
isLoading={isLoading || !isFormValid}
|
disabled={!isFormValid}
|
||||||
|
isLoading={isLoading}
|
||||||
bs3Props={{
|
bs3Props={{
|
||||||
loading: isLoading ? `${t('saving')}…` : t('update'),
|
loading: isLoading ? `${t('saving')}…` : t('update'),
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { useTranslation, Trans } from 'react-i18next'
|
import { useTranslation, Trans } from 'react-i18next'
|
||||||
import { Modal, Button } from 'react-bootstrap'
|
import { Modal } from 'react-bootstrap'
|
||||||
import AccessibleModal from '../../../../../../shared/components/accessible-modal'
|
import AccessibleModal from '../../../../../../shared/components/accessible-modal'
|
||||||
import { MergeAndOverride } from '../../../../../../../../types/utils'
|
import { MergeAndOverride } from '../../../../../../../../types/utils'
|
||||||
|
import ButtonWrapper from '@/features/ui/components/bootstrap-5/wrappers/button-wrapper'
|
||||||
|
|
||||||
type ConfirmationModalProps = MergeAndOverride<
|
type ConfirmationModalProps = MergeAndOverride<
|
||||||
React.ComponentProps<typeof AccessibleModal>,
|
React.ComponentProps<typeof AccessibleModal>,
|
||||||
|
@ -40,22 +41,24 @@ function ConfirmationModal({
|
||||||
<p className="mb-0">{t('log_in_with_primary_email_address')}</p>
|
<p className="mb-0">{t('log_in_with_primary_email_address')}</p>
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<Button
|
<ButtonWrapper
|
||||||
bsStyle={null}
|
variant="secondary"
|
||||||
className="btn-secondary-info btn-secondary"
|
|
||||||
onClick={onHide}
|
onClick={onHide}
|
||||||
|
bs3Props={{
|
||||||
|
bsStyle: null,
|
||||||
|
className: 'btn-secondary-info btn-secondary',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{t('cancel')}
|
{t('cancel')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
<Button
|
<ButtonWrapper
|
||||||
type="button"
|
variant="primary"
|
||||||
bsStyle={null}
|
|
||||||
className="btn-primary"
|
|
||||||
disabled={isConfirmDisabled}
|
disabled={isConfirmDisabled}
|
||||||
onClick={onConfirm}
|
onClick={onConfirm}
|
||||||
|
bs3Props={{ bsStyle: null, className: 'btn-primary' }}
|
||||||
>
|
>
|
||||||
{t('confirm')}
|
{t('confirm')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
</Modal.Footer>
|
</Modal.Footer>
|
||||||
</AccessibleModal>
|
</AccessibleModal>
|
||||||
)
|
)
|
||||||
|
|
|
@ -82,7 +82,7 @@ function MakePrimary({ userEmailData, makePrimaryAsync }: MakePrimaryProps) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{makePrimaryAsync.isLoading ? (
|
{makePrimaryAsync.isLoading ? (
|
||||||
<PrimaryButton disabled>
|
<PrimaryButton disabled isLoading={state.isLoading}>
|
||||||
{t('processing_uppercase')}…
|
{t('processing_uppercase')}…
|
||||||
</PrimaryButton>
|
</PrimaryButton>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
@ -1,19 +1,24 @@
|
||||||
import ButtonWrapper, {
|
import ButtonWrapper, {
|
||||||
ButtonWrapperProps,
|
ButtonWrapperProps,
|
||||||
} from '@/features/ui/components/bootstrap-5/wrappers/button-wrapper'
|
} from '@/features/ui/components/bootstrap-5/wrappers/button-wrapper'
|
||||||
import { bsVersion } from '@/features/utils/bootstrap-5'
|
|
||||||
|
|
||||||
function PrimaryButton({ children, disabled, onClick }: ButtonWrapperProps) {
|
function PrimaryButton({
|
||||||
|
children,
|
||||||
|
disabled,
|
||||||
|
isLoading,
|
||||||
|
onClick,
|
||||||
|
}: ButtonWrapperProps) {
|
||||||
return (
|
return (
|
||||||
<ButtonWrapper
|
<ButtonWrapper
|
||||||
size="small"
|
size="small"
|
||||||
disabled={disabled}
|
disabled={disabled && !isLoading}
|
||||||
|
isLoading={isLoading}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
bs3Props={{ bsStyle: null }}
|
bs3Props={{
|
||||||
className={bsVersion({
|
bsStyle: null,
|
||||||
bs3: 'btn-secondary btn-secondary-info',
|
className: 'btn-secondary btn-secondary-info',
|
||||||
})}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</ButtonWrapper>
|
</ButtonWrapper>
|
||||||
|
|
|
@ -214,7 +214,8 @@ function AddEmail() {
|
||||||
>
|
>
|
||||||
<AddNewEmailBtn
|
<AddNewEmailBtn
|
||||||
email={newEmail}
|
email={newEmail}
|
||||||
disabled={isLoading || state.isLoading}
|
disabled={state.isLoading}
|
||||||
|
isLoading={isLoading}
|
||||||
onClick={handleAddNewEmail}
|
onClick={handleAddNewEmail}
|
||||||
/>
|
/>
|
||||||
</Cell>
|
</Cell>
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Button, ButtonProps } from 'react-bootstrap'
|
import ButtonWrapper, {
|
||||||
|
ButtonWrapperProps,
|
||||||
|
} from '@/features/ui/components/bootstrap-5/wrappers/button-wrapper'
|
||||||
|
|
||||||
function AddAnotherEmailBtn({ onClick, ...props }: ButtonProps) {
|
function AddAnotherEmailBtn({ onClick, ...props }: ButtonWrapperProps) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<ButtonWrapper
|
||||||
className="btn-inline-link"
|
variant="link"
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
{...props}
|
{...props}
|
||||||
bsStyle={null}
|
bs3Props={{ bsStyle: null, className: 'btn-inline-link' }}
|
||||||
>
|
>
|
||||||
{t('add_another_email')}
|
{t('add_another_email')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Button, ButtonProps } from 'react-bootstrap'
|
import ButtonWrapper, {
|
||||||
|
ButtonWrapperProps,
|
||||||
|
} from '@/features/ui/components/bootstrap-5/wrappers/button-wrapper'
|
||||||
|
|
||||||
const isValidEmail = (email: string) => {
|
const isValidEmail = (email: string) => {
|
||||||
return Boolean(email)
|
return Boolean(email)
|
||||||
|
@ -7,20 +9,26 @@ const isValidEmail = (email: string) => {
|
||||||
|
|
||||||
type AddNewEmailColProps = {
|
type AddNewEmailColProps = {
|
||||||
email: string
|
email: string
|
||||||
} & ButtonProps
|
} & ButtonWrapperProps
|
||||||
|
|
||||||
function AddNewEmailBtn({ email, disabled, ...props }: AddNewEmailColProps) {
|
function AddNewEmailBtn({
|
||||||
|
email,
|
||||||
|
disabled,
|
||||||
|
isLoading,
|
||||||
|
...props
|
||||||
|
}: AddNewEmailColProps) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<ButtonWrapper
|
||||||
bsSize="small"
|
size="small"
|
||||||
bsStyle="primary"
|
variant="primary"
|
||||||
disabled={disabled || !isValidEmail(email)}
|
disabled={(disabled && !isLoading) || !isValidEmail(email)}
|
||||||
|
isLoading={isLoading}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{t('add_new_email')}
|
{t('add_new_email')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,25 @@
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Button, ButtonProps } from 'react-bootstrap'
|
import ButtonWrapper, {
|
||||||
|
ButtonWrapperProps,
|
||||||
|
} from '@/features/ui/components/bootstrap-5/wrappers/button-wrapper'
|
||||||
|
|
||||||
function EmailAffiliatedWithInstitution({ onClick, ...props }: ButtonProps) {
|
function EmailAffiliatedWithInstitution({
|
||||||
|
onClick,
|
||||||
|
...props
|
||||||
|
}: ButtonWrapperProps) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mt-1">
|
<div className="mt-1">
|
||||||
{t('is_email_affiliated')}
|
{t('is_email_affiliated')}
|
||||||
<Button
|
<ButtonWrapper
|
||||||
className="btn-inline-link"
|
variant="link"
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
|
bs3Props={{ bsStyle: null, className: 'btn-inline-link' }}
|
||||||
{...props}
|
{...props}
|
||||||
bsStyle={null}
|
|
||||||
>
|
>
|
||||||
{t('let_us_know')}
|
{t('let_us_know')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { Button } from 'react-bootstrap'
|
|
||||||
import { Trans, useTranslation } from 'react-i18next'
|
import { Trans, useTranslation } from 'react-i18next'
|
||||||
import { DomainInfo } from './input'
|
import { DomainInfo } from './input'
|
||||||
import { ExposedSettings } from '../../../../../../../types/exposed-settings'
|
import { ExposedSettings } from '../../../../../../../types/exposed-settings'
|
||||||
import getMeta from '../../../../../utils/meta'
|
import getMeta from '../../../../../utils/meta'
|
||||||
import { useLocation } from '../../../../../shared/hooks/use-location'
|
import { useLocation } from '../../../../../shared/hooks/use-location'
|
||||||
|
import ButtonWrapper from '@/features/ui/components/bootstrap-5/wrappers/button-wrapper'
|
||||||
|
|
||||||
type SSOLinkingInfoProps = {
|
type SSOLinkingInfoProps = {
|
||||||
domainInfo: DomainInfo
|
domainInfo: DomainInfo
|
||||||
|
@ -54,14 +54,15 @@ function SsoLinkingInfo({ domainInfo, email }: SSOLinkingInfoProps) {
|
||||||
{t('find_out_more_about_institution_login')}.
|
{t('find_out_more_about_institution_login')}.
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
<Button
|
<ButtonWrapper
|
||||||
bsStyle="primary"
|
variant="primary"
|
||||||
className="btn-sm btn-link-accounts"
|
className="btn-link-accounts"
|
||||||
|
size="small"
|
||||||
disabled={linkAccountsButtonDisabled}
|
disabled={linkAccountsButtonDisabled}
|
||||||
onClick={handleLinkAccountsButtonClick}
|
onClick={handleLinkAccountsButtonClick}
|
||||||
>
|
>
|
||||||
{t('link_accounts_and_add_email')}
|
{t('link_accounts_and_add_email')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Button } from 'react-bootstrap'
|
import ButtonWrapper from '@/features/ui/components/bootstrap-5/wrappers/button-wrapper'
|
||||||
|
|
||||||
type UniversityNameProps = {
|
type UniversityNameProps = {
|
||||||
name: string
|
name: string
|
||||||
|
@ -14,9 +14,13 @@ function UniversityName({ name, onClick }: UniversityNameProps) {
|
||||||
{name}
|
{name}
|
||||||
<span className="small">
|
<span className="small">
|
||||||
{' '}
|
{' '}
|
||||||
<Button className="btn-inline-link" onClick={onClick} bsStyle={null}>
|
<ButtonWrapper
|
||||||
|
variant="link"
|
||||||
|
onClick={onClick}
|
||||||
|
bs3Props={{ bsStyle: null, className: 'btn-inline-link' }}
|
||||||
|
>
|
||||||
{t('change')}
|
{t('change')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { useState, useEffect, useRef } from 'react'
|
import { useState, useEffect, useRef } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { UserEmailData } from '../../../../../../types/user-email'
|
import { UserEmailData } from '../../../../../../types/user-email'
|
||||||
import { Button } from 'react-bootstrap'
|
|
||||||
import { isChangingAffiliation } from '../../utils/selectors'
|
import { isChangingAffiliation } from '../../utils/selectors'
|
||||||
import { useUserEmailsContext } from '../../context/user-email-context'
|
import { useUserEmailsContext } from '../../context/user-email-context'
|
||||||
import DownshiftInput from './downshift-input'
|
import DownshiftInput from './downshift-input'
|
||||||
|
@ -10,6 +9,7 @@ import { getJSON, postJSON } from '../../../../infrastructure/fetch-json'
|
||||||
import defaultRoles from '../../data/roles'
|
import defaultRoles from '../../data/roles'
|
||||||
import defaultDepartments from '../../data/departments'
|
import defaultDepartments from '../../data/departments'
|
||||||
import { University } from '../../../../../../types/university'
|
import { University } from '../../../../../../types/university'
|
||||||
|
import ButtonWrapper from '@/features/ui/components/bootstrap-5/wrappers/button-wrapper'
|
||||||
|
|
||||||
type InstitutionAndRoleProps = {
|
type InstitutionAndRoleProps = {
|
||||||
userEmailData: UserEmailData
|
userEmailData: UserEmailData
|
||||||
|
@ -107,11 +107,15 @@ function InstitutionAndRole({ userEmailData }: InstitutionAndRoleProps) {
|
||||||
<br />
|
<br />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<Button className="btn-inline-link" onClick={handleChangeAffiliation}>
|
<ButtonWrapper
|
||||||
|
onClick={handleChangeAffiliation}
|
||||||
|
variant="link"
|
||||||
|
bs3Props={{ className: 'btn-inline-link' }}
|
||||||
|
>
|
||||||
{!affiliation.department && !affiliation.role
|
{!affiliation.department && !affiliation.role
|
||||||
? t('add_role_and_department')
|
? t('add_role_and_department')
|
||||||
: t('change')}
|
: t('change')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="affiliation-change-container small">
|
<div className="affiliation-change-container small">
|
||||||
|
@ -135,23 +139,30 @@ function InstitutionAndRole({ userEmailData }: InstitutionAndRoleProps) {
|
||||||
setValue={setDepartment}
|
setValue={setDepartment}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<ButtonWrapper
|
||||||
bsSize="small"
|
size="small"
|
||||||
bsStyle="primary"
|
variant="primary"
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={!role || !department || isLoading || state.isLoading}
|
disabled={!role || !department}
|
||||||
|
isLoading={isLoading}
|
||||||
|
bs3Props={{
|
||||||
|
loading: isLoading
|
||||||
|
? `${t('saving')}…`
|
||||||
|
: t('save_or_cancel-save'),
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{isLoading ? <>{t('saving')}…</> : t('save_or_cancel-save')}
|
{t('save_or_cancel-save')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
{!isLoading && (
|
{!isLoading && (
|
||||||
<>
|
<>
|
||||||
<span className="mx-1">{t('save_or_cancel-or')}</span>
|
<span className="mx-1">{t('save_or_cancel-or')}</span>
|
||||||
<Button
|
<ButtonWrapper
|
||||||
className="btn-inline-link"
|
variant="link"
|
||||||
onClick={handleCancelAffiliationChange}
|
onClick={handleCancelAffiliationChange}
|
||||||
|
bs3Props={{ className: 'btn-inline-link' }}
|
||||||
>
|
>
|
||||||
{t('save_or_cancel-cancel')}
|
{t('save_or_cancel-cancel')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -146,9 +146,13 @@ function ReconfirmationInfo({ userEmailData }: ReconfirmationInfoProps) {
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<ButtonWrapper
|
<ButtonWrapper
|
||||||
className="btn-inline-link"
|
variant="link"
|
||||||
disabled={state.isLoading}
|
disabled={state.isLoading}
|
||||||
onClick={handleRequestReconfirmation}
|
onClick={handleRequestReconfirmation}
|
||||||
|
bs3Props={{
|
||||||
|
className: 'btn-inline-link',
|
||||||
|
bsStyle: null,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{t('resend_confirmation_email')}
|
{t('resend_confirmation_email')}
|
||||||
</ButtonWrapper>
|
</ButtonWrapper>
|
||||||
|
@ -157,7 +161,8 @@ function ReconfirmationInfo({ userEmailData }: ReconfirmationInfoProps) {
|
||||||
) : (
|
) : (
|
||||||
<ButtonWrapper
|
<ButtonWrapper
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
disabled={state.isLoading || isPending}
|
disabled={isPending}
|
||||||
|
isLoading={isLoading}
|
||||||
onClick={handleRequestReconfirmation}
|
onClick={handleRequestReconfirmation}
|
||||||
bs3Props={{ bsStyle: 'info' }}
|
bs3Props={{ bsStyle: 'info' }}
|
||||||
>
|
>
|
||||||
|
@ -200,9 +205,10 @@ function ReconfirmationInfo({ userEmailData }: ReconfirmationInfoProps) {
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<ButtonWrapper
|
<ButtonWrapper
|
||||||
className="btn-inline-link"
|
variant="link"
|
||||||
disabled={state.isLoading}
|
disabled={state.isLoading}
|
||||||
onClick={handleRequestReconfirmation}
|
onClick={handleRequestReconfirmation}
|
||||||
|
bs3Props={{ className: 'btn-inline-link', bsStyle: null }}
|
||||||
>
|
>
|
||||||
{t('resend_confirmation_email')}
|
{t('resend_confirmation_email')}
|
||||||
</ButtonWrapper>
|
</ButtonWrapper>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import Icon from '../../../../shared/components/icon'
|
import Icon from '../../../../shared/components/icon'
|
||||||
import { Button } from 'react-bootstrap'
|
|
||||||
import { FetchError, postJSON } from '../../../../infrastructure/fetch-json'
|
import { FetchError, postJSON } from '../../../../infrastructure/fetch-json'
|
||||||
import useAsync from '../../../../shared/hooks/use-async'
|
import useAsync from '../../../../shared/hooks/use-async'
|
||||||
import { UserEmailData } from '../../../../../../types/user-email'
|
import { UserEmailData } from '../../../../../../types/user-email'
|
||||||
import { useUserEmailsContext } from '../../context/user-email-context'
|
import { useUserEmailsContext } from '../../context/user-email-context'
|
||||||
|
import ButtonWrapper from '@/features/ui/components/bootstrap-5/wrappers/button-wrapper'
|
||||||
|
|
||||||
type ResendConfirmationEmailButtonProps = {
|
type ResendConfirmationEmailButtonProps = {
|
||||||
email: UserEmailData['email']
|
email: UserEmailData['email']
|
||||||
|
@ -47,14 +47,14 @@ function ResendConfirmationEmailButton({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button
|
<ButtonWrapper
|
||||||
className="btn-inline-link"
|
variant="link"
|
||||||
disabled={state.isLoading}
|
disabled={state.isLoading || isLoading}
|
||||||
onClick={handleResendConfirmationEmail}
|
onClick={handleResendConfirmationEmail}
|
||||||
bsStyle={null}
|
bs3Props={{ bsStyle: null, className: 'btn-inline-link' }}
|
||||||
>
|
>
|
||||||
{t('resend_confirmation_email')}
|
{t('resend_confirmation_email')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
<br />
|
<br />
|
||||||
{isError && (
|
{isError && (
|
||||||
<div className="text-danger">
|
<div className="text-danger">
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { Trans, useTranslation } from 'react-i18next'
|
import { Trans, useTranslation } from 'react-i18next'
|
||||||
import { UserEmailData } from '../../../../../../types/user-email'
|
import { UserEmailData } from '../../../../../../types/user-email'
|
||||||
import { Button } from 'react-bootstrap'
|
|
||||||
import Email from './email'
|
import Email from './email'
|
||||||
import InstitutionAndRole from './institution-and-role'
|
import InstitutionAndRole from './institution-and-role'
|
||||||
import EmailCell from './cell'
|
import EmailCell from './cell'
|
||||||
|
@ -16,6 +15,7 @@ import { useLocation } from '../../../../shared/hooks/use-location'
|
||||||
import RowWrapper from '@/features/ui/components/bootstrap-5/wrappers/row-wrapper'
|
import RowWrapper from '@/features/ui/components/bootstrap-5/wrappers/row-wrapper'
|
||||||
import ColWrapper from '@/features/ui/components/bootstrap-5/wrappers/col-wrapper'
|
import ColWrapper from '@/features/ui/components/bootstrap-5/wrappers/col-wrapper'
|
||||||
import { bsVersion } from '@/features/utils/bootstrap-5'
|
import { bsVersion } from '@/features/utils/bootstrap-5'
|
||||||
|
import ButtonWrapper from '@/features/ui/components/bootstrap-5/wrappers/button-wrapper'
|
||||||
|
|
||||||
type EmailsRowProps = {
|
type EmailsRowProps = {
|
||||||
userEmailData: UserEmailData
|
userEmailData: UserEmailData
|
||||||
|
@ -160,14 +160,15 @@ function SSOAffiliationInfo({ userEmailData }: SSOAffiliationInfoProps) {
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<EmailCell>
|
<EmailCell>
|
||||||
<Button
|
<ButtonWrapper
|
||||||
bsStyle="primary"
|
variant="primary"
|
||||||
className="btn-sm btn-link-accounts"
|
className="btn-link-accounts"
|
||||||
disabled={linkAccountsButtonDisabled}
|
disabled={linkAccountsButtonDisabled}
|
||||||
onClick={handleLinkAccountsButtonClick}
|
onClick={handleLinkAccountsButtonClick}
|
||||||
|
size="small"
|
||||||
>
|
>
|
||||||
{t('link_accounts')}
|
{t('link_accounts')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
</EmailCell>
|
</EmailCell>
|
||||||
</ColWrapper>
|
</ColWrapper>
|
||||||
</RowWrapper>
|
</RowWrapper>
|
||||||
|
|
|
@ -2,6 +2,8 @@ import { useState, useCallback } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import LeaveModal from './leave/modal'
|
import LeaveModal from './leave/modal'
|
||||||
import getMeta from '../../../utils/meta'
|
import getMeta from '../../../utils/meta'
|
||||||
|
import ButtonWrapper from '@/features/ui/components/bootstrap-5/wrappers/button-wrapper'
|
||||||
|
import { bsVersion } from '@/features/utils/bootstrap-5'
|
||||||
|
|
||||||
function LeaveSection() {
|
function LeaveSection() {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
@ -28,9 +30,16 @@ function LeaveSection() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{t('need_to_leave')}{' '}
|
{t('need_to_leave')}{' '}
|
||||||
<button className="btn btn-inline-link btn-danger" onClick={handleOpen}>
|
<ButtonWrapper
|
||||||
|
className={bsVersion({
|
||||||
|
bs3: 'btn btn-inline-link btn-danger',
|
||||||
|
bs5: 'btn-link',
|
||||||
|
})}
|
||||||
|
variant="danger"
|
||||||
|
onClick={handleOpen}
|
||||||
|
>
|
||||||
{t('delete_your_account')}
|
{t('delete_your_account')}
|
||||||
</button>
|
</ButtonWrapper>
|
||||||
<LeaveModal isOpen={isModalOpen} handleClose={handleClose} />
|
<LeaveModal isOpen={isModalOpen} handleClose={handleClose} />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { useState, Dispatch, SetStateAction } from 'react'
|
import { useState, Dispatch, SetStateAction } from 'react'
|
||||||
import { Modal, Button } from 'react-bootstrap'
|
import { Modal } from 'react-bootstrap'
|
||||||
import { useTranslation, Trans } from 'react-i18next'
|
import { useTranslation, Trans } from 'react-i18next'
|
||||||
import getMeta from '../../../../utils/meta'
|
import getMeta from '../../../../utils/meta'
|
||||||
import LeaveModalForm, { LeaveModalFormProps } from './modal-form'
|
import LeaveModalForm, { LeaveModalFormProps } from './modal-form'
|
||||||
import { ExposedSettings } from '../../../../../../types/exposed-settings'
|
import { ExposedSettings } from '../../../../../../types/exposed-settings'
|
||||||
|
import ButtonWrapper from '@/features/ui/components/bootstrap-5/wrappers/button-wrapper'
|
||||||
|
|
||||||
type LeaveModalContentProps = {
|
type LeaveModalContentProps = {
|
||||||
handleHide: () => void
|
handleHide: () => void
|
||||||
|
@ -68,24 +69,23 @@ function LeaveModalContent({
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
|
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<Button
|
<ButtonWrapper
|
||||||
type="button"
|
|
||||||
disabled={inFlight}
|
disabled={inFlight}
|
||||||
onClick={handleHide}
|
onClick={handleHide}
|
||||||
bsStyle={null}
|
variant="secondary"
|
||||||
className="btn-secondary"
|
bs3Props={{ bsStyle: null, className: 'btn-secondary' }}
|
||||||
>
|
>
|
||||||
{t('cancel')}
|
{t('cancel')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
|
|
||||||
<Button
|
<ButtonWrapper
|
||||||
form="leave-form"
|
form="leave-form"
|
||||||
type="submit"
|
type="submit"
|
||||||
bsStyle="danger"
|
variant="danger"
|
||||||
disabled={inFlight || !isFormValid}
|
disabled={inFlight || !isFormValid}
|
||||||
>
|
>
|
||||||
{inFlight ? <>{t('deleting')}…</> : t('delete')}
|
{inFlight ? <>{t('deleting')}…</> : t('delete')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
</Modal.Footer>
|
</Modal.Footer>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { ReactNode } from 'react'
|
import { ReactNode } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Button } from 'react-bootstrap'
|
|
||||||
import { sendMB } from '@/infrastructure/event-tracking'
|
import { sendMB } from '@/infrastructure/event-tracking'
|
||||||
import BadgeWrapper from '@/features/ui/components/bootstrap-5/wrappers/badge-wrapper'
|
import BadgeWrapper from '@/features/ui/components/bootstrap-5/wrappers/badge-wrapper'
|
||||||
|
import ButtonWrapper from '@/features/ui/components/bootstrap-5/wrappers/button-wrapper'
|
||||||
|
|
||||||
function trackUpgradeClick() {
|
function trackUpgradeClick() {
|
||||||
sendMB('settings-upgrade-click')
|
sendMB('settings-upgrade-click')
|
||||||
|
@ -92,36 +92,39 @@ function ActionButton({
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
if (!hasFeature) {
|
if (!hasFeature) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<ButtonWrapper
|
||||||
bsStyle={null}
|
variant="primary"
|
||||||
className="btn-primary"
|
|
||||||
href="/user/subscription/plans"
|
href="/user/subscription/plans"
|
||||||
onClick={trackUpgradeClick}
|
onClick={trackUpgradeClick}
|
||||||
|
bs3Props={{ bsStyle: null, className: 'btn-primary' }}
|
||||||
>
|
>
|
||||||
<span className="text-capitalize">{t('upgrade')}</span>
|
<span className="text-capitalize">{t('upgrade')}</span>
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
)
|
)
|
||||||
} else if (linked) {
|
} else if (linked) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<ButtonWrapper
|
||||||
className="btn-danger-ghost"
|
variant="danger-ghost"
|
||||||
onClick={handleUnlinkClick}
|
onClick={handleUnlinkClick}
|
||||||
bsStyle={null}
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
bs3Props={{ bsStyle: null, className: 'btn-danger-ghost' }}
|
||||||
>
|
>
|
||||||
{t('turn_off')}
|
{t('turn_off')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<Button
|
<ButtonWrapper
|
||||||
|
variant="secondary"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
bsStyle={null}
|
|
||||||
onClick={handleLinkClick}
|
onClick={handleLinkClick}
|
||||||
className="btn btn-secondary-info btn-secondary text-capitalize"
|
bs3Props={{
|
||||||
|
bsStyle: null,
|
||||||
|
className: 'btn btn-secondary-info btn-secondary',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{t('turn_on')}
|
{t('turn_on')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import { useCallback, useState, ReactNode } from 'react'
|
import { useCallback, useState, ReactNode } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import AccessibleModal from '../../../../shared/components/accessible-modal'
|
import AccessibleModal from '../../../../shared/components/accessible-modal'
|
||||||
|
import { Modal } from 'react-bootstrap'
|
||||||
import BadgeWrapper from '@/features/ui/components/bootstrap-5/wrappers/badge-wrapper'
|
import BadgeWrapper from '@/features/ui/components/bootstrap-5/wrappers/badge-wrapper'
|
||||||
import { Button, Modal } from 'react-bootstrap'
|
|
||||||
import getMeta from '../../../../utils/meta'
|
import getMeta from '../../../../utils/meta'
|
||||||
import { sendMB } from '../../../../infrastructure/event-tracking'
|
import { sendMB } from '../../../../infrastructure/event-tracking'
|
||||||
|
import ButtonWrapper from '@/features/ui/components/bootstrap-5/wrappers/button-wrapper'
|
||||||
|
import { bsVersion } from '@/features/utils/bootstrap-5'
|
||||||
|
|
||||||
function trackUpgradeClick() {
|
function trackUpgradeClick() {
|
||||||
sendMB('settings-upgrade-click')
|
sendMB('settings-upgrade-click')
|
||||||
|
@ -107,43 +109,52 @@ function ActionButton({
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
if (!hasFeature) {
|
if (!hasFeature) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<ButtonWrapper
|
||||||
bsStyle={null}
|
variant="primary"
|
||||||
className="btn-primary"
|
|
||||||
href="/user/subscription/plans"
|
href="/user/subscription/plans"
|
||||||
onClick={trackUpgradeClick}
|
onClick={trackUpgradeClick}
|
||||||
|
bs3Props={{ bsStyle: null, className: 'btn-primary' }}
|
||||||
>
|
>
|
||||||
<span className="text-capitalize">{t('upgrade')}</span>
|
<span className="text-capitalize">{t('upgrade')}</span>
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
)
|
)
|
||||||
} else if (linked) {
|
} else if (linked) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<ButtonWrapper
|
||||||
className="btn-danger-ghost"
|
variant="danger-ghost"
|
||||||
onClick={handleUnlinkClick}
|
onClick={handleUnlinkClick}
|
||||||
bsStyle={null}
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
bs3Props={{ bsStyle: null, className: 'btn-danger-ghost' }}
|
||||||
>
|
>
|
||||||
{t('unlink')}
|
{t('unlink')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{disabled ? (
|
{disabled ? (
|
||||||
<button
|
<ButtonWrapper
|
||||||
disabled
|
disabled
|
||||||
className="btn btn-secondary-info btn-secondary text-capitalize"
|
variant="secondary"
|
||||||
|
className={bsVersion({
|
||||||
|
bs3: 'btn btn-secondary-info btn-secondary text-capitalize',
|
||||||
|
bs5: 'text-capitalize',
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
{t('link')}
|
{t('link')}
|
||||||
</button>
|
</ButtonWrapper>
|
||||||
) : (
|
) : (
|
||||||
<a
|
<ButtonWrapper
|
||||||
className="btn btn-secondary-info btn-secondary text-capitalize"
|
variant="secondary"
|
||||||
href={linkPath}
|
href={linkPath}
|
||||||
|
className={bsVersion({
|
||||||
|
bs3: 'btn btn-secondary-info btn-secondary text-capitalize',
|
||||||
|
bs5: 'text-capitalize',
|
||||||
|
})}
|
||||||
|
bs3Props={{ bsStyle: null }}
|
||||||
>
|
>
|
||||||
{t('link')}
|
{t('link')}
|
||||||
</a>
|
</ButtonWrapper>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -167,9 +178,7 @@ function UnlinkConfirmationModal({
|
||||||
}: UnlinkConfirmModalProps) {
|
}: UnlinkConfirmModalProps) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const handleCancel = (
|
const handleCancel = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
event: React.MouseEvent<HTMLButtonElement & Button>
|
|
||||||
) => {
|
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
handleHide()
|
handleHide()
|
||||||
}
|
}
|
||||||
|
@ -186,15 +195,23 @@ function UnlinkConfirmationModal({
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<form action={unlinkPath} method="POST" className="form-inline">
|
<form action={unlinkPath} method="POST" className="form-inline">
|
||||||
<input type="hidden" name="_csrf" value={getMeta('ol-csrfToken')} />
|
<input type="hidden" name="_csrf" value={getMeta('ol-csrfToken')} />
|
||||||
<Button
|
<ButtonWrapper
|
||||||
className="btn-secondary-info btn-secondary"
|
variant="secondary"
|
||||||
onClick={handleCancel}
|
onClick={handleCancel}
|
||||||
|
bs3Props={{
|
||||||
|
bsStyle: null,
|
||||||
|
className: 'btn-secondary-info btn-secondary',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{t('cancel')}
|
{t('cancel')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
<Button type="submit" className="btn-danger-ghost" bsStyle={null}>
|
<ButtonWrapper
|
||||||
|
type="submit"
|
||||||
|
variant="danger-ghost"
|
||||||
|
bs3Props={{ bsStyle: null, className: 'btn-danger-ghost' }}
|
||||||
|
>
|
||||||
{t('unlink')}
|
{t('unlink')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
</form>
|
</form>
|
||||||
</Modal.Footer>
|
</Modal.Footer>
|
||||||
</AccessibleModal>
|
</AccessibleModal>
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
import { useCallback, useState } from 'react'
|
import { useCallback, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Button, Modal } from 'react-bootstrap'
|
import { Modal } from 'react-bootstrap'
|
||||||
import { FetchError } from '../../../../infrastructure/fetch-json'
|
import { FetchError } from '../../../../infrastructure/fetch-json'
|
||||||
import AccessibleModal from '../../../../shared/components/accessible-modal'
|
import AccessibleModal from '../../../../shared/components/accessible-modal'
|
||||||
import IEEELogo from '../../../../shared/svgs/ieee-logo'
|
import IEEELogo from '../../../../shared/svgs/ieee-logo'
|
||||||
import GoogleLogo from '../../../../shared/svgs/google-logo'
|
import GoogleLogo from '../../../../shared/svgs/google-logo'
|
||||||
import OrcidLogo from '../../../../shared/svgs/orcid-logo'
|
import OrcidLogo from '../../../../shared/svgs/orcid-logo'
|
||||||
import LinkingStatus from './status'
|
import LinkingStatus from './status'
|
||||||
|
import ButtonWrapper from '@/features/ui/components/bootstrap-5/wrappers/button-wrapper'
|
||||||
|
import { bsVersion } from '@/features/utils/bootstrap-5'
|
||||||
|
|
||||||
const providerLogos: { readonly [p: string]: JSX.Element } = {
|
const providerLogos: { readonly [p: string]: JSX.Element } = {
|
||||||
collabratec: <IEEELogo />,
|
collabratec: <IEEELogo />,
|
||||||
|
@ -112,28 +114,37 @@ function ActionButton({
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
if (unlinkRequestInflight) {
|
if (unlinkRequestInflight) {
|
||||||
return (
|
return (
|
||||||
<Button className="btn-danger-ghost" bsStyle={null} disabled>
|
<ButtonWrapper
|
||||||
|
variant="danger-ghost"
|
||||||
|
disabled
|
||||||
|
bs3Props={{ bsStyle: null, className: 'btn-danger-ghost' }}
|
||||||
|
>
|
||||||
{t('unlinking')}
|
{t('unlinking')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
)
|
)
|
||||||
} else if (accountIsLinked) {
|
} else if (accountIsLinked) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<ButtonWrapper
|
||||||
className="btn-danger-ghost"
|
variant="danger-ghost"
|
||||||
bsStyle={null}
|
|
||||||
onClick={onUnlinkClick}
|
onClick={onUnlinkClick}
|
||||||
|
bs3Props={{ bsStyle: null, className: 'btn-danger-ghost' }}
|
||||||
>
|
>
|
||||||
{t('unlink')}
|
{t('unlink')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<a
|
<ButtonWrapper
|
||||||
|
variant="secondary"
|
||||||
href={linkPath}
|
href={linkPath}
|
||||||
className="btn btn-secondary-info btn-secondary text-capitalize"
|
bs3Props={{ bsStyle: null }}
|
||||||
|
className={bsVersion({
|
||||||
|
bs3: 'btn btn-secondary-info btn-secondary text-capitalize',
|
||||||
|
bs5: 'text-capitalize',
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
{t('link')}
|
{t('link')}
|
||||||
</a>
|
</ButtonWrapper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,20 +177,23 @@ function UnlinkConfirmModal({
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
|
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<Button
|
<ButtonWrapper
|
||||||
bsStyle={null}
|
variant="secondary"
|
||||||
className="btn-secondary-info btn-secondary"
|
|
||||||
onClick={handleHide}
|
onClick={handleHide}
|
||||||
|
bs3Props={{
|
||||||
|
bsStyle: null,
|
||||||
|
className: 'btn-secondary-info btn-secondary',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{t('cancel')}
|
{t('cancel')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
<Button
|
<ButtonWrapper
|
||||||
className="btn-danger-ghost"
|
variant="danger-ghost"
|
||||||
bsStyle={null}
|
|
||||||
onClick={handleConfirmation}
|
onClick={handleConfirmation}
|
||||||
|
bs3Props={{ bsStyle: null, className: 'btn-danger-ghost' }}
|
||||||
>
|
>
|
||||||
{t('unlink')}
|
{t('unlink')}
|
||||||
</Button>
|
</ButtonWrapper>
|
||||||
</Modal.Footer>
|
</Modal.Footer>
|
||||||
</AccessibleModal>
|
</AccessibleModal>
|
||||||
)
|
)
|
||||||
|
|
|
@ -201,7 +201,8 @@ function PasswordForm() {
|
||||||
form="password-change-form"
|
form="password-change-form"
|
||||||
type="submit"
|
type="submit"
|
||||||
variant="primary"
|
variant="primary"
|
||||||
disabled={isLoading || !isFormValid}
|
disabled={!isFormValid}
|
||||||
|
isLoading={isLoading}
|
||||||
bs3Props={{
|
bs3Props={{
|
||||||
loading: isLoading ? `${t('saving')}…` : t('change'),
|
loading: isLoading ? `${t('saving')}…` : t('change'),
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import MaterialIcon from '@/shared/components/material-icon'
|
||||||
import { Trans, useTranslation } from 'react-i18next'
|
import { Trans, useTranslation } from 'react-i18next'
|
||||||
import { GroupSSOLinkingStatus } from '../../../../../types/subscription/sso'
|
import { GroupSSOLinkingStatus } from '../../../../../types/subscription/sso'
|
||||||
import getMeta from '../../../utils/meta'
|
import getMeta from '../../../utils/meta'
|
||||||
|
import ButtonWrapper from '@/features/ui/components/bootstrap-5/wrappers/button-wrapper'
|
||||||
|
|
||||||
function SecuritySection() {
|
function SecuritySection() {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
@ -84,12 +85,13 @@ function SecuritySection() {
|
||||||
</div>
|
</div>
|
||||||
{linked ? null : (
|
{linked ? null : (
|
||||||
<div className="button-column">
|
<div className="button-column">
|
||||||
<a
|
<ButtonWrapper
|
||||||
className="btn btn-primary"
|
variant="primary"
|
||||||
|
bs3Props={{ className: 'btn btn-primary', bsStyle: null }}
|
||||||
href={`/subscription/${groupId}/sso_enrollment`}
|
href={`/subscription/${groupId}/sso_enrollment`}
|
||||||
>
|
>
|
||||||
{t('set_up_sso')}
|
{t('set_up_sso')}
|
||||||
</a>
|
</ButtonWrapper>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,6 +7,7 @@ import Button from '../button'
|
||||||
export type ButtonWrapperProps = ButtonProps & {
|
export type ButtonWrapperProps = ButtonProps & {
|
||||||
bs3Props?: {
|
bs3Props?: {
|
||||||
bsStyle?: string | null
|
bsStyle?: string | null
|
||||||
|
className?: string
|
||||||
loading?: React.ReactNode
|
loading?: React.ReactNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,11 +27,12 @@ export default function ButtonWrapper(props: ButtonWrapperProps) {
|
||||||
const { bs3Props, ...rest } = props
|
const { bs3Props, ...rest } = props
|
||||||
|
|
||||||
const bs3ButtonProps: BS3ButtonProps = {
|
const bs3ButtonProps: BS3ButtonProps = {
|
||||||
bsStyle: rest.variant,
|
bsStyle: rest.variant === 'secondary' ? 'default' : rest.variant,
|
||||||
bsSize: mapBsButtonSizes(rest.size),
|
bsSize: mapBsButtonSizes(rest.size),
|
||||||
className: rest.className,
|
className: rest.className,
|
||||||
disabled: rest.isLoading || rest.disabled,
|
disabled: rest.isLoading || rest.disabled,
|
||||||
form: rest.form,
|
form: rest.form,
|
||||||
|
href: rest.href,
|
||||||
onClick: rest.onClick,
|
onClick: rest.onClick,
|
||||||
type: rest.type,
|
type: rest.type,
|
||||||
...bs3Props,
|
...bs3Props,
|
||||||
|
|
|
@ -19,4 +19,5 @@ export type ButtonProps = {
|
||||||
| 'danger'
|
| 'danger'
|
||||||
| 'danger-ghost'
|
| 'danger-ghost'
|
||||||
| 'premium'
|
| 'premium'
|
||||||
|
| 'link'
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
// Use CSS variables for link colors to make it easy to override in marketing page
|
// Use CSS variables for link colors to make it easy to override in marketing page
|
||||||
:root {
|
:root {
|
||||||
--link-color: var(--link-ui-visited);
|
--link-color: var(--link-ui);
|
||||||
--link-hover-color: var(--link-ui-hover);
|
--link-hover-color: var(--link-ui-hover);
|
||||||
--link-visited-color: var(--link-ui-visited);
|
--link-visited-color: var(--link-ui-visited);
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a:not([role='button']) {
|
||||||
color: var(--link-color);
|
color: var(--link-color);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
|
|
@ -87,10 +87,44 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Link buttons
|
||||||
|
// -------------------------
|
||||||
|
|
||||||
|
// Make a button look and behave like a link
|
||||||
|
.btn-link {
|
||||||
|
color: var(--link-ui);
|
||||||
|
font-weight: normal;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 0;
|
||||||
|
text-decoration: underline;
|
||||||
|
padding: 0;
|
||||||
|
font-size: inherit;
|
||||||
|
vertical-align: inherit;
|
||||||
|
|
||||||
|
&,
|
||||||
|
&:active,
|
||||||
|
&[disabled],
|
||||||
|
fieldset[disabled] & {
|
||||||
|
background-color: transparent;
|
||||||
|
@include box-shadow(none);
|
||||||
|
}
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
color: var(--link-ui-hover);
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.btn-danger {
|
||||||
|
color: var(--content-danger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.button-loading {
|
.button-loading {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: inline-grid;
|
display: inline-grid;
|
||||||
grid-template-areas: 'container'; // Define a single grid area
|
grid-template-areas: 'container'; // Define a single grid area
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-loading > * {
|
.button-loading > * {
|
||||||
|
|
Loading…
Reference in a new issue