fix: ctrl+p print dialog, gallery 400 error, poll multi-choice UX

- Suppress Ctrl+P browser print dialog via SuppressPrintShortcut in
  ClientNonUIFeatures (no UI opened, just preventDefault)
- mxcUrlToHttp: build URL manually instead of delegating to SDK.
  The SDK forces allow_redirect=true when useAuthentication=true;
  Synapse's /_matrix/client/v1/media/thumbnail rejects that with 400.
  Manual construction omits allow_redirect entirely.
- Gallery: redesign using folds color tokens (color.Surface.*) instead
  of non-existent CSS custom properties; add ThumbState so broken
  images show an icon placeholder; use useAuthentication for thumbnails
  now that the URL builder is fixed; "Load More" always visible.
- PollCreator: replace raw <button> with folds Button components so the
  Single/Multiple choice toggle renders with actual visual difference.
- PollContent: support multiple-choice polls end-to-end —
  myVote:string → myVotes:Set<string>; computeVotes collects all
  m.selections (not just [0]); toggle-select for multi, radio for
  single; checkbox/radio indicator icons next to each option;
  "◉ Poll · Multiple choice" / "Single choice" label in header;
  sends full selections array on every vote event.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-03 11:23:44 -04:00
parent 9232e1ec8e
commit a3f776134f
5 changed files with 294 additions and 214 deletions
+30 -49
View File
@@ -1,6 +1,6 @@
import React, { useState } from 'react';
import { Room } from 'matrix-js-sdk';
import { Box, Icon, IconButton, Icons, Text, config } from 'folds';
import { Box, Button, Icon, IconButton, Icons, Text, config } from 'folds';
import { useMatrixClient } from '../../hooks/useMatrixClient';
interface PollCreatorProps {
@@ -193,34 +193,26 @@ export function PollCreator({ roomId, onClose }: PollCreatorProps) {
)}
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: config.space.S100 }}>
<Box direction="Column" gap="100">
<Text size="L400">Selection Type</Text>
<div style={{ display: 'flex', gap: config.space.S200 }}>
<Box gap="200">
{(['single', 'multiple'] as const).map((type) => {
const active = type === 'multiple' ? isMultiple : !isMultiple;
return (
<button
<Button
key={type}
type="button"
size="300"
variant="Primary"
fill={active ? 'Solid' : 'None'}
radii="300"
onClick={() => setIsMultiple(type === 'multiple')}
style={{
padding: `${config.space.S100} ${config.space.S300}`,
borderRadius: config.radii.R300,
border: `1px solid ${active ? 'var(--bg-primary-main)' : 'var(--bg-surface-border)'}`,
background: active ? 'var(--bg-primary-main)' : 'transparent',
color: active ? 'var(--tc-primary-on-primary)' : 'var(--tc-surface-high)',
cursor: 'pointer',
fontSize: '13px',
fontWeight: active ? 600 : 400,
transition: 'all 0.15s ease',
}}
>
{type === 'single' ? 'Single choice' : 'Multiple choice'}
</button>
<Text size="B300">{type === 'single' ? 'Single choice' : 'Multiple choice'}</Text>
</Button>
);
})}
</div>
</div>
</Box>
</Box>
{error && (
<Text size="T200" style={{ color: 'var(--tc-danger-normal)' }}>
@@ -229,38 +221,27 @@ export function PollCreator({ roomId, onClose }: PollCreatorProps) {
)}
<Box direction="Row" justifyContent="End" gap="200">
<button
type="button"
<Button
size="400"
variant="Secondary"
fill="Soft"
radii="300"
onClick={onClose}
style={{
background: 'var(--bg-surface-low)',
border: '1px solid var(--bg-surface-border)',
borderRadius: config.radii.R300,
padding: `${config.space.S200} ${config.space.S400}`,
cursor: 'pointer',
color: 'var(--tc-surface-high)',
fontSize: '14px',
}}
>
Cancel
</button>
<button
type="button"
onClick={handleSubmit}
disabled={submitting}
style={{
background: 'var(--bg-primary-main)',
border: 'none',
borderRadius: config.radii.R300,
padding: `${config.space.S200} ${config.space.S400}`,
cursor: submitting ? 'not-allowed' : 'pointer',
color: 'var(--tc-primary-on-primary)',
fontSize: '14px',
opacity: submitting ? 0.7 : 1,
}}
>
{submitting ? 'Creating...' : 'Create Poll'}
</button>
<Text size="B400">Cancel</Text>
</Button>
<Button
size="400"
variant="Primary"
fill="Solid"
radii="300"
onClick={handleSubmit}
type="button"
disabled={submitting}
>
<Text size="B400">{submitting ? 'Creating…' : 'Create Poll'}</Text>
</Button>
</Box>
</div>
</div>