优化后台
This commit is contained in:
@@ -71,6 +71,37 @@ const IMAGE_PRESETS: PresetItem[] = [
|
||||
const MENTION_REF_LIMIT = 20;
|
||||
const ROLE_REF_LIMIT = 3;
|
||||
|
||||
function playPresetPreview(card: HTMLElement) {
|
||||
const video = card.querySelector<HTMLVideoElement>("video");
|
||||
if (!video || video.dataset.broken === "1") return;
|
||||
const reveal = () => {
|
||||
if (video.dataset.broken === "1" || video.videoWidth === 0) return;
|
||||
video.classList.add("is-playing");
|
||||
};
|
||||
const fail = () => {
|
||||
video.dataset.broken = "1";
|
||||
video.classList.remove("is-playing");
|
||||
video.pause();
|
||||
};
|
||||
video.addEventListener("error", fail, { once: true });
|
||||
video.addEventListener("playing", reveal, { once: true });
|
||||
void video.play().catch(fail);
|
||||
}
|
||||
|
||||
function stopPresetPreview(card: HTMLElement) {
|
||||
const video = card.querySelector<HTMLVideoElement>("video");
|
||||
if (!video) return;
|
||||
video.pause();
|
||||
if (video.dataset.broken !== "1" && Number.isFinite(video.duration)) {
|
||||
try {
|
||||
video.currentTime = 0;
|
||||
} catch {
|
||||
/* Safari 在还没解码时不允许回绕 */
|
||||
}
|
||||
}
|
||||
video.classList.remove("is-playing");
|
||||
}
|
||||
|
||||
const MENTION_TABS: Array<{ type: CreationRef["type"]; label: string; Icon: typeof ImageIcon }> = [
|
||||
{ type: "asset", label: "素材", Icon: ImageIcon },
|
||||
{ type: "character", label: "角色", Icon: UserRound },
|
||||
@@ -671,39 +702,22 @@ export function OmniCreatePage({
|
||||
className={`omni-case-card${selectedCase?.name === card.name ? " active" : ""}`}
|
||||
data-mode={card.mode}
|
||||
key={card.name}
|
||||
onMouseEnter={(event) => {
|
||||
const video = event.currentTarget.querySelector<HTMLVideoElement>("video");
|
||||
void video?.play().catch(() => undefined);
|
||||
}}
|
||||
onMouseLeave={(event) => {
|
||||
const video = event.currentTarget.querySelector<HTMLVideoElement>("video");
|
||||
if (!video) return;
|
||||
video.pause();
|
||||
video.currentTime = 0;
|
||||
}}
|
||||
onFocus={(event) => {
|
||||
const video = event.currentTarget.querySelector<HTMLVideoElement>("video");
|
||||
void video?.play().catch(() => undefined);
|
||||
}}
|
||||
onBlur={(event) => {
|
||||
const video = event.currentTarget.querySelector<HTMLVideoElement>("video");
|
||||
if (!video) return;
|
||||
video.pause();
|
||||
video.currentTime = 0;
|
||||
}}
|
||||
onMouseEnter={(event) => playPresetPreview(event.currentTarget)}
|
||||
onMouseLeave={(event) => stopPresetPreview(event.currentTarget)}
|
||||
onFocus={(event) => playPresetPreview(event.currentTarget)}
|
||||
onBlur={(event) => stopPresetPreview(event.currentTarget)}
|
||||
onClick={() => {
|
||||
if (card.mode === "image") applyPreset(card);
|
||||
else setPreviewCase(card);
|
||||
}}
|
||||
>
|
||||
<span className="omni-case-visual">
|
||||
<img src={card.cover} alt="" />
|
||||
{card.previewVideo ? (
|
||||
<video muted loop playsInline preload="metadata" poster={card.cover} aria-label={`${card.title} 样片预览`}>
|
||||
<video muted loop playsInline preload="none" poster={card.cover} aria-hidden="true">
|
||||
<source src={card.previewVideo} type="video/mp4" />
|
||||
</video>
|
||||
) : (
|
||||
<img src={card.cover} alt="" />
|
||||
)}
|
||||
) : null}
|
||||
</span>
|
||||
<span className="omni-case-copy">
|
||||
<strong>{card.title}</strong>
|
||||
|
||||
Reference in New Issue
Block a user