diff --git a/web/constants.js b/web/constants.js
index 441a766..df0d251 100644
--- a/web/constants.js
+++ b/web/constants.js
@@ -1,10 +1,24 @@
export const BUTTON_STYLES = {
- base: "width: 100%; padding: 8px 12px; font-size: 12px; color: white; border: none; border-radius: 4px; cursor: pointer; transition: all 0.2s; font-weight: 500;",
- clearMemory: "background-color: #555;",
- success: "background-color: #3ca03c;",
- error: "background-color: #c04c4c;",
+ // Base styles with unified padding
+ base: "width: 100%; padding: 4px 14px; color: white; border: none; border-radius: 4px; cursor: pointer; transition: all 0.2s; font-size: 12px; font-weight: 500;",
+
+ // Context-specific combined styles
+ workerControl: "flex: 1; font-size: 11px;",
+
+ // Layout modifiers
+ hidden: "display: none;",
+ marginLeftAuto: "margin-left: auto;",
+
+ // Color variants
+ cancel: "background-color: #555;",
+ info: "background-color: #333;",
+ success: "background-color: #4a7c4a;",
+ error: "background-color: #7c4a4a;",
launch: "background-color: #4a7c4a;",
stop: "background-color: #7c4a4a;",
+ log: "background-color: #685434;",
+ clearMemory: "background-color: #555; padding: 6px 14px;",
+ interrupt: "background-color: #555; padding: 6px 14px;",
};
export const STATUS_COLORS = {
@@ -30,22 +44,23 @@ export const PULSE_ANIMATION_CSS = `
@keyframes pulse {
0% {
opacity: 1;
- transform: scale(1);
+ transform: scale(0.8);
box-shadow: 0 0 0 0 rgba(240, 173, 78, 0.7);
}
50% {
opacity: 0.3;
- transform: scale(1.3);
+ transform: scale(1.1);
box-shadow: 0 0 0 6px rgba(240, 173, 78, 0);
}
100% {
opacity: 1;
- transform: scale(1);
+ transform: scale(0.8);
box-shadow: 0 0 0 0 rgba(240, 173, 78, 0);
}
}
.status-pulsing {
animation: pulse 1.2s ease-in-out infinite;
+ transform-origin: center;
}
/* Button hover effects */
diff --git a/web/sidebarRenderer.js b/web/sidebarRenderer.js
index 3187ee4..9fc95a0 100644
--- a/web/sidebarRenderer.js
+++ b/web/sidebarRenderer.js
@@ -24,7 +24,9 @@ export async function renderSidebarContent(extension, el) {
el.innerHTML = '';
const loadingDiv = document.createElement("div");
loadingDiv.style.cssText = "display: flex; align-items: center; justify-content: center; height: calc(100vh - 100px); color: #888;";
- loadingDiv.innerHTML = `
◐
`;
+ loadingDiv.innerHTML = ``;
el.appendChild(loadingDiv);
// Add rotation animation
@@ -36,7 +38,7 @@ export async function renderSidebarContent(extension, el) {
}
`;
document.head.appendChild(style);
- loadingDiv.querySelector('div').style.animation = 'rotate 1s linear infinite';
+ loadingDiv.querySelector('svg').style.animation = 'rotate 1s linear infinite';
// Preload data outside render
await extension.loadConfig();
@@ -128,15 +130,15 @@ export async function renderSidebarContent(extension, el) {
BUTTON_STYLES.clearMemory
);
clearMemButton.title = "Clear VRAM on all enabled worker GPUs (not master)";
- clearMemButton.style.cssText += " flex: 1;";
+ clearMemButton.style.cssText = BUTTON_STYLES.base + " flex: 1;" + BUTTON_STYLES.clearMemory;
const interruptButton = extension.ui.createButtonHelper(
"Interrupt Workers",
(e) => extension._handleInterruptWorkers(e.target),
- BUTTON_STYLES.clearMemory
+ BUTTON_STYLES.interrupt
);
interruptButton.title = "Cancel/interrupt execution on all enabled worker GPUs";
- interruptButton.style.cssText += " flex: 1;";
+ interruptButton.style.cssText = BUTTON_STYLES.base + " flex: 1;" + BUTTON_STYLES.interrupt;
buttonRow.appendChild(clearMemButton);
buttonRow.appendChild(interruptButton);
diff --git a/web/ui.js b/web/ui.js
index 24f0808..de41240 100644
--- a/web/ui.js
+++ b/web/ui.js
@@ -591,17 +591,17 @@ export class DistributedUI {
const saveBtn = this.createButton("Save",
() => extension.saveWorkerSettings(worker.id),
"background-color: #4a7c4a;");
- saveBtn.style.cssText += " padding: 6px 14px; font-size: 12px; font-weight: 500;";
+ saveBtn.style.cssText = BUTTON_STYLES.base + BUTTON_STYLES.success;
const cancelBtn = this.createButton("Cancel",
() => extension.cancelWorkerSettings(worker.id),
"background-color: #555;");
- cancelBtn.style.cssText += " padding: 6px 14px; font-size: 12px; font-weight: 500;";
+ cancelBtn.style.cssText = BUTTON_STYLES.base + BUTTON_STYLES.cancel;
const deleteBtn = this.createButton("Delete",
() => extension.deleteWorker(worker.id),
"background-color: #7c4a4a;");
- deleteBtn.style.cssText += " padding: 6px 14px; font-size: 12px; font-weight: 500; margin-left: auto;";
+ deleteBtn.style.cssText = BUTTON_STYLES.base + BUTTON_STYLES.error + BUTTON_STYLES.marginLeftAuto;
const buttonGroup = this.createButtonGroup([saveBtn, cancelBtn, deleteBtn], " margin-top: 8px;");
form.appendChild(buttonGroup);
@@ -728,8 +728,8 @@ export class DistributedUI {
if (config.dynamic && data) {
if (isRemote) {
- const remoteInfo = this.createButton("Remote worker", null, "background-color: #333;");
- remoteInfo.style.cssText += " flex: 1; padding: 5px 14px; font-size: 11px; font-weight: 500; color: #999; cursor: default;";
+ const remoteInfo = this.createButton("Remote worker", null, BUTTON_STYLES.info);
+ remoteInfo.style.cssText = BUTTON_STYLES.base + BUTTON_STYLES.workerControl + BUTTON_STYLES.info + " color: #999; cursor: default;";
remoteInfo.disabled = true;
controlsWrapper.appendChild(remoteInfo);
} else {
@@ -743,13 +743,13 @@ export class DistributedUI {
const stopBtn = controls.querySelector(`#stop-${data.id}`);
const logBtn = controls.querySelector(`#log-${data.id}`);
- launchBtn.style.cssText += ` flex: 1; padding: 5px 14px; font-size: 11px; font-weight: 500; ${BUTTON_STYLES.launch}`;
+ launchBtn.style.cssText = BUTTON_STYLES.base + BUTTON_STYLES.workerControl + BUTTON_STYLES.launch;
launchBtn.title = "Launch worker (runs in background with logging)";
- stopBtn.style.cssText += ` flex: 1; padding: 5px 14px; font-size: 11px; font-weight: 500; ${BUTTON_STYLES.stop} display: none;`;
+ stopBtn.style.cssText = BUTTON_STYLES.base + BUTTON_STYLES.workerControl + BUTTON_STYLES.stop + BUTTON_STYLES.hidden;
stopBtn.title = "Stop worker";
- logBtn.style.cssText += ' flex: 1; padding: 5px 14px; font-size: 11px; font-weight: 500; display: none; background-color: #685434;';
+ logBtn.style.cssText = BUTTON_STYLES.base + BUTTON_STYLES.workerControl + BUTTON_STYLES.log + BUTTON_STYLES.hidden;
while (controls.firstChild) {
controlsWrapper.appendChild(controls.firstChild);
@@ -757,7 +757,7 @@ export class DistributedUI {
}
} else if (config.type === 'info') {
const infoBtn = this.createButton(config.text, null, config.style || "");
- infoBtn.style.cssText += " flex: 1; padding: 5px 14px; font-size: 11px; font-weight: 500; cursor: default;";
+ infoBtn.style.cssText = BUTTON_STYLES.base + BUTTON_STYLES.workerControl + (config.style || BUTTON_STYLES.info) + " cursor: default;";
infoBtn.disabled = true;
controlsWrapper.appendChild(infoBtn);
} else if (config.type === 'ghost') {
@@ -860,13 +860,13 @@ export class DistributedUI {
saveBtn.textContent = "Saved!";
setTimeout(() => { saveBtn.textContent = "Save"; }, TIMEOUTS.FLASH_LONG);
}, "background-color: #4a7c4a;");
- saveBtn.style.cssText += " padding: 6px 12px; font-size: 12px;";
+ saveBtn.style.cssText = BUTTON_STYLES.base + BUTTON_STYLES.success;
const cancelBtn = this.createButton("Cancel", () => {
document.getElementById('master-name').value = extension.config?.master?.name || "Master";
document.getElementById('master-host').value = extension.config?.master?.host || "";
}, "background-color: #555;");
- cancelBtn.style.cssText += " padding: 6px 12px; font-size: 12px;";
+ cancelBtn.style.cssText = BUTTON_STYLES.base + BUTTON_STYLES.cancel;
const buttonGroup = this.createButtonGroup([saveBtn, cancelBtn], " margin-top: 8px;");
settingsForm.appendChild(buttonGroup);