feat(playlists): библиотека плейлистов приложения

CRUD в редакторе, read-only окно на пульте, отдельный аудиоканал, экспорт/импорт и маппинг из Foundry.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ivan Fontosh
2026-09-03 10:37:21 +08:00
parent cfb6e62331
commit 278eb78637
46 changed files with 2438 additions and 41 deletions
@@ -0,0 +1,15 @@
.page {
height: 100vh;
display: flex;
flex-direction: column;
gap: 12px;
padding: 12px;
box-sizing: border-box;
background: var(--bg);
color: var(--text);
}
.panel {
flex: 1;
min-height: 0;
}
+33
View File
@@ -0,0 +1,33 @@
import React, { useEffect, useMemo } from 'react';
import { ipcChannels } from '../../shared/ipc/contracts';
import { useEditorI18n } from '../editor/i18n/EditorI18nContext';
import { getDndApi } from '../shared/dndApi';
import {
PlaylistsPanel,
playlistsPanelLabelsFromT,
} from '../shared/playlists/PlaylistsPanel';
import styles from './PlaylistsApp.module.css';
export function PlaylistsApp() {
const { t } = useEditorI18n();
const api = getDndApi();
const labels = useMemo(() => playlistsPanelLabelsFromT(t), [t]);
useEffect(() => {
const onKey = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
void api.invoke(ipcChannels.windows.closePlaylists, {});
}
};
window.addEventListener('keydown', onKey);
return () => window.removeEventListener('keydown', onKey);
}, [api]);
return (
<div className={styles.page} data-testid="playlists-app">
<PlaylistsPanel labels={labels} className={styles.panel} readOnly />
</div>
);
}
+23
View File
@@ -0,0 +1,23 @@
import React from 'react';
import { createRoot } from 'react-dom/client';
import '../shared/ui/globals.css';
import { EditorI18nProvider } from '../editor/i18n/EditorI18nContext';
import { WindowErrorBoundary } from '../shared/ui/WindowErrorBoundary';
import { PlaylistsApp } from './PlaylistsApp';
const rootEl = document.getElementById('root');
if (!rootEl) {
throw new Error('Missing #root element');
}
createRoot(rootEl).render(
<React.StrictMode>
<WindowErrorBoundary title="Playlists">
<EditorI18nProvider>
<PlaylistsApp />
</EditorI18nProvider>
</WindowErrorBoundary>
</React.StrictMode>,
);