mirror of
https://github.com/imgfloat/server.git
synced 2026-02-05 03:39:26 +00:00
Improve visibility
This commit is contained in:
@@ -122,6 +122,12 @@ body {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.ghost {
|
||||
background: transparent;
|
||||
border: 1px solid #2d3a57;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.secondary {
|
||||
background: #475569;
|
||||
}
|
||||
@@ -176,6 +182,12 @@ body {
|
||||
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 {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
@@ -475,6 +487,29 @@ body {
|
||||
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 {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
@@ -560,6 +595,38 @@ body {
|
||||
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 {
|
||||
opacity: 0.6;
|
||||
}
|
||||
@@ -602,6 +669,27 @@ body {
|
||||
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 {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
@@ -27,12 +27,29 @@ const selectedAssetName = document.getElementById('selected-asset-name');
|
||||
const selectedAssetMeta = document.getElementById('selected-asset-meta');
|
||||
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 aspectLockState = new Map();
|
||||
|
||||
if (widthInput) widthInput.addEventListener('input', () => handleSizeInputChange('width'));
|
||||
if (heightInput) heightInput.addEventListener('input', () => handleSizeInputChange('height'));
|
||||
if (speedInput) speedInput.addEventListener('change', updatePlaybackFromInputs);
|
||||
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() {
|
||||
const socket = new SockJS('/ws');
|
||||
@@ -599,8 +616,8 @@ function renderAssetList() {
|
||||
|
||||
const toggleBtn = document.createElement('button');
|
||||
toggleBtn.type = 'button';
|
||||
toggleBtn.className = 'secondary';
|
||||
toggleBtn.textContent = asset.hidden ? 'Show' : 'Hide';
|
||||
toggleBtn.className = 'ghost icon-button';
|
||||
toggleBtn.innerHTML = `<span class="icon" aria-hidden="true">${asset.hidden ? '👁️' : '🙈'}</span><span class="label">${asset.hidden ? 'Show' : 'Hide'}</span>`;
|
||||
toggleBtn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
selectedAssetId = asset.id;
|
||||
@@ -609,8 +626,8 @@ function renderAssetList() {
|
||||
|
||||
const deleteBtn = document.createElement('button');
|
||||
deleteBtn.type = 'button';
|
||||
deleteBtn.className = 'secondary';
|
||||
deleteBtn.textContent = 'Delete';
|
||||
deleteBtn.className = 'ghost danger icon-button';
|
||||
deleteBtn.innerHTML = '<span class="icon" aria-hidden="true">🗑️</span><span class="label">Delete</span>';
|
||||
deleteBtn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
deleteAsset(asset);
|
||||
@@ -678,6 +695,14 @@ function updateSelectedAssetControls() {
|
||||
if (selectedTypeLabel) {
|
||||
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 (heightInput) heightInput.value = Math.round(asset.height);
|
||||
@@ -686,7 +711,7 @@ function updateSelectedAssetControls() {
|
||||
aspectLockInput.onchange = () => setAspectLock(asset.id, aspectLockInput.checked);
|
||||
}
|
||||
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) {
|
||||
muteInput.checked = !!asset.muted;
|
||||
@@ -723,8 +748,8 @@ function applyTransformFromInputs() {
|
||||
function updatePlaybackFromInputs() {
|
||||
const asset = getSelectedAsset();
|
||||
if (!asset) return;
|
||||
const nextSpeed = Math.max(0.1, parseFloat(speedInput?.value) || asset.speed || 1);
|
||||
asset.speed = nextSpeed;
|
||||
const percent = Math.max(10, Math.min(400, parseFloat(speedInput?.value) || 100));
|
||||
asset.speed = percent / 100;
|
||||
renderStates.set(asset.id, { ...asset });
|
||||
persistTransform(asset);
|
||||
drawAndList();
|
||||
|
||||
@@ -27,12 +27,25 @@
|
||||
<ul id="asset-list" class="asset-list"></ul>
|
||||
<div id="asset-controls" class="panel hidden asset-settings">
|
||||
<div class="panel-header">
|
||||
<div>
|
||||
<p class="eyebrow subtle">Asset settings</p>
|
||||
<div class="title-row">
|
||||
<h4 id="selected-asset-name">Selected asset</h4>
|
||||
<div class="selected-asset-banner">
|
||||
<div class="selected-asset-main">
|
||||
<p class="eyebrow subtle">Asset settings</p>
|
||||
<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>
|
||||
<p class="muted meta-text" id="selected-asset-meta"></p>
|
||||
</div>
|
||||
<div class="panel-summary">
|
||||
<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">
|
||||
<label>
|
||||
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>
|
||||
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 class="checkbox-inline">
|
||||
<input id="maintain-aspect" type="checkbox" checked />
|
||||
@@ -68,8 +81,8 @@
|
||||
</div>
|
||||
<div class="control-grid condensed">
|
||||
<label>
|
||||
Animation speed
|
||||
<input id="asset-speed" type="number" min="0.1" step="0.1" value="1" />
|
||||
Animation speed (% of original)
|
||||
<input id="asset-speed" class="number-input" type="number" min="10" max="400" step="5" value="100" />
|
||||
</label>
|
||||
<label class="checkbox-inline">
|
||||
<input id="asset-muted" type="checkbox" />
|
||||
|
||||
Reference in New Issue
Block a user