1
0
Fork 0
forked from Mirrors/gomuks

web/timeline: insert mention when clicking name

This commit is contained in:
Tulir Asokan 2024-11-12 17:01:00 +02:00
parent 9b65140302
commit b552b07c74
4 changed files with 22 additions and 1 deletions

View file

@ -90,6 +90,10 @@ const MessageComposer = () => {
const textRows = useRef(1) const textRows = useRef(1)
const typingSentAt = useRef(0) const typingSentAt = useRef(0)
const replyToEvt = useRoomEvent(room, state.replyTo) const replyToEvt = useRoomEvent(room, state.replyTo)
roomCtx.insertText = useCallback((text: string) => {
textInput.current?.focus()
document.execCommand("insertText", false, text)
}, [])
roomCtx.setReplyTo = useCallback((evt: EventID | null) => { roomCtx.setReplyTo = useCallback((evt: EventID | null) => {
setState({ replyTo: evt }) setState({ replyTo: evt })
textInput.current?.focus() textInput.current?.focus()

View file

@ -17,6 +17,7 @@ import { RefObject, createContext, createRef, use } from "react"
import { RoomStateStore } from "@/api/statestore" import { RoomStateStore } from "@/api/statestore"
import { EventID, EventRowID, MemDBEvent } from "@/api/types" import { EventID, EventRowID, MemDBEvent } from "@/api/types"
import { NonNullCachedEventDispatcher } from "@/util/eventdispatcher.ts" import { NonNullCachedEventDispatcher } from "@/util/eventdispatcher.ts"
import { escapeMarkdown } from "@/util/markdown.ts"
const noop = (name: string) => () => { const noop = (name: string) => () => {
console.warn(`${name} called before initialization`) console.warn(`${name} called before initialization`)
@ -26,6 +27,7 @@ export class RoomContextData {
public timelineBottomRef: RefObject<HTMLDivElement | null> = createRef() public timelineBottomRef: RefObject<HTMLDivElement | null> = createRef()
public setReplyTo: (eventID: EventID | null) => void = noop("setReplyTo") public setReplyTo: (eventID: EventID | null) => void = noop("setReplyTo")
public setEditing: (evt: MemDBEvent | null) => void = noop("setEditing") public setEditing: (evt: MemDBEvent | null) => void = noop("setEditing")
public insertText: (text: string) => void = noop("insertText")
public isEditing = new NonNullCachedEventDispatcher<boolean>(false) public isEditing = new NonNullCachedEventDispatcher<boolean>(false)
public ownMessages: EventRowID[] = [] public ownMessages: EventRowID[] = []
public scrolledToBottom = true public scrolledToBottom = true
@ -37,6 +39,15 @@ export class RoomContextData {
this.timelineBottomRef.current?.scrollIntoView() this.timelineBottomRef.current?.scrollIntoView()
} }
} }
appendMentionToComposer = (evt: React.MouseEvent<HTMLSpanElement>) => {
const targetUser = evt.currentTarget.getAttribute("data-target-user")
if (!targetUser) {
return
}
const targetUserName = evt.currentTarget.innerText
this.insertText(`[${escapeMarkdown(targetUserName)}](https://matrix.to/#/${encodeURIComponent(targetUser)}) `)
}
} }
export const RoomContext = createContext<RoomContextData | undefined>(undefined) export const RoomContext = createContext<RoomContextData | undefined>(undefined)

View file

@ -52,6 +52,8 @@ div.timeline-event {
> span.event-sender { > span.event-sender {
font-weight: bold; font-weight: bold;
user-select: none;
cursor: var(--clickable-cursor);
} }
> span.event-time, > span.event-edited { > span.event-time, > span.event-edited {

View file

@ -120,7 +120,11 @@ const TimelineEvent = ({ evt, prevEvt, disableMenu }: TimelineEventProps) => {
/> />
</div>} </div>}
{!eventTimeOnly ? <div className="event-sender-and-time"> {!eventTimeOnly ? <div className="event-sender-and-time">
<span className={`event-sender sender-color-${getUserColorIndex(evt.sender)}`}> <span
className={`event-sender sender-color-${getUserColorIndex(evt.sender)}`}
data-target-user={evt.sender}
onClick={roomCtx.appendMentionToComposer}
>
{memberEvtContent?.displayname || evt.sender} {memberEvtContent?.displayname || evt.sender}
</span> </span>
<span className="event-time" title={fullTime}>{shortTime}</span> <span className="event-time" title={fullTime}>{shortTime}</span>