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
+13 -1
View File
@@ -1,5 +1,5 @@
import { useAtomValue } from 'jotai';
import React, { ReactNode, useCallback, useEffect, useRef, useState } from 'react';
import React, { ReactNode, useCallback, useEffect, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import { RoomEvent, RoomEventHandlerMap } from 'matrix-js-sdk';
import { roomToUnreadAtom, unreadEqual, unreadInfoToUnread } from '../../state/room/roomToUnread';
@@ -265,9 +265,21 @@ type ClientNonUIFeaturesProps = {
children: ReactNode;
};
function SuppressPrintShortcut() {
useEffect(() => {
const handler = (e: KeyboardEvent) => {
if ((e.ctrlKey || e.metaKey) && e.code === 'KeyP') e.preventDefault();
};
window.addEventListener('keydown', handler);
return () => window.removeEventListener('keydown', handler);
}, []);
return null;
}
export function ClientNonUIFeatures({ children }: ClientNonUIFeaturesProps) {
return (
<>
<SuppressPrintShortcut />
<SystemEmojiFeature />
<PageZoomFeature />
<FaviconUpdater />