feat(notice): persist toast position preference (#5621)

* feat(notice): persist toast position preference

* docs: Changelog.md
This commit is contained in:
Sline
2025-12-19 18:04:23 +08:00
committed by GitHub
parent bd8eccdcea
commit fc84dc561c
21 changed files with 195 additions and 7 deletions
+47 -6
View File
@@ -1,6 +1,12 @@
import { CloseRounded } from "@mui/icons-material";
import { Snackbar, Alert, IconButton, Box } from "@mui/material";
import React, { useSyncExternalStore } from "react";
import {
Snackbar,
Alert,
IconButton,
Box,
type SnackbarOrigin,
} from "@mui/material";
import React, { useMemo, useSyncExternalStore } from "react";
import { useTranslation } from "react-i18next";
import {
@@ -10,8 +16,41 @@ import {
} from "@/services/notice-service";
import type { TranslationKey } from "@/types/generated/i18n-keys";
export const NoticeManager: React.FC = () => {
type NoticePosition = NonNullable<IVergeConfig["notice_position"]>;
const VALID_POSITIONS: NoticePosition[] = [
"top-left",
"top-right",
"bottom-left",
"bottom-right",
];
const resolvePosition = (position?: NoticePosition | null): NoticePosition => {
if (position && VALID_POSITIONS.includes(position)) {
return position;
}
return "top-right";
};
const getAnchorOrigin = (position: NoticePosition): SnackbarOrigin => {
const [vertical, horizontal] = position.split("-") as [
SnackbarOrigin["vertical"],
SnackbarOrigin["horizontal"],
];
return { vertical, horizontal };
};
interface NoticeManagerProps {
position?: NoticePosition | null;
}
export const NoticeManager: React.FC<NoticeManagerProps> = ({ position }) => {
const { t } = useTranslation();
const resolvedPosition = useMemo(() => resolvePosition(position), [position]);
const anchorOrigin = useMemo(
() => getAnchorOrigin(resolvedPosition),
[resolvedPosition],
);
const currentNotices = useSyncExternalStore(
subscribeNotices,
getSnapshotNotices,
@@ -25,8 +64,10 @@ export const NoticeManager: React.FC = () => {
<Box
sx={{
position: "fixed",
top: "20px",
right: "20px",
top: anchorOrigin.vertical === "top" ? "20px" : "auto",
bottom: anchorOrigin.vertical === "bottom" ? "20px" : "auto",
left: anchorOrigin.horizontal === "left" ? "20px" : "auto",
right: anchorOrigin.horizontal === "right" ? "20px" : "auto",
zIndex: 1500,
display: "flex",
flexDirection: "column",
@@ -38,7 +79,7 @@ export const NoticeManager: React.FC = () => {
<Snackbar
key={notice.id}
open={true}
anchorOrigin={{ vertical: "top", horizontal: "right" }}
anchorOrigin={anchorOrigin}
sx={{
position: "relative",
transform: "none",