mirror of
https://github.com/tulir/gomuks.git
synced 2025-04-19 18:13:41 -05:00
web/modal: add generic modal component
This commit is contained in:
parent
692cb323a5
commit
d18b7a43a1
8 changed files with 71 additions and 16 deletions
|
@ -18,9 +18,10 @@ import { ScaleLoader } from "react-spinners"
|
|||
import Client from "./api/client.ts"
|
||||
import WSClient from "./api/wsclient.ts"
|
||||
import { ClientContext } from "./ui/ClientContext.ts"
|
||||
import { LightboxWrapper } from "./ui/Lightbox.tsx"
|
||||
import MainScreen from "./ui/MainScreen.tsx"
|
||||
import { LoginScreen, VerificationScreen } from "./ui/login"
|
||||
import { LightboxWrapper } from "./ui/modal/Lightbox.tsx"
|
||||
import { ModalWrapper } from "./ui/modal/Modal.tsx"
|
||||
import { useEventAsState } from "./util/eventdispatcher.ts"
|
||||
|
||||
function App() {
|
||||
|
@ -53,7 +54,9 @@ function App() {
|
|||
} else {
|
||||
return <ClientContext value={client}>
|
||||
<LightboxWrapper>
|
||||
<MainScreen/>
|
||||
<ModalWrapper>
|
||||
<MainScreen/>
|
||||
</ModalWrapper>
|
||||
</LightboxWrapper>
|
||||
</ClientContext>
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@ import { use, useRef } from "react"
|
|||
import { getAvatarURL } from "@/api/media.ts"
|
||||
import { RoomStateStore } from "@/api/statestore"
|
||||
import { useNonNullEventAsState } from "@/util/eventdispatcher.ts"
|
||||
import { LightboxContext } from "./Lightbox.tsx"
|
||||
import MessageComposer from "./composer/MessageComposer.tsx"
|
||||
import { LightboxContext } from "./modal/Lightbox.tsx"
|
||||
import { RoomContext, RoomContextData } from "./roomcontext.ts"
|
||||
import TimelineView from "./timeline/TimelineView.tsx"
|
||||
import BackIcon from "@/icons/back.svg?react"
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
div.overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background-color: rgba(0, 0, 0, 0.75);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&.lightbox > div.controls {
|
||||
&.dimmed {
|
||||
background-color: rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
}
|
||||
|
||||
div.lightbox {
|
||||
> div.controls {
|
||||
position: fixed;
|
||||
top: .5rem;
|
||||
right: .5rem;
|
||||
|
@ -29,7 +34,7 @@ div.overlay {
|
|||
}
|
||||
}
|
||||
|
||||
&.lightbox > img {
|
||||
> img {
|
||||
max-width: 75%;
|
||||
max-height: 75%;
|
||||
|
|
@ -14,12 +14,12 @@
|
|||
// 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, { Component, RefObject, createContext, createRef, useCallback, useState } from "react"
|
||||
import CloseIcon from "../icons/close.svg?react"
|
||||
import DownloadIcon from "../icons/download.svg?react"
|
||||
import RotateLeftIcon from "../icons/rotate-left.svg?react"
|
||||
import RotateRightIcon from "../icons/rotate-right.svg?react"
|
||||
import ZoomInIcon from "../icons/zoom-in.svg?react"
|
||||
import ZoomOutIcon from "../icons/zoom-out.svg?react"
|
||||
import CloseIcon from "@/icons/close.svg?react"
|
||||
import DownloadIcon from "@/icons/download.svg?react"
|
||||
import RotateLeftIcon from "@/icons/rotate-left.svg?react"
|
||||
import RotateRightIcon from "@/icons/rotate-right.svg?react"
|
||||
import ZoomInIcon from "@/icons/zoom-in.svg?react"
|
||||
import ZoomOutIcon from "@/icons/zoom-out.svg?react"
|
||||
import "./Lightbox.css"
|
||||
|
||||
const isTouchDevice = window.ontouchstart !== undefined
|
||||
|
@ -158,7 +158,7 @@ export class Lightbox extends Component<LightboxProps> {
|
|||
|
||||
render() {
|
||||
return <div
|
||||
className="overlay lightbox"
|
||||
className="overlay dimmed lightbox"
|
||||
onClick={this.onClick}
|
||||
onMouseMove={isTouchDevice ? undefined : this.onMouseMove}
|
||||
>
|
47
web/src/ui/modal/Modal.tsx
Normal file
47
web/src/ui/modal/Modal.tsx
Normal file
|
@ -0,0 +1,47 @@
|
|||
// gomuks - A Matrix client written in Go.
|
||||
// Copyright (C) 2024 Tulir Asokan
|
||||
//
|
||||
// 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 React, { JSX, createContext, useCallback, useState } from "react"
|
||||
|
||||
export interface ModalState {
|
||||
content: JSX.Element
|
||||
dimmed?: boolean
|
||||
wrapperClass?: string
|
||||
onClose?: () => void
|
||||
}
|
||||
|
||||
type openModal = (state: ModalState) => void
|
||||
|
||||
export const ModalContext = createContext<openModal>(() =>
|
||||
console.error("Tried to open modal without being inside context"))
|
||||
|
||||
export const ModalWrapper = ({ children }: { children: React.ReactNode }) => {
|
||||
const [state, setState] = useState<ModalState | null>(null)
|
||||
const onClose = useCallback(() => {
|
||||
setState(null)
|
||||
state?.onClose?.()
|
||||
}, [state])
|
||||
return <>
|
||||
<ModalContext value={setState}>
|
||||
{children}
|
||||
</ModalContext>
|
||||
{state && <div
|
||||
className={`overlay ${state.wrapperClass ?? "modal"} ${state.dimmed ? "dimmed" : ""}`}
|
||||
onClick={onClose}
|
||||
>
|
||||
{state.content}
|
||||
</div>}
|
||||
</>
|
||||
}
|
|
@ -19,7 +19,7 @@ import { useRoomState } from "@/api/statestore"
|
|||
import { MemDBEvent, MemberEventContent, UnreadType } from "@/api/types"
|
||||
import { isEventID } from "@/util/validation.ts"
|
||||
import { ClientContext } from "../ClientContext.ts"
|
||||
import { LightboxContext } from "../Lightbox.tsx"
|
||||
import { LightboxContext } from "../modal/Lightbox.tsx"
|
||||
import { useRoomContext } from "../roomcontext.ts"
|
||||
import EventMenu from "./EventMenu.tsx"
|
||||
import { ReplyIDBody } from "./ReplyBody.tsx"
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
import React, { use } from "react"
|
||||
import { getAvatarURL } from "@/api/media.ts"
|
||||
import { MemberEventContent, UserID } from "@/api/types"
|
||||
import { LightboxContext } from "../../Lightbox.tsx"
|
||||
import { LightboxContext } from "../../modal/Lightbox.tsx"
|
||||
import EventContentProps from "./props.ts"
|
||||
|
||||
function useChangeDescription(
|
||||
|
|
|
@ -17,7 +17,7 @@ import { CSSProperties, use } from "react"
|
|||
import { getEncryptedMediaURL, getMediaURL } from "@/api/media.ts"
|
||||
import type { EventType, MediaMessageEventContent } from "@/api/types"
|
||||
import { ImageContainerSize, calculateMediaSize } from "@/util/mediasize.ts"
|
||||
import { LightboxContext } from "../../Lightbox.tsx"
|
||||
import { LightboxContext } from "../../modal/Lightbox.tsx"
|
||||
import DownloadIcon from "@/icons/download.svg?react"
|
||||
|
||||
export const useMediaContent = (
|
||||
|
|
Loading…
Add table
Reference in a new issue