feat: 完善课程模板通用能力

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
zhongyidianandClaude Opus 5 committed 2026-09-08 14:07:42 +08:00
1 parent 1e02c7835e
commit a641d0e2ea
70 files changed
+2868 -205

No files matched your search

+53
View File
@@ -0,0 +1,53 @@
import { useEffect, useRef } from "react";
import type { GameAudioManager } from "./audio.types";
import { GameAudioContext } from "./audioContext";
import { createAudioManager } from "./audioManager";
import type { GameAudioProviderProps } from "./GameAudioProvider.types";
import { createHowlerAudioEngine } from "./howlerEngine";
const activeManagers = new Set<GameAudioManager>();
export function GameAudioProvider({
children,
manager: injectedManager,
}: GameAudioProviderProps) {
const managerRef = useRef<GameAudioManager | null>(null);
if (!managerRef.current) {
managerRef.current =
injectedManager ??
createAudioManager({ engine: createHowlerAudioEngine() });
}
const manager = managerRef.current;
useEffect(() => {
activeManagers.add(manager);
const handleVisibilityChange = () => {
manager.handleVisibilityChange(document.hidden);
};
const handlePageHide = () => manager.stopAll();
document.addEventListener("visibilitychange", handleVisibilityChange);
window.addEventListener("pagehide", handlePageHide);
handleVisibilityChange();
return () => {
document.removeEventListener("visibilitychange", handleVisibilityChange);
window.removeEventListener("pagehide", handlePageHide);
activeManagers.delete(manager);
manager.stopAll();
};
}, [manager]);
return (
<GameAudioContext.Provider value={manager}>
{children}
</GameAudioContext.Provider>
);
}
if (import.meta.hot) {
import.meta.hot.dispose(() => {
for (const manager of activeManagers) manager.stopAll();
activeManagers.clear();
});
}