fix: GIFs, topic display, formatting toolbar, Copy Link in Invite, support URL

- RoomInput: GIF domain check uses endsWith('.giphy.com') — handles all
  Giphy CDN shards; all silent failure paths now show user-facing error
- RoomProfile: topic plain-text field is now HTML-stripped (no markdown
  syntax visible in header); formatting toolbar (B/I/S/code) above the
  textarea wraps selected text with correct markdown syntax
- InviteUserPrompt: Copy Link button added to dialog header with
  'Copied!' confirmation; removed Copy Link from both three-dot menus
- RoomViewHeader/RoomNavItem: unused copy-link imports removed
- nginx (live): support_page URL updated from lotusguild.org →
  matrix.lotusguild.org

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-02 09:55:04 -04:00
parent 16a15efe9b
commit 0bbfe17559
5 changed files with 119 additions and 70 deletions
@@ -34,7 +34,13 @@ import { isKeyHotkey } from 'is-hotkey';
import FocusTrap from 'focus-trap-react';
import { stopPropagation } from '../../utils/keyboard';
import { useDirectUsers } from '../../hooks/useDirectUsers';
import { getMxIdLocalPart, getMxIdServer, isUserId } from '../../utils/matrix';
import {
getCanonicalAliasOrRoomId,
getMxIdLocalPart,
getMxIdServer,
isRoomAlias,
isUserId,
} from '../../utils/matrix';
import { Membership } from '../../../types/matrix/room';
import { useAsyncSearch, UseAsyncSearchOptions } from '../../hooks/useAsyncSearch';
import { highlightText, makeHighlightRegex } from '../../plugins/react-custom-html-parser';
@@ -42,6 +48,9 @@ import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { BreakWord } from '../../styles/Text.css';
import { useAlive } from '../../hooks/useAlive';
import { copyToClipboard } from '../../utils/dom';
import { getMatrixToRoom } from '../../plugins/matrix-to';
import { getViaServers } from '../../plugins/via-servers';
const SEARCH_OPTIONS: UseAsyncSearchOptions = {
limit: 1000,
@@ -58,6 +67,15 @@ type InviteUserProps = {
export function InviteUserPrompt({ room, requestClose }: InviteUserProps) {
const mx = useMatrixClient();
const alive = useAlive();
const [linkCopied, setLinkCopied] = useState(false);
const handleCopyLink = () => {
const roomIdOrAlias = getCanonicalAliasOrRoomId(mx, room.roomId);
const viaServers = isRoomAlias(roomIdOrAlias) ? undefined : getViaServers(room);
copyToClipboard(getMatrixToRoom(roomIdOrAlias, viaServers));
setLinkCopied(true);
setTimeout(() => setLinkCopied(false), 2000);
};
const inputRef = useRef<HTMLInputElement>(null);
const directUsers = useDirectUsers();
@@ -172,7 +190,18 @@ export function InviteUserPrompt({ room, requestClose }: InviteUserProps) {
Invite
</Text>
</Box>
<Box shrink="No">
<Box shrink="No" gap="100" alignItems="Center">
<Button
size="300"
variant={linkCopied ? 'Success' : 'Secondary'}
fill="Soft"
radii="300"
before={<Icon size="100" src={linkCopied ? Icons.Check : Icons.Link} />}
onClick={handleCopyLink}
aria-label="Copy room link"
>
<Text size="B300">{linkCopied ? 'Copied!' : 'Copy Link'}</Text>
</Button>
<IconButton size="300" radii="300" onClick={requestClose} aria-label="Close">
<Icon src={Icons.Cross} />
</IconButton>