Refine routing UI and rebuild Windows package
This commit is contained in:
Vendored
BIN
Binary file not shown.
Vendored
+6
-4
File diff suppressed because one or more lines are too long
+246111
-57272
File diff suppressed because it is too large
Load Diff
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Generated
+1131
-1621
File diff suppressed because it is too large
Load Diff
+3
-3
@@ -9,11 +9,11 @@
|
|||||||
"dist:win": "set CSC_IDENTITY_AUTO_DISCOVERY=false&& electron-builder --win portable"
|
"dist:win": "set CSC_IDENTITY_AUTO_DISCOVERY=false&& electron-builder --win portable"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"electron": "^31.7.7",
|
"electron": "^42.4.0",
|
||||||
"electron-builder": "^24.13.3"
|
"electron-builder": "^26.15.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"knx": "^2.5.4",
|
"knx": "^0.0.1",
|
||||||
"modbus-serial": "^8.0.25",
|
"modbus-serial": "^8.0.25",
|
||||||
"mqtt": "^5.10.4",
|
"mqtt": "^5.10.4",
|
||||||
"serialport": "^13.0.0"
|
"serialport": "^13.0.0"
|
||||||
|
|||||||
+79
-27
@@ -3,7 +3,7 @@
|
|||||||
const RULER_HEIGHT = 34;
|
const RULER_HEIGHT = 34;
|
||||||
const POINT_RADIUS = 7;
|
const POINT_RADIUS = 7;
|
||||||
const FPS_DEFAULT = 30;
|
const FPS_DEFAULT = 30;
|
||||||
const LEFT_GUTTER = 126;
|
const LEFT_GUTTER = 162;
|
||||||
const RIGHT_PADDING = 24;
|
const RIGHT_PADDING = 24;
|
||||||
const MIN_CANVAS_HEIGHT = 420;
|
const MIN_CANVAS_HEIGHT = 420;
|
||||||
const EXTERNAL_RESYNC_MS = 1000;
|
const EXTERNAL_RESYNC_MS = 1000;
|
||||||
@@ -189,7 +189,7 @@
|
|||||||
routing: createDefaultRouting(),
|
routing: createDefaultRouting(),
|
||||||
ui: {
|
ui: {
|
||||||
settingsOpen: false,
|
settingsOpen: false,
|
||||||
settingsTab: "routing"
|
settingsTab: "midi"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -531,13 +531,13 @@
|
|||||||
if (track.type === "sacn-channel") return `Uni ${track.universe} / Addr ${track.address}`;
|
if (track.type === "sacn-channel") return `Uni ${track.universe} / Addr ${track.address}`;
|
||||||
if (track.type === "audio-file") {
|
if (track.type === "audio-file") {
|
||||||
const bpmText = track.analysisBpm ? ` / ${Math.round(track.analysisBpm)} BPM` : "";
|
const bpmText = track.analysisBpm ? ` / ${Math.round(track.analysisBpm)} BPM` : "";
|
||||||
return `${escapeHtml(track.mediaName || basenameFromPath(track.filePath))}${bpmText}`;
|
return `${track.mediaName || basenameFromPath(track.filePath)}${bpmText}`;
|
||||||
}
|
}
|
||||||
if (track.type === "serial-value") return escapeHtml(track.template);
|
if (track.type === "serial-value") return track.template;
|
||||||
if (track.type === "modbus-tcp" || track.type === "modbus-rtu") return `ID ${track.unitId} / Addr ${track.address}`;
|
if (track.type === "modbus-tcp" || track.type === "modbus-rtu") return `ID ${track.unitId} / Addr ${track.address}`;
|
||||||
if (track.type === "knx-value") return `${escapeHtml(track.groupAddress)} / ${escapeHtml(track.dpt)}`;
|
if (track.type === "knx-value") return `${track.groupAddress} / ${track.dpt}`;
|
||||||
if (track.type === "osc-value") return escapeHtml(track.address);
|
if (track.type === "osc-value") return track.address;
|
||||||
return escapeHtml(track.topic);
|
return track.topic;
|
||||||
}
|
}
|
||||||
|
|
||||||
function basenameFromPath(filePath) {
|
function basenameFromPath(filePath) {
|
||||||
@@ -829,6 +829,29 @@
|
|||||||
return escapeHtml(value).replaceAll("\"", """);
|
return escapeHtml(value).replaceAll("\"", """);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shortenLabel(value, maxLength = 18) {
|
||||||
|
const text = String(value || "").trim();
|
||||||
|
if (text.length <= maxLength) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
return `${text.slice(0, Math.max(1, maxLength - 3)).trimEnd()}...`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function truncateCanvasText(text, maxWidth) {
|
||||||
|
const value = String(text || "");
|
||||||
|
if (!value) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (ctx.measureText(value).width <= maxWidth) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
let shortened = value;
|
||||||
|
while (shortened.length > 1 && ctx.measureText(`${shortened}...`).width > maxWidth) {
|
||||||
|
shortened = shortened.slice(0, -1);
|
||||||
|
}
|
||||||
|
return `${shortened.trimEnd()}...`;
|
||||||
|
}
|
||||||
|
|
||||||
function chooseTimeStep(duration) {
|
function chooseTimeStep(duration) {
|
||||||
if (duration <= 15) return 0.5;
|
if (duration <= 15) return 0.5;
|
||||||
if (duration <= 60) return 1;
|
if (duration <= 60) return 1;
|
||||||
@@ -921,25 +944,29 @@
|
|||||||
function drawTrackLaneLabel(track, trackIndex) {
|
function drawTrackLaneLabel(track, trackIndex) {
|
||||||
const top = RULER_HEIGHT + (trackIndex * TRACK_HEIGHT);
|
const top = RULER_HEIGHT + (trackIndex * TRACK_HEIGHT);
|
||||||
const color = getTrackColor(track);
|
const color = getTrackColor(track);
|
||||||
|
const labelLeft = 66;
|
||||||
|
const labelWidth = LEFT_GUTTER - labelLeft - 14;
|
||||||
|
const trackName = track.name || "Unbenannt";
|
||||||
|
const detailText = describeTrack(track);
|
||||||
|
|
||||||
ctx.fillStyle = color;
|
ctx.fillStyle = color;
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.roundRect(18, top + 14, 44, 24, 8);
|
ctx.roundRect(16, top + 15, 40, 22, 8);
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
|
|
||||||
ctx.fillStyle = "#091018";
|
ctx.fillStyle = "#091018";
|
||||||
ctx.font = "bold 11px Trebuchet MS";
|
ctx.font = "bold 10px Trebuchet MS";
|
||||||
ctx.textAlign = "center";
|
ctx.textAlign = "center";
|
||||||
ctx.fillText(getTrackKindLabel(track), 40, top + 30);
|
ctx.fillText(getTrackKindLabel(track), 36, top + 29);
|
||||||
|
|
||||||
ctx.save();
|
ctx.textAlign = "left";
|
||||||
ctx.translate(92, top + (TRACK_HEIGHT / 2));
|
|
||||||
ctx.rotate(-Math.PI / 2);
|
|
||||||
ctx.fillStyle = "rgba(255,255,255,0.86)";
|
ctx.fillStyle = "rgba(255,255,255,0.86)";
|
||||||
ctx.font = "bold 13px Trebuchet MS";
|
ctx.font = "bold 12px Trebuchet MS";
|
||||||
ctx.textAlign = "center";
|
ctx.fillText(truncateCanvasText(trackName, labelWidth), labelLeft, top + 33);
|
||||||
ctx.fillText(track.name, 0, 0);
|
|
||||||
ctx.restore();
|
ctx.fillStyle = "rgba(164,178,204,0.92)";
|
||||||
|
ctx.font = "11px Trebuchet MS";
|
||||||
|
ctx.fillText(truncateCanvasText(detailText, labelWidth), labelLeft, top + 52);
|
||||||
|
|
||||||
if (track.id === state.selectedTrackId) {
|
if (track.id === state.selectedTrackId) {
|
||||||
ctx.strokeStyle = "rgba(110,194,242,0.76)";
|
ctx.strokeStyle = "rgba(110,194,242,0.76)";
|
||||||
@@ -1137,12 +1164,13 @@
|
|||||||
function renderTimelineList() {
|
function renderTimelineList() {
|
||||||
refs.timelineList.innerHTML = "";
|
refs.timelineList.innerHTML = "";
|
||||||
for (const timeline of state.project.timelines) {
|
for (const timeline of state.project.timelines) {
|
||||||
|
const shortName = shortenLabel(timeline.name, 26);
|
||||||
const card = document.createElement("div");
|
const card = document.createElement("div");
|
||||||
card.className = `timeline-card selectable-card ${timeline.id === state.selectedTimelineId ? "active" : ""}`;
|
card.className = `timeline-card selectable-card ${timeline.id === state.selectedTimelineId ? "active" : ""}`;
|
||||||
card.dataset.timelineId = timeline.id;
|
card.dataset.timelineId = timeline.id;
|
||||||
card.innerHTML = `
|
card.innerHTML = `
|
||||||
<strong>${escapeHtml(timeline.name)}</strong>
|
<strong class="truncate-text" title="${escapeAttribute(timeline.name)}">${escapeHtml(shortName)}</strong>
|
||||||
<div class="meta-row">
|
<div class="meta-row compact">
|
||||||
<span>${timeline.tracks.length} Tracks</span>
|
<span>${timeline.tracks.length} Tracks</span>
|
||||||
<span>${timeline.duration}s</span>
|
<span>${timeline.duration}s</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -1173,18 +1201,22 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const track of timeline.tracks) {
|
for (const track of timeline.tracks) {
|
||||||
|
const fullName = track.name || "Unbenannt";
|
||||||
|
const shortName = shortenLabel(fullName, 24);
|
||||||
|
const detail = describeTrack(track);
|
||||||
|
const shortDetail = shortenLabel(detail, 34);
|
||||||
const card = document.createElement("div");
|
const card = document.createElement("div");
|
||||||
card.className = `track-card ${track.id === state.selectedTrackId ? "active" : ""}`;
|
card.className = `track-card ${track.id === state.selectedTrackId ? "active" : ""}`;
|
||||||
card.dataset.trackId = track.id;
|
card.dataset.trackId = track.id;
|
||||||
card.innerHTML = `
|
card.innerHTML = `
|
||||||
<div class="track-card-top">
|
<div class="track-card-top">
|
||||||
<div class="track-card-body selectable-card" data-track-id="${track.id}">
|
<div class="track-card-body selectable-card" data-track-id="${track.id}">
|
||||||
<div class="panel-header">
|
<div class="track-card-header">
|
||||||
<strong>${escapeHtml(track.name)}</strong>
|
<strong class="truncate-text" title="${escapeAttribute(fullName)}">${escapeHtml(shortName)}</strong>
|
||||||
<span class="track-pill ${pillClassForTrack(track)}">${getTrackKindLabel(track)}</span>
|
<span class="track-pill ${pillClassForTrack(track)}" title="${escapeAttribute(getTrackKindLabel(track))}">${getTrackKindLabel(track)}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="meta-row">
|
<div class="meta-row compact">
|
||||||
<span>${describeTrack(track)}</span>
|
<span class="truncate-text" title="${escapeAttribute(detail)}">${escapeHtml(shortDetail)}</span>
|
||||||
<span>${track.points.length} Punkte</span>
|
<span>${track.points.length} Punkte</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1201,6 +1233,7 @@
|
|||||||
function renderTimelineInspector() {
|
function renderTimelineInspector() {
|
||||||
const timeline = getSelectedTimeline();
|
const timeline = getSelectedTimeline();
|
||||||
refs.timelineTitle.textContent = timeline ? timeline.name : "Keine Timeline ausgewaehlt";
|
refs.timelineTitle.textContent = timeline ? timeline.name : "Keine Timeline ausgewaehlt";
|
||||||
|
refs.timelineTitle.title = timeline ? timeline.name : "";
|
||||||
if (!timeline) {
|
if (!timeline) {
|
||||||
refs.timelineInspector.innerHTML = `<div class="empty-state">Keine Timeline ausgewaehlt.</div>`;
|
refs.timelineInspector.innerHTML = `<div class="empty-state">Keine Timeline ausgewaehlt.</div>`;
|
||||||
return;
|
return;
|
||||||
@@ -1635,12 +1668,22 @@
|
|||||||
|
|
||||||
function openSettings(tab = state.ui.settingsTab) {
|
function openSettings(tab = state.ui.settingsTab) {
|
||||||
state.ui.settingsOpen = true;
|
state.ui.settingsOpen = true;
|
||||||
state.ui.settingsTab = tab;
|
state.ui.settingsTab = tab || "midi";
|
||||||
void refreshNetworkAdapters();
|
void refreshNetworkAdapters();
|
||||||
void refreshAudioOutputs();
|
void refreshAudioOutputs();
|
||||||
renderAll();
|
renderAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateCanvasHoverTitle(x, y) {
|
||||||
|
const hit = findCanvasHit(x, y);
|
||||||
|
const nextTitle = hit?.track
|
||||||
|
? `${hit.track.name || "Unbenannt"}\n${describeTrack(hit.track)}`
|
||||||
|
: "";
|
||||||
|
if (refs.timelineCanvas.title !== nextTitle) {
|
||||||
|
refs.timelineCanvas.title = nextTitle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function closeSettings() {
|
function closeSettings() {
|
||||||
state.ui.settingsOpen = false;
|
state.ui.settingsOpen = false;
|
||||||
renderAll();
|
renderAll();
|
||||||
@@ -2896,12 +2939,12 @@
|
|||||||
refs.playButton.addEventListener("click", playTransport);
|
refs.playButton.addEventListener("click", playTransport);
|
||||||
refs.pauseButton.addEventListener("click", pauseTransport);
|
refs.pauseButton.addEventListener("click", pauseTransport);
|
||||||
refs.stopButton.addEventListener("click", () => stopTransport(true));
|
refs.stopButton.addEventListener("click", () => stopTransport(true));
|
||||||
refs.openSettingsButton.addEventListener("click", () => openSettings("routing"));
|
refs.openSettingsButton.addEventListener("click", () => openSettings());
|
||||||
refs.closeSettingsButton.addEventListener("click", closeSettings);
|
refs.closeSettingsButton.addEventListener("click", closeSettings);
|
||||||
refs.settingsBackdrop.addEventListener("click", closeSettings);
|
refs.settingsBackdrop.addEventListener("click", closeSettings);
|
||||||
refs.settingsTabButtons.forEach((button) => {
|
refs.settingsTabButtons.forEach((button) => {
|
||||||
button.addEventListener("click", () => {
|
button.addEventListener("click", () => {
|
||||||
state.ui.settingsTab = button.dataset.settingsTab || "routing";
|
state.ui.settingsTab = button.dataset.settingsTab || "midi";
|
||||||
renderAll();
|
renderAll();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -2998,6 +3041,15 @@
|
|||||||
addPointFromCanvas(event.clientX - rect.left, event.clientY - rect.top);
|
addPointFromCanvas(event.clientX - rect.left, event.clientY - rect.top);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
refs.timelineCanvas.addEventListener("mousemove", (event) => {
|
||||||
|
const rect = refs.timelineCanvas.getBoundingClientRect();
|
||||||
|
updateCanvasHoverTitle(event.clientX - rect.left, event.clientY - rect.top);
|
||||||
|
});
|
||||||
|
|
||||||
|
refs.timelineCanvas.addEventListener("mouseleave", () => {
|
||||||
|
refs.timelineCanvas.title = "";
|
||||||
|
});
|
||||||
|
|
||||||
refs.timelineCanvas.addEventListener("mousedown", (event) => {
|
refs.timelineCanvas.addEventListener("mousedown", (event) => {
|
||||||
const rect = refs.timelineCanvas.getBoundingClientRect();
|
const rect = refs.timelineCanvas.getBoundingClientRect();
|
||||||
const x = event.clientX - rect.left;
|
const x = event.clientX - rect.left;
|
||||||
|
|||||||
+50
-29
@@ -97,14 +97,14 @@
|
|||||||
|
|
||||||
<section class="editor panel">
|
<section class="editor panel">
|
||||||
<div class="editor-header">
|
<div class="editor-header">
|
||||||
<div>
|
<div class="editor-title-block">
|
||||||
<div class="eyebrow">Editor</div>
|
<div class="eyebrow">Editor</div>
|
||||||
<h2 id="timelineTitle">Keine Timeline ausgewählt</h2>
|
<h2 id="timelineTitle">Keine Timeline ausgewaehlt</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="editor-hints">
|
<div class="editor-hints">
|
||||||
<span>Doppelklick: Punkt setzen</span>
|
<span>Doppelklick: Punkt setzen</span>
|
||||||
<span>Ziehen: Zeit/Wert ändern</span>
|
<span>Ziehen: Zeit/Wert aendern</span>
|
||||||
<span>Entf: Punkt löschen</span>
|
<span>Entf: Punkt loeschen</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="canvas-frame">
|
<div class="canvas-frame">
|
||||||
@@ -112,6 +112,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<aside class="inspector">
|
||||||
|
<section class="panel inspector-panel">
|
||||||
|
<div class="panel-header">
|
||||||
|
<h2>Timeline</h2>
|
||||||
|
</div>
|
||||||
|
<div id="timelineInspector"></div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="panel inspector-panel">
|
||||||
|
<div class="panel-header">
|
||||||
|
<h2>Auswahl</h2>
|
||||||
|
</div>
|
||||||
|
<div id="selectionInspector"></div>
|
||||||
|
</section>
|
||||||
|
</aside>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="settingsModal" class="settings-modal" aria-hidden="true">
|
<div id="settingsModal" class="settings-modal" aria-hidden="true">
|
||||||
@@ -127,19 +143,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="settings-tabbar" role="tablist" aria-label="Einstellungen">
|
<div class="settings-tabbar" role="tablist" aria-label="Ausgaben">
|
||||||
<button class="settings-tab active" type="button" data-settings-tab="routing">Routing</button>
|
<button class="settings-tab active" type="button" data-settings-tab="midi" title="MIDI">MIDI</button>
|
||||||
<button class="settings-tab" type="button" data-settings-tab="timeline">Timeline</button>
|
<button class="settings-tab" type="button" data-settings-tab="audio" title="Audio">Audio</button>
|
||||||
<button class="settings-tab" type="button" data-settings-tab="selection">Auswahl</button>
|
<button class="settings-tab" type="button" data-settings-tab="artnet" title="Art-Net">Art-Net</button>
|
||||||
|
<button class="settings-tab" type="button" data-settings-tab="sacn" title="sACN">sACN</button>
|
||||||
|
<button class="settings-tab" type="button" data-settings-tab="osc" title="Open Sound Control">OSC</button>
|
||||||
|
<button class="settings-tab" type="button" data-settings-tab="mqtt" title="MQTT">MQTT</button>
|
||||||
|
<button class="settings-tab" type="button" data-settings-tab="serial" title="Serial">Serial</button>
|
||||||
|
<button class="settings-tab" type="button" data-settings-tab="modbusTcp" title="Modbus TCP">MB TCP</button>
|
||||||
|
<button class="settings-tab" type="button" data-settings-tab="modbusRtu" title="Modbus RTU">MB RTU</button>
|
||||||
|
<button class="settings-tab" type="button" data-settings-tab="knx" title="KNX">KNX</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="settings-content">
|
<div class="settings-content">
|
||||||
<div class="settings-tab-panel active" data-settings-panel="routing">
|
|
||||||
<div class="settings-stack">
|
|
||||||
<div class="info-card">
|
<div class="info-card">
|
||||||
Adapter = lokale Netzwerkkarte bzw. lokale IP. Leer bedeutet automatische Auswahl durch das Betriebssystem.
|
Adapter = lokale Netzwerkkarte bzw. lokale IP. Leer bedeutet automatische Auswahl durch das Betriebssystem.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-tab-panel active" data-settings-panel="midi">
|
||||||
<section class="settings-section">
|
<section class="settings-section">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<h2>MIDI</h2>
|
<h2>MIDI</h2>
|
||||||
@@ -153,7 +175,9 @@
|
|||||||
<select id="midiOutputSelect"></select>
|
<select id="midiOutputSelect"></select>
|
||||||
</label>
|
</label>
|
||||||
</section>
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-tab-panel" data-settings-panel="audio">
|
||||||
<section class="settings-section">
|
<section class="settings-section">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<h2>Audio</h2>
|
<h2>Audio</h2>
|
||||||
@@ -163,7 +187,9 @@
|
|||||||
<select id="audioOutputSelect"></select>
|
<select id="audioOutputSelect"></select>
|
||||||
</label>
|
</label>
|
||||||
</section>
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-tab-panel" data-settings-panel="artnet">
|
||||||
<section class="settings-section">
|
<section class="settings-section">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<h2>Art-Net</h2>
|
<h2>Art-Net</h2>
|
||||||
@@ -201,7 +227,9 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-tab-panel" data-settings-panel="sacn">
|
||||||
<section class="settings-section">
|
<section class="settings-section">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<h2>sACN</h2>
|
<h2>sACN</h2>
|
||||||
@@ -235,7 +263,9 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-tab-panel" data-settings-panel="osc">
|
||||||
<section class="settings-section">
|
<section class="settings-section">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<h2>OSC</h2>
|
<h2>OSC</h2>
|
||||||
@@ -259,7 +289,9 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-tab-panel" data-settings-panel="mqtt">
|
||||||
<section class="settings-section">
|
<section class="settings-section">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<h2>MQTT</h2>
|
<h2>MQTT</h2>
|
||||||
@@ -291,7 +323,9 @@
|
|||||||
<input id="mqttClientIdInput" type="text" placeholder="time4midi-desktop">
|
<input id="mqttClientIdInput" type="text" placeholder="time4midi-desktop">
|
||||||
</label>
|
</label>
|
||||||
</section>
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-tab-panel" data-settings-panel="serial">
|
||||||
<section class="settings-section">
|
<section class="settings-section">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<h2>Serial</h2>
|
<h2>Serial</h2>
|
||||||
@@ -328,7 +362,9 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-tab-panel" data-settings-panel="modbusTcp">
|
||||||
<section class="settings-section">
|
<section class="settings-section">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<h2>Modbus TCP</h2>
|
<h2>Modbus TCP</h2>
|
||||||
@@ -352,7 +388,9 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-tab-panel" data-settings-panel="modbusRtu">
|
||||||
<section class="settings-section">
|
<section class="settings-section">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<h2>Modbus RTU</h2>
|
<h2>Modbus RTU</h2>
|
||||||
@@ -380,7 +418,9 @@
|
|||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
</section>
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-tab-panel" data-settings-panel="knx">
|
||||||
<section class="settings-section">
|
<section class="settings-section">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<h2>KNX</h2>
|
<h2>KNX</h2>
|
||||||
@@ -416,25 +456,6 @@
|
|||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="settings-tab-panel" data-settings-panel="timeline">
|
|
||||||
<section class="settings-section">
|
|
||||||
<div class="panel-header">
|
|
||||||
<h2>Timeline</h2>
|
|
||||||
</div>
|
|
||||||
<div id="timelineInspector"></div>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="settings-tab-panel" data-settings-panel="selection">
|
|
||||||
<section class="settings-section">
|
|
||||||
<div class="panel-header">
|
|
||||||
<h2>Auswahl</h2>
|
|
||||||
</div>
|
|
||||||
<div id="selectionInspector"></div>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
+82
-3
@@ -76,14 +76,15 @@ select {
|
|||||||
|
|
||||||
.app-shell {
|
.app-shell {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 286px minmax(0, 1fr);
|
grid-template-columns: 286px minmax(0, 1fr) 308px;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar,
|
.sidebar,
|
||||||
.workspace {
|
.workspace,
|
||||||
|
.inspector {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
@@ -239,6 +240,14 @@ p {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.truncate-text {
|
||||||
|
display: block;
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
.timeline-list,
|
.timeline-list,
|
||||||
.track-list,
|
.track-list,
|
||||||
#timelineInspector,
|
#timelineInspector,
|
||||||
@@ -337,6 +346,7 @@ p {
|
|||||||
|
|
||||||
.track-card-body {
|
.track-card-body {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.track-card-actions {
|
.track-card-actions {
|
||||||
@@ -379,6 +389,14 @@ p {
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.inspector {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inspector-panel {
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.transport-bar {
|
.transport-bar {
|
||||||
padding: 12px 14px;
|
padding: 12px 14px;
|
||||||
}
|
}
|
||||||
@@ -404,6 +422,17 @@ p {
|
|||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.editor-title-block {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#timelineTitle {
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
.canvas-frame {
|
.canvas-frame {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
@@ -476,8 +505,12 @@ p {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.settings-tab {
|
.settings-tab {
|
||||||
min-width: 92px;
|
min-width: 0;
|
||||||
|
max-width: 96px;
|
||||||
background: rgba(255, 255, 255, 0.04);
|
background: rgba(255, 255, 255, 0.04);
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-tab.active {
|
.settings-tab.active {
|
||||||
@@ -489,6 +522,8 @@ p {
|
|||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding-right: 4px;
|
padding-right: 4px;
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-tab-panel {
|
.settings-tab-panel {
|
||||||
@@ -538,9 +573,49 @@ p {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1320px) {
|
@media (max-width: 1320px) {
|
||||||
|
.app-shell {
|
||||||
|
grid-template-columns: 262px minmax(0, 1fr) 280px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-dialog {
|
||||||
|
width: min(1040px, calc(100vw - 32px));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.track-card-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.track-card-header strong {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta-row.compact {
|
||||||
|
grid-template-columns: minmax(0, 1fr) auto;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta-row.compact span:first-child {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-card strong {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1180px) {
|
||||||
.app-shell {
|
.app-shell {
|
||||||
grid-template-columns: 270px minmax(0, 1fr);
|
grid-template-columns: 270px minmax(0, 1fr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.inspector {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 980px) {
|
@media (max-width: 980px) {
|
||||||
@@ -555,6 +630,10 @@ p {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.inspector {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
.field-grid {
|
.field-grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user