mirror of
https://github.com/tulir/gomuks.git
synced 2025-04-18 17:53:42 -05:00
web/{timeline,composer}: render m.room.tombstone
events (#608)
This commit is contained in:
parent
5f50cf8e77
commit
769d60c459
5 changed files with 103 additions and 2 deletions
|
@ -102,6 +102,11 @@ export interface RoomNameEventContent {
|
|||
name?: string
|
||||
}
|
||||
|
||||
export interface RoomCanonicalAliasEventContent {
|
||||
alias?: RoomAlias | null
|
||||
alt_aliases?: RoomAlias[]
|
||||
}
|
||||
|
||||
export interface RoomTopicEventContent {
|
||||
topic?: string
|
||||
}
|
||||
|
|
|
@ -14,6 +14,11 @@ div.message-composer {
|
|||
text-wrap: auto !important;
|
||||
}
|
||||
|
||||
&.tombstoned {
|
||||
min-height: unset;
|
||||
padding: .5rem;
|
||||
}
|
||||
|
||||
> div.input-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
@ -13,9 +13,19 @@
|
|||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import React, { CSSProperties, use, useCallback, useEffect, useLayoutEffect, useReducer, useRef, useState } from "react"
|
||||
import React, {
|
||||
CSSProperties,
|
||||
JSX,
|
||||
use,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
useReducer,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react"
|
||||
import { ScaleLoader } from "react-spinners"
|
||||
import { useRoomEvent } from "@/api/statestore"
|
||||
import { useRoomEvent, useRoomState } from "@/api/statestore"
|
||||
import type {
|
||||
EventID,
|
||||
MediaMessageEventContent,
|
||||
|
@ -28,6 +38,7 @@ import type {
|
|||
import { PartialEmoji, emojiToMarkdown } from "@/util/emoji"
|
||||
import { isMobileDevice } from "@/util/ismobile.ts"
|
||||
import { escapeMarkdown } from "@/util/markdown.ts"
|
||||
import { getServerName } from "@/util/validation.ts"
|
||||
import ClientContext from "../ClientContext.ts"
|
||||
import EmojiPicker from "../emojipicker/EmojiPicker.tsx"
|
||||
import GIFPicker from "../emojipicker/GIFPicker.tsx"
|
||||
|
@ -576,6 +587,35 @@ const MessageComposer = () => {
|
|||
const inlineButtons = state.text === "" || window.innerWidth > 720
|
||||
const showSendButton = canSend || window.innerWidth > 720
|
||||
const disableClearMedia = editing && state.media?.msgtype === "m.sticker"
|
||||
const tombstoneEvent = useRoomState(room, "m.room.tombstone", "")
|
||||
if (tombstoneEvent !== null) {
|
||||
const content = tombstoneEvent.content
|
||||
const hasReplacement = content.replacement_room?.startsWith("!")
|
||||
let link: JSX.Element | null = null
|
||||
if (hasReplacement) {
|
||||
const via = getServerName(tombstoneEvent.sender)
|
||||
const handleNavigate = (e: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
|
||||
e.preventDefault()
|
||||
window.mainScreenContext.setActiveRoom(content.replacement_room, {
|
||||
via: [via],
|
||||
})
|
||||
}
|
||||
const url = `matrix:roomid/${content.replacement_room.slice(1)}?via=${via}`
|
||||
link = <a href={url} onClick={handleNavigate}>
|
||||
Join the new one here
|
||||
</a>
|
||||
}
|
||||
let body = content.body
|
||||
if (!body) {
|
||||
body = hasReplacement ? "This room has been replaced." : "This room has been shut down."
|
||||
}
|
||||
if (!body.endsWith(".")) {
|
||||
body += "."
|
||||
}
|
||||
return <div className="message-composer tombstoned" ref={composerRef}>
|
||||
{body} {link}
|
||||
</div>
|
||||
}
|
||||
return <>
|
||||
{Autocompleter && autocomplete && <div className="autocompletions-wrapper"><Autocompleter
|
||||
params={autocomplete}
|
||||
|
|
46
web/src/ui/timeline/content/RoomTombstoneBody.tsx
Normal file
46
web/src/ui/timeline/content/RoomTombstoneBody.tsx
Normal file
|
@ -0,0 +1,46 @@
|
|||
// gomuks - A Matrix client written in Go.
|
||||
// Copyright (C) 2024 Nexus Nicholson
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import { JSX } from "react"
|
||||
import { TombstoneEventContent } from "@/api/types"
|
||||
import EventContentProps from "./props.ts"
|
||||
|
||||
const RoomTombstoneBody = ({ event, sender }: EventContentProps) => {
|
||||
const content = event.content as TombstoneEventContent
|
||||
const end = content.body?.length > 0 ? ` with the message: ${content.body}` : "."
|
||||
const onClick = (e: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
|
||||
e.preventDefault()
|
||||
window.mainScreenContext.setActiveRoom(content.replacement_room)
|
||||
}
|
||||
let description: JSX.Element
|
||||
if (content.replacement_room?.length && content.replacement_room.startsWith("!")) {
|
||||
description = (
|
||||
<span>
|
||||
replaced this room with
|
||||
<a onClick={onClick} href={"matrix:roomid/" + content.replacement_room.slice(1)}
|
||||
className="hicli-matrix-uri">
|
||||
{content.replacement_room}
|
||||
</a>{end}
|
||||
</span>
|
||||
)
|
||||
} else {
|
||||
description = <span>shut down this room{end}</span>
|
||||
}
|
||||
return <div className="room-tombstone-body">
|
||||
{sender?.content.displayname ?? event.sender} {description}
|
||||
</div>
|
||||
}
|
||||
|
||||
export default RoomTombstoneBody
|
|
@ -12,6 +12,7 @@ import PowerLevelBody from "./PowerLevelBody.tsx"
|
|||
import RedactedBody from "./RedactedBody.tsx"
|
||||
import RoomAvatarBody from "./RoomAvatarBody.tsx"
|
||||
import RoomNameBody from "./RoomNameBody.tsx"
|
||||
import RoomTombstoneBody from "./RoomTombstoneBody.tsx"
|
||||
import TextMessageBody from "./TextMessageBody.tsx"
|
||||
import UnknownMessageBody from "./UnknownMessageBody.tsx"
|
||||
import EventContentProps from "./props.ts"
|
||||
|
@ -31,6 +32,7 @@ export { default as RedactedBody } from "./RedactedBody.tsx"
|
|||
export { default as RoomAvatarBody } from "./RoomAvatarBody.tsx"
|
||||
export { default as RoomNameBody } from "./RoomNameBody.tsx"
|
||||
export { default as TextMessageBody } from "./TextMessageBody.tsx"
|
||||
export { default as RoomTombstoneBody } from "./RoomTombstoneBody.tsx"
|
||||
export { default as UnknownMessageBody } from "./UnknownMessageBody.tsx"
|
||||
export type { default as EventContentProps } from "./props.ts"
|
||||
|
||||
|
@ -51,6 +53,8 @@ export function getBodyType(evt: MemDBEvent, forReply = false): React.FunctionCo
|
|||
return PinnedEventsBody
|
||||
case "m.room.power_levels":
|
||||
return PowerLevelBody
|
||||
case "m.room.tombstone":
|
||||
return RoomTombstoneBody
|
||||
}
|
||||
} else if (evt.state_key !== undefined) {
|
||||
// State events which must have a non-empty state key
|
||||
|
@ -120,6 +124,7 @@ export function isSmallEvent(bodyType: React.FunctionComponent<EventContentProps
|
|||
case PolicyRuleBody:
|
||||
case PinnedEventsBody:
|
||||
case PowerLevelBody:
|
||||
case RoomTombstoneBody:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
|
|
Loading…
Add table
Reference in a new issue