refactor: centralize button styles in app.css

- Add global .btn, .btn-primary, .btn-secondary, .btn-danger, .btn-ghost classes
- Add --danger color CSS variables for multi-theme support
- Add .btn-sm and .btn-lg size modifiers
- Refactor all modals and views to use global button classes
- Remove 260+ lines of duplicated button CSS across components

Files updated:
- FavoritesEditModal, FolderEditModal, FolderSettingsModal
- LocalLibraryTagEditorModal, MigrationModal, PlaylistImportModal
- PlaylistModal, Sidebar, LocalLibraryView, PlaylistManagerView
This commit is contained in:
vicrodh committed 2026-01-26 18:02:58 -06:00
1 parent 1751a83499
commit fcda0ddf36
11 files changed
+97 -357

No files matched your search

+85
View File
@@ -16,6 +16,11 @@
--accent-hover: #5a9bf4;
--accent-active: #3275e4;
--danger: #ef4444;
--danger-bg: rgba(239, 68, 68, 0.1);
--danger-border: rgba(239, 68, 68, 0.3);
--danger-hover: rgba(239, 68, 68, 0.2);
--border-subtle: #2a2a2a;
--border-strong: #3a3a3a;
@@ -75,6 +80,11 @@
--border-subtle: #e0e0e0;
--border-strong: #cccccc;
--danger: #dc2626;
--danger-bg: rgba(220, 38, 38, 0.1);
--danger-border: rgba(220, 38, 38, 0.3);
--danger-hover: rgba(220, 38, 38, 0.15);
/* Alpha overrides for light theme - use black-based */
--alpha-4: rgba(0, 0, 0, 0.04);
--alpha-5: rgba(0, 0, 0, 0.05);
@@ -448,3 +458,78 @@ select {
box-shadow: inset 0 0 0 1px var(--accent-primary);
color: var(--accent-primary);
}
/* ============ Standard Buttons ============ */
/* Reusable button styles for modals, forms, and actions */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 8px 20px;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 150ms ease;
border: 1px solid transparent;
white-space: nowrap;
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.btn-primary {
background: var(--accent-primary);
color: var(--bg-primary);
}
.btn-primary:hover:not(:disabled) {
opacity: 0.9;
}
.btn-secondary {
background: var(--bg-secondary);
border-color: var(--bg-tertiary);
color: var(--text-primary);
}
.btn-secondary:hover:not(:disabled) {
background: var(--bg-tertiary);
}
.btn-danger {
background: var(--danger-bg);
border: 1px solid var(--danger-border);
color: var(--danger);
}
.btn-danger:hover:not(:disabled) {
background: var(--danger-hover);
}
.btn-ghost {
background: transparent;
color: var(--text-muted);
}
.btn-ghost:hover:not(:disabled) {
background: var(--bg-hover);
color: var(--text-primary);
}
/* Button sizes */
.btn-sm {
padding: 6px 14px;
font-size: 13px;
border-radius: 6px;
}
.btn-lg {
padding: 12px 28px;
font-size: 15px;
border-radius: 10px;
}
@@ -550,39 +550,6 @@
padding-top: 24px;
}
.btn {
padding: 8px 20px;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 150ms ease;
border: none;
}
.btn-secondary {
background: var(--bg-secondary);
color: var(--text-primary);
}
.btn-secondary:hover:not(:disabled) {
background: var(--bg-tertiary);
}
.btn-primary {
background: var(--accent-primary);
color: var(--bg-primary);
}
.btn-primary:hover:not(:disabled) {
opacity: 0.9;
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.btn-custom-gradient {
width: 100%;
padding: 8px 16px;
+2 -41
View File
@@ -429,47 +429,8 @@
gap: 12px;
}
.btn {
padding: 8px 20px;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 150ms ease;
border: 1px solid transparent;
}
.btn-secondary {
background: var(--bg-secondary);
color: var(--text-primary);
}
.btn-secondary:hover:not(:disabled) {
background: var(--bg-tertiary);
}
.btn-primary {
background: var(--accent-primary);
color: var(--bg-primary);
}
.btn-primary:hover:not(:disabled) {
opacity: 0.9;
}
.btn-danger {
/* Layout-specific: push danger button to the left */
.modal-actions :global(.btn-danger) {
margin-right: auto;
background: rgba(239, 68, 68, 0.1);
border: 1px solid rgba(239, 68, 68, 0.3);
color: #ef4444;
}
.btn-danger:hover:not(:disabled) {
background: rgba(239, 68, 68, 0.2);
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
</style>
@@ -689,42 +689,6 @@
cursor: not-allowed;
}
.btn-secondary,
.btn-primary {
padding: 10px 20px;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 150ms ease;
}
.btn-secondary {
background: transparent;
border: 1px solid var(--text-muted);
color: var(--text-primary);
}
.btn-secondary:hover:not(:disabled) {
border-color: var(--text-primary);
}
.btn-primary {
background: var(--accent-primary);
border: none;
color: white;
}
.btn-primary:hover:not(:disabled) {
background: var(--accent-hover);
}
.btn-secondary:disabled,
.btn-primary:disabled {
opacity: 0.5;
cursor: not-allowed;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
@@ -299,8 +299,8 @@
{/if}
</div>
<div class="footer-actions">
<button class="secondary-btn" onclick={onClose} disabled={saving}>Cancel</button>
<button class="primary-btn" onclick={handleSave} disabled={saving}>
<button class="btn btn-secondary" onclick={onClose} disabled={saving}>Cancel</button>
<button class="btn btn-primary" onclick={handleSave} disabled={saving}>
{saving ? 'Saving...' : 'Save'}
</button>
</div>
@@ -520,11 +520,8 @@ input[type="number"] {
margin-left: auto;
}
.footer-actions :global(.primary-btn),
.footer-actions :global(.secondary-btn) {
.footer-actions :global(.btn) {
min-width: 96px;
height: 40px;
border-radius: 10px;
}
.select-inline {
+2 -31
View File
@@ -327,37 +327,8 @@
width: 100%;
}
.btn {
/* Layout-specific: equal width buttons */
.modal-footer :global(.btn) {
flex: 1;
padding: 10px 20px;
border-radius: 8px;
font-weight: 500;
cursor: pointer;
transition: all 150ms ease;
border: none;
font-size: 14px;
}
.btn-primary {
background: var(--accent-primary);
color: white;
}
.btn-primary:hover:not(:disabled) {
background: var(--accent-primary-hover);
}
.btn-secondary {
background: var(--bg-secondary);
color: var(--text-primary);
}
.btn-secondary:hover:not(:disabled) {
background: var(--bg-tertiary);
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
</style>
@@ -523,35 +523,6 @@
border-top: 1px solid var(--bg-tertiary);
}
.btn-secondary,
.btn-primary {
padding: 10px 16px;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: transform 150ms ease, background 150ms ease, opacity 150ms ease;
}
.btn-secondary {
background: transparent;
border: 1px solid var(--bg-tertiary);
color: var(--text-secondary);
}
.btn-primary {
background: var(--accent-primary);
border: none;
color: var(--text-on-accent);
}
.btn-primary:disabled,
.btn-secondary:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
.spinner {
width: 14px;
height: 14px;
-36
View File
@@ -777,42 +777,6 @@
margin-left: auto;
}
.btn-secondary,
.btn-primary {
padding: 10px 20px;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 150ms ease;
}
.btn-secondary {
background: transparent;
border: 1px solid var(--text-muted);
color: var(--text-primary);
}
.btn-secondary:hover:not(:disabled) {
border-color: var(--text-primary);
}
.btn-primary {
background: var(--accent-primary);
border: none;
color: white;
}
.btn-primary:hover:not(:disabled) {
background: var(--accent-hover);
}
.btn-secondary:disabled,
.btn-primary:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.hidden-label {
display: flex;
align-items: center;
-35
View File
@@ -1596,41 +1596,6 @@
justify-content: flex-end;
}
.btn-secondary,
.btn-primary {
padding: 8px 16px;
border-radius: 8px;
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: background-color 150ms ease, opacity 150ms ease;
}
.btn-secondary {
background: var(--bg-tertiary);
border: 1px solid var(--alpha-10);
color: var(--text-primary);
}
.btn-secondary:hover {
background: var(--bg-hover);
}
.btn-primary {
background: var(--accent-primary);
border: none;
color: white;
}
.btn-primary:hover:not(:disabled) {
background: var(--accent-secondary);
}
.btn-primary:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.toggle-btn {
position: absolute;
right: -10px;
@@ -2533,7 +2533,7 @@
{/if}
<div class="settings-actions">
<button class="secondary-btn" onclick={toggleHiddenAlbumsView}>
<button class="btn btn-secondary" onclick={toggleHiddenAlbumsView}>
<span>{showHiddenAlbums ? 'Show Active Albums' : 'View Hidden Albums'}</span>
{#if hiddenAlbums.length > 0}
<span class="count">({hiddenAlbums.length})</span>
@@ -2541,7 +2541,7 @@
</button>
{#if hasDiscogsCredentials}
<button
class="secondary-btn"
class="btn btn-secondary"
onclick={handleFetchMissingArtwork}
disabled={fetchingArtwork || isOffline}
title={isOffline ? 'Artwork fetching unavailable offline' : ''}
@@ -2645,7 +2645,7 @@
<div class="albums-section">
<div class="section-header">
<h3>Hidden Albums ({hiddenAlbums.length})</h3>
<button class="secondary-btn" onclick={toggleHiddenAlbumsView}>
<button class="btn btn-secondary" onclick={toggleHiddenAlbumsView}>
<span>Back to Active Albums</span>
</button>
</div>
@@ -3281,10 +3281,10 @@
</div>
<div class="footer-actions">
<button class="secondary-btn" onclick={() => showAlbumEditModal = false}>
<button class="btn btn-secondary" onclick={() => showAlbumEditModal = false}>
Cancel
</button>
<button class="primary-btn" onclick={saveAlbumEdit}>
<button class="btn btn-primary" onclick={saveAlbumEdit}>
Save
</button>
</div>
@@ -3707,30 +3707,6 @@
align-items: center;
}
.secondary-btn {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
background: var(--bg-tertiary);
color: var(--text-primary);
border: 1px solid var(--border-subtle);
border-radius: 8px;
font-size: 13px;
cursor: pointer;
transition: all 150ms ease;
}
.secondary-btn:hover:not(:disabled) {
background: var(--bg-hover);
border-color: var(--text-muted);
}
.secondary-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.discogs-hint {
font-size: 12px;
color: var(--text-muted);
@@ -5414,35 +5390,4 @@
.footer-hint {
margin-top: 0;
}
.secondary-btn,
.primary-btn {
padding: 10px 20px;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 150ms ease;
}
.secondary-btn {
background: transparent;
border: 1px solid var(--text-muted);
color: var(--text-secondary);
}
.secondary-btn:hover {
border-color: var(--text-primary);
color: var(--text-primary);
}
.primary-btn {
background: var(--accent-primary);
border: none;
color: white;
}
.primary-btn:hover {
background: var(--accent-hover);
}
</style>
@@ -1534,56 +1534,6 @@
gap: 12px;
}
.btn-secondary,
.btn-primary,
.btn-danger {
padding: 8px 16px;
border-radius: 8px;
font-size: 13px;
font-weight: 500;
cursor: pointer;
display: flex;
align-items: center;
gap: 6px;
transition: background-color 150ms ease, opacity 150ms ease;
}
.btn-secondary {
background: var(--bg-tertiary);
border: 1px solid var(--alpha-10);
color: var(--text-primary);
}
.btn-secondary:hover {
background: var(--bg-hover);
}
.btn-primary {
background: var(--accent-primary);
border: none;
color: white;
}
.btn-primary:hover:not(:disabled) {
background: var(--accent-secondary);
}
.btn-primary:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.btn-danger {
background: transparent;
border: 1px solid var(--error);
color: var(--error);
}
.btn-danger:hover {
background: var(--error);
color: white;
}
.controls {
display: flex;
align-items: center;