1
0
Fork 0
forked from Mirrors/gomuks

web/modal: add boxing to modal utility

This commit is contained in:
Tulir Asokan 2024-11-17 02:36:01 +02:00
parent 303ea43834
commit f4be132313
6 changed files with 48 additions and 54 deletions

View file

@ -8,6 +8,21 @@ div.overlay {
&.dimmed {
background-color: var(--dimmed-overlay-background-color);
}
&.modal > div.modal-box {
background-color: var(--background-color);
border-radius: 1rem;
padding: 1rem;
max-width: min(80rem, 80vw);
max-height: min(80rem, 80vh);
overflow: hidden;
display: flex;
> div.modal-box-inner {
overflow: scroll;
}
}
}
div.lightbox {

View file

@ -18,7 +18,9 @@ import React, { JSX, createContext, useCallback, useLayoutEffect, useReducer, us
export interface ModalState {
content: JSX.Element
dimmed?: boolean
wrapperClass?: string
boxed?: boolean
boxClass?: string
innerBoxClass?: string
onClose?: () => void
}
@ -52,18 +54,28 @@ export const ModalWrapper = ({ children }: { children: React.ReactNode }) => {
wrapperRef.current.focus()
}
}, [state])
return <ModalContext value={setState}>
{children}
{state && <div
className={`overlay ${state.wrapperClass ?? "modal"} ${state.dimmed ? "dimmed" : ""}`}
let modal: JSX.Element | null = null
if (state) {
let content = <ModalCloseContext value={onClickWrapper}>{state.content}</ModalCloseContext>
if (state.boxed) {
content = <div className={`modal-box ${state.boxClass ?? ""}`}>
<div className={`modal-box-inner ${state.innerBoxClass ?? ""}`}>
{content}
</div>
</div>
}
modal = <div
className={`overlay modal ${state.dimmed ? "dimmed" : ""}`}
onClick={onClickWrapper}
onKeyDown={onKeyWrapper}
tabIndex={-1}
ref={wrapperRef}
>
<ModalCloseContext value={onClickWrapper}>
{state.content}
</ModalCloseContext>
</div>}
{content}
</div>
}
return <ModalContext value={setState}>
{children}
{modal}
</ModalContext>
}

View file

@ -40,7 +40,7 @@ const ConfirmWithMessageModal = ({
const onChangeReason = useCallback((evt: React.ChangeEvent<HTMLInputElement>) => {
setReason(evt.target.value)
}, [])
return <div className="confirm-message-modal">
return <>
<h3>{title}</h3>
<div className="timeline-event-container">
<TimelineEvent evt={evt} prevEvt={null} disableMenu={true} />
@ -53,7 +53,7 @@ const ConfirmWithMessageModal = ({
<button onClick={closeModal}>Cancel</button>
<button onClick={onConfirmWrapped}>{confirmButton}</button>
</div>
</div>
</>
}
export default ConfirmWithMessageModal

View file

@ -19,8 +19,8 @@ import { MemDBEvent, PowerLevelEventContent } from "@/api/types"
import ClientContext from "../../ClientContext.ts"
import { ModalCloseContext, ModalContext } from "../../modal/Modal.tsx"
import { RoomContext, RoomContextData } from "../../roomview/roomcontext.ts"
import JSONView from "../../util/JSONView.tsx"
import ConfirmWithMessageModal from "./ConfirmWithMessageModal.tsx"
import ViewSourceModal from "./ViewSourceModal.tsx"
import ViewSourceIcon from "@/icons/code.svg?react"
import DeleteIcon from "@/icons/delete.svg?react"
import PinIcon from "@/icons/pin.svg?react"
@ -39,11 +39,17 @@ const EventExtraMenu = ({ evt, room, style }: EventExtraMenuProps) => {
const closeModal = use(ModalCloseContext)
const openModal = use(ModalContext)
const onClickViewSource = useCallback(() => {
openModal({ dimmed: true, content: <ViewSourceModal evt={evt}/> })
openModal({
dimmed: true,
boxed: true,
content: <JSONView data={evt} />,
})
}, [evt, openModal])
const onClickReport = useCallback(() => {
openModal({
dimmed: true,
boxed: true,
innerBoxClass: "confirm-message-modal",
content: <RoomContext value={new RoomContextData(room)}>
<ConfirmWithMessageModal
evt={evt}
@ -62,6 +68,8 @@ const EventExtraMenu = ({ evt, room, style }: EventExtraMenuProps) => {
const onClickRedact = useCallback(() => {
openModal({
dimmed: true,
boxed: true,
innerBoxClass: "confirm-message-modal",
content: <RoomContext value={new RoomContextData(room)}>
<ConfirmWithMessageModal
evt={evt}

View file

@ -1,29 +0,0 @@
// 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 { MemDBEvent } from "@/api/types"
import JSONView from "../../util/JSONView.tsx"
interface ViewSourceModalProps {
evt: MemDBEvent
}
const ViewSourceModal = ({ evt }: ViewSourceModalProps) => {
return <div className="view-source-modal">
<JSONView data={evt} />
</div>
}
export default ViewSourceModal

View file

@ -45,21 +45,9 @@ div.event-context-menu-extra {
}
}
div.view-source-modal {
max-width: min(80rem, 80vw);
max-height: min(80rem, 80vh);
overflow: auto;
background-color: var(--background-color);
border-radius: 1rem;
padding: 1rem;
}
div.confirm-message-modal {
width: min(40rem, 80vw);
max-height: min(40rem, 80vh);
background-color: var(--background-color);
border-radius: 1rem;
padding: 1rem;
display: flex;
flex-direction: column;
gap: .5rem;