mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00:00
feat(client): Customized Radio Buttons in settings page (#50094)
Co-authored-by: Bruce B <bbsmooth@gmail.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
function ToggleCheck(
|
||||
props: JSX.IntrinsicAttributes & React.SVGProps<SVGSVGElement>
|
||||
): JSX.Element {
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
import {
|
||||
ToggleButtonGroup as BSBG,
|
||||
ToggleButton as TB
|
||||
} from '@freecodecamp/react-bootstrap';
|
||||
import React from 'react';
|
||||
|
||||
import './toggle-button.css';
|
||||
import Spacer from '../../assets/icons/spacer';
|
||||
import ToggleCheck from '../../assets/icons/toggle-check';
|
||||
|
||||
interface ButtonProps {
|
||||
name: string;
|
||||
offLabel: string;
|
||||
onChange: (value: string) => void;
|
||||
onLabel: string;
|
||||
value: boolean;
|
||||
condition?: boolean;
|
||||
}
|
||||
|
||||
type ActiveClass = Pick<ButtonProps, 'condition'>;
|
||||
|
||||
function getActiveClass(condition: ActiveClass | unknown) {
|
||||
return condition ? 'active' : 'not-active';
|
||||
}
|
||||
|
||||
export default function ToggleButton({
|
||||
name,
|
||||
onChange,
|
||||
value,
|
||||
onLabel = 'On',
|
||||
offLabel = 'Off'
|
||||
}: ButtonProps): JSX.Element {
|
||||
const checkIconStyle = {
|
||||
height: '15px',
|
||||
paddingTop: '5',
|
||||
width: '20px'
|
||||
};
|
||||
return (
|
||||
<BSBG name={name} onChange={onChange} type='radio'>
|
||||
<TB
|
||||
bsSize='sm'
|
||||
bsStyle='primary'
|
||||
className={`toggle-${getActiveClass(value)}`}
|
||||
disabled={value}
|
||||
type='radio'
|
||||
value={1}
|
||||
>
|
||||
{value ? (
|
||||
<ToggleCheck style={checkIconStyle} />
|
||||
) : (
|
||||
<Spacer style={checkIconStyle} />
|
||||
)}
|
||||
{onLabel}
|
||||
</TB>
|
||||
<TB
|
||||
bsSize='sm'
|
||||
bsStyle='primary'
|
||||
className={`toggle-${getActiveClass(!value)}`}
|
||||
disabled={!value}
|
||||
type='radio'
|
||||
value={2}
|
||||
>
|
||||
{offLabel}
|
||||
{!value ? (
|
||||
<ToggleCheck style={checkIconStyle} />
|
||||
) : (
|
||||
<Spacer style={checkIconStyle} />
|
||||
)}
|
||||
</TB>
|
||||
</BSBG>
|
||||
);
|
||||
}
|
||||
|
||||
ToggleButton.displayName = 'ToggleButton';
|
||||
@@ -4,11 +4,6 @@ import type { ToggleSettingProps } from './toggle-radio-setting';
|
||||
import '../helpers/toggle-button.css';
|
||||
import './toggle-setting.css';
|
||||
|
||||
const checkIconStyle = {
|
||||
height: '1rem',
|
||||
width: '1.25rem'
|
||||
};
|
||||
|
||||
export default function ToggleButtonSetting({
|
||||
action,
|
||||
explain,
|
||||
@@ -43,7 +38,7 @@ export default function ToggleButtonSetting({
|
||||
>
|
||||
<span>
|
||||
{restProps.onLabel}
|
||||
{flag ? <ToggleCheck style={checkIconStyle} /> : null}
|
||||
{flag ? <ToggleCheck className='checkIcon' /> : null}
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
@@ -54,7 +49,7 @@ export default function ToggleButtonSetting({
|
||||
>
|
||||
<span>
|
||||
{restProps.offLabel}
|
||||
{!flag ? <ToggleCheck style={checkIconStyle} /> : null}
|
||||
{!flag ? <ToggleCheck className='checkIcon' /> : null}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -41,7 +41,7 @@ export default function ToggleRadioSetting({
|
||||
{explain ? <p id={`desc${flagName}`}>{explain}</p> : null}
|
||||
</div>
|
||||
<div className='toggle-radio-group'>
|
||||
<label htmlFor={firstRadioId} data-checked={flag}>
|
||||
<label htmlFor={firstRadioId}>
|
||||
<input
|
||||
id={firstRadioId}
|
||||
type='radio'
|
||||
@@ -50,9 +50,10 @@ export default function ToggleRadioSetting({
|
||||
name={flagName}
|
||||
value='1'
|
||||
/>
|
||||
<span className='custom-circle'></span>
|
||||
<span>{restProps.onLabel}</span>
|
||||
</label>
|
||||
<label htmlFor={secondRadioId} data-checked={!flag}>
|
||||
<label htmlFor={secondRadioId}>
|
||||
<input
|
||||
id={secondRadioId}
|
||||
type='radio'
|
||||
@@ -61,6 +62,7 @@ export default function ToggleRadioSetting({
|
||||
name={flagName}
|
||||
value='2'
|
||||
/>
|
||||
<span className='custom-circle' />
|
||||
<span>{restProps.offLabel}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -78,52 +78,57 @@
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.toggle-radio-group {
|
||||
display: flex;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.toggle-radio-group label {
|
||||
font-weight: normal;
|
||||
display: flex;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.toggle-radio-group input {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
height: 0.8rem;
|
||||
width: 0.8rem;
|
||||
border-radius: 50%;
|
||||
background: transparent;
|
||||
border: 2px solid var(--secondary-color);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.toggle-radio-group [data-checked='true'] input {
|
||||
background: var(--secondary-color);
|
||||
}
|
||||
|
||||
.toggle-radio-group [data-checked='true'] span {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.toggle-radio-group input:focus-visible {
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
.toggle-radio-group label[data-checked='false']:hover,
|
||||
.toggle-radio-group label[data-checked='false'] input:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.toggle-radio-group label + label {
|
||||
margin-inline-start: 2rem;
|
||||
}
|
||||
|
||||
.toggle-radio-group input {
|
||||
margin-inline-end: 0.35rem;
|
||||
accent-color: var(--secondary-color);
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
}
|
||||
|
||||
.custom-circle {
|
||||
margin-inline-end: 8px;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
min-width: calc(0.889em + 4px);
|
||||
min-height: calc(0.889em + 4px);
|
||||
max-width: calc(0.889em + 4px);
|
||||
max-height: calc(0.889em + 4px);
|
||||
border-radius: 50%;
|
||||
background-color: var(--secondary-background);
|
||||
border: 2px solid var(--primary-color);
|
||||
}
|
||||
|
||||
.toggle-radio-group input:focus-visible + .custom-circle {
|
||||
outline: 3px solid var(--focus-outline-color);
|
||||
}
|
||||
|
||||
.toggle-radio-group input:checked + .custom-circle:after {
|
||||
content: '';
|
||||
width: 0.556rem;
|
||||
height: 0.556rem;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
background-color: var(--primary-color);
|
||||
border-radius: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.toggle-radio-group span {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* checkIconStyle css */
|
||||
.checkIcon {
|
||||
height: 1rem;
|
||||
width: 1.25rem;
|
||||
}
|
||||
|
||||
@media (max-width: 35rem) {
|
||||
|
||||
@@ -17,7 +17,8 @@ const setPrivacyTogglesToPublic = () => {
|
||||
cy.get('#privacy-settings')
|
||||
.find('[type=radio][value=2]')
|
||||
.each(element => {
|
||||
cy.wrap(element).click().should('be.checked');
|
||||
cy.wrap(element).parent().click();
|
||||
cy.wrap(element).should('be.checked');
|
||||
});
|
||||
cy.get('[data-cy=save-privacy-settings]').click();
|
||||
cy.get('#honesty-policy').find('button').click();
|
||||
|
||||
Reference in New Issue
Block a user