fix(poll): render vote buttons with folds tokens (N4)
Poll answer buttons referenced undefined CSS vars (--accent-cyan, --accent-cyan-dim, --accent-cyan-border, --border-color) plus hardcoded rgba()/#fff and raw rem font sizes, so they rendered unstyled on every non-TDS theme (invisible borders, no selected/progress state). Replace all colors with always-defined folds tokens (Primary.* for the selected/indicator state, SurfaceVariant.* for the resting surface + progress fill), size/spacing/radii with config.* tokens, and the checkbox/radio glyphs + percentage/label text with folds <Text>. The progress-bar-behind-text affordance is preserved (folds Button has no equivalent), now theme-reactive. Merged the duplicate checkbox/radio indicator spans into one. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import { Box, Text } from 'folds';
|
import { Box, color, config, Text, toRem } from 'folds';
|
||||||
import { RelationsEvent } from 'matrix-js-sdk/lib/models/relations';
|
import { RelationsEvent } from 'matrix-js-sdk/lib/models/relations';
|
||||||
import { RoomEvent } from 'matrix-js-sdk';
|
import { RoomEvent } from 'matrix-js-sdk';
|
||||||
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
||||||
@@ -175,7 +175,7 @@ export function PollContent({
|
|||||||
|
|
||||||
if (!poll) {
|
if (!poll) {
|
||||||
return (
|
return (
|
||||||
<Text style={{ opacity: 0.6 }}>
|
<Text priority="300">
|
||||||
<i>Poll (unreadable format)</i>
|
<i>Poll (unreadable format)</i>
|
||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
@@ -244,21 +244,20 @@ export function PollContent({
|
|||||||
gap="200"
|
gap="200"
|
||||||
style={{ maxWidth: '340px', paddingTop: '2px', paddingBottom: '4px' }}
|
style={{ maxWidth: '340px', paddingTop: '2px', paddingBottom: '4px' }}
|
||||||
>
|
>
|
||||||
<Box
|
<Text
|
||||||
alignItems="Center"
|
as="div"
|
||||||
gap="100"
|
size="T200"
|
||||||
|
priority="300"
|
||||||
data-poll-content-label
|
data-poll-content-label
|
||||||
style={{
|
style={{
|
||||||
fontSize: '0.68rem',
|
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
letterSpacing: '0.12em',
|
letterSpacing: '0.12em',
|
||||||
textTransform: 'uppercase',
|
textTransform: 'uppercase',
|
||||||
opacity: 0.55,
|
marginBottom: config.space.S100,
|
||||||
marginBottom: '2px',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{`◉ Poll · ${isMultiple ? 'Multiple choice' : 'Single choice'}`}
|
{`◉ Poll · ${isMultiple ? 'Multiple choice' : 'Single choice'}`}
|
||||||
</Box>
|
</Text>
|
||||||
<Text size="T400" style={{ fontWeight: 600 }}>
|
<Text size="T400" style={{ fontWeight: 600 }}>
|
||||||
{questionText}
|
{questionText}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -280,18 +279,19 @@ export function PollContent({
|
|||||||
data-selected={selected}
|
data-selected={selected}
|
||||||
onClick={canVote ? () => handleVote(id) : undefined}
|
onClick={canVote ? () => handleVote(id) : undefined}
|
||||||
style={{
|
style={{
|
||||||
padding: '7px 12px',
|
padding: `${config.space.S200} ${config.space.S300}`,
|
||||||
borderRadius: '8px',
|
borderRadius: config.radii.R300,
|
||||||
background: selected ? 'var(--accent-cyan-dim)' : 'rgba(255,255,255,0.04)',
|
background: selected ? color.Primary.Container : color.SurfaceVariant.Container,
|
||||||
border: `1.5px solid ${selected ? 'var(--accent-cyan)' : 'var(--border-color)'}`,
|
border: `${config.borderWidth.B300} solid ${
|
||||||
fontSize: '0.88rem',
|
selected ? color.Primary.Main : color.SurfaceVariant.ContainerLine
|
||||||
|
}`,
|
||||||
lineHeight: 1.4,
|
lineHeight: 1.4,
|
||||||
textAlign: 'left',
|
textAlign: 'left',
|
||||||
cursor: canVote ? 'pointer' : 'default',
|
cursor: canVote ? 'pointer' : 'default',
|
||||||
color: 'inherit',
|
color: 'inherit',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
gap: '4px',
|
gap: config.space.S100,
|
||||||
width: '100%',
|
width: '100%',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
@@ -306,58 +306,59 @@ export function PollContent({
|
|||||||
inset: 0,
|
inset: 0,
|
||||||
right: 'auto',
|
right: 'auto',
|
||||||
width: `${pct}%`,
|
width: `${pct}%`,
|
||||||
background: selected ? 'var(--accent-cyan-dim)' : 'rgba(255,255,255,0.03)',
|
background: selected
|
||||||
|
? color.Primary.ContainerActive
|
||||||
|
: color.SurfaceVariant.ContainerActive,
|
||||||
pointerEvents: 'none',
|
pointerEvents: 'none',
|
||||||
transition: 'width 0.3s ease',
|
transition: 'width 0.3s ease',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<span
|
<span
|
||||||
style={{ display: 'flex', alignItems: 'center', gap: '8px', position: 'relative' }}
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: config.space.S200,
|
||||||
|
position: 'relative',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{isMultiple && (
|
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
width: '14px',
|
width: toRem(14),
|
||||||
height: '14px',
|
height: toRem(14),
|
||||||
border: `1.5px solid ${selected ? 'var(--accent-cyan)' : 'var(--accent-cyan-border)'}`,
|
border: `${config.borderWidth.B300} solid ${
|
||||||
borderRadius: '3px',
|
selected ? color.Primary.Main : color.Primary.ContainerLine
|
||||||
background: selected ? 'var(--accent-cyan)' : 'none',
|
}`,
|
||||||
|
borderRadius: isMultiple ? config.radii.R300 : config.radii.Pill,
|
||||||
|
background: selected ? color.Primary.Main : 'transparent',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
fontSize: '10px',
|
color: color.Primary.OnMain,
|
||||||
color: '#fff',
|
|
||||||
transition: 'all 0.15s',
|
transition: 'all 0.15s',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{selected ? '✓' : ''}
|
{selected && isMultiple ? (
|
||||||
|
<Text as="span" size="T200" style={{ lineHeight: 1 }}>
|
||||||
|
✓
|
||||||
|
</Text>
|
||||||
|
) : null}
|
||||||
</span>
|
</span>
|
||||||
)}
|
<Text as="span" size="T300" style={{ flexGrow: 1 }}>
|
||||||
{!isMultiple && (
|
{text}
|
||||||
<span
|
</Text>
|
||||||
style={{
|
|
||||||
flexShrink: 0,
|
|
||||||
width: '14px',
|
|
||||||
height: '14px',
|
|
||||||
border: `1.5px solid ${selected ? 'var(--accent-cyan)' : 'var(--accent-cyan-border)'}`,
|
|
||||||
borderRadius: '50%',
|
|
||||||
background: selected ? 'var(--accent-cyan)' : 'none',
|
|
||||||
transition: 'all 0.15s',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<span style={{ flexGrow: 1 }}>{text}</span>
|
|
||||||
{total > 0 && (
|
{total > 0 && (
|
||||||
<span style={{ opacity: 0.55, fontSize: '0.78rem', flexShrink: 0 }}>{pct}%</span>
|
<Text as="span" size="T200" priority="300" style={{ flexShrink: 0 }}>
|
||||||
|
{pct}%
|
||||||
|
</Text>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Box>
|
</Box>
|
||||||
<Text size="T200" style={{ opacity: 0.5, marginTop: '2px' }}>
|
<Text size="T200" priority="300" style={{ marginTop: '2px' }}>
|
||||||
<i>
|
<i>
|
||||||
{total > 0 ? `${total} vote${total === 1 ? '' : 's'} · ` : ''}
|
{total > 0 ? `${total} vote${total === 1 ? '' : 's'} · ` : ''}
|
||||||
{canVote
|
{canVote
|
||||||
|
|||||||
Reference in New Issue
Block a user