enhance release v2 experience

This commit is contained in:
ajnart committed 2026-08-14 02:18:46 +02:00
1 parent 9b4970583e
commit ef2ed6c602
152 files changed
+7236 -764

No files matched your search

+8 -1
View File
@@ -14,6 +14,8 @@ import { ConfirmModal } from "./confirm-modal";
import type { ModalsState, ModalStateWithReference } from "./reducer";
import { modalReducer } from "./reducer";
import type { inferInnerProps, ModalDefinition } from "./type";
import presentationClasses from "./modal-presentation.module.css";
import { getModalPresentationClassNames } from "./modal-presentation";
interface ModalContextProps {
openModalInner: <TModal extends ModalDefinition>(props: {
@@ -94,7 +96,11 @@ const ActiveModal = ({ modal, state, handleCloseModal }: ActiveModalProps) => {
setTimeout(() => setOpened(true), 0);
}, []);
const { defaultTitle: _ignored, ...otherModalProps } = modal.reference.modalProps;
const { defaultTitle: _ignored, presentation, ...otherModalProps } = modal.reference.modalProps;
const presentationClassNames = getModalPresentationClassNames(presentation, {
inner: presentationClasses.inspectorInner,
content: presentationClasses.inspectorContent,
});
return (
<Modal
@@ -113,6 +119,7 @@ const ActiveModal = ({ modal, state, handleCloseModal }: ActiveModalProps) => {
},
}}
trapFocus={modal.id === state.current?.id}
classNames={presentationClassNames}
{...otherModalProps}
title={translateIfNecessary(t, modal.props.defaultTitle)}
opened={opened}
@@ -0,0 +1,30 @@
.inspectorInner {
align-items: flex-end;
justify-content: center;
padding: 0;
}
.inspectorContent {
--modal-content-flex: 0 0 100%;
--modal-content-max-height: min(88dvh, 52rem);
width: 100%;
max-width: 100%;
border-radius: var(--mantine-radius-lg) var(--mantine-radius-lg) 0 0;
}
@media (min-width: 48em) {
.inspectorInner {
align-items: stretch;
justify-content: flex-end;
}
.inspectorContent {
--modal-content-flex: 0 0 min(34rem, 46vw);
--modal-content-height: 100dvh;
--modal-content-max-height: 100dvh;
width: min(34rem, 46vw);
border-radius: 0;
}
}
@@ -0,0 +1,5 @@
declare const classes: {
readonly inspectorInner: string;
readonly inspectorContent: string;
};
export default classes;
@@ -0,0 +1,19 @@
import { describe, expect, test } from "vitest";
import { getModalPresentationClassNames } from "./modal-presentation";
describe("getModalPresentationClassNames", () => {
const inspectorClassNames = { inner: "inspector-inner", content: "inspector-content" };
test("leaves the default modal presentation unchanged", () => {
expect(getModalPresentationClassNames("default", inspectorClassNames)).toBeUndefined();
expect(getModalPresentationClassNames(undefined, inspectorClassNames)).toBeUndefined();
});
test("selects the dock and sheet selectors for inspector modals", () => {
expect(getModalPresentationClassNames("inspector", inspectorClassNames)).toEqual({
inner: "inspector-inner",
content: "inspector-content",
});
});
});
+18
View File
@@ -0,0 +1,18 @@
export type ModalPresentation = "default" | "inspector";
interface InspectorClassNames {
inner: string;
content: string;
}
export const getModalPresentationClassNames = (
presentation: ModalPresentation | undefined,
inspectorClassNames: InspectorClassNames,
) => {
if (presentation !== "inspector") return undefined;
return {
inner: inspectorClassNames.inner,
content: inspectorClassNames.content,
};
};
+4
View File
@@ -3,6 +3,8 @@ import type { ModalProps } from "@mantine/core";
import type { stringOrTranslation } from "@homarr/translation";
import type { ModalPresentation } from "./modal-presentation";
export type ModalComponent<TInnerProps> = (props: {
actions: { closeModal: () => void };
innerProps: TInnerProps;
@@ -23,6 +25,7 @@ export type CreateModalOptions = Pick<
| "closeOnEscape"
> & {
defaultTitle: stringOrTranslation;
presentation?: ModalPresentation;
};
export interface ModalDefinition {
@@ -34,6 +37,7 @@ export interface ModalDefinition {
type ModalOptions<TInnerProps> = Partial<Omit<ModalProps, "opened">> & {
innerProps: TInnerProps;
defaultTitle?: stringOrTranslation;
presentation?: ModalPresentation;
};
export interface ModalState<TModal extends ModalDefinition = ModalDefinition> {