Visual Character counter for post titles, poll options (#466)
* Indicate how many chars remain for title field and poll options Live counter update to help authors know how many more chars they have to use in their post titles, and also poll options * Use InputInner for consistency * Refactor to reuse title hint across all forms * Character(s) * Move maxLength hint impl to InputInner, per PR feedback --------- Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
This commit is contained in:
parent
cd3dbeb19b
commit
77daa458cf
|
@ -10,6 +10,7 @@ import { SubSelectInitial } from './sub-select-form'
|
|||
import CancelButton from './cancel-button'
|
||||
import { useCallback } from 'react'
|
||||
import { normalizeForwards } from '../lib/form'
|
||||
import { MAX_TITLE_LENGTH } from '../lib/constants'
|
||||
|
||||
export function BountyForm ({
|
||||
item,
|
||||
|
@ -98,7 +99,14 @@ export function BountyForm ({
|
|||
storageKeyPrefix={item ? undefined : 'bounty'}
|
||||
>
|
||||
{children}
|
||||
<Input label={titleLabel} name='title' required autoFocus clear />
|
||||
<Input
|
||||
label={titleLabel}
|
||||
name='title'
|
||||
required
|
||||
autoFocus
|
||||
clear
|
||||
maxLength={MAX_TITLE_LENGTH}
|
||||
/>
|
||||
<Input
|
||||
label={bountyLabel} name='bounty' required
|
||||
append={<InputGroup.Text className='text-monospace'>sats</InputGroup.Text>}
|
||||
|
|
|
@ -14,6 +14,7 @@ import { SubSelectInitial } from './sub-select-form'
|
|||
import CancelButton from './cancel-button'
|
||||
import { useCallback } from 'react'
|
||||
import { normalizeForwards } from '../lib/form'
|
||||
import { MAX_TITLE_LENGTH } from '../lib/constants'
|
||||
|
||||
export function DiscussionForm ({
|
||||
item, sub, editThreshold, titleLabel = 'title',
|
||||
|
@ -101,6 +102,7 @@ export function DiscussionForm ({
|
|||
})
|
||||
}
|
||||
}}
|
||||
maxLength={MAX_TITLE_LENGTH}
|
||||
/>
|
||||
<MarkdownInput
|
||||
topLevel
|
||||
|
|
|
@ -20,6 +20,7 @@ import { USER_SEARCH } from '../fragments/users'
|
|||
import TextareaAutosize from 'react-textarea-autosize'
|
||||
import { useToast } from './toast'
|
||||
import { useInvoiceable } from './invoice'
|
||||
import { numWithUnits } from '../lib/format'
|
||||
|
||||
export function SubmitButton ({
|
||||
children, variant, value, onClick, disabled, cost, ...props
|
||||
|
@ -320,6 +321,11 @@ function InputInner ({
|
|||
{hint}
|
||||
</BootstrapForm.Text>
|
||||
)}
|
||||
{props.maxLength && (
|
||||
<BootstrapForm.Text>
|
||||
{`${numWithUnits(props.maxLength - (field.value || '').length, { abbreviate: false, unitSingular: 'character', unitPlural: 'characters' })} remaining`}
|
||||
</BootstrapForm.Text>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import Avatar from './avatar'
|
|||
import ActionTooltip from './action-tooltip'
|
||||
import { jobSchema } from '../lib/validate'
|
||||
import CancelButton from './cancel-button'
|
||||
import { MAX_TITLE_LENGTH } from '../lib/constants'
|
||||
|
||||
function satsMin2Mo (minute) {
|
||||
return minute * 30 * 24 * 60
|
||||
|
@ -116,6 +117,7 @@ export default function JobForm ({ item, sub }) {
|
|||
required
|
||||
autoFocus
|
||||
clear
|
||||
maxLength={MAX_TITLE_LENGTH}
|
||||
/>
|
||||
<Input
|
||||
label='company'
|
||||
|
|
|
@ -15,6 +15,7 @@ import Moon from '../svgs/moon-fill.svg'
|
|||
import { SubSelectInitial } from './sub-select-form'
|
||||
import CancelButton from './cancel-button'
|
||||
import { normalizeForwards } from '../lib/form'
|
||||
import { MAX_TITLE_LENGTH } from '../lib/constants'
|
||||
|
||||
export function LinkForm ({ item, sub, editThreshold, children }) {
|
||||
const router = useRouter()
|
||||
|
@ -146,6 +147,7 @@ export function LinkForm ({ item, sub, editThreshold, children }) {
|
|||
txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()))
|
||||
}
|
||||
}}
|
||||
maxLength={MAX_TITLE_LENGTH}
|
||||
/>
|
||||
<Input
|
||||
label='url'
|
||||
|
|
|
@ -3,7 +3,7 @@ import { useRouter } from 'next/router'
|
|||
import { gql, useApolloClient, useMutation } from '@apollo/client'
|
||||
import Countdown from './countdown'
|
||||
import AdvPostForm, { AdvPostInitial } from './adv-post-form'
|
||||
import { MAX_POLL_NUM_CHOICES } from '../lib/constants'
|
||||
import { MAX_POLL_CHOICE_LENGTH, MAX_POLL_NUM_CHOICES, MAX_TITLE_LENGTH } from '../lib/constants'
|
||||
import FeeButton, { EditFeeButton } from './fee-button'
|
||||
import Delete from './delete'
|
||||
import Button from 'react-bootstrap/Button'
|
||||
|
@ -76,6 +76,7 @@ export function PollForm ({ item, sub, editThreshold, children }) {
|
|||
label='title'
|
||||
name='title'
|
||||
required
|
||||
maxLength={MAX_TITLE_LENGTH}
|
||||
/>
|
||||
<MarkdownInput
|
||||
topLevel
|
||||
|
@ -92,6 +93,7 @@ export function PollForm ({ item, sub, editThreshold, children }) {
|
|||
hint={editThreshold
|
||||
? <div className='text-muted fw-bold'><Countdown date={editThreshold} /></div>
|
||||
: null}
|
||||
maxLength={MAX_POLL_CHOICE_LENGTH}
|
||||
/>
|
||||
<AdvPostForm edit={!!item} />
|
||||
<div className='mt-3'>
|
||||
|
|
Loading…
Reference in New Issue