ui: replace inline state styles with css classes
This commit is contained in:
@@ -2,18 +2,18 @@
|
|||||||
|
|
||||||
## Current
|
## Current
|
||||||
|
|
||||||
### `feat/frontend-css-state-cleanup`
|
### `feat/frontend-performance-polish`
|
||||||
|
|
||||||
Status: in_progress
|
Status: in_progress
|
||||||
|
|
||||||
DoD:
|
DoD:
|
||||||
- button and control state visuals move from inline `element.style` mutations into CSS classes
|
- repeated O(n) filtering in hot render paths is removed
|
||||||
- wizard navigation and similar interactive UI use semantic state classes instead of manual style strings
|
- tab counts and similar derived UI metrics use cached/derived snapshots instead of recomputing the same filters
|
||||||
- existing UI e2e coverage stays green after the CSS-state cleanup
|
- existing UI e2e coverage stays green after the performance polish
|
||||||
|
|
||||||
## Next
|
## Next
|
||||||
|
|
||||||
- `feat/frontend-performance-polish`
|
- `feat/frontend-observability-and-testability`
|
||||||
|
|
||||||
## Backlog
|
## Backlog
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,19 @@
|
|||||||
box-shadow: 0 0 0 3px var(--accent-ring);
|
box-shadow: 0 0 0 3px var(--accent-ring);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-primary:disabled,
|
||||||
|
.btn-primary.is-disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:disabled:hover,
|
||||||
|
.btn-primary.is-disabled:hover {
|
||||||
|
background: var(--accent);
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
.btn-secondary {
|
.btn-secondary {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -989,6 +989,17 @@
|
|||||||
border-color: var(--bg-muted);
|
border-color: var(--bg-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-back:disabled {
|
||||||
|
opacity: 0.35;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-back:disabled:hover {
|
||||||
|
background: var(--bg-overlay);
|
||||||
|
color: var(--text-secondary);
|
||||||
|
border-color: var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
.btn-save-draft {
|
.btn-save-draft {
|
||||||
background: none;
|
background: none;
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
@@ -1044,6 +1055,20 @@
|
|||||||
box-shadow: 0 1px 4px rgba(13, 148, 136, 0.3);
|
box-shadow: 0 1px 4px rgba(13, 148, 136, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-continue.is-final-step {
|
||||||
|
background: #3fb950;
|
||||||
|
border-color: #2ea043;
|
||||||
|
box-shadow: 0 1px 4px rgba(63, 185, 80, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-continue.is-final-step:hover {
|
||||||
|
background: #2ea043;
|
||||||
|
border-color: transparent;
|
||||||
|
box-shadow:
|
||||||
|
0 2px 10px rgba(63, 185, 80, 0.45),
|
||||||
|
0 0 0 3px rgba(63, 185, 80, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Code editor ── */
|
/* ── Code editor ── */
|
||||||
.code-block {
|
.code-block {
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
|
|||||||
@@ -203,6 +203,11 @@
|
|||||||
gap: 10px;
|
gap: 10px;
|
||||||
margin-top: 24px;
|
margin-top: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ws-submit-btn {
|
||||||
|
padding: 9px 22px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
.ws-setup-footer-note {
|
.ws-setup-footer-note {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
|
|||||||
@@ -201,7 +201,7 @@
|
|||||||
<div class="action-bar" role="toolbar" aria-label="Wizard navigation">
|
<div class="action-bar" role="toolbar" aria-label="Wizard navigation">
|
||||||
<div class="action-bar-inner">
|
<div class="action-bar-inner">
|
||||||
|
|
||||||
<button class="btn btn-back" type="button" disabled style="opacity: 0.35; cursor: not-allowed;">
|
<button class="btn btn-back" type="button" disabled>
|
||||||
<svg width="13" height="13" viewBox="0 0 16 16" fill="currentColor">
|
<svg width="13" height="13" viewBox="0 0 16 16" fill="currentColor">
|
||||||
<path d="M9.78 12.78a.75.75 0 01-1.06 0L4.47 8.53a.75.75 0 010-1.06l4.25-4.25a.75.75 0 011.06 1.06L6.06 8l3.72 3.72a.75.75 0 010 1.06z"/>
|
<path d="M9.78 12.78a.75.75 0 01-1.06 0L4.47 8.53a.75.75 0 010-1.06l4.25-4.25a.75.75 0 011.06 1.06L6.06 8l3.72 3.72a.75.75 0 010 1.06z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
@@ -286,7 +286,7 @@
|
|||||||
<!-- ── Actions ── -->
|
<!-- ── Actions ── -->
|
||||||
<div class="ws-setup-actions">
|
<div class="ws-setup-actions">
|
||||||
<a href="javascript:history.back()" class="btn-ghost-sm" style="padding:9px 18px;font-size:13px;text-decoration:none;color:var(--text-secondary);" data-i18n="btn.cancel">Cancel</a>
|
<a href="javascript:history.back()" class="btn-ghost-sm" style="padding:9px 18px;font-size:13px;text-decoration:none;color:var(--text-secondary);" data-i18n="btn.cancel">Cancel</a>
|
||||||
<button class="btn-primary" id="submit-btn" type="button" onclick="submitForm()" style="padding:9px 22px;font-size:13px;" data-i18n="workspace_setup.actions.save">Save changes</button>
|
<button class="btn-primary ws-submit-btn" id="submit-btn" type="button" onclick="submitForm()" data-i18n="workspace_setup.actions.save">Save changes</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ws-setup-footer-note" id="footer-note" style="display:none;">
|
<div class="ws-setup-footer-note" id="footer-note" style="display:none;">
|
||||||
|
|||||||
@@ -84,15 +84,7 @@
|
|||||||
|
|
||||||
var backButton = document.querySelector('.btn-back');
|
var backButton = document.querySelector('.btn-back');
|
||||||
if (backButton) {
|
if (backButton) {
|
||||||
if (step === 1) {
|
backButton.disabled = step === 1;
|
||||||
backButton.disabled = true;
|
|
||||||
backButton.style.opacity = '0.35';
|
|
||||||
backButton.style.cursor = 'not-allowed';
|
|
||||||
} else {
|
|
||||||
backButton.disabled = false;
|
|
||||||
backButton.style.opacity = '';
|
|
||||||
backButton.style.cursor = '';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var continueButton = document.querySelector('.btn-continue');
|
var continueButton = document.querySelector('.btn-continue');
|
||||||
@@ -100,10 +92,10 @@
|
|||||||
if (step === TOTAL_STEPS) {
|
if (step === TOTAL_STEPS) {
|
||||||
var finalLabel = window.wizardMode === 'edit' ? tKey('wizard.button.save_changes') : tKey('wizard.button.create');
|
var finalLabel = window.wizardMode === 'edit' ? tKey('wizard.button.save_changes') : tKey('wizard.button.create');
|
||||||
continueButton.innerHTML = finalLabel + ' ' + ARROW_SVG;
|
continueButton.innerHTML = finalLabel + ' ' + ARROW_SVG;
|
||||||
continueButton.style.cssText = 'background:#3fb950;border-color:#2ea043;box-shadow:0 1px 4px rgba(63,185,80,0.4);';
|
continueButton.classList.add('is-final-step');
|
||||||
} else {
|
} else {
|
||||||
continueButton.innerHTML = tKey('wizard.button.continue') + ' ' + ARROW_SVG;
|
continueButton.innerHTML = tKey('wizard.button.continue') + ' ' + ARROW_SVG;
|
||||||
continueButton.style.cssText = '';
|
continueButton.classList.remove('is-final-step');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -231,12 +231,12 @@ function updatePageMode() {
|
|||||||
document.getElementById('footer-note').style.display = '';
|
document.getElementById('footer-note').style.display = '';
|
||||||
submit.textContent = tKey('workspace_setup.actions.create');
|
submit.textContent = tKey('workspace_setup.actions.create');
|
||||||
submit.disabled = true;
|
submit.disabled = true;
|
||||||
submit.style.opacity = '0.5';
|
submit.classList.add('is-disabled');
|
||||||
submit.style.cursor = 'not-allowed';
|
|
||||||
} else {
|
} else {
|
||||||
document.getElementById('section-members').style.display = '';
|
document.getElementById('section-members').style.display = '';
|
||||||
document.getElementById('section-danger').style.display = '';
|
document.getElementById('section-danger').style.display = '';
|
||||||
submit.textContent = tKey('workspace_setup.actions.save');
|
submit.textContent = tKey('workspace_setup.actions.save');
|
||||||
|
submit.classList.remove('is-disabled');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,8 +276,7 @@ function validateCreateForm() {
|
|||||||
var elements = formElements();
|
var elements = formElements();
|
||||||
var valid = Boolean(elements.name.value.trim() && elements.slug.value.trim());
|
var valid = Boolean(elements.name.value.trim() && elements.slug.value.trim());
|
||||||
elements.submit.disabled = !valid;
|
elements.submit.disabled = !valid;
|
||||||
elements.submit.style.opacity = valid ? '1' : '0.5';
|
elements.submit.classList.toggle('is-disabled', !valid);
|
||||||
elements.submit.style.cursor = valid ? 'pointer' : 'not-allowed';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function inviteRows() {
|
function inviteRows() {
|
||||||
|
|||||||
Reference in New Issue
Block a user