feat(playlists): библиотека плейлистов приложения
CRUD в редакторе, read-only окно на пульте, отдельный аудиоканал, экспорт/импорт и маппинг из Foundry. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -60,6 +60,7 @@ import { MaterialEditModal, MaterialsManagerModal } from './MaterialsModals';
|
||||
import { PlayersManagerModal } from './PlayersModals';
|
||||
import { LaunchPlayersModal } from './LaunchPlayersModal';
|
||||
import { PresentationSettingsModal } from './PresentationSettingsModal';
|
||||
import { PlaylistsManagerModal } from './PlaylistsModal';
|
||||
import { isSceneDescriptionEmpty, sanitizeSceneDescriptionHtml } from './sceneDescriptionHtml';
|
||||
import { SceneDescriptionModal } from './SceneDescriptionModal';
|
||||
import type { ProjectNoticeCode } from './state/projectState';
|
||||
@@ -161,6 +162,7 @@ export function EditorApp() {
|
||||
const [materialsManagerOpen, setMaterialsManagerOpen] = useState(false);
|
||||
const [playersManagerOpen, setPlayersManagerOpen] = useState(false);
|
||||
const [launchPlayersOpen, setLaunchPlayersOpen] = useState(false);
|
||||
const [playlistsManagerOpen, setPlaylistsManagerOpen] = useState(false);
|
||||
const [presentationSettingsOpen, setPresentationSettingsOpen] = useState(false);
|
||||
const [runMenuOpen, setRunMenuOpen] = useState(false);
|
||||
const [runMenuPos, setRunMenuPos] = useState<{ left: number; top: number } | null>(null);
|
||||
@@ -382,7 +384,10 @@ export function EditorApp() {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (presentationOpen) setLaunching(false);
|
||||
if (presentationOpen) {
|
||||
setLaunching(false);
|
||||
setPlaylistsManagerOpen(false);
|
||||
}
|
||||
}, [presentationOpen]);
|
||||
|
||||
const currentProjectName = state.project?.meta.name ?? '';
|
||||
@@ -864,6 +869,23 @@ export function EditorApp() {
|
||||
{t('top.players')}
|
||||
</button>
|
||||
) : null}
|
||||
<button
|
||||
type="button"
|
||||
data-testid="playlists-header-btn"
|
||||
className={styles.fileMenuTrigger}
|
||||
disabled={!licenseActive}
|
||||
title={!licenseActive ? t('top.afterLicense') : undefined}
|
||||
onClick={() => {
|
||||
if (!licenseActive) return;
|
||||
setProjectMenuOpen(false);
|
||||
setSettingsMenuOpen(false);
|
||||
setAboutMenuOpen(false);
|
||||
setFileMenuOpen(false);
|
||||
setPlaylistsManagerOpen(true);
|
||||
}}
|
||||
>
|
||||
{t('top.playlists')}
|
||||
</button>
|
||||
</div>
|
||||
<div className={styles.flex1} />
|
||||
{appVersionText ? (
|
||||
@@ -1561,8 +1583,8 @@ export function EditorApp() {
|
||||
storylineLabels={storylineLabels}
|
||||
loadStorylines={loadProjectStorylines}
|
||||
onClose={() => setExportModalOpen(false)}
|
||||
onExport={async (projectId, selections, npcIds) => {
|
||||
await actions.exportProject(projectId, selections, npcIds, storylineLabels);
|
||||
onExport={async (projectId, selections, npcIds, playlistIds) => {
|
||||
await actions.exportProject(projectId, selections, npcIds, storylineLabels, playlistIds);
|
||||
}}
|
||||
/>
|
||||
<ImportSourceModal
|
||||
@@ -1656,6 +1678,10 @@ export function EditorApp() {
|
||||
open={presentationSettingsOpen}
|
||||
onClose={() => setPresentationSettingsOpen(false)}
|
||||
/>
|
||||
<PlaylistsManagerModal
|
||||
open={playlistsManagerOpen}
|
||||
onClose={() => setPlaylistsManagerOpen(false)}
|
||||
/>
|
||||
{USERS_BRANCH_FEATURES_ENABLED ? (
|
||||
<>
|
||||
<PlayersManagerModal open={playersManagerOpen} onClose={() => setPlayersManagerOpen(false)} />
|
||||
|
||||
Reference in New Issue
Block a user