mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Merge pull request #15249 from overleaf/rd-odc-radio
Radio buttons for Onboarding Data Collection GitOrigin-RevId: 8c4d1e965f3263b4c8a41c129c5c3d6e3ef10986
This commit is contained in:
parent
af4b22fab5
commit
a2946f8601
9 changed files with 207 additions and 3 deletions
|
@ -457,6 +457,7 @@
|
|||
"headers": "",
|
||||
"help": "",
|
||||
"help_improve_overleaf_fill_out_this_survey": "",
|
||||
"helps_us_tailor_your_experience": "",
|
||||
"hide_configuration": "",
|
||||
"hide_document_preamble": "",
|
||||
"hide_outline": "",
|
||||
|
@ -839,6 +840,12 @@
|
|||
"premium_plan_label": "",
|
||||
"press_shortcut_to_open_advanced_reference_search": "",
|
||||
"price": "",
|
||||
"primarily_work_study_question": "",
|
||||
"primarily_work_study_question_government": "",
|
||||
"primarily_work_study_question_nonprofit_ngo": "",
|
||||
"primarily_work_study_question_other": "",
|
||||
"primarily_work_study_question_private_company": "",
|
||||
"primarily_work_study_question_university_school": "",
|
||||
"priority_support": "",
|
||||
"private": "",
|
||||
"problem_talking_to_publishing_service": "",
|
||||
|
|
42
services/web/frontend/js/shared/components/radio-chip.tsx
Normal file
42
services/web/frontend/js/shared/components/radio-chip.tsx
Normal file
|
@ -0,0 +1,42 @@
|
|||
import React from 'react'
|
||||
|
||||
type RadioChipProps<ValueType> = {
|
||||
checked?: boolean
|
||||
disabled?: boolean
|
||||
name: string
|
||||
onChange: (value: ValueType) => void
|
||||
required?: boolean
|
||||
label: React.ReactElement | string
|
||||
value: ValueType
|
||||
}
|
||||
|
||||
const RadioChip = <T extends string>({
|
||||
checked,
|
||||
disabled,
|
||||
name,
|
||||
onChange,
|
||||
label,
|
||||
required,
|
||||
value,
|
||||
}: RadioChipProps<T>) => {
|
||||
const handleChange = () => {
|
||||
onChange(value)
|
||||
}
|
||||
|
||||
return (
|
||||
<label className="radio-chip" data-disabled={disabled ? 'true' : undefined}>
|
||||
<input
|
||||
checked={checked}
|
||||
disabled={disabled}
|
||||
name={name}
|
||||
onChange={handleChange}
|
||||
type="radio"
|
||||
required={required}
|
||||
value={value}
|
||||
/>
|
||||
{label}
|
||||
</label>
|
||||
)
|
||||
}
|
||||
|
||||
export default RadioChip
|
23
services/web/frontend/stories/radio-chip.stories.tsx
Normal file
23
services/web/frontend/stories/radio-chip.stories.tsx
Normal file
|
@ -0,0 +1,23 @@
|
|||
import RadioChip from '../js/shared/components/radio-chip'
|
||||
|
||||
type Args = React.ComponentProps<typeof RadioChip>
|
||||
|
||||
export const RadioChipDefault = (args: Args) => {
|
||||
return <RadioChip {...args} />
|
||||
}
|
||||
|
||||
export const RadioChipDisabled = (args: Args) => {
|
||||
return <RadioChip {...args} disabled />
|
||||
}
|
||||
|
||||
export const RadioChipDisabledSelected = (args: Args) => {
|
||||
return <RadioChip {...args} checked disabled />
|
||||
}
|
||||
|
||||
export default {
|
||||
title: 'Shared / Components / RadioChip',
|
||||
component: RadioChip,
|
||||
args: {
|
||||
label: 'Option',
|
||||
},
|
||||
}
|
|
@ -66,6 +66,7 @@
|
|||
@import 'components/split-menu.less';
|
||||
@import 'components/group-members.less';
|
||||
@import 'components/stepper.less';
|
||||
@import 'components/radio-chip.less';
|
||||
|
||||
// Components w/ JavaScript
|
||||
@import 'components/modals.less';
|
||||
|
|
57
services/web/frontend/stylesheets/components/radio-chip.less
Normal file
57
services/web/frontend/stylesheets/components/radio-chip.less
Normal file
|
@ -0,0 +1,57 @@
|
|||
.radio-chip {
|
||||
background: @white;
|
||||
border: 1px solid @neutral-60;
|
||||
border-radius: 999px;
|
||||
color: @neutral-90;
|
||||
display: inline-flex;
|
||||
font-weight: 400;
|
||||
gap: 4px;
|
||||
inline-size: fit-content;
|
||||
line-height: 1.4;
|
||||
padding: 8px 16px 8px 8px;
|
||||
|
||||
@media only screen and (max-width: @screen-sm-min) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: @neutral-20;
|
||||
}
|
||||
|
||||
&:focus-within {
|
||||
box-shadow: 0px 0px 0px 2px @blue-30;
|
||||
}
|
||||
|
||||
input[type='radio'] {
|
||||
accent-color: @green-50;
|
||||
height: 16px;
|
||||
margin: 4px;
|
||||
width: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.radio-chip[data-disabled='true'] {
|
||||
border-color: @neutral-20;
|
||||
|
||||
&:hover {
|
||||
background: @white;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.radio-group-col-1 {
|
||||
align-items: flex-start;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.radio-group-col-2 {
|
||||
display: grid;
|
||||
grid-gap: 16px;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
|
||||
@media (max-width: @screen-sm-min) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
|
@ -77,6 +77,7 @@
|
|||
@import 'components/switch.less';
|
||||
@import 'components/switcher.less';
|
||||
@import 'components/stepper.less';
|
||||
@import 'components/radio-chip.less';
|
||||
|
||||
// Components w/ JavaScript
|
||||
@import 'components/modals.less';
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
}
|
||||
|
||||
#onboarding-data-collection {
|
||||
width: 720px;
|
||||
max-width: 720px;
|
||||
padding: 24px;
|
||||
margin: 0 auto;
|
||||
background: #fff;
|
||||
|
@ -40,9 +40,13 @@
|
|||
flex-direction: column;
|
||||
gap: 24px;
|
||||
|
||||
p {
|
||||
.onboarding-question-title {
|
||||
font-size: 20px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
|
@ -60,6 +64,11 @@
|
|||
justify-content: stretch;
|
||||
gap: 24px;
|
||||
|
||||
@media (max-width: @screen-xs-max) {
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
|
|
@ -732,6 +732,7 @@
|
|||
"help_articles_matching": "Help articles matching your subject",
|
||||
"help_improve_overleaf_fill_out_this_survey": "If you would like to help us improve Overleaf, please take a moment to fill out <0>this survey</0>.",
|
||||
"help_us_spread_word": "Help us spread the word about __appName__",
|
||||
"helps_us_tailor_your_experience": "This helps us tailor your Overleaf experience.",
|
||||
"hide_configuration": "Hide configuration",
|
||||
"hide_document_preamble": "Hide document preamble",
|
||||
"hide_outline": "Hide File outline",
|
||||
|
@ -1318,6 +1319,12 @@
|
|||
"press_and_awards": "Press & awards",
|
||||
"press_shortcut_to_open_advanced_reference_search": "Press <strong>__ctrlSpace__</strong> or <strong>__altSpace__</strong> to open <strong>Advanced Reference Search</strong>",
|
||||
"price": "Price",
|
||||
"primarily_work_study_question": "Where do you primarily work or study?",
|
||||
"primarily_work_study_question_government": "In the government",
|
||||
"primarily_work_study_question_nonprofit_ngo": "In a nonprofit/NGO",
|
||||
"primarily_work_study_question_other": "Other",
|
||||
"primarily_work_study_question_private_company": "In a private company",
|
||||
"primarily_work_study_question_university_school": "In a university or school",
|
||||
"primary_email_check_question": "Is <0>__email__</0> still your email address?",
|
||||
"priority_support": "Priority support",
|
||||
"priority_support_info": "Our helpful Support team will prioritise and escalate your support requests where necessary.",
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
import { expect } from 'chai'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import RadioChip from '@/shared/components/radio-chip'
|
||||
|
||||
describe('<RadioChip />', function () {
|
||||
const defaultProps = {
|
||||
name: 'test',
|
||||
label: 'Test',
|
||||
value: 'testValue',
|
||||
onChange: () => {},
|
||||
}
|
||||
|
||||
describe('component renders and with label', function () {
|
||||
it('renders and label is provided', function () {
|
||||
render(<RadioChip {...defaultProps} />)
|
||||
screen.getByText('Test')
|
||||
})
|
||||
})
|
||||
|
||||
describe('props', function () {
|
||||
it('should be checked when the checked prop is provided', function () {
|
||||
render(<RadioChip {...defaultProps} checked />)
|
||||
const radioChip = screen.getByRole('radio') as HTMLInputElement
|
||||
expect(radioChip.checked).to.equal(true)
|
||||
})
|
||||
|
||||
it('should be disabled when the disabled prop is provided', function () {
|
||||
render(<RadioChip {...defaultProps} disabled />)
|
||||
const radioChip = screen.getByRole('radio') as HTMLInputElement
|
||||
expect(radioChip.disabled).to.equal(true)
|
||||
})
|
||||
|
||||
it('should have the required attribute when the required prop is provided', function () {
|
||||
render(<RadioChip {...defaultProps} required />)
|
||||
const radioChip = screen.getByRole('radio') as HTMLInputElement
|
||||
expect(radioChip.required).to.equal(true)
|
||||
})
|
||||
|
||||
it('should use the provided name prop', function () {
|
||||
render(<RadioChip {...defaultProps} name="testName" />)
|
||||
const radioChip = screen.getByRole('radio') as HTMLInputElement
|
||||
expect(radioChip.name).to.equal('testName')
|
||||
})
|
||||
|
||||
it('should use the provided value prop', function () {
|
||||
render(<RadioChip {...defaultProps} />)
|
||||
const radioChip = screen.getByRole('radio') as HTMLInputElement
|
||||
expect(radioChip.value).to.equal('testValue')
|
||||
})
|
||||
|
||||
it('should have the data-disabled attribute when the disabled prop is provided', function () {
|
||||
render(<RadioChip {...defaultProps} disabled />)
|
||||
const label = screen.getByText('Test')?.closest('label')
|
||||
expect(label?.getAttribute('data-disabled')).to.equal('true')
|
||||
})
|
||||
})
|
||||
})
|
Loading…
Reference in a new issue