mirror of
https://github.com/imgfloat/server.git
synced 2026-02-05 11:49:25 +00:00
Improve visibility
This commit is contained in:
@@ -122,6 +122,12 @@ body {
|
|||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ghost {
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid #2d3a57;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
.secondary {
|
.secondary {
|
||||||
background: #475569;
|
background: #475569;
|
||||||
}
|
}
|
||||||
@@ -176,6 +182,12 @@ body {
|
|||||||
border-color: rgba(148, 163, 184, 0.2);
|
border-color: rgba(148, 163, 184, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.badge.danger {
|
||||||
|
background: rgba(248, 113, 113, 0.12);
|
||||||
|
color: #fecdd3;
|
||||||
|
border-color: rgba(248, 113, 113, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
.badge-row {
|
.badge-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
@@ -475,6 +487,29 @@ body {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.selected-asset-banner {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 14px;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: linear-gradient(135deg, rgba(124, 58, 237, 0.08), rgba(59, 130, 246, 0.05));
|
||||||
|
border: 1px solid rgba(124, 58, 237, 0.2);
|
||||||
|
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-asset-main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-asset-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.panel ul {
|
.panel ul {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -560,6 +595,38 @@ body {
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-button {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 8px 10px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid rgba(148, 163, 184, 0.25);
|
||||||
|
background: rgba(255, 255, 255, 0.04);
|
||||||
|
color: #e2e8f0;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button .icon {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button:hover {
|
||||||
|
border-color: rgba(124, 58, 237, 0.4);
|
||||||
|
box-shadow: 0 5px 18px rgba(0, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button.danger {
|
||||||
|
border-color: rgba(248, 113, 113, 0.35);
|
||||||
|
color: #fecdd3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button.danger:hover {
|
||||||
|
border-color: rgba(248, 113, 113, 0.6);
|
||||||
|
background: rgba(248, 113, 113, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
.asset-item.hidden {
|
.asset-item.hidden {
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
@@ -602,6 +669,27 @@ body {
|
|||||||
color: #e2e8f0;
|
color: #e2e8f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.number-input {
|
||||||
|
position: relative;
|
||||||
|
padding-right: 48px !important;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
|
||||||
|
.number-input::-webkit-outer-spin-button,
|
||||||
|
.number-input::-webkit-inner-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.number-input {
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
}
|
||||||
|
|
||||||
|
.number-input:focus {
|
||||||
|
border-color: #7c3aed;
|
||||||
|
box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
.control-actions {
|
.control-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
|||||||
@@ -27,12 +27,29 @@ const selectedAssetName = document.getElementById('selected-asset-name');
|
|||||||
const selectedAssetMeta = document.getElementById('selected-asset-meta');
|
const selectedAssetMeta = document.getElementById('selected-asset-meta');
|
||||||
const selectedZLabel = document.getElementById('asset-z-level');
|
const selectedZLabel = document.getElementById('asset-z-level');
|
||||||
const selectedTypeLabel = document.getElementById('asset-type-label');
|
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 aspectLockState = new Map();
|
const aspectLockState = new Map();
|
||||||
|
|
||||||
if (widthInput) widthInput.addEventListener('input', () => handleSizeInputChange('width'));
|
if (widthInput) widthInput.addEventListener('input', () => handleSizeInputChange('width'));
|
||||||
if (heightInput) heightInput.addEventListener('input', () => handleSizeInputChange('height'));
|
if (heightInput) heightInput.addEventListener('input', () => handleSizeInputChange('height'));
|
||||||
if (speedInput) speedInput.addEventListener('change', updatePlaybackFromInputs);
|
if (speedInput) speedInput.addEventListener('change', 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');
|
||||||
@@ -599,8 +616,8 @@ function renderAssetList() {
|
|||||||
|
|
||||||
const toggleBtn = document.createElement('button');
|
const toggleBtn = document.createElement('button');
|
||||||
toggleBtn.type = 'button';
|
toggleBtn.type = 'button';
|
||||||
toggleBtn.className = 'secondary';
|
toggleBtn.className = 'ghost icon-button';
|
||||||
toggleBtn.textContent = asset.hidden ? 'Show' : 'Hide';
|
toggleBtn.innerHTML = `<span class="icon" aria-hidden="true">${asset.hidden ? '👁️' : '🙈'}</span><span class="label">${asset.hidden ? 'Show' : 'Hide'}</span>`;
|
||||||
toggleBtn.addEventListener('click', (e) => {
|
toggleBtn.addEventListener('click', (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
selectedAssetId = asset.id;
|
selectedAssetId = asset.id;
|
||||||
@@ -609,8 +626,8 @@ function renderAssetList() {
|
|||||||
|
|
||||||
const deleteBtn = document.createElement('button');
|
const deleteBtn = document.createElement('button');
|
||||||
deleteBtn.type = 'button';
|
deleteBtn.type = 'button';
|
||||||
deleteBtn.className = 'secondary';
|
deleteBtn.className = 'ghost danger icon-button';
|
||||||
deleteBtn.textContent = 'Delete';
|
deleteBtn.innerHTML = '<span class="icon" aria-hidden="true">🗑️</span><span class="label">Delete</span>';
|
||||||
deleteBtn.addEventListener('click', (e) => {
|
deleteBtn.addEventListener('click', (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
deleteAsset(asset);
|
deleteAsset(asset);
|
||||||
@@ -678,6 +695,14 @@ function updateSelectedAssetControls() {
|
|||||||
if (selectedTypeLabel) {
|
if (selectedTypeLabel) {
|
||||||
selectedTypeLabel.textContent = getDisplayMediaType(asset);
|
selectedTypeLabel.textContent = getDisplayMediaType(asset);
|
||||||
}
|
}
|
||||||
|
if (selectedVisibilityBadge) {
|
||||||
|
selectedVisibilityBadge.textContent = asset.hidden ? 'Hidden' : 'Visible';
|
||||||
|
selectedVisibilityBadge.classList.toggle('danger', !!asset.hidden);
|
||||||
|
}
|
||||||
|
if (selectedToggleBtn) {
|
||||||
|
selectedToggleBtn.querySelector('.label').textContent = asset.hidden ? 'Show' : 'Hide';
|
||||||
|
selectedToggleBtn.querySelector('.icon').textContent = asset.hidden ? '👁️' : '🙈';
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
@@ -686,7 +711,7 @@ function updateSelectedAssetControls() {
|
|||||||
aspectLockInput.onchange = () => setAspectLock(asset.id, aspectLockInput.checked);
|
aspectLockInput.onchange = () => setAspectLock(asset.id, aspectLockInput.checked);
|
||||||
}
|
}
|
||||||
if (speedInput) {
|
if (speedInput) {
|
||||||
speedInput.value = Math.round((asset.speed && asset.speed > 0 ? asset.speed : 1) * 100) / 100;
|
speedInput.value = Math.round((asset.speed && asset.speed > 0 ? asset.speed : 1) * 100);
|
||||||
}
|
}
|
||||||
if (muteInput) {
|
if (muteInput) {
|
||||||
muteInput.checked = !!asset.muted;
|
muteInput.checked = !!asset.muted;
|
||||||
@@ -723,8 +748,8 @@ function applyTransformFromInputs() {
|
|||||||
function updatePlaybackFromInputs() {
|
function updatePlaybackFromInputs() {
|
||||||
const asset = getSelectedAsset();
|
const asset = getSelectedAsset();
|
||||||
if (!asset) return;
|
if (!asset) return;
|
||||||
const nextSpeed = Math.max(0.1, parseFloat(speedInput?.value) || asset.speed || 1);
|
const percent = Math.max(10, Math.min(400, parseFloat(speedInput?.value) || 100));
|
||||||
asset.speed = nextSpeed;
|
asset.speed = percent / 100;
|
||||||
renderStates.set(asset.id, { ...asset });
|
renderStates.set(asset.id, { ...asset });
|
||||||
persistTransform(asset);
|
persistTransform(asset);
|
||||||
drawAndList();
|
drawAndList();
|
||||||
|
|||||||
@@ -27,12 +27,25 @@
|
|||||||
<ul id="asset-list" class="asset-list"></ul>
|
<ul id="asset-list" class="asset-list"></ul>
|
||||||
<div id="asset-controls" class="panel hidden asset-settings">
|
<div id="asset-controls" class="panel hidden asset-settings">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<div>
|
<div class="selected-asset-banner">
|
||||||
<p class="eyebrow subtle">Asset settings</p>
|
<div class="selected-asset-main">
|
||||||
<div class="title-row">
|
<p class="eyebrow subtle">Asset settings</p>
|
||||||
<h4 id="selected-asset-name">Selected asset</h4>
|
<div class="title-row">
|
||||||
|
<h4 id="selected-asset-name">Selected asset</h4>
|
||||||
|
<span class="badge subtle" id="selected-asset-visibility">Visible</span>
|
||||||
|
</div>
|
||||||
|
<p class="muted meta-text" id="selected-asset-meta"></p>
|
||||||
|
</div>
|
||||||
|
<div class="selected-asset-actions">
|
||||||
|
<button type="button" id="selected-asset-toggle" class="ghost icon-button" title="Toggle visibility">
|
||||||
|
<span class="icon" aria-hidden="true">🙈</span>
|
||||||
|
<span class="label">Hide</span>
|
||||||
|
</button>
|
||||||
|
<button type="button" id="selected-asset-delete" class="ghost danger icon-button" title="Delete asset">
|
||||||
|
<span class="icon" aria-hidden="true">🗑️</span>
|
||||||
|
<span class="label">Delete</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="muted meta-text" id="selected-asset-meta"></p>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-summary">
|
<div class="panel-summary">
|
||||||
<p class="muted">Fine-tune the selected overlay item with sizing, playback, and layering controls.</p>
|
<p class="muted">Fine-tune the selected overlay item with sizing, playback, and layering controls.</p>
|
||||||
@@ -47,11 +60,11 @@
|
|||||||
<div class="control-grid condensed">
|
<div class="control-grid condensed">
|
||||||
<label>
|
<label>
|
||||||
Width
|
Width
|
||||||
<input id="asset-width" type="number" min="10" step="5" />
|
<input id="asset-width" class="number-input" type="number" min="10" step="5" />
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
Height
|
Height
|
||||||
<input id="asset-height" type="number" min="10" step="5" />
|
<input id="asset-height" class="number-input" type="number" min="10" step="5" />
|
||||||
</label>
|
</label>
|
||||||
<label class="checkbox-inline">
|
<label class="checkbox-inline">
|
||||||
<input id="maintain-aspect" type="checkbox" checked />
|
<input id="maintain-aspect" type="checkbox" checked />
|
||||||
@@ -68,8 +81,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="control-grid condensed">
|
<div class="control-grid condensed">
|
||||||
<label>
|
<label>
|
||||||
Animation speed
|
Animation speed (% of original)
|
||||||
<input id="asset-speed" type="number" min="0.1" step="0.1" value="1" />
|
<input id="asset-speed" class="number-input" type="number" min="10" max="400" step="5" value="100" />
|
||||||
</label>
|
</label>
|
||||||
<label class="checkbox-inline">
|
<label class="checkbox-inline">
|
||||||
<input id="asset-muted" type="checkbox" />
|
<input id="asset-muted" type="checkbox" />
|
||||||
|
|||||||
Reference in New Issue
Block a user