mirror of
https://github.com/logto-io/logto.git
synced 2025-03-24 22:41:28 -05:00
feat(console): add tool tips to disabled action items in sie (#2371)
This commit is contained in:
parent
c0e9788ca9
commit
f64a0f2df4
14 changed files with 148 additions and 48 deletions
|
@ -20,11 +20,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
input {
|
||||
input,
|
||||
.disabledMask {
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
left: 0;
|
||||
// Note: add a left value to make the input element align with the icon
|
||||
left: _.unit(0.5);
|
||||
top: 0;
|
||||
margin: 0;
|
||||
opacity: 0%;
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import classNames from 'classnames';
|
||||
import { nanoid } from 'nanoid';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useRef, useState } from 'react';
|
||||
|
||||
import Tooltip from '../Tooltip';
|
||||
import Icon from './Icon';
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
|
@ -14,11 +15,14 @@ type Props = {
|
|||
// eslint-disable-next-line react/boolean-prop-naming
|
||||
disabled: boolean;
|
||||
className?: string;
|
||||
disabledTooltip?: ReactNode;
|
||||
};
|
||||
|
||||
const Checkbox = ({ value, onChange, label, disabled, className }: Props) => {
|
||||
const Checkbox = ({ value, onChange, label, disabled, className, disabledTooltip }: Props) => {
|
||||
const [id, setId] = useState(nanoid());
|
||||
|
||||
const tipRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
return (
|
||||
<div className={classNames(styles.checkbox, className)}>
|
||||
<input
|
||||
|
@ -30,6 +34,12 @@ const Checkbox = ({ value, onChange, label, disabled, className }: Props) => {
|
|||
onChange(event.target.checked);
|
||||
}}
|
||||
/>
|
||||
{disabled && disabledTooltip && (
|
||||
<>
|
||||
<div ref={tipRef} className={styles.disabledMask} />
|
||||
<Tooltip anchorRef={tipRef} content={disabledTooltip} />
|
||||
</>
|
||||
)}
|
||||
<Icon className={styles.icon} />
|
||||
{label && <label htmlFor={id}>{label}</label>}
|
||||
</div>
|
||||
|
|
|
@ -14,13 +14,19 @@
|
|||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
> svg {
|
||||
color: var(--color-text-secondary);
|
||||
.icon {
|
||||
> svg {
|
||||
display: block;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&:disabled {
|
||||
> svg {
|
||||
color: var(--color-neutral-80);
|
||||
.icon {
|
||||
> svg {
|
||||
color: var(--color-neutral-80);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,9 +46,11 @@
|
|||
height: 24px;
|
||||
width: 24px;
|
||||
|
||||
> svg {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
.icon {
|
||||
> svg {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,9 +58,11 @@
|
|||
height: 28px;
|
||||
width: 28px;
|
||||
|
||||
> svg {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
.icon {
|
||||
> svg {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,9 +70,11 @@
|
|||
height: 32px;
|
||||
width: 32px;
|
||||
|
||||
> svg {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
.icon {
|
||||
> svg {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,49 +1,35 @@
|
|||
import type { AdminConsoleKey } from '@logto/phrases';
|
||||
import type { Nullable } from '@silverhand/essentials';
|
||||
import classNames from 'classnames';
|
||||
import type { ForwardedRef, HTMLProps } from 'react';
|
||||
import { forwardRef, useImperativeHandle, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import type { ForwardedRef, HTMLProps, ReactNode } from 'react';
|
||||
import { forwardRef, useRef } from 'react';
|
||||
|
||||
import Tooltip from '../Tooltip';
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
export type Props = Omit<HTMLProps<HTMLButtonElement>, 'size' | 'type'> & {
|
||||
size?: 'small' | 'medium' | 'large';
|
||||
tooltip?: AdminConsoleKey;
|
||||
tooltip?: ReactNode;
|
||||
};
|
||||
|
||||
const IconButton = (
|
||||
{ size = 'medium', children, className, tooltip, ...rest }: Props,
|
||||
reference: ForwardedRef<HTMLButtonElement>
|
||||
) => {
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const innerReference = useRef<HTMLButtonElement>(null);
|
||||
|
||||
useImperativeHandle<Nullable<HTMLButtonElement>, Nullable<HTMLButtonElement>>(
|
||||
reference,
|
||||
() => innerReference.current
|
||||
);
|
||||
const tipRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
ref={innerReference}
|
||||
type="button"
|
||||
className={classNames(styles.button, styles[size], className)}
|
||||
{...rest}
|
||||
>
|
||||
<button
|
||||
ref={reference}
|
||||
type="button"
|
||||
className={classNames(styles.button, styles[size], className)}
|
||||
{...rest}
|
||||
>
|
||||
<div ref={tipRef} className={styles.icon}>
|
||||
{children}
|
||||
</button>
|
||||
</div>
|
||||
{tooltip && (
|
||||
<Tooltip
|
||||
anchorRef={innerReference}
|
||||
content={t(tooltip)}
|
||||
position="top"
|
||||
horizontalAlign="center"
|
||||
/>
|
||||
<Tooltip anchorRef={tipRef} content={tooltip} position="top" horizontalAlign="center" />
|
||||
)}
|
||||
</>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -160,7 +160,7 @@ const LanguageDetails = () => {
|
|||
</div>
|
||||
{!isBuiltIn && (
|
||||
<IconButton
|
||||
tooltip="sign_in_exp.others.manage_language.deletion_tip"
|
||||
tooltip={t('sign_in_exp.others.manage_language.deletion_tip')}
|
||||
onClick={() => {
|
||||
setIsDeletionAlertOpen(true);
|
||||
}}
|
||||
|
@ -189,7 +189,7 @@ const LanguageDetails = () => {
|
|||
<IconButton
|
||||
size="small"
|
||||
className={style.clearButton}
|
||||
tooltip="sign_in_exp.others.manage_language.clear_all_tip"
|
||||
tooltip={t('sign_in_exp.others.manage_language.clear_all_tip')}
|
||||
onClick={() => {
|
||||
for (const [key, value] of Object.entries(
|
||||
flattenTranslation(emptyUiTranslation)
|
||||
|
|
|
@ -100,6 +100,7 @@ const SignUpForm = () => {
|
|||
label={t('sign_in_exp.sign_up_and_sign_in.sign_up.set_a_password_option')}
|
||||
disabled={signUpIdentifier === SignUpIdentifier.Username}
|
||||
value={value ?? false}
|
||||
disabledTooltip={t('sign_in_exp.sign_up_and_sign_in.tip.set_a_password')}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)}
|
||||
|
@ -113,6 +114,7 @@ const SignUpForm = () => {
|
|||
label={t('sign_in_exp.sign_up_and_sign_in.sign_up.verify_at_sign_up_option')}
|
||||
value={value ?? false}
|
||||
disabled={requiredVerifySignUpIdentifiers.includes(signUpIdentifier)}
|
||||
disabledTooltip={t('sign_in_exp.sign_up_and_sign_in.tip.verify_at_sign_up')}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { SignInIdentifier } from '@logto/schemas';
|
||||
import { conditional } from '@silverhand/essentials';
|
||||
import classNames from 'classnames';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { snakeCase } from 'snake-case';
|
||||
|
@ -57,6 +58,7 @@ const SignInMethodItem = ({
|
|||
label={t('sign_in_exp.sign_up_and_sign_in.sign_in.password_auth')}
|
||||
value={password}
|
||||
disabled={!isPasswordCheckable}
|
||||
disabledTooltip={t('sign_in_exp.sign_up_and_sign_in.tip.password_auth')}
|
||||
onChange={(checked) => {
|
||||
onVerificationStateChange(identifier, 'password', checked);
|
||||
}}
|
||||
|
@ -65,7 +67,7 @@ const SignInMethodItem = ({
|
|||
<>
|
||||
<IconButton
|
||||
className={styles.swapButton}
|
||||
tooltip="sign_in_exp.sign_up_and_sign_in.sign_in.auth_swap_tip"
|
||||
tooltip={t('sign_in_exp.sign_up_and_sign_in.sign_in.auth_swap_tip')}
|
||||
onClick={() => {
|
||||
onToggleVerificationPrimary(identifier);
|
||||
}}
|
||||
|
@ -77,6 +79,7 @@ const SignInMethodItem = ({
|
|||
label={t('sign_in_exp.sign_up_and_sign_in.sign_in.verification_code_auth')}
|
||||
value={verificationCode}
|
||||
disabled={!isVerificationCodeCheckable}
|
||||
disabledTooltip={t('sign_in_exp.sign_up_and_sign_in.tip.verification_code_auth')}
|
||||
onChange={(checked) => {
|
||||
onVerificationStateChange(identifier, 'verificationCode', checked);
|
||||
}}
|
||||
|
@ -87,6 +90,14 @@ const SignInMethodItem = ({
|
|||
</div>
|
||||
<IconButton
|
||||
disabled={!isDeletable}
|
||||
tooltip={conditional(
|
||||
!isDeletable &&
|
||||
t('sign_in_exp.sign_up_and_sign_in.tip.delete_sign_in_method', {
|
||||
identifier: t('sign_in_exp.sign_up_and_sign_in.identifiers', {
|
||||
context: snakeCase(identifier),
|
||||
}).toLocaleLowerCase(),
|
||||
})
|
||||
)}
|
||||
onClick={() => {
|
||||
onDelete(identifier);
|
||||
}}
|
||||
|
|
|
@ -55,6 +55,17 @@ const sign_in_exp = {
|
|||
go_to: 'social connectors or go to “Connectors” section.', // UNTRANSLATED
|
||||
},
|
||||
},
|
||||
tip: {
|
||||
set_a_password: 'A unique set of a password to your username is a must.', // UNTRANSLATED
|
||||
verify_at_sign_up:
|
||||
'Right now we only support email verified at sign up but soon to open this capability!', // UNTRANSLATED
|
||||
password_auth:
|
||||
'This is essential as you have enabled the option to set a password during the sign-up process.', // UNTRANSLATED
|
||||
verification_code_auth:
|
||||
'This is essential as you have only enabled the option to provide verification code when signing up. You’re free to uncheck the box when password set-up is allowed at the sign-up process.', // UNTRANSLATED
|
||||
delete_sign_in_method:
|
||||
'This is essential as you have selected {{identifier}} as a required identifier.', // UNTRANSLATED
|
||||
},
|
||||
},
|
||||
color: {
|
||||
title: 'FARBE',
|
||||
|
|
|
@ -77,6 +77,17 @@ const sign_in_exp = {
|
|||
go_to: 'social connectors or go to “Connectors” section.',
|
||||
},
|
||||
},
|
||||
tip: {
|
||||
set_a_password: 'A unique set of a password to your username is a must.',
|
||||
verify_at_sign_up:
|
||||
'Right now we only support email verified at sign up but soon to open this capability!',
|
||||
password_auth:
|
||||
'This is essential as you have enabled the option to set a password during the sign-up process.',
|
||||
verification_code_auth:
|
||||
'This is essential as you have only enabled the option to provide verification code when signing up. You’re free to uncheck the box when password set-up is allowed at the sign-up process.',
|
||||
delete_sign_in_method:
|
||||
'This is essential as you have selected {{identifier}} as a required identifier.',
|
||||
},
|
||||
},
|
||||
sign_in_methods: {
|
||||
title: 'SIGN-IN METHODS',
|
||||
|
|
|
@ -79,6 +79,17 @@ const sign_in_exp = {
|
|||
go_to: 'social connectors or go to “Connectors” section.', // UNTRANSLATED
|
||||
},
|
||||
},
|
||||
tip: {
|
||||
set_a_password: 'A unique set of a password to your username is a must.', // UNTRANSLATED
|
||||
verify_at_sign_up:
|
||||
'Right now we only support email verified at sign up but soon to open this capability!', // UNTRANSLATED
|
||||
password_auth:
|
||||
'This is essential as you have enabled the option to set a password during the sign-up process.', // UNTRANSLATED
|
||||
verification_code_auth:
|
||||
'This is essential as you have only enabled the option to provide verification code when signing up. You’re free to uncheck the box when password set-up is allowed at the sign-up process.', // UNTRANSLATED
|
||||
delete_sign_in_method:
|
||||
'This is essential as you have selected {{identifier}} as a required identifier.', // UNTRANSLATED
|
||||
},
|
||||
},
|
||||
sign_in_methods: {
|
||||
title: 'METHODES DE CONNEXION',
|
||||
|
|
|
@ -74,6 +74,17 @@ const sign_in_exp = {
|
|||
go_to: 'social connectors or go to “Connectors” section.', // UNTRANSLATED
|
||||
},
|
||||
},
|
||||
tip: {
|
||||
set_a_password: 'A unique set of a password to your username is a must.', // UNTRANSLATED
|
||||
verify_at_sign_up:
|
||||
'Right now we only support email verified at sign up but soon to open this capability!', // UNTRANSLATED
|
||||
password_auth:
|
||||
'This is essential as you have enabled the option to set a password during the sign-up process.', // UNTRANSLATED
|
||||
verification_code_auth:
|
||||
'This is essential as you have only enabled the option to provide verification code when signing up. You’re free to uncheck the box when password set-up is allowed at the sign-up process.', // UNTRANSLATED
|
||||
delete_sign_in_method:
|
||||
'This is essential as you have selected {{identifier}} as a required identifier.', // UNTRANSLATED
|
||||
},
|
||||
},
|
||||
sign_in_methods: {
|
||||
title: '로그인 방법',
|
||||
|
|
|
@ -77,6 +77,17 @@ const sign_in_exp = {
|
|||
go_to: 'social connectors or go to “Connectors” section.', // UNTRANSLATED
|
||||
},
|
||||
},
|
||||
tip: {
|
||||
set_a_password: 'A unique set of a password to your username is a must.', // UNTRANSLATED
|
||||
verify_at_sign_up:
|
||||
'Right now we only support email verified at sign up but soon to open this capability!', // UNTRANSLATED
|
||||
password_auth:
|
||||
'This is essential as you have enabled the option to set a password during the sign-up process.', // UNTRANSLATED
|
||||
verification_code_auth:
|
||||
'This is essential as you have only enabled the option to provide verification code when signing up. You’re free to uncheck the box when password set-up is allowed at the sign-up process.', // UNTRANSLATED
|
||||
delete_sign_in_method:
|
||||
'This is essential as you have selected {{identifier}} as a required identifier.', // UNTRANSLATED
|
||||
},
|
||||
},
|
||||
sign_in_methods: {
|
||||
title: 'MÉTODOS DE LOGIN',
|
||||
|
|
|
@ -78,6 +78,17 @@ const sign_in_exp = {
|
|||
go_to: 'social connectors or go to “Connectors” section.', // UNTRANSLATED
|
||||
},
|
||||
},
|
||||
tip: {
|
||||
set_a_password: 'A unique set of a password to your username is a must.', // UNTRANSLATED
|
||||
verify_at_sign_up:
|
||||
'Right now we only support email verified at sign up but soon to open this capability!', // UNTRANSLATED
|
||||
password_auth:
|
||||
'This is essential as you have enabled the option to set a password during the sign-up process.', // UNTRANSLATED
|
||||
verification_code_auth:
|
||||
'This is essential as you have only enabled the option to provide verification code when signing up. You’re free to uncheck the box when password set-up is allowed at the sign-up process.', // UNTRANSLATED
|
||||
delete_sign_in_method:
|
||||
'This is essential as you have selected {{identifier}} as a required identifier.', // UNTRANSLATED
|
||||
},
|
||||
},
|
||||
sign_in_methods: {
|
||||
title: 'OTURUM AÇMA YÖNTEMLERİ',
|
||||
|
|
|
@ -75,6 +75,17 @@ const sign_in_exp = {
|
|||
go_to: 'social connectors or go to “Connectors” section.', // UNTRANSLATED
|
||||
},
|
||||
},
|
||||
tip: {
|
||||
set_a_password: 'A unique set of a password to your username is a must.', // UNTRANSLATED
|
||||
verify_at_sign_up:
|
||||
'Right now we only support email verified at sign up but soon to open this capability!', // UNTRANSLATED
|
||||
password_auth:
|
||||
'This is essential as you have enabled the option to set a password during the sign-up process.', // UNTRANSLATED
|
||||
verification_code_auth:
|
||||
'This is essential as you have only enabled the option to provide verification code when signing up. You’re free to uncheck the box when password set-up is allowed at the sign-up process.', // UNTRANSLATED
|
||||
delete_sign_in_method:
|
||||
'This is essential as you have selected {{identifier}} as a required identifier.', // UNTRANSLATED
|
||||
},
|
||||
},
|
||||
sign_in_methods: {
|
||||
title: '登录方式',
|
||||
|
|
Loading…
Add table
Reference in a new issue