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
+246022
-57183
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
+1130
-1620
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"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "^31.7.7",
|
||||
"electron-builder": "^24.13.3"
|
||||
"electron": "^42.4.0",
|
||||
"electron-builder": "^26.15.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"knx": "^2.5.4",
|
||||
"knx": "^0.0.1",
|
||||
"modbus-serial": "^8.0.25",
|
||||
"mqtt": "^5.10.4",
|
||||
"serialport": "^13.0.0"
|
||||
|
||||
+79
-27
@@ -3,7 +3,7 @@
|
||||
const RULER_HEIGHT = 34;
|
||||
const POINT_RADIUS = 7;
|
||||
const FPS_DEFAULT = 30;
|
||||
const LEFT_GUTTER = 126;
|
||||
const LEFT_GUTTER = 162;
|
||||
const RIGHT_PADDING = 24;
|
||||
const MIN_CANVAS_HEIGHT = 420;
|
||||
const EXTERNAL_RESYNC_MS = 1000;
|
||||
@@ -189,7 +189,7 @@
|
||||
routing: createDefaultRouting(),
|
||||
ui: {
|
||||
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 === "audio-file") {
|
||||
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 === "knx-value") return `${escapeHtml(track.groupAddress)} / ${escapeHtml(track.dpt)}`;
|
||||
if (track.type === "osc-value") return escapeHtml(track.address);
|
||||
return escapeHtml(track.topic);
|
||||
if (track.type === "knx-value") return `${track.groupAddress} / ${track.dpt}`;
|
||||
if (track.type === "osc-value") return track.address;
|
||||
return track.topic;
|
||||
}
|
||||
|
||||
function basenameFromPath(filePath) {
|
||||
@@ -829,6 +829,29 @@
|
||||
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) {
|
||||
if (duration <= 15) return 0.5;
|
||||
if (duration <= 60) return 1;
|
||||
@@ -921,25 +944,29 @@
|
||||
function drawTrackLaneLabel(track, trackIndex) {
|
||||
const top = RULER_HEIGHT + (trackIndex * TRACK_HEIGHT);
|
||||
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.beginPath();
|
||||
ctx.roundRect(18, top + 14, 44, 24, 8);
|
||||
ctx.roundRect(16, top + 15, 40, 22, 8);
|
||||
ctx.fill();
|
||||
|
||||
ctx.fillStyle = "#091018";
|
||||
ctx.font = "bold 11px Trebuchet MS";
|
||||
ctx.font = "bold 10px Trebuchet MS";
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText(getTrackKindLabel(track), 40, top + 30);
|
||||
ctx.fillText(getTrackKindLabel(track), 36, top + 29);
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(92, top + (TRACK_HEIGHT / 2));
|
||||
ctx.rotate(-Math.PI / 2);
|
||||
ctx.textAlign = "left";
|
||||
ctx.fillStyle = "rgba(255,255,255,0.86)";
|
||||
ctx.font = "bold 13px Trebuchet MS";
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText(track.name, 0, 0);
|
||||
ctx.restore();
|
||||
ctx.font = "bold 12px Trebuchet MS";
|
||||
ctx.fillText(truncateCanvasText(trackName, labelWidth), labelLeft, top + 33);
|
||||
|
||||
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) {
|
||||
ctx.strokeStyle = "rgba(110,194,242,0.76)";
|
||||
@@ -1137,12 +1164,13 @@
|
||||
function renderTimelineList() {
|
||||
refs.timelineList.innerHTML = "";
|
||||
for (const timeline of state.project.timelines) {
|
||||
const shortName = shortenLabel(timeline.name, 26);
|
||||
const card = document.createElement("div");
|
||||
card.className = `timeline-card selectable-card ${timeline.id === state.selectedTimelineId ? "active" : ""}`;
|
||||
card.dataset.timelineId = timeline.id;
|
||||
card.innerHTML = `
|
||||
<strong>${escapeHtml(timeline.name)}</strong>
|
||||
<div class="meta-row">
|
||||
<strong class="truncate-text" title="${escapeAttribute(timeline.name)}">${escapeHtml(shortName)}</strong>
|
||||
<div class="meta-row compact">
|
||||
<span>${timeline.tracks.length} Tracks</span>
|
||||
<span>${timeline.duration}s</span>
|
||||
</div>
|
||||
@@ -1173,18 +1201,22 @@
|
||||
}
|
||||
|
||||
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");
|
||||
card.className = `track-card ${track.id === state.selectedTrackId ? "active" : ""}`;
|
||||
card.dataset.trackId = track.id;
|
||||
card.innerHTML = `
|
||||
<div class="track-card-top">
|
||||
<div class="track-card-body selectable-card" data-track-id="${track.id}">
|
||||
<div class="panel-header">
|
||||
<strong>${escapeHtml(track.name)}</strong>
|
||||
<span class="track-pill ${pillClassForTrack(track)}">${getTrackKindLabel(track)}</span>
|
||||
<div class="track-card-header">
|
||||
<strong class="truncate-text" title="${escapeAttribute(fullName)}">${escapeHtml(shortName)}</strong>
|
||||
<span class="track-pill ${pillClassForTrack(track)}" title="${escapeAttribute(getTrackKindLabel(track))}">${getTrackKindLabel(track)}</span>
|
||||
</div>
|
||||
<div class="meta-row">
|
||||
<span>${describeTrack(track)}</span>
|
||||
<div class="meta-row compact">
|
||||
<span class="truncate-text" title="${escapeAttribute(detail)}">${escapeHtml(shortDetail)}</span>
|
||||
<span>${track.points.length} Punkte</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1201,6 +1233,7 @@
|
||||
function renderTimelineInspector() {
|
||||
const timeline = getSelectedTimeline();
|
||||
refs.timelineTitle.textContent = timeline ? timeline.name : "Keine Timeline ausgewaehlt";
|
||||
refs.timelineTitle.title = timeline ? timeline.name : "";
|
||||
if (!timeline) {
|
||||
refs.timelineInspector.innerHTML = `<div class="empty-state">Keine Timeline ausgewaehlt.</div>`;
|
||||
return;
|
||||
@@ -1635,12 +1668,22 @@
|
||||
|
||||
function openSettings(tab = state.ui.settingsTab) {
|
||||
state.ui.settingsOpen = true;
|
||||
state.ui.settingsTab = tab;
|
||||
state.ui.settingsTab = tab || "midi";
|
||||
void refreshNetworkAdapters();
|
||||
void refreshAudioOutputs();
|
||||
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() {
|
||||
state.ui.settingsOpen = false;
|
||||
renderAll();
|
||||
@@ -2896,12 +2939,12 @@
|
||||
refs.playButton.addEventListener("click", playTransport);
|
||||
refs.pauseButton.addEventListener("click", pauseTransport);
|
||||
refs.stopButton.addEventListener("click", () => stopTransport(true));
|
||||
refs.openSettingsButton.addEventListener("click", () => openSettings("routing"));
|
||||
refs.openSettingsButton.addEventListener("click", () => openSettings());
|
||||
refs.closeSettingsButton.addEventListener("click", closeSettings);
|
||||
refs.settingsBackdrop.addEventListener("click", closeSettings);
|
||||
refs.settingsTabButtons.forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
state.ui.settingsTab = button.dataset.settingsTab || "routing";
|
||||
state.ui.settingsTab = button.dataset.settingsTab || "midi";
|
||||
renderAll();
|
||||
});
|
||||
});
|
||||
@@ -2998,6 +3041,15 @@
|
||||
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) => {
|
||||
const rect = refs.timelineCanvas.getBoundingClientRect();
|
||||
const x = event.clientX - rect.left;
|
||||
|
||||
+50
-29
@@ -97,14 +97,14 @@
|
||||
|
||||
<section class="editor panel">
|
||||
<div class="editor-header">
|
||||
<div>
|
||||
<div class="editor-title-block">
|
||||
<div class="eyebrow">Editor</div>
|
||||
<h2 id="timelineTitle">Keine Timeline ausgewählt</h2>
|
||||
<h2 id="timelineTitle">Keine Timeline ausgewaehlt</h2>
|
||||
</div>
|
||||
<div class="editor-hints">
|
||||
<span>Doppelklick: Punkt setzen</span>
|
||||
<span>Ziehen: Zeit/Wert ändern</span>
|
||||
<span>Entf: Punkt löschen</span>
|
||||
<span>Ziehen: Zeit/Wert aendern</span>
|
||||
<span>Entf: Punkt loeschen</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="canvas-frame">
|
||||
@@ -112,6 +112,22 @@
|
||||
</div>
|
||||
</section>
|
||||
</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 id="settingsModal" class="settings-modal" aria-hidden="true">
|
||||
@@ -127,19 +143,25 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-tabbar" role="tablist" aria-label="Einstellungen">
|
||||
<button class="settings-tab active" type="button" data-settings-tab="routing">Routing</button>
|
||||
<button class="settings-tab" type="button" data-settings-tab="timeline">Timeline</button>
|
||||
<button class="settings-tab" type="button" data-settings-tab="selection">Auswahl</button>
|
||||
<div class="settings-tabbar" role="tablist" aria-label="Ausgaben">
|
||||
<button class="settings-tab active" type="button" data-settings-tab="midi" title="MIDI">MIDI</button>
|
||||
<button class="settings-tab" type="button" data-settings-tab="audio" title="Audio">Audio</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 class="settings-content">
|
||||
<div class="settings-tab-panel active" data-settings-panel="routing">
|
||||
<div class="settings-stack">
|
||||
<div class="info-card">
|
||||
Adapter = lokale Netzwerkkarte bzw. lokale IP. Leer bedeutet automatische Auswahl durch das Betriebssystem.
|
||||
</div>
|
||||
|
||||
<div class="settings-tab-panel active" data-settings-panel="midi">
|
||||
<section class="settings-section">
|
||||
<div class="panel-header">
|
||||
<h2>MIDI</h2>
|
||||
@@ -153,7 +175,9 @@
|
||||
<select id="midiOutputSelect"></select>
|
||||
</label>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="settings-tab-panel" data-settings-panel="audio">
|
||||
<section class="settings-section">
|
||||
<div class="panel-header">
|
||||
<h2>Audio</h2>
|
||||
@@ -163,7 +187,9 @@
|
||||
<select id="audioOutputSelect"></select>
|
||||
</label>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="settings-tab-panel" data-settings-panel="artnet">
|
||||
<section class="settings-section">
|
||||
<div class="panel-header">
|
||||
<h2>Art-Net</h2>
|
||||
@@ -201,7 +227,9 @@
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="settings-tab-panel" data-settings-panel="sacn">
|
||||
<section class="settings-section">
|
||||
<div class="panel-header">
|
||||
<h2>sACN</h2>
|
||||
@@ -235,7 +263,9 @@
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="settings-tab-panel" data-settings-panel="osc">
|
||||
<section class="settings-section">
|
||||
<div class="panel-header">
|
||||
<h2>OSC</h2>
|
||||
@@ -259,7 +289,9 @@
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="settings-tab-panel" data-settings-panel="mqtt">
|
||||
<section class="settings-section">
|
||||
<div class="panel-header">
|
||||
<h2>MQTT</h2>
|
||||
@@ -291,7 +323,9 @@
|
||||
<input id="mqttClientIdInput" type="text" placeholder="time4midi-desktop">
|
||||
</label>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="settings-tab-panel" data-settings-panel="serial">
|
||||
<section class="settings-section">
|
||||
<div class="panel-header">
|
||||
<h2>Serial</h2>
|
||||
@@ -328,7 +362,9 @@
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="settings-tab-panel" data-settings-panel="modbusTcp">
|
||||
<section class="settings-section">
|
||||
<div class="panel-header">
|
||||
<h2>Modbus TCP</h2>
|
||||
@@ -352,7 +388,9 @@
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="settings-tab-panel" data-settings-panel="modbusRtu">
|
||||
<section class="settings-section">
|
||||
<div class="panel-header">
|
||||
<h2>Modbus RTU</h2>
|
||||
@@ -380,7 +418,9 @@
|
||||
</select>
|
||||
</label>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="settings-tab-panel" data-settings-panel="knx">
|
||||
<section class="settings-section">
|
||||
<div class="panel-header">
|
||||
<h2>KNX</h2>
|
||||
@@ -416,25 +456,6 @@
|
||||
</section>
|
||||
</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>
|
||||
</div>
|
||||
|
||||
|
||||
+82
-3
@@ -76,14 +76,15 @@ select {
|
||||
|
||||
.app-shell {
|
||||
display: grid;
|
||||
grid-template-columns: 286px minmax(0, 1fr);
|
||||
grid-template-columns: 286px minmax(0, 1fr) 308px;
|
||||
gap: 12px;
|
||||
min-height: 100vh;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.sidebar,
|
||||
.workspace {
|
||||
.workspace,
|
||||
.inspector {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
@@ -239,6 +240,14 @@ p {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.truncate-text {
|
||||
display: block;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.timeline-list,
|
||||
.track-list,
|
||||
#timelineInspector,
|
||||
@@ -337,6 +346,7 @@ p {
|
||||
|
||||
.track-card-body {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.track-card-actions {
|
||||
@@ -379,6 +389,14 @@ p {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.inspector {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.inspector-panel {
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.transport-bar {
|
||||
padding: 12px 14px;
|
||||
}
|
||||
@@ -404,6 +422,17 @@ p {
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.editor-title-block {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
#timelineTitle {
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.canvas-frame {
|
||||
margin-top: 10px;
|
||||
flex: 1;
|
||||
@@ -476,8 +505,12 @@ p {
|
||||
}
|
||||
|
||||
.settings-tab {
|
||||
min-width: 92px;
|
||||
min-width: 0;
|
||||
max-width: 96px;
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.settings-tab.active {
|
||||
@@ -489,6 +522,8 @@ p {
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
padding-right: 4px;
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.settings-tab-panel {
|
||||
@@ -538,9 +573,49 @@ p {
|
||||
}
|
||||
|
||||
@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 {
|
||||
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) {
|
||||
@@ -555,6 +630,10 @@ p {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.inspector {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.field-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user