client/dialogs: add support for custom title bar buttons

This commit is contained in:
Adorian Doran 2025-11-30 01:44:20 +02:00
parent 6735b257b4
commit 07fb5ab017
2 changed files with 25 additions and 3 deletions

View File

@ -25,6 +25,7 @@
.modal .modal-header .btn-close, .modal .modal-header .btn-close,
.modal .modal-header .help-button, .modal .modal-header .help-button,
.modal .modal-header .custom-title-bar-button,
#toast-container .toast .toast-header .btn-close { #toast-container .toast .toast-header .btn-close {
display: flex; display: flex;
justify-content: center; justify-content: center;
@ -55,15 +56,17 @@
font-family: boxicons; font-family: boxicons;
} }
.modal .modal-header .help-button { .modal .modal-header .help-button,
.modal .modal-header .custom-title-bar-button {
margin-inline-end: 0; margin-inline-end: 0;
font-size: calc(var(--modal-control-button-size) * .75); font-size: calc(var(--modal-control-button-size) * .65);
font-family: unset; font-family: unset;
font-weight: bold; font-weight: bold;
} }
.modal .modal-header .btn-close:hover, .modal .modal-header .btn-close:hover,
.modal .modal-header .help-button:hover, .modal .modal-header .help-button:hover,
.modal .modal-header .custom-title-bar-button:hover,
#toast-container .toast .toast-header .btn-close:hover { #toast-container .toast .toast-header .btn-close:hover {
background: var(--modal-control-button-hover-background); background: var(--modal-control-button-hover-background);
color: var(--modal-control-button-hover-color); color: var(--modal-control-button-hover-color);
@ -71,6 +74,7 @@
.modal .modal-header .btn-close:active, .modal .modal-header .btn-close:active,
.modal .modal-header .help-button:active, .modal .modal-header .help-button:active,
.modal .modal-header .custom-title-bar-button:active,
#toast-container .toast .toast-header .btn-close:active { #toast-container .toast .toast-header .btn-close:active {
transform: scale(.85); transform: scale(.85);
} }

View File

@ -1,3 +1,4 @@
import clsx from "clsx";
import { useEffect, useRef, useMemo } from "preact/hooks"; import { useEffect, useRef, useMemo } from "preact/hooks";
import { t } from "../../services/i18n"; import { t } from "../../services/i18n";
import { ComponentChildren } from "preact"; import { ComponentChildren } from "preact";
@ -7,9 +8,16 @@ import { Modal as BootstrapModal } from "bootstrap";
import { memo } from "preact/compat"; import { memo } from "preact/compat";
import { useSyncedRef } from "./hooks"; import { useSyncedRef } from "./hooks";
interface CustomTitleBarButton {
title: string;
iconClassName: string;
onClick: () => void;
}
interface ModalProps { interface ModalProps {
className: string; className: string;
title: string | ComponentChildren; title: string | ComponentChildren;
customTitleBarButtons?: (CustomTitleBarButton | null)[];
size: "xl" | "lg" | "md" | "sm"; size: "xl" | "lg" | "md" | "sm";
children: ComponentChildren; children: ComponentChildren;
/** /**
@ -72,7 +80,7 @@ interface ModalProps {
noFocus?: boolean; noFocus?: boolean;
} }
export default function Modal({ children, className, size, title, header, footer, footerStyle, footerAlignment, onShown, onSubmit, helpPageId, minWidth, maxWidth, zIndex, scrollable, onHidden: onHidden, modalRef: externalModalRef, formRef, bodyStyle, show, stackable, keepInDom, noFocus }: ModalProps) { export default function Modal({ children, className, size, title, customTitleBarButtons: titleBarButtons, header, footer, footerStyle, footerAlignment, onShown, onSubmit, helpPageId, minWidth, maxWidth, zIndex, scrollable, onHidden: onHidden, modalRef: externalModalRef, formRef, bodyStyle, show, stackable, keepInDom, noFocus }: ModalProps) {
const modalRef = useSyncedRef<HTMLDivElement>(externalModalRef); const modalRef = useSyncedRef<HTMLDivElement>(externalModalRef);
const modalInstanceRef = useRef<BootstrapModal>(); const modalInstanceRef = useRef<BootstrapModal>();
const elementToFocus = useRef<Element | null>(); const elementToFocus = useRef<Element | null>();
@ -148,7 +156,17 @@ export default function Modal({ children, className, size, title, header, footer
{helpPageId && ( {helpPageId && (
<button className="help-button" type="button" data-in-app-help={helpPageId} title={t("modal.help_title")}>?</button> <button className="help-button" type="button" data-in-app-help={helpPageId} title={t("modal.help_title")}>?</button>
)} )}
{titleBarButtons?.filter((b) => b !== null).map((titleBarButton) => (
<button type="button"
className={clsx("custom-title-bar-button bx", titleBarButton.iconClassName)}
title={titleBarButton.title}
onClick={titleBarButton.onClick}>
</button>
))}
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label={t("modal.close")}></button> <button type="button" className="btn-close" data-bs-dismiss="modal" aria-label={t("modal.close")}></button>
</div> </div>
{onSubmit ? ( {onSubmit ? (