Improve Web UI with footer, icon buttons, and better modals
Some checks failed
Validate / validate (push) Failing after 7s
Some checks failed
Validate / validate (push) Failing after 7s
- Add footer with author info (name, email, git repository link) - Replace device action buttons with icons to save space: - Start/Stop: ▶️/⏹️, Settings: ⚙️, Calibrate: 📐, Remove: 🗑️ - Added hover tooltips with translated text - Added btn-icon CSS class for compact styling - Replace native browser confirm() with custom modal dialog: - Matches app theme and supports translations - Used for logout and device removal confirmations - Added confirm.title, confirm.yes, confirm.no translations - Disable background scrolling when modals are open: - Added modal-open class to body when any modal opens - Prevents page scroll behind modals for better UX - Applied to all modals: login, settings, calibration, confirmation Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -464,22 +464,22 @@ function createDeviceCard(device) {
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
${isProcessing ? `
|
||||
<button class="btn btn-danger" onclick="stopProcessing('${device.id}')">
|
||||
${t('device.button.stop')}
|
||||
<button class="btn btn-icon btn-danger" onclick="stopProcessing('${device.id}')" title="${t('device.button.stop')}">
|
||||
⏹️
|
||||
</button>
|
||||
` : `
|
||||
<button class="btn btn-primary" onclick="startProcessing('${device.id}')">
|
||||
${t('device.button.start')}
|
||||
<button class="btn btn-icon btn-primary" onclick="startProcessing('${device.id}')" title="${t('device.button.start')}">
|
||||
▶️
|
||||
</button>
|
||||
`}
|
||||
<button class="btn btn-secondary" onclick="showSettings('${device.id}')">
|
||||
${t('device.button.settings')}
|
||||
<button class="btn btn-icon btn-secondary" onclick="showSettings('${device.id}')" title="${t('device.button.settings')}">
|
||||
⚙️
|
||||
</button>
|
||||
<button class="btn btn-secondary" onclick="showCalibration('${device.id}')">
|
||||
${t('device.button.calibrate')}
|
||||
<button class="btn btn-icon btn-secondary" onclick="showCalibration('${device.id}')" title="${t('device.button.calibrate')}">
|
||||
📐
|
||||
</button>
|
||||
<button class="btn btn-danger" onclick="removeDevice('${device.id}')">
|
||||
${t('device.button.remove')}
|
||||
<button class="btn btn-icon btn-danger" onclick="removeDevice('${device.id}')" title="${t('device.button.remove')}">
|
||||
🗑️
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -542,7 +542,8 @@ async function stopProcessing(deviceId) {
|
||||
}
|
||||
|
||||
async function removeDevice(deviceId) {
|
||||
if (!confirm('Are you sure you want to remove this device?')) {
|
||||
const confirmed = await showConfirm(t('device.remove.confirm'));
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -603,6 +604,7 @@ async function showSettings(deviceId) {
|
||||
// Show modal
|
||||
const modal = document.getElementById('device-settings-modal');
|
||||
modal.style.display = 'flex';
|
||||
document.body.classList.add('modal-open');
|
||||
|
||||
// Focus first input
|
||||
setTimeout(() => {
|
||||
@@ -620,6 +622,7 @@ function closeDeviceSettingsModal() {
|
||||
const error = document.getElementById('settings-error');
|
||||
modal.style.display = 'none';
|
||||
error.style.display = 'none';
|
||||
document.body.classList.remove('modal-open');
|
||||
}
|
||||
|
||||
async function saveDeviceSettings() {
|
||||
@@ -742,6 +745,40 @@ function showToast(message, type = 'info') {
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// Confirmation modal
|
||||
let confirmResolve = null;
|
||||
|
||||
function showConfirm(message, title = null) {
|
||||
return new Promise((resolve) => {
|
||||
confirmResolve = resolve;
|
||||
|
||||
const modal = document.getElementById('confirm-modal');
|
||||
const titleEl = document.getElementById('confirm-title');
|
||||
const messageEl = document.getElementById('confirm-message');
|
||||
const yesBtn = document.getElementById('confirm-yes-btn');
|
||||
const noBtn = document.getElementById('confirm-no-btn');
|
||||
|
||||
titleEl.textContent = title || t('confirm.title');
|
||||
messageEl.textContent = message;
|
||||
yesBtn.textContent = t('confirm.yes');
|
||||
noBtn.textContent = t('confirm.no');
|
||||
|
||||
modal.style.display = 'flex';
|
||||
document.body.classList.add('modal-open');
|
||||
});
|
||||
}
|
||||
|
||||
function closeConfirmModal(result) {
|
||||
const modal = document.getElementById('confirm-modal');
|
||||
modal.style.display = 'none';
|
||||
document.body.classList.remove('modal-open');
|
||||
|
||||
if (confirmResolve) {
|
||||
confirmResolve(result);
|
||||
confirmResolve = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Calibration functions
|
||||
async function showCalibration(deviceId) {
|
||||
try {
|
||||
@@ -788,6 +825,7 @@ async function showCalibration(deviceId) {
|
||||
// Show modal
|
||||
const modal = document.getElementById('calibration-modal');
|
||||
modal.style.display = 'flex';
|
||||
document.body.classList.add('modal-open');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to load calibration:', error);
|
||||
@@ -800,6 +838,7 @@ function closeCalibrationModal() {
|
||||
const error = document.getElementById('calibration-error');
|
||||
modal.style.display = 'none';
|
||||
error.style.display = 'none';
|
||||
document.body.classList.remove('modal-open');
|
||||
}
|
||||
|
||||
function updateCalibrationPreview() {
|
||||
|
||||
Reference in New Issue
Block a user