99 lines
4.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { h, ref } from 'vue';
import { fetchScoreText, putScoreText } from '../api.js';
import { patchScore } from '../exporter.js';
import { StatusPoller } from './StatusPoller.js';
export const PaneCP = {
props: ['store', 'onImportClick'],
setup(props) {
const exporting = ref(false);
const exportError = ref('');
function breadcrumbLabel(node) {
if (!node) return '?';
if (node.type === 'score') return 'Score';
if (node.type === 'instrument') return node.name;
if (node.type === 'variation') return node.dependsOn ? `var(${node.dependsOn})` : 'variation';
if (node.type === 'label_spec') return node.label ?? 'label';
if (node.type === 'bar') return node.id;
return node.type;
}
async function doExport() {
exportError.value = '';
exporting.value = true;
try {
const raw = await fetchScoreText(props.store.credentials);
props.store.rawScoreText = raw;
const patched = patchScore(raw, props.store.scoreModel.instruments);
await putScoreText(patched, props.store.credentials);
// Start polling
props.store.synthesisStatus = { frozen: false, progress: 0 };
} catch (e) {
exportError.value = e.message;
} finally {
exporting.value = false;
}
}
return () => {
const store = props.store;
const model = store.scoreModel;
const fp = store.focusPath;
return h('div', { class: 'se-pane' }, [
// Header
h('div', { class: 'se-cp-header' }, [
h('span', { class: 'se-cp-title' },
model ? (model.info?.title ?? 'Untitled score') : 'No score loaded'),
h('button', {
class: 'se-btn',
disabled: store.isDirty,
title: store.isDirty ? 'Save or discard edits before re-importing' : 'Import from server',
onClick: props.onImportClick,
}, 'Import'),
model ? h('button', {
class: 'se-btn se-btn-primary',
disabled: !store.isDirty || exporting.value,
onClick: doExport,
}, exporting.value ? 'Exporting…' : 'Export') : null,
]),
// Breadcrumb
fp.length ? h('div', { class: 'se-breadcrumb' }, [
h('span', { onClick: () => store.setFocus([]) }, 'Score'),
...fp.map((node, i) => [
' ',
h('span', { onClick: () => store.setFocus(fp.slice(0, i + 1)) },
breadcrumbLabel(node)),
]).flat(),
]) : null,
// Score info
model ? h('dl', { style: 'font-size:0.8rem;margin:0.5rem 0' }, [
h('dt', null, 'Instruments'),
h('dd', null, String(model.instruments.length)),
h('dt', null, 'Bars'),
h('dd', null, String(model.bars.length)),
]) : null,
// Export error
exportError.value ? h('div', { class: 'se-error' }, exportError.value) : null,
// Status poller (shown after export started)
store.synthesisStatus && !store.synthesisStatus.frozen
? h(StatusPoller, { store })
: null,
// Result link
store.synthesisStatus?.frozen && !store.synthesisStatus?.error
? h('a', {
href: '/sompyle/result.mp3',
style: 'display:block;margin-top:0.5rem',
}, 'Download result')
: null,
]);
};
},
};