Feat v0.6.11 CSS deduplication (#46)
Some checks failed
CI/CD / detect-changes (pull_request) Successful in 4s
CI/CD / test-sqlite (pull_request) Has been cancelled
CI/CD / build-and-deploy (pull_request) Has been cancelled
CI/CD / test-go-pg (pull_request) Has been cancelled
CI/CD / test-frontend (pull_request) Has been cancelled

Retire old primitives.css button/toast/popup-menu/dropdown/tabs systems.
sw-primitives.css is now the single source of truth.

- Migrate 29 files from .btn-* to .sw-btn .sw-btn--{variant} .sw-btn--{size}
- Delete old toast, popup-menu, dropdown, tabs CSS (no JS references)
- Resolve .sw-dropdown and .sw-tabs class name collisions
- Resolve .settings-section duplicate (modals.css removed, surfaces.css authoritative)
- Add .sw-btn--success variant, --bg-active CSS variable
- Fix sdk-test-runner wrong variable names, icd-test-runner button fallbacks
- Add scripts/audit-css-collisions.sh

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-01 11:17:40 +00:00
parent ca3f845c34
commit e199777093
44 changed files with 311 additions and 317 deletions

View File

@@ -343,8 +343,8 @@
(ch.description ? '<div style="font-size:12px;color:var(--text-2);margin-bottom:8px;"><strong>Description:</strong> ' + (typeof esc === 'function' ? esc(ch.description) : ch.description) + '</div>' : '') +
(ch.created_at ? '<div style="font-size:12px;color:var(--text-3);margin-bottom:16px;">Created: ' + new Date(ch.created_at).toLocaleString() + '</div>' : '') +
'<div style="display:flex;justify-content:flex-end;gap:8px;">' +
'<button class="btn-small" id="dashDetailClose">Close</button>' +
'<button class="btn-small btn-primary" id="dashDetailOpen">Open Chat</button>' +
'<button class="sw-btn sw-btn--secondary sw-btn--sm" id="dashDetailClose">Close</button>' +
'<button class="sw-btn sw-btn--primary sw-btn--sm" id="dashDetailOpen">Open Chat</button>' +
'</div>';
modal.appendChild(box);

View File

@@ -509,7 +509,7 @@
border-bottom: 1px solid var(--border, #2a2a2e);
}
.surface-editor .notes-toolbar .btn-small {
.surface-editor .notes-toolbar .sw-btn--sm {
font-size: 11px;
padding: 3px 6px;
}

View File

@@ -447,11 +447,4 @@
color: var(--text-3);
}
.btn-danger {
background: var(--danger, #e53e3e);
color: #fff;
border: none;
}
.btn-danger:hover {
opacity: 0.9;
}
/* git-board danger button override — uses kernel .sw-btn--danger */

View File

@@ -168,7 +168,7 @@
onSelect=${function (o, r) { setOwner(o); setRepo(r); }} />
</div>
<div class="gb-header__right">
<button class="btn-small" onClick=${loadBoard} disabled=${loading}>
<button class="sw-btn sw-btn--secondary sw-btn--sm" onClick=${loadBoard} disabled=${loading}>
${loading ? '↻' : 'Refresh'}
</button>
</div>
@@ -196,7 +196,7 @@
<p>Ask your admin to add a <strong>Gitea</strong> connection in
<strong>Admin → Connections</strong>, or add a personal one in
<strong>Settings → Connections</strong>.</p>
<button class="btn-small btn-primary"
<button class="sw-btn sw-btn--primary sw-btn--sm"
onClick=${function () { window.location.href = base + '/settings'; }}>
Open Settings
</button>
@@ -449,11 +449,11 @@
if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) postComment();
}} />
<div class="gb-modal__actions">
<button class="btn-small btn-primary" disabled=${posting || !comment.trim()}
<button class="sw-btn sw-btn--primary sw-btn--sm" disabled=${posting || !comment.trim()}
onClick=${postComment}>
${posting ? 'Posting…' : 'Comment'}
</button>
<button class="btn-small ${issue.state === 'open' ? 'btn-danger' : 'btn-secondary'}"
<button class="sw-btn sw-btn--secondary sw-btn--sm ${issue.state === 'open' ? 'sw-btn sw-btn--danger sw-btn--md' : 'sw-btn sw-btn--secondary sw-btn--md'}"
onClick=${toggleState}>
${issue.state === 'open' ? 'Close Issue' : 'Reopen Issue'}
</button>

View File

@@ -34,8 +34,8 @@
'Registered via surface manifest', '') +
'</div>' +
'<div class="hello-actions">' +
'<button class="btn-primary" id="helloToast">Show Toast</button>' +
'<button class="btn-secondary" id="helloApi">Test API</button>' +
'<button class="sw-btn sw-btn--primary sw-btn--md" id="helloToast">Show Toast</button>' +
'<button class="sw-btn sw-btn--secondary sw-btn--md" id="helloApi">Test API</button>' +
'</div>' +
'<pre class="hello-manifest">' + esc(JSON.stringify(manifest, null, 2)) + '</pre>' +
'</div>';

View File

@@ -26,45 +26,9 @@
background: var(--bg-hover) !important;
}
/* Buttons — override small padding for our use */
#extension-mount .btn-primary,
#extension-mount .btn-secondary,
#extension-mount .btn-ghost {
font-size: 13px;
padding: 7px 16px;
border-radius: var(--radius, 8px);
cursor: pointer;
font-family: var(--font, 'DM Sans', sans-serif);
/* Buttons — uses kernel sw-btn system, minor overrides for weight */
#extension-mount .sw-btn {
font-weight: 600;
transition: background var(--transition, 180ms ease), opacity var(--transition, 180ms ease);
}
/* Fallback button styles if platform classes not loaded */
#extension-mount button.btn-primary {
background: var(--accent, #6c9fff);
color: #fff;
border: none;
}
#extension-mount button.btn-primary:hover {
opacity: 0.88;
}
#extension-mount button.btn-secondary {
background: var(--accent-dim, rgba(108,159,255,0.12));
color: var(--accent, #6c9fff);
border: none;
}
#extension-mount button.btn-secondary:hover {
background: var(--accent-dim, rgba(108,159,255,0.2));
}
#extension-mount button.btn-ghost {
background: transparent;
color: var(--text-2, #9898a8);
border: 1px solid var(--border, #2e2e35);
}
#extension-mount button.btn-ghost:hover {
background: var(--bg-hover, #2a2a30);
}
/* Status dot animation for running state */

View File

@@ -93,7 +93,7 @@
// Configure button
var cfgBtn = $('button', {
className: T.providerSetup.configured ? 'btn-ghost' : 'btn-primary',
className: T.providerSetup.configured ? 'sw-btn sw-btn--ghost sw-btn--sm' : 'sw-btn sw-btn--primary sw-btn--md',
style: { alignSelf: 'flex-end', whiteSpace: 'nowrap' },
onClick: function () {
if (!T.providerSetup.apiKey) {
@@ -110,7 +110,7 @@
if (T.providerSetup.configured) {
var clearBtn = $('button', {
className: 'btn-ghost',
className: 'sw-btn sw-btn--ghost sw-btn--sm',
style: { alignSelf: 'flex-end', color: 'var(--danger)', whiteSpace: 'nowrap' },
onClick: function () {
T.providerSetup.apiKey = '';
@@ -189,19 +189,19 @@
T.renderControls = function () {
T.el.controls.innerHTML = '';
var btnSmoke = $('button', {
className: 'btn-primary',
className: 'sw-btn sw-btn--primary sw-btn--md',
onClick: function () { T.runSuite('smoke'); }
}, 'Smoke');
var btnCrud = $('button', {
className: 'btn-secondary',
className: 'sw-btn sw-btn--secondary sw-btn--md',
onClick: function () { T.runSuite('crud'); }
}, 'CRUD');
var btnAll = $('button', {
className: 'btn-primary',
className: 'sw-btn sw-btn--primary sw-btn--md',
onClick: function () { T.runSuite('all'); }
}, 'Run All');
var btnClear = $('button', {
className: 'btn-ghost',
className: 'sw-btn sw-btn--ghost sw-btn--sm',
onClick: function () { T.results = []; T.renderProgress(); T.renderSummary(); T.renderDetail(); }
}, 'Clear');
T.el.controls.appendChild(btnSmoke);
@@ -210,14 +210,14 @@
// AuthZ button — only useful if admin (needs fixtures)
if (T.user.role === 'admin') {
var btnAuthz = $('button', {
className: T.fixtures.ready ? 'btn-secondary' : 'btn-ghost',
className: T.fixtures.ready ? 'sw-btn sw-btn--secondary sw-btn--md' : 'sw-btn sw-btn--ghost sw-btn--sm',
style: { opacity: T.fixtures.ready ? '1' : '0.5' },
onClick: function () { T.runSuite('authz'); }
}, 'AuthZ');
T.el.controls.appendChild(btnAuthz);
var btnSecurity = $('button', {
className: T.fixtures.ready ? 'btn-secondary' : 'btn-ghost',
className: T.fixtures.ready ? 'sw-btn sw-btn--secondary sw-btn--md' : 'sw-btn sw-btn--ghost sw-btn--sm',
style: {
opacity: T.fixtures.ready ? '1' : '0.5',
borderColor: T.fixtures.ready ? 'var(--danger)' : undefined,
@@ -230,7 +230,7 @@
// Provider tier button — needs provider setup
var btnProv = $('button', {
className: T.providerSetup.configured ? 'btn-secondary' : 'btn-ghost',
className: T.providerSetup.configured ? 'sw-btn sw-btn--secondary sw-btn--md' : 'sw-btn sw-btn--ghost sw-btn--sm',
style: { opacity: T.providerSetup.configured ? '1' : '0.5' },
onClick: function () { T.runSuite('provider'); }
}, 'Providers');
@@ -238,7 +238,7 @@
// SDK tier button — tests armature-sdk.js contract
var btnSdk = $('button', {
className: (typeof window.sw !== 'undefined') ? 'btn-secondary' : 'btn-ghost',
className: (typeof window.sw !== 'undefined') ? 'sw-btn sw-btn--secondary sw-btn--md' : 'sw-btn sw-btn--ghost sw-btn--sm',
style: { opacity: (typeof window.sw !== 'undefined') ? '1' : '0.5' },
onClick: function () { T.runSuite('sdk'); }
}, 'SDK');
@@ -246,7 +246,7 @@
// Packaging tier button — extension permission lifecycle (v0.29.0)
var btnPkg = $('button', {
className: 'btn-secondary',
className: 'sw-btn sw-btn--secondary sw-btn--md',
onClick: function () { T.runSuite('packaging'); }
}, 'Packaging');
T.el.controls.appendChild(btnPkg);
@@ -259,11 +259,11 @@
// Export buttons
var btnCopy = $('button', {
className: 'btn-ghost',
className: 'sw-btn sw-btn--ghost sw-btn--sm',
onClick: function () { T.exportReport('clipboard'); }
}, 'Copy Report');
var btnDownload = $('button', {
className: 'btn-ghost',
className: 'sw-btn sw-btn--ghost sw-btn--sm',
onClick: function () { T.exportReport('download'); }
}, 'Download');
T.el.controls.appendChild(btnCopy);
@@ -274,12 +274,12 @@
T.el.controls.appendChild($('div', { style: { width: '1px', height: '28px', background: 'var(--border)', flexShrink: '0' } }));
if (!T.fixtures.ready) {
T.el.controls.appendChild($('button', {
className: 'btn-secondary',
className: 'sw-btn sw-btn--secondary sw-btn--md',
onClick: async function () { await T.provisionFixtures(); T.renderControls(); }
}, 'Provision Test Users'));
} else {
T.el.controls.appendChild($('button', {
className: 'btn-ghost',
className: 'sw-btn sw-btn--ghost sw-btn--sm',
style: { color: 'var(--danger)' },
onClick: async function () { await T.teardownFixtures(); T.renderControls(); }
}, 'Tear Down Fixtures'));

View File

@@ -14,12 +14,12 @@
}
.sdkr-version {
font-size: 12px;
color: var(--text3, #888);
color: var(--text-3, #888);
font-family: 'JetBrains Mono', monospace;
}
.sdkr-desc {
font-size: 13px;
color: var(--text2, #aaa);
color: var(--text-2, #aaa);
margin: 0 0 16px 0;
line-height: 1.5;
}
@@ -30,7 +30,7 @@
padding: 10px 14px;
border: 1px solid var(--border, #333);
border-radius: 6px;
background: var(--bg1, #1a1a1a);
background: var(--bg-raised, #1a1a1a);
}
.sdkr-fixture-row {
display: flex;
@@ -41,14 +41,14 @@
.sdkr-fixture-label {
font-size: 12px;
font-weight: 600;
color: var(--text2, #aaa);
color: var(--text-2, #aaa);
text-transform: uppercase;
white-space: nowrap;
}
.sdkr-select {
padding: 4px 8px;
font-size: 13px;
background: var(--bg2, #222);
background: var(--bg-raised, #222);
color: var(--text, #e0e0e0);
border: 1px solid var(--border, #444);
border-radius: 4px;
@@ -57,7 +57,7 @@
.sdkr-input {
padding: 4px 8px;
font-size: 13px;
background: var(--bg2, #222);
background: var(--bg-raised, #222);
color: var(--text, #e0e0e0);
border: 1px solid var(--border, #444);
border-radius: 4px;
@@ -67,17 +67,17 @@
font-family: 'JetBrains Mono', monospace;
}
.sdkr-input::placeholder {
color: var(--text3, #666);
color: var(--text-3, #666);
font-family: inherit;
}
.sdkr-fixture-status {
font-size: 12px;
color: var(--text3, #888);
color: var(--text-3, #888);
font-family: 'JetBrains Mono', monospace;
}
.sdkr-fixture-note {
font-size: 11px;
color: var(--text3, #666);
color: var(--text-3, #666);
margin-top: 6px;
line-height: 1.4;
}
@@ -98,7 +98,7 @@
.sdkr-filter-label {
font-size: 12px;
font-weight: 600;
color: var(--text2, #aaa);
color: var(--text-2, #aaa);
text-transform: uppercase;
letter-spacing: 0.05em;
}
@@ -119,13 +119,13 @@
padding: 6px 14px;
border-radius: 6px;
border: 1px solid var(--border, #444);
background: var(--bg2, #2a2a2a);
background: var(--bg-raised, #2a2a2a);
color: var(--text, #e0e0e0);
font-size: 13px;
cursor: pointer;
transition: background 0.15s;
}
.sdkr-btn:hover { background: var(--bg3, #383838); }
.sdkr-btn:hover { background: var(--bg-hover, #383838); }
.sdkr-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.sdkr-btn-primary {
background: var(--accent, #3b82f6);
@@ -146,7 +146,7 @@
gap: 8px;
margin-bottom: 12px;
padding: 10px 12px;
background: var(--bg2, #1e1e1e);
background: var(--bg-raised, #1e1e1e);
border-radius: 8px;
border: 1px solid var(--border, #333);
}
@@ -173,8 +173,8 @@
.sdkr-table th {
text-align: left;
padding: 8px 10px;
background: var(--bg2, #1e1e1e);
color: var(--text2, #aaa);
background: var(--bg-raised, #1e1e1e);
color: var(--text-2, #aaa);
font-weight: 600;
font-size: 11px;
text-transform: uppercase;
@@ -205,12 +205,12 @@
.sdkr-ms {
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
color: var(--text3, #888);
color: var(--text-3, #888);
text-align: right;
}
.sdkr-detail {
font-size: 11px;
color: var(--text3, #888);
color: var(--text-3, #888);
max-width: 400px;
word-break: break-word;
}

View File

@@ -213,17 +213,7 @@
cursor: pointer;
font-weight: 500;
}
.demo-card .btn-primary {
background: var(--accent);
color: var(--text-on-color);
}
.demo-card .btn-primary:hover {
background: var(--accent-hover);
}
.demo-card .btn-primary:disabled {
opacity: 0.5;
cursor: default;
}
/* demo-card buttons — uses kernel .sw-btn--primary */
/* Public link row */
.public-link-row {

View File

@@ -216,7 +216,7 @@
}
const tryBtn = document.createElement('button');
tryBtn.className = 'btn btn-primary';
tryBtn.className = 'sw-btn sw-btn--primary sw-btn--md';
tryBtn.textContent = 'Try It';
tryBtn.disabled = !isReady;
if (!isReady) {