mirror of
https://github.com/imgfloat/server.git
synced 2026-02-05 03:39:26 +00:00
Remove redundant info
This commit is contained in:
@@ -399,6 +399,13 @@ body {
|
|||||||
background: #0b1220;
|
background: #0b1220;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.assets-panel {
|
||||||
|
margin-top: 16px;
|
||||||
|
background: #0b1220;
|
||||||
|
border-top: 1px solid #1f2937;
|
||||||
|
padding: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
.controls ul {
|
.controls ul {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -588,6 +595,11 @@ body {
|
|||||||
box-shadow: 0 0 0 1px rgba(124, 58, 237, 0.6);
|
box-shadow: 0 0 0 1px rgba(124, 58, 237, 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.asset-item.is-hidden {
|
||||||
|
opacity: 0.72;
|
||||||
|
border-style: dashed;
|
||||||
|
}
|
||||||
|
|
||||||
.asset-row {
|
.asset-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -614,6 +626,10 @@ body {
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.asset-meta-badges {
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.asset-detail {
|
.asset-detail {
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,35 +25,26 @@ const heightInput = document.getElementById('asset-height');
|
|||||||
const aspectLockInput = document.getElementById('maintain-aspect');
|
const aspectLockInput = document.getElementById('maintain-aspect');
|
||||||
const speedInput = document.getElementById('asset-speed');
|
const speedInput = document.getElementById('asset-speed');
|
||||||
const muteInput = document.getElementById('asset-muted');
|
const muteInput = document.getElementById('asset-muted');
|
||||||
const selectedAssetName = document.getElementById('selected-asset-name');
|
|
||||||
const selectedZLabel = document.getElementById('asset-z-level');
|
const selectedZLabel = document.getElementById('asset-z-level');
|
||||||
const selectedTypeLabel = document.getElementById('asset-type-label');
|
|
||||||
const selectedVisibilityBadge = document.getElementById('selected-asset-visibility');
|
|
||||||
const selectedToggleBtn = document.getElementById('selected-asset-toggle');
|
|
||||||
const selectedDeleteBtn = document.getElementById('selected-asset-delete');
|
|
||||||
const playbackSection = document.getElementById('playback-section');
|
const playbackSection = document.getElementById('playback-section');
|
||||||
const controlsPlaceholder = document.getElementById('asset-controls-placeholder');
|
const controlsPlaceholder = document.getElementById('asset-controls-placeholder');
|
||||||
const aspectLockState = new Map();
|
const aspectLockState = new Map();
|
||||||
|
const commitSizeChange = debounce(() => applyTransformFromInputs(), 180);
|
||||||
|
|
||||||
|
function debounce(fn, wait = 150) {
|
||||||
|
let timeout;
|
||||||
|
return (...args) => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = setTimeout(() => fn(...args), wait);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (widthInput) widthInput.addEventListener('input', () => handleSizeInputChange('width'));
|
if (widthInput) widthInput.addEventListener('input', () => handleSizeInputChange('width'));
|
||||||
|
if (widthInput) widthInput.addEventListener('change', () => commitSizeChange());
|
||||||
if (heightInput) heightInput.addEventListener('input', () => handleSizeInputChange('height'));
|
if (heightInput) heightInput.addEventListener('input', () => handleSizeInputChange('height'));
|
||||||
|
if (heightInput) heightInput.addEventListener('change', () => commitSizeChange());
|
||||||
if (speedInput) speedInput.addEventListener('input', updatePlaybackFromInputs);
|
if (speedInput) speedInput.addEventListener('input', updatePlaybackFromInputs);
|
||||||
if (muteInput) muteInput.addEventListener('change', updateMuteFromInput);
|
if (muteInput) muteInput.addEventListener('change', updateMuteFromInput);
|
||||||
if (selectedToggleBtn) selectedToggleBtn.addEventListener('click', (event) => {
|
|
||||||
event.stopPropagation();
|
|
||||||
const asset = getSelectedAsset();
|
|
||||||
if (asset) {
|
|
||||||
updateVisibility(asset, !asset.hidden);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (selectedDeleteBtn) selectedDeleteBtn.addEventListener('click', (event) => {
|
|
||||||
event.stopPropagation();
|
|
||||||
const asset = getSelectedAsset();
|
|
||||||
if (asset) {
|
|
||||||
deleteAsset(asset);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function connect() {
|
function connect() {
|
||||||
const socket = new SockJS('/ws');
|
const socket = new SockJS('/ws');
|
||||||
stompClient = Stomp.over(socket);
|
stompClient = Stomp.over(socket);
|
||||||
@@ -642,9 +633,7 @@ function renderAssetList() {
|
|||||||
if (asset.id === selectedAssetId) {
|
if (asset.id === selectedAssetId) {
|
||||||
li.classList.add('selected');
|
li.classList.add('selected');
|
||||||
}
|
}
|
||||||
if (asset.hidden) {
|
li.classList.toggle('is-hidden', !!asset.hidden);
|
||||||
li.classList.add('hidden');
|
|
||||||
}
|
|
||||||
|
|
||||||
const row = document.createElement('div');
|
const row = document.createElement('div');
|
||||||
row.className = 'asset-row';
|
row.className = 'asset-row';
|
||||||
@@ -656,10 +645,21 @@ function renderAssetList() {
|
|||||||
const name = document.createElement('strong');
|
const name = document.createElement('strong');
|
||||||
name.textContent = asset.name || `Asset ${asset.id.slice(0, 6)}`;
|
name.textContent = asset.name || `Asset ${asset.id.slice(0, 6)}`;
|
||||||
const details = document.createElement('small');
|
const details = document.createElement('small');
|
||||||
details.textContent = `Z ${asset.zIndex ?? 1} · ${Math.round(asset.width)}x${Math.round(asset.height)} · ${getDisplayMediaType(asset)} · ${asset.hidden ? 'Hidden' : 'Visible'}`;
|
details.textContent = `${Math.round(asset.width)}x${Math.round(asset.height)}`;
|
||||||
meta.appendChild(name);
|
meta.appendChild(name);
|
||||||
meta.appendChild(details);
|
meta.appendChild(details);
|
||||||
|
|
||||||
|
const badges = document.createElement('div');
|
||||||
|
badges.className = 'badge-row asset-meta-badges';
|
||||||
|
badges.appendChild(createBadge(asset.hidden ? 'Hidden' : 'Visible', asset.hidden ? 'danger' : ''));
|
||||||
|
badges.appendChild(createBadge(getDisplayMediaType(asset)));
|
||||||
|
badges.appendChild(createBadge(`Z ${asset.zIndex ?? 1}`));
|
||||||
|
const aspectLabel = formatAspectRatioLabel(asset);
|
||||||
|
if (aspectLabel) {
|
||||||
|
badges.appendChild(createBadge(aspectLabel, 'subtle'));
|
||||||
|
}
|
||||||
|
meta.appendChild(badges);
|
||||||
|
|
||||||
const actions = document.createElement('div');
|
const actions = document.createElement('div');
|
||||||
actions.className = 'actions';
|
actions.className = 'actions';
|
||||||
|
|
||||||
@@ -712,6 +712,13 @@ function renderAssetList() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createBadge(label, extraClass = '') {
|
||||||
|
const badge = document.createElement('span');
|
||||||
|
badge.className = `badge ${extraClass}`.trim();
|
||||||
|
badge.textContent = label;
|
||||||
|
return badge;
|
||||||
|
}
|
||||||
|
|
||||||
function createPreviewElement(asset) {
|
function createPreviewElement(asset) {
|
||||||
if (isVideoAsset(asset)) {
|
if (isVideoAsset(asset)) {
|
||||||
const video = document.createElement('video');
|
const video = document.createElement('video');
|
||||||
@@ -744,24 +751,9 @@ function updateSelectedAssetControls(asset = getSelectedAsset()) {
|
|||||||
|
|
||||||
controlsPanel.classList.remove('hidden');
|
controlsPanel.classList.remove('hidden');
|
||||||
lastSizeInputChanged = null;
|
lastSizeInputChanged = null;
|
||||||
selectedAssetName.textContent = asset.name || `Asset ${asset.id.slice(0, 6)}`;
|
|
||||||
if (selectedZLabel) {
|
if (selectedZLabel) {
|
||||||
selectedZLabel.textContent = asset.zIndex ?? 1;
|
selectedZLabel.textContent = asset.zIndex ?? 1;
|
||||||
}
|
}
|
||||||
if (selectedTypeLabel) {
|
|
||||||
selectedTypeLabel.textContent = getDisplayMediaType(asset);
|
|
||||||
}
|
|
||||||
if (selectedVisibilityBadge) {
|
|
||||||
selectedVisibilityBadge.textContent = asset.hidden ? 'Hidden' : 'Visible';
|
|
||||||
selectedVisibilityBadge.classList.toggle('danger', !!asset.hidden);
|
|
||||||
}
|
|
||||||
if (selectedToggleBtn) {
|
|
||||||
const icon = selectedToggleBtn.querySelector('i');
|
|
||||||
if (icon) {
|
|
||||||
icon.className = `fa-solid ${asset.hidden ? 'fa-eye' : 'fa-eye-slash'}`;
|
|
||||||
}
|
|
||||||
selectedToggleBtn.title = asset.hidden ? 'Show asset' : 'Hide asset';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (widthInput) widthInput.value = Math.round(asset.width);
|
if (widthInput) widthInput.value = Math.round(asset.width);
|
||||||
if (heightInput) heightInput.value = Math.round(asset.height);
|
if (heightInput) heightInput.value = Math.round(asset.height);
|
||||||
@@ -925,6 +917,15 @@ function getAssetAspectRatio(asset) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatAspectRatioLabel(asset) {
|
||||||
|
const ratio = getAssetAspectRatio(asset);
|
||||||
|
if (!ratio) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const normalized = ratio >= 1 ? `${ratio.toFixed(2)}:1` : `1:${(1 / ratio).toFixed(2)}`;
|
||||||
|
return `AR ${normalized}`;
|
||||||
|
}
|
||||||
|
|
||||||
function setAspectLock(assetId, locked) {
|
function setAspectLock(assetId, locked) {
|
||||||
aspectLockState.set(assetId, locked);
|
aspectLockState.set(assetId, locked);
|
||||||
}
|
}
|
||||||
@@ -936,7 +937,11 @@ function isAspectLocked(assetId) {
|
|||||||
function handleSizeInputChange(type) {
|
function handleSizeInputChange(type) {
|
||||||
lastSizeInputChanged = type;
|
lastSizeInputChanged = type;
|
||||||
const asset = getSelectedAsset();
|
const asset = getSelectedAsset();
|
||||||
if (!asset || !isAspectLocked(asset.id)) {
|
if (!asset) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isAspectLocked(asset.id)) {
|
||||||
|
commitSizeChange();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const ratio = getAssetAspectRatio(asset);
|
const ratio = getAssetAspectRatio(asset);
|
||||||
@@ -954,6 +959,7 @@ function handleSizeInputChange(type) {
|
|||||||
widthInput.value = Math.round(height * ratio);
|
widthInput.value = Math.round(height * ratio);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
commitSizeChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateVisibility(asset, hidden) {
|
function updateVisibility(asset, hidden) {
|
||||||
|
|||||||
@@ -19,7 +19,11 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<section class="controls">
|
<section class="overlay" id="admin-overlay">
|
||||||
|
<iframe th:src="${'https://player.twitch.tv/?channel=' + broadcaster + '&parent=localhost'}" allowfullscreen></iframe>
|
||||||
|
<canvas id="admin-canvas"></canvas>
|
||||||
|
</section>
|
||||||
|
<section class="controls assets-panel">
|
||||||
<div>
|
<div>
|
||||||
<h3>Overlay assets</h3>
|
<h3>Overlay assets</h3>
|
||||||
<p>Upload overlay visuals and adjust them inline.</p>
|
<p>Upload overlay visuals and adjust them inline.</p>
|
||||||
@@ -28,24 +32,6 @@
|
|||||||
<ul id="asset-list" class="asset-list"></ul>
|
<ul id="asset-list" class="asset-list"></ul>
|
||||||
<div id="asset-controls-placeholder" class="hidden"></div>
|
<div id="asset-controls-placeholder" class="hidden"></div>
|
||||||
<div id="asset-controls" class="panel hidden asset-settings">
|
<div id="asset-controls" class="panel hidden asset-settings">
|
||||||
<div class="panel-header">
|
|
||||||
<h4 id="selected-asset-name">Asset settings</h4>
|
|
||||||
<div class="selected-asset-actions">
|
|
||||||
<button type="button" id="selected-asset-toggle" class="ghost icon-button" title="Toggle visibility">
|
|
||||||
<i class="fa-solid fa-eye" aria-hidden="true"></i>
|
|
||||||
<span class="sr-only">Toggle visibility</span>
|
|
||||||
</button>
|
|
||||||
<button type="button" id="selected-asset-delete" class="ghost danger icon-button" title="Delete asset">
|
|
||||||
<i class="fa-solid fa-trash" aria-hidden="true"></i>
|
|
||||||
<span class="sr-only">Delete asset</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="badge-row stacked">
|
|
||||||
<span class="badge subtle" id="selected-asset-visibility">Visible</span>
|
|
||||||
<span class="badge subtle" id="asset-type-label"></span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel-section">
|
<div class="panel-section">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
<h5>Layout & order</h5>
|
<h5>Layout & order</h5>
|
||||||
@@ -78,6 +64,8 @@
|
|||||||
<button type="button" onclick="bringForward()" class="secondary" title="Move forward"><i class="fa-solid fa-arrow-up"></i></button>
|
<button type="button" onclick="bringForward()" class="secondary" title="Move forward"><i class="fa-solid fa-arrow-up"></i></button>
|
||||||
<button type="button" onclick="bringToFront()" class="secondary" title="Bring to front"><i class="fa-solid fa-angles-up"></i></button>
|
<button type="button" onclick="bringToFront()" class="secondary" title="Bring to front"><i class="fa-solid fa-angles-up"></i></button>
|
||||||
<button type="button" onclick="recenterSelectedAsset()" class="secondary" title="Center on canvas"><i class="fa-solid fa-bullseye"></i></button>
|
<button type="button" onclick="recenterSelectedAsset()" class="secondary" title="Center on canvas"><i class="fa-solid fa-bullseye"></i></button>
|
||||||
|
<button type="button" onclick="nudgeRotation(-5)" class="secondary" title="Rotate left"><i class="fa-solid fa-rotate-left"></i></button>
|
||||||
|
<button type="button" onclick="nudgeRotation(5)" class="secondary" title="Rotate right"><i class="fa-solid fa-rotate-right"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -97,19 +85,9 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="control-actions filled compact">
|
|
||||||
<button type="button" onclick="nudgeRotation(-5)" class="secondary" title="Rotate left"><i class="fa-solid fa-rotate-left"></i></button>
|
|
||||||
<button type="button" onclick="nudgeRotation(5)" class="secondary" title="Rotate right"><i class="fa-solid fa-rotate-right"></i></button>
|
|
||||||
<button type="button" onclick="applyTransformFromInputs()" title="Apply size"><i class="fa-solid fa-floppy-disk"></i><span class="sr-only">Apply size</span></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section class="overlay" id="admin-overlay">
|
|
||||||
<iframe th:src="${'https://player.twitch.tv/?channel=' + broadcaster + '&parent=localhost'}" allowfullscreen></iframe>
|
|
||||||
<canvas id="admin-canvas"></canvas>
|
|
||||||
</section>
|
|
||||||
</div>
|
</div>
|
||||||
<script th:inline="javascript">
|
<script th:inline="javascript">
|
||||||
const broadcaster = /*[[${broadcaster}]]*/ '';
|
const broadcaster = /*[[${broadcaster}]]*/ '';
|
||||||
|
|||||||
Reference in New Issue
Block a user