Beautify poll

This commit is contained in:
Lim Chee Aun 2023-03-30 11:11:35 +08:00
parent c2ee8c55d3
commit d2214c59be
2 changed files with 104 additions and 74 deletions

View file

@ -843,34 +843,48 @@ a.card:is(:hover, :focus) {
.poll.read-only {
pointer-events: none;
}
.poll-options {
display: flex;
flex-direction: column;
gap: 4px;
padding: 4px;
border-radius: 16px;
border: 1px solid var(--outline-color);
background-color: var(--bg-faded-color);
}
.poll-option {
padding: 8px;
padding: 4px;
display: flex;
gap: 8px;
justify-content: space-between;
background-color: var(--bg-faded-color);
background-image: linear-gradient(
to right,
var(--link-faded-color),
var(--link-faded-color) var(--percentage),
transparent var(--percentage),
transparent
);
background-repeat: no-repeat;
/* border-radius: 8px; */
border: 1px solid var(--outline-color);
border-bottom: 0;
align-items: center;
text-shadow: 0 1px var(--bg-blur-color);
position: relative;
}
.poll-option:first-child {
border-top-left-radius: 8px;
border-top-right-radius: 8px;
.poll-option:after {
content: '';
position: absolute;
inset: 0;
border-radius: 4px;
background-color: var(--link-faded-color);
opacity: 0;
pointer-events: none;
transition: all 0.2s ease-in-out;
mix-blend-mode: multiply;
}
.poll-option:last-of-type {
border-bottom: 1px solid var(--outline-color);
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
.poll-option:first-child:after {
border-top-left-radius: 12px;
border-top-right-radius: 12px;
}
.poll-option:last-child:after {
border-bottom-left-radius: 12px;
border-bottom-right-radius: 12px;
}
.poll-option:hover:after {
opacity: 1;
}
.poll-option.poll-result:after {
width: var(--percentage);
opacity: 1;
}
.poll-label {
width: 100%;
@ -897,6 +911,9 @@ a.card:is(:hover, :focus) {
margin: 8px 0;
font-size: 90%;
}
.poll-option-title {
text-shadow: 0 1px var(--bg-color);
}
.poll-option-title .icon {
vertical-align: middle;
}

View file

@ -1309,53 +1309,64 @@ function Poll({
roundPrecision = 2;
}
const [showResults, setShowResults] = useState(false);
const optionsHaveVoteCounts = options.every((o) => o.votesCount !== null);
return (
<div
lang={lang}
class={`poll ${readOnly ? 'read-only' : ''} ${
uiState === 'loading' ? 'loading' : ''
}`}
onDblClick={() => {
setShowResults(!showResults);
}}
>
{voted || expired ? (
options.map((option, i) => {
const { title, votesCount: optionVotesCount } = option;
const percentage = pollVotesCount
? ((optionVotesCount / pollVotesCount) * 100).toFixed(
roundPrecision,
)
: 0;
// check if current poll choice is the leading one
const isLeading =
optionVotesCount > 0 &&
optionVotesCount === Math.max(...options.map((o) => o.votesCount));
return (
<div
key={`${i}-${title}-${optionVotesCount}`}
class={`poll-option ${isLeading ? 'poll-option-leading' : ''}`}
style={{
'--percentage': `${percentage}%`,
}}
>
<div class="poll-option-title">
{title}
{voted && ownVotes.includes(i) && (
<>
{' '}
<Icon icon="check-circle" />
</>
)}
</div>
{(showResults && optionsHaveVoteCounts) || voted || expired ? (
<div class="poll-options">
{options.map((option, i) => {
const { title, votesCount: optionVotesCount } = option;
const percentage = pollVotesCount
? ((optionVotesCount / pollVotesCount) * 100).toFixed(
roundPrecision,
)
: 0;
// check if current poll choice is the leading one
const isLeading =
optionVotesCount > 0 &&
optionVotesCount ===
Math.max(...options.map((o) => o.votesCount));
return (
<div
class="poll-option-votes"
title={`${optionVotesCount} vote${
optionVotesCount === 1 ? '' : 's'
key={`${i}-${title}-${optionVotesCount}`}
class={`poll-option poll-result ${
isLeading ? 'poll-option-leading' : ''
}`}
style={{
'--percentage': `${percentage}%`,
}}
>
{percentage}%
<div class="poll-option-title">
{title}
{voted && ownVotes.includes(i) && (
<>
{' '}
<Icon icon="check-circle" />
</>
)}
</div>
<div
class="poll-option-votes"
title={`${optionVotesCount} vote${
optionVotesCount === 1 ? '' : 's'
}`}
>
{percentage}%
</div>
</div>
</div>
);
})
);
})}
</div>
) : (
<form
onSubmit={async (e) => {
@ -1374,23 +1385,25 @@ function Poll({
setUIState('default');
}}
>
{options.map((option, i) => {
const { title } = option;
return (
<div class="poll-option">
<label class="poll-label">
<input
type={multiple ? 'checkbox' : 'radio'}
name="poll"
value={i}
disabled={uiState === 'loading'}
readOnly={readOnly}
/>
<span class="poll-option-title">{title}</span>
</label>
</div>
);
})}
<div class="poll-options">
{options.map((option, i) => {
const { title } = option;
return (
<div class="poll-option">
<label class="poll-label">
<input
type={multiple ? 'checkbox' : 'radio'}
name="poll"
value={i}
disabled={uiState === 'loading'}
readOnly={readOnly}
/>
<span class="poll-option-title">{title}</span>
</label>
</div>
);
})}
</div>
{!readOnly && (
<button
class="poll-vote-button"