mirror of
https://github.com/tulir/gomuks.git
synced 2025-04-19 18:13:41 -05:00
web/timeline: add click handlers for matrix URIs
This commit is contained in:
parent
c6992b0fca
commit
c2d0020c8c
5 changed files with 62 additions and 17 deletions
|
@ -43,6 +43,7 @@ class ContextFields implements MainScreenContextFields {
|
|||
) {
|
||||
this.keybindings = new Keybindings(client.store, this)
|
||||
client.store.switchRoom = this.setActiveRoom
|
||||
window.mainScreenContext = this
|
||||
}
|
||||
|
||||
setActiveRoom = (roomID: RoomID | null) => {
|
||||
|
|
|
@ -27,7 +27,7 @@ export interface MainScreenContextFields {
|
|||
clickRightPanelOpener: (evt: React.MouseEvent) => void
|
||||
}
|
||||
|
||||
const MainScreenContext = createContext<MainScreenContextFields>({
|
||||
const stubContext = {
|
||||
get setActiveRoom(): never {
|
||||
throw new Error("MainScreenContext used outside main screen")
|
||||
},
|
||||
|
@ -46,6 +46,9 @@ const MainScreenContext = createContext<MainScreenContextFields>({
|
|||
get clickRightPanelOpener(): never {
|
||||
throw new Error("MainScreenContext used outside main screen")
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const MainScreenContext = createContext<MainScreenContextFields>(stubContext)
|
||||
window.mainScreenContext = stubContext
|
||||
|
||||
export default MainScreenContext
|
||||
|
|
|
@ -14,43 +14,55 @@
|
|||
// 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, use } from "react"
|
||||
import type { UserID } from "@/api/types"
|
||||
import MainScreenContext from "../MainScreenContext.ts"
|
||||
import PinnedMessages from "./PinnedMessages.tsx"
|
||||
import CloseButton from "@/icons/close.svg?react"
|
||||
import "./RightPanel.css"
|
||||
|
||||
export type RightPanelType = "pinned-messages" | "members"
|
||||
export type RightPanelType = "pinned-messages" | "members" | "user"
|
||||
|
||||
export interface RightPanelProps {
|
||||
type: RightPanelType
|
||||
interface RightPanelSimpleProps {
|
||||
type: "pinned-messages" | "members"
|
||||
}
|
||||
|
||||
interface RightPanelUserProps {
|
||||
type: "user"
|
||||
userID: UserID
|
||||
}
|
||||
|
||||
export type RightPanelProps = RightPanelUserProps | RightPanelSimpleProps
|
||||
|
||||
function getTitle(type: RightPanelType): string {
|
||||
switch (type) {
|
||||
case "pinned-messages":
|
||||
return "Pinned Messages"
|
||||
case "members":
|
||||
return "Room Members"
|
||||
case "user":
|
||||
return "User Info"
|
||||
}
|
||||
}
|
||||
|
||||
function renderRightPanelContent({ type }: RightPanelProps): JSX.Element | null {
|
||||
switch (type) {
|
||||
function renderRightPanelContent(props: RightPanelProps): JSX.Element | null {
|
||||
switch (props.type) {
|
||||
case "pinned-messages":
|
||||
return <PinnedMessages />
|
||||
case "members":
|
||||
return <>Member list is not yet implemented</>
|
||||
case "user":
|
||||
return <>{props.userID}</>
|
||||
}
|
||||
}
|
||||
|
||||
const RightPanel = ({ type, ...rest }: RightPanelProps) => {
|
||||
const RightPanel = (props: RightPanelProps) => {
|
||||
return <div className="right-panel">
|
||||
<div className="right-panel-header">
|
||||
<div className="panel-name">{getTitle(type)}</div>
|
||||
<div className="panel-name">{getTitle(props.type)}</div>
|
||||
<button onClick={use(MainScreenContext).closeRightPanel}><CloseButton/></button>
|
||||
</div>
|
||||
<div className={`right-panel-content ${type}`}>
|
||||
{renderRightPanelContent({ type, ...rest })}
|
||||
<div className={`right-panel-content ${props.type}`}>
|
||||
{renderRightPanelContent(props)}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -20,15 +20,42 @@ function isImageElement(elem: EventTarget): elem is HTMLImageElement {
|
|||
return (elem as HTMLImageElement).tagName === "IMG"
|
||||
}
|
||||
|
||||
const onClickHTML = (evt: React.MouseEvent<HTMLDivElement>) => {
|
||||
if (isImageElement(evt.target)) {
|
||||
window.openLightbox({
|
||||
src: evt.target.src,
|
||||
alt: evt.target.alt,
|
||||
function isAnchorElement(elem: EventTarget): elem is HTMLAnchorElement {
|
||||
return (elem as HTMLAnchorElement).tagName === "A"
|
||||
}
|
||||
|
||||
function onClickMatrixURI(href: string) {
|
||||
const url = new URL(href)
|
||||
const pathParts = url.pathname.split("/")
|
||||
switch (pathParts[0]) {
|
||||
case "u":
|
||||
return window.mainScreenContext.setRightPanel({
|
||||
type: "user",
|
||||
userID: pathParts[1],
|
||||
})
|
||||
} else if ((evt.target as HTMLElement).closest?.("span.hicli-spoiler")?.classList.toggle("spoiler-revealed")) {
|
||||
case "roomid":
|
||||
return window.mainScreenContext.setActiveRoom(pathParts[1])
|
||||
case "r":
|
||||
return window.client.rpc.resolveAlias(`#${pathParts[1]}`).then(
|
||||
res => window.mainScreenContext.setActiveRoom(res.room_id),
|
||||
err => window.alert(`Failed to resolve room alias #${pathParts[1]}: ${err}`),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const onClickHTML = (evt: React.MouseEvent<HTMLDivElement>) => {
|
||||
const targetElem = evt.target as HTMLElement
|
||||
if (isImageElement(targetElem)) {
|
||||
window.openLightbox({
|
||||
src: targetElem.src,
|
||||
alt: targetElem.alt,
|
||||
})
|
||||
} else if (targetElem.closest?.("span.hicli-spoiler")?.classList.toggle("spoiler-revealed")) {
|
||||
// When unspoilering, don't trigger links and other clickables inside the spoiler
|
||||
evt.preventDefault()
|
||||
} else if (isAnchorElement(targetElem) && targetElem.href.startsWith("matrix:")) {
|
||||
onClickMatrixURI(targetElem.href)
|
||||
evt.preventDefault()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
2
web/src/vite-env.d.ts
vendored
2
web/src/vite-env.d.ts
vendored
|
@ -2,10 +2,12 @@
|
|||
/// <reference types="vite-plugin-svgr/client" />
|
||||
|
||||
import type Client from "@/api/client.ts"
|
||||
import type { MainScreenContextFields } from "@/ui/MainScreenContext.ts"
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
client: Client
|
||||
mainScreenContext: MainScreenContextFields
|
||||
openLightbox: (params: { src: string, alt: string }) => void
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue