mirror of
https://github.com/mastodon/mastodon.git
synced 2024-08-20 21:08:15 -07:00
Improve polls: option lengths & redesign (#13257)
This commit redesign the polls and increases characters limit for the options from 25 to 50 characters, giving pollsters more freedom. Summarizing, the redesign is making the polls more adaptive for upcoming changes to the options characters limit: the bar, or a "chart", is now displayed separately from the option itself; vote check mark is moved next to the option text, making the percentages take less space. Option lengths are taken into account and text is wrapped to multiple lines if necessary to avoid overflow.
This commit is contained in:
parent
a9a063c0e9
commit
37b3985bfa
6 changed files with 48 additions and 38 deletions
|
@ -127,15 +127,7 @@ class Poll extends ImmutablePureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li key={option.get('title')}>
|
<li key={option.get('title')}>
|
||||||
{showResults && (
|
<label className={classNames('poll__option', { selectable: !showResults })}>
|
||||||
<Motion defaultStyle={{ width: 0 }} style={{ width: spring(percent, { stiffness: 180, damping: 12 }) }}>
|
|
||||||
{({ width }) =>
|
|
||||||
<span className={classNames('poll__chart', { leading })} style={{ width: `${width}%` }} />
|
|
||||||
}
|
|
||||||
</Motion>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<label className={classNames('poll__text', { selectable: !showResults })}>
|
|
||||||
<input
|
<input
|
||||||
name='vote-options'
|
name='vote-options'
|
||||||
type={poll.get('multiple') ? 'checkbox' : 'radio'}
|
type={poll.get('multiple') ? 'checkbox' : 'radio'}
|
||||||
|
@ -157,12 +149,26 @@ class Poll extends ImmutablePureComponent {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showResults && <span className='poll__number'>
|
{showResults && <span className='poll__number'>
|
||||||
{!!voted && <Icon id='check' className='poll__vote__mark' title={intl.formatMessage(messages.voted)} />}
|
|
||||||
{Math.round(percent)}%
|
{Math.round(percent)}%
|
||||||
</span>}
|
</span>}
|
||||||
|
|
||||||
<span dangerouslySetInnerHTML={{ __html: titleEmojified }} />
|
<span
|
||||||
|
className='poll__option__text'
|
||||||
|
dangerouslySetInnerHTML={{ __html: titleEmojified }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{!!voted && <span className='poll__voted'>
|
||||||
|
<Icon id='check' className='poll__voted__mark' title={intl.formatMessage(messages.voted)} />
|
||||||
|
</span>}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
{showResults && (
|
||||||
|
<Motion defaultStyle={{ width: 0 }} style={{ width: spring(percent, { stiffness: 180, damping: 12 }) }}>
|
||||||
|
{({ width }) =>
|
||||||
|
<span className={classNames('poll__chart', { leading })} style={{ width: `${width}%` }} />
|
||||||
|
}
|
||||||
|
</Motion>
|
||||||
|
)}
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ class Option extends React.PureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li>
|
<li>
|
||||||
<label className='poll__text editable'>
|
<label className='poll__option editable'>
|
||||||
<span
|
<span
|
||||||
className={classNames('poll__input', { checkbox: isPollMultiple })}
|
className={classNames('poll__input', { checkbox: isPollMultiple })}
|
||||||
onClick={this.handleToggleMultiple}
|
onClick={this.handleToggleMultiple}
|
||||||
|
@ -88,7 +88,7 @@ class Option extends React.PureComponent {
|
||||||
|
|
||||||
<AutosuggestInput
|
<AutosuggestInput
|
||||||
placeholder={intl.formatMessage(messages.option_placeholder, { number: index + 1 })}
|
placeholder={intl.formatMessage(messages.option_placeholder, { number: index + 1 })}
|
||||||
maxLength={25}
|
maxLength={50}
|
||||||
value={title}
|
value={title}
|
||||||
onChange={this.handleOptionTitleChange}
|
onChange={this.handleOptionTitleChange}
|
||||||
suggestions={this.props.suggestions}
|
suggestions={this.props.suggestions}
|
||||||
|
|
|
@ -142,7 +142,7 @@ html {
|
||||||
}
|
}
|
||||||
|
|
||||||
.compose-form__autosuggest-wrapper,
|
.compose-form__autosuggest-wrapper,
|
||||||
.poll__text input[type="text"],
|
.poll__option input[type="text"],
|
||||||
.compose-form .spoiler-input__input,
|
.compose-form .spoiler-input__input,
|
||||||
.compose-form__poll-wrapper select,
|
.compose-form__poll-wrapper select,
|
||||||
.search__input,
|
.search__input,
|
||||||
|
|
|
@ -8,20 +8,18 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&__chart {
|
&__chart {
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
height: 100%;
|
|
||||||
display: inline-block;
|
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background: darken($ui-primary-color, 14%);
|
display: block;
|
||||||
|
background: darken($ui-primary-color, 5%);
|
||||||
|
height: 5px;
|
||||||
|
min-width: 1%;
|
||||||
|
|
||||||
&.leading {
|
&.leading {
|
||||||
background: $ui-highlight-color;
|
background: $ui-highlight-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__text {
|
&__option {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 6px 0;
|
padding: 6px 0;
|
||||||
|
@ -29,6 +27,13 @@
|
||||||
cursor: default;
|
cursor: default;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
display: inline-block;
|
||||||
|
word-wrap: break-word;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
max-width: calc(100% - 45px - 25px);
|
||||||
|
}
|
||||||
|
|
||||||
input[type=radio],
|
input[type=radio],
|
||||||
input[type=checkbox] {
|
input[type=checkbox] {
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -112,19 +117,18 @@
|
||||||
|
|
||||||
&__number {
|
&__number {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 52px;
|
width: 45px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
padding: 0 10px;
|
flex: 0 0 45px;
|
||||||
padding-left: 8px;
|
|
||||||
text-align: right;
|
|
||||||
margin-top: auto;
|
|
||||||
margin-bottom: auto;
|
|
||||||
flex: 0 0 52px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__vote__mark {
|
&__voted {
|
||||||
float: left;
|
padding: 0 5px;
|
||||||
line-height: 18px;
|
display: inline-block;
|
||||||
|
|
||||||
|
&__mark {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__footer {
|
&__footer {
|
||||||
|
@ -199,7 +203,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.poll__text {
|
.poll__option {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
width: calc(100% - (23px + 6px));
|
width: calc(100% - (23px + 6px));
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
class PollValidator < ActiveModel::Validator
|
class PollValidator < ActiveModel::Validator
|
||||||
MAX_OPTIONS = 4
|
MAX_OPTIONS = 4
|
||||||
MAX_OPTION_CHARS = 25
|
MAX_OPTION_CHARS = 50
|
||||||
MAX_EXPIRATION = 1.month.freeze
|
MAX_EXPIRATION = 1.month.freeze
|
||||||
MIN_EXPIRATION = 5.minutes.freeze
|
MIN_EXPIRATION = 5.minutes.freeze
|
||||||
|
|
||||||
|
|
|
@ -8,16 +8,16 @@
|
||||||
%li
|
%li
|
||||||
- if show_results
|
- if show_results
|
||||||
- percent = total_votes_count > 0 ? 100 * option.votes_count / total_votes_count : 0
|
- percent = total_votes_count > 0 ? 100 * option.votes_count / total_votes_count : 0
|
||||||
%span.poll__chart{ style: "width: #{percent}%" }
|
%label.poll__option><
|
||||||
|
|
||||||
%label.poll__text><
|
|
||||||
%span.poll__number><
|
%span.poll__number><
|
||||||
- if own_votes.include?(index)
|
- if own_votes.include?(index)
|
||||||
%i.poll__vote__mark.fa.fa-check
|
%i.poll__voted__mark.fa.fa-check
|
||||||
= percent.round
|
= percent.round
|
||||||
= Formatter.instance.format_poll_option(status, option, autoplay: autoplay)
|
= Formatter.instance.format_poll_option(status, option, autoplay: autoplay)
|
||||||
|
|
||||||
|
%span.poll__chart{ style: "width: #{percent}%" }
|
||||||
- else
|
- else
|
||||||
%label.poll__text><
|
%label.poll__option><
|
||||||
%span.poll__input{ class: poll.multiple? ? 'checkbox' : nil}><
|
%span.poll__input{ class: poll.multiple? ? 'checkbox' : nil}><
|
||||||
= Formatter.instance.format_poll_option(status, option, autoplay: autoplay)
|
= Formatter.instance.format_poll_option(status, option, autoplay: autoplay)
|
||||||
.poll__footer
|
.poll__footer
|
||||||
|
|
Loading…
Reference in a new issue