ui: add snackbar util

This commit is contained in:
CrescentLeaf
2025-09-07 20:07:06 +08:00
parent 71b368a5ac
commit f06e93ef06
2 changed files with 103 additions and 8 deletions

View File

@@ -10,9 +10,10 @@ import RecentChat from "../api/client_data/RecentChat.ts"
import * as React from 'react'
import * as CryptoES from 'crypto-es'
import { Button, Dialog, NavigationRail, snackbar, TextField } from "mdui"
import { Button, Dialog, NavigationRail, TextField } from "mdui"
import Split from 'split.js'
import 'mdui/jsx.zh-cn.d.ts'
import { checkApiSuccessOrSncakbar } from "./snackbar.ts";
declare global {
namespace React {
@@ -74,10 +75,8 @@ export default function App() {
account: account,
password: CryptoES.SHA256(password),
})
if (re.code != 200)
snackbar({
message: "登錄失敗: " + re.msg
})
if (checkApiSuccessOrSncakbar(re, "登錄失敗")) return
})
React.useEffect(() => {
@@ -95,9 +94,7 @@ export default function App() {
if (re.code == 401)
loginDialogRef.current!.open = true
else if (re.code != 200)
snackbar({
message: "驗證失敗: " + re.msg
})
if (checkApiSuccessOrSncakbar(re, "驗證失敗")) return
})()
}, [])

98
client/ui/snackbar.ts Normal file
View File

@@ -0,0 +1,98 @@
import { snackbar as mduiSnackbar, Snackbar } from "mdui"
import ApiCallbackMessage from "../api/ApiCallbackMessage.ts"
interface Options {
/**
* Snackbar 出现的位置。默认为 `bottom`。可选值为:
* * `top`:位于顶部,居中对齐
* * `top-start`:位于顶部,左对齐
* * `top-end`:位于顶部,右对齐
* * `bottom`:位于底部,居中对齐
* * `bottom-start`:位于底部,左对齐
* * `bottom-end`:位于底部,右对齐
*/
placement?: 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end';
/**
* 操作按钮的文本
*/
action?: string;
/**
* 是否在右侧显示关闭按钮
*/
closeable?: boolean;
/**
* 消息文本最多显示几行。默认不限制行数。可选值为
* * `1`:消息文本最多显示一行
* * `2`:消息文本最多显示两行
*/
messageLine?: 1 | 2;
/**
* 在多长时间后自动关闭(单位为毫秒)。设置为 0 时,不自动关闭。默认为 5 秒后自动关闭。
*/
autoCloseDelay?: number;
/**
* 点击或触摸 Snackbar 以外的区域时是否关闭 Snackbar
*/
closeOnOutsideClick?: boolean;
/**
* 队列名称。
* 默认不启用队列,在多次调用该函数时,将同时显示多个 snackbar。
* 可在该参数中传入一个队列名称,具有相同队列名称的 snackbar 函数,将在上一个 snackbar 关闭后才打开下一个 snackbar。
*/
queue?: string;
/**
* 点击 Snackbar 时的回调函数。
* 函数参数为 snackbar 实例,`this` 也指向 snackbar 实例。
* @param snackbar
*/
onClick?: (snackbar: Snackbar) => void;
/**
* 点击操作按钮时的回调函数。
* 函数参数为 snackbar 实例,`this` 也指向 snackbar 实例。
* 默认点击后会关闭 snackbar若返回值为 false则不关闭 snackbar若返回值为 promise则将在 promise 被 resolve 后,关闭 snackbar。
* @param snackbar
*/
onActionClick?: (snackbar: Snackbar) => void | boolean | Promise<void>;
/**
* Snackbar 开始显示时的回调函数。
* 函数参数为 snackbar 实例,`this` 也指向 snackbar 实例。
* @param snackbar
*/
onOpen?: (snackbar: Snackbar) => void;
/**
* Snackbar 显示动画完成时的回调函数。
* 函数参数为 snackbar 实例,`this` 也指向 snackbar 实例。
* @param snackbar
*/
onOpened?: (snackbar: Snackbar) => void;
/**
* Snackbar 开始隐藏时的回调函数。
* 函数参数为 snackbar 实例,`this` 也指向 snackbar 实例。
* @param snackbar
*/
onClose?: (snackbar: Snackbar) => void;
/**
* Snackbar 隐藏动画完成时的回调函数。
* 函数参数为 snackbar 实例,`this` 也指向 snackbar 实例。
* @param snackbar
*/
onClosed?: (snackbar: Snackbar) => void;
}
interface SnackbarOptions extends Options {
message: string
}
export function checkApiSuccessOrSncakbar(re: ApiCallbackMessage, msg_ahead: string, opinions_override: Options = {}): Snackbar | null {
return re.code != 200 ? snackbar(
Object.assign({
message: `${msg_ahead}: ${re.msg} [${re.code}]`,
placement: "top",
} as SnackbarOptions, opinions_override)
) : null
}
export function snackbar(opinions: SnackbarOptions) {
opinions.autoCloseDelay == null && (opinions.autoCloseDelay = 2500)
return mduiSnackbar(opinions)
}