From 381bd3938a60ec53cd50bff317aeb5a451bee873 Mon Sep 17 00:00:00 2001 From: Will Miao <13051207myq@gmail.com> Date: Fri, 25 Jul 2025 23:23:57 +0800 Subject: [PATCH] refactor: rename 'lora-card' to 'model-card' across styles and scripts for consistency --- static/css/components/bulk.css | 4 +-- static/css/components/card.css | 26 +++++++++---------- static/css/components/duplicates.css | 22 ++++++++-------- static/css/components/loading.css | 2 +- .../ContextMenu/CheckpointContextMenu.js | 2 +- .../ContextMenu/EmbeddingContextMenu.js | 2 +- .../components/ContextMenu/LoraContextMenu.js | 2 +- .../ContextMenu/RecipeContextMenu.js | 2 +- static/js/components/DuplicatesManager.js | 8 +++--- .../js/components/ModelDuplicatesManager.js | 4 +-- static/js/components/RecipeCard.js | 2 +- static/js/components/controls/PageControls.js | 4 +-- static/js/components/shared/ModelCard.js | 12 ++++----- static/js/components/shared/ModelModal.js | 2 +- static/js/components/shared/PresetTags.js | 2 +- static/js/components/shared/RecipeTab.js | 2 +- static/js/managers/BulkManager.js | 8 +++--- static/js/managers/SettingsManager.js | 2 +- static/js/utils/cardUpdater.js | 2 +- static/js/utils/modalUtils.js | 4 +-- static/js/utils/uiHelpers.js | 4 +-- 21 files changed, 58 insertions(+), 60 deletions(-) diff --git a/static/css/components/bulk.css b/static/css/components/bulk.css index 18f04001..40ec2bf2 100644 --- a/static/css/components/bulk.css +++ b/static/css/components/bulk.css @@ -73,12 +73,12 @@ } /* Style for selected cards */ -.lora-card.selected { +.model-card.selected { box-shadow: 0 0 0 2px var(--lora-accent); position: relative; } -.lora-card.selected::after { +.model-card.selected::after { content: "✓"; position: absolute; top: 10px; diff --git a/static/css/components/card.css b/static/css/components/card.css index acaeb5b6..1137db35 100644 --- a/static/css/components/card.css +++ b/static/css/components/card.css @@ -14,7 +14,7 @@ box-sizing: border-box; /* Include padding in width calculation */ } -.lora-card { +.model-card { background: var(--lora-surface); border: 1px solid var(--lora-border); border-radius: var(--border-radius-base); @@ -30,12 +30,12 @@ overflow: hidden; } -.lora-card:hover { +.model-card:hover { transform: translateY(-2px); background: oklch(100% 0 0 / 0.6); } -.lora-card:focus-visible { +.model-card:focus-visible { outline: 2px solid var(--lora-accent); outline-offset: 2px; } @@ -47,7 +47,7 @@ grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); } - .lora-card { + .model-card { max-width: 270px; } } @@ -59,7 +59,7 @@ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); } - .lora-card { + .model-card { max-width: 280px; } } @@ -70,7 +70,7 @@ grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); } - .lora-card { + .model-card { max-width: 240px; } } @@ -259,8 +259,8 @@ transition: opacity 0.2s ease; } -.hover-reveal .lora-card:hover .card-header, -.hover-reveal .lora-card:hover .card-footer { +.hover-reveal .model-card:hover .card-header, +.hover-reveal .model-card:hover .card-footer { opacity: 1; } @@ -345,7 +345,7 @@ grid-template-columns: minmax(260px, 1fr); /* Adjusted minimum size for mobile */ } - .lora-card { + .model-card { max-width: 100%; /* Allow cards to fill available space on mobile */ } } @@ -425,8 +425,8 @@ } /* Prevent text selection on cards and interactive elements */ -.lora-card, -.lora-card *, +.model-card, +.model-card *, .card-actions, .card-actions i, .toggle-blur-btn, @@ -510,7 +510,7 @@ } } -/* Add after the existing .lora-card:hover styles */ +/* Add after the existing .model-card:hover styles */ @keyframes update-pulse { 0% { box-shadow: 0 0 0 0 var(--lora-accent-transparent); } @@ -523,7 +523,7 @@ --lora-accent-transparent: oklch(var(--lora-accent-l) var(--lora-accent-c) var(--lora-accent-h) / 0.6); } - .lora-card.updated { + .model-card.updated { animation: update-pulse 1.2s ease-out; } diff --git a/static/css/components/duplicates.css b/static/css/components/duplicates.css index 74f58dcf..d521b3c4 100644 --- a/static/css/components/duplicates.css +++ b/static/css/components/duplicates.css @@ -195,7 +195,7 @@ } /* Make cards in duplicate groups have consistent width */ -.card-group-container .lora-card { +.card-group-container .model-card { flex: 0 0 auto; width: 240px; margin: 0; @@ -241,26 +241,26 @@ } /* Duplicate card styling */ -.lora-card.duplicate { +.model-card.duplicate { position: relative; transition: all 0.2s ease; } -.lora-card.duplicate:hover { +.model-card.duplicate:hover { border-color: var(--lora-accent-l) var(--lora-accent-c) var(--lora-accent-h); } -.lora-card.duplicate.latest { +.model-card.duplicate.latest { border-style: solid; border-color: oklch(var(--lora-warning-l) var(--lora-warning-c) var(--lora-warning-h)); } -.lora-card.duplicate-selected { +.model-card.duplicate-selected { border: 2px solid oklch(var(--lora-accent-l) var(--lora-accent-c) var(--lora-accent-h)); box-shadow: 0 0 8px rgba(0, 0, 0, 0.2); } -.lora-card .selector-checkbox { +.model-card .selector-checkbox { position: absolute; top: 10px; right: 10px; @@ -271,7 +271,7 @@ } /* Latest indicator */ -.lora-card.duplicate.latest::after { +.model-card.duplicate.latest::after { content: "Latest"; position: absolute; top: 10px; @@ -365,13 +365,13 @@ } /* Hash Mismatch Styling */ -.lora-card.duplicate.hash-mismatch { +.model-card.duplicate.hash-mismatch { border: 2px dashed oklch(var(--lora-warning-l) var(--lora-warning-c) var(--lora-warning-h)); opacity: 0.85; position: relative; } -.lora-card.duplicate.hash-mismatch::before { +.model-card.duplicate.hash-mismatch::before { content: ""; position: absolute; top: 0; @@ -389,7 +389,7 @@ pointer-events: none; } -.lora-card.duplicate.hash-mismatch .card-preview { +.model-card.duplicate.hash-mismatch .card-preview { filter: grayscale(20%); } @@ -407,7 +407,7 @@ } /* Disabled checkbox style */ -.lora-card.duplicate.hash-mismatch .selector-checkbox { +.model-card.duplicate.hash-mismatch .selector-checkbox { opacity: 0.5; cursor: not-allowed; } diff --git a/static/css/components/loading.css b/static/css/components/loading.css index e118c4a9..44e29b24 100644 --- a/static/css/components/loading.css +++ b/static/css/components/loading.css @@ -109,7 +109,7 @@ } @media (prefers-reduced-motion: reduce) { - .lora-card, + .model-card, .progress-bar, .current-item-bar { transition: none; diff --git a/static/js/components/ContextMenu/CheckpointContextMenu.js b/static/js/components/ContextMenu/CheckpointContextMenu.js index dbff3711..20eccea2 100644 --- a/static/js/components/ContextMenu/CheckpointContextMenu.js +++ b/static/js/components/ContextMenu/CheckpointContextMenu.js @@ -6,7 +6,7 @@ import { showDeleteModal, showExcludeModal } from '../../utils/modalUtils.js'; export class CheckpointContextMenu extends BaseContextMenu { constructor() { - super('checkpointContextMenu', '.lora-card'); + super('checkpointContextMenu', '.model-card'); this.nsfwSelector = document.getElementById('nsfwLevelSelector'); this.modelType = 'checkpoint'; this.resetAndReload = resetAndReload; diff --git a/static/js/components/ContextMenu/EmbeddingContextMenu.js b/static/js/components/ContextMenu/EmbeddingContextMenu.js index 10f1dec0..c0ef079b 100644 --- a/static/js/components/ContextMenu/EmbeddingContextMenu.js +++ b/static/js/components/ContextMenu/EmbeddingContextMenu.js @@ -6,7 +6,7 @@ import { showDeleteModal, showExcludeModal } from '../../utils/modalUtils.js'; export class EmbeddingContextMenu extends BaseContextMenu { constructor() { - super('embeddingContextMenu', '.embedding-card'); + super('embeddingContextMenu', '.model-card'); this.nsfwSelector = document.getElementById('nsfwLevelSelector'); this.modelType = 'embedding'; this.resetAndReload = resetAndReload; diff --git a/static/js/components/ContextMenu/LoraContextMenu.js b/static/js/components/ContextMenu/LoraContextMenu.js index 28f9c1d9..61ba4837 100644 --- a/static/js/components/ContextMenu/LoraContextMenu.js +++ b/static/js/components/ContextMenu/LoraContextMenu.js @@ -6,7 +6,7 @@ import { showExcludeModal, showDeleteModal } from '../../utils/modalUtils.js'; export class LoraContextMenu extends BaseContextMenu { constructor() { - super('loraContextMenu', '.lora-card'); + super('loraContextMenu', '.model-card'); this.nsfwSelector = document.getElementById('nsfwLevelSelector'); this.modelType = 'lora'; this.resetAndReload = resetAndReload; diff --git a/static/js/components/ContextMenu/RecipeContextMenu.js b/static/js/components/ContextMenu/RecipeContextMenu.js index f2862298..953d380a 100644 --- a/static/js/components/ContextMenu/RecipeContextMenu.js +++ b/static/js/components/ContextMenu/RecipeContextMenu.js @@ -7,7 +7,7 @@ import { state } from '../../state/index.js'; export class RecipeContextMenu extends BaseContextMenu { constructor() { - super('recipeContextMenu', '.lora-card'); + super('recipeContextMenu', '.model-card'); this.nsfwSelector = document.getElementById('nsfwLevelSelector'); this.modelType = 'recipe'; diff --git a/static/js/components/DuplicatesManager.js b/static/js/components/DuplicatesManager.js index 477e7cd7..49fb22b2 100644 --- a/static/js/components/DuplicatesManager.js +++ b/static/js/components/DuplicatesManager.js @@ -243,7 +243,7 @@ export class DuplicatesManager { checkboxes.forEach(checkbox => { checkbox.checked = !allSelected; const recipeId = checkbox.dataset.recipeId; - const card = checkbox.closest('.lora-card'); + const card = checkbox.closest('.model-card'); if (!allSelected) { this.selectedForDeletion.add(recipeId); @@ -268,7 +268,7 @@ export class DuplicatesManager { checkboxes.forEach(checkbox => { checkbox.checked = true; this.selectedForDeletion.add(checkbox.dataset.recipeId); - checkbox.closest('.lora-card').classList.add('duplicate-selected'); + checkbox.closest('.model-card').classList.add('duplicate-selected'); }); // Update the button text @@ -299,7 +299,7 @@ export class DuplicatesManager { if (checkbox) { checkbox.checked = true; this.selectedForDeletion.add(recipeId); - checkbox.closest('.lora-card').classList.add('duplicate-selected'); + checkbox.closest('.model-card').classList.add('duplicate-selected'); } } @@ -310,7 +310,7 @@ export class DuplicatesManager { if (latestCheckbox) { latestCheckbox.checked = false; this.selectedForDeletion.delete(latestId); - latestCheckbox.closest('.lora-card').classList.remove('duplicate-selected'); + latestCheckbox.closest('.model-card').classList.remove('duplicate-selected'); } this.updateSelectedCount(); diff --git a/static/js/components/ModelDuplicatesManager.js b/static/js/components/ModelDuplicatesManager.js index 425e8ca0..06596642 100644 --- a/static/js/components/ModelDuplicatesManager.js +++ b/static/js/components/ModelDuplicatesManager.js @@ -330,7 +330,7 @@ export class ModelDuplicatesManager { renderModelCard(model, groupHash) { // Create basic card structure const card = document.createElement('div'); - card.className = 'lora-card duplicate'; + card.className = 'model-card duplicate'; card.dataset.hash = model.sha256; card.dataset.filePath = model.file_path; @@ -549,7 +549,7 @@ export class ModelDuplicatesManager { checkboxes.forEach(checkbox => { checkbox.checked = !allSelected; const filePath = checkbox.dataset.filePath; - const card = checkbox.closest('.lora-card'); + const card = checkbox.closest('.model-card'); if (!allSelected) { this.selectedForDeletion.add(filePath); diff --git a/static/js/components/RecipeCard.js b/static/js/components/RecipeCard.js index 84edc925..d8fd9b56 100644 --- a/static/js/components/RecipeCard.js +++ b/static/js/components/RecipeCard.js @@ -17,7 +17,7 @@ class RecipeCard { createCardElement() { const card = document.createElement('div'); - card.className = 'lora-card'; + card.className = 'model-card'; card.dataset.filepath = this.recipe.file_path; card.dataset.title = this.recipe.title; card.dataset.nsfwLevel = this.recipe.preview_nsfw_level || 0; diff --git a/static/js/components/controls/PageControls.js b/static/js/components/controls/PageControls.js index 53a2d8ef..b39a8f57 100644 --- a/static/js/components/controls/PageControls.js +++ b/static/js/components/controls/PageControls.js @@ -242,7 +242,7 @@ export class PageControls { * @param {string} folderPath - Folder path to filter by */ filterByFolder(folderPath) { - const cardSelector = this.pageType === 'loras' ? '.lora-card' : '.checkpoint-card'; + const cardSelector = this.pageType === 'loras' ? '.model-card' : '.checkpoint-card'; document.querySelectorAll(cardSelector).forEach(card => { card.style.display = card.dataset.folder === folderPath ? '' : 'none'; }); @@ -374,7 +374,7 @@ export class PageControls { openCivitai(modelName) { // Get card selector based on page type const cardSelector = this.pageType === 'loras' - ? `.lora-card[data-name="${modelName}"]` + ? `.model-card[data-name="${modelName}"]` : `.checkpoint-card[data-name="${modelName}"]`; const card = document.querySelector(cardSelector); diff --git a/static/js/components/shared/ModelCard.js b/static/js/components/shared/ModelCard.js index 6eda1f66..84cad5fa 100644 --- a/static/js/components/shared/ModelCard.js +++ b/static/js/components/shared/ModelCard.js @@ -28,10 +28,8 @@ export function setupModelCardEventDelegation(modelType) { // Event delegation handler for all model card events function handleModelCardEvent_internal(event, modelType) { // Find the closest card element - const card = event.target.closest('.lora-card'); + const card = event.target.closest('.model-card'); if (!card) return; - - const apiClient = getModelApiClient(); // Handle specific elements within the card if (event.target.closest('.toggle-blur-btn')) { @@ -80,7 +78,7 @@ function handleModelCardEvent_internal(event, modelType) { if (event.target.closest('.fa-image')) { event.stopPropagation(); - apiClient.replaceModelPreview(card.dataset.filepath); + getModelApiClient().replaceModelPreview(card.dataset.filepath); return; } @@ -137,7 +135,7 @@ async function toggleFavorite(card) { const newFavoriteState = !isFavorite; try { - await apiClient.saveModelMetadata(card.dataset.filepath, { + await getModelApiClient().saveModelMetadata(card.dataset.filepath, { favorite: newFavoriteState }); @@ -364,7 +362,7 @@ function showExampleAccessModal(card, modelType) { export function createModelCard(model, modelType) { const card = document.createElement('div'); - card.className = 'lora-card'; // Reuse the same class for styling + card.className = 'model-card'; // Reuse the same class for styling card.dataset.sha256 = model.sha256; card.dataset.filepath = model.file_path; card.dataset.name = model.model_name; @@ -518,7 +516,7 @@ export function updateCardsForBulkMode(isBulkMode) { document.body.classList.toggle('bulk-mode', isBulkMode); // Get all lora cards - this can now be from the DOM or through the virtual scroller - const loraCards = document.querySelectorAll('.lora-card'); + const loraCards = document.querySelectorAll('.model-card'); loraCards.forEach(card => { // Get all action containers for this card diff --git a/static/js/components/shared/ModelModal.js b/static/js/components/shared/ModelModal.js index d069531b..d6246487 100644 --- a/static/js/components/shared/ModelModal.js +++ b/static/js/components/shared/ModelModal.js @@ -380,7 +380,7 @@ function setupLoraSpecificFields(filePath) { if (!key || !value) return; - const loraCard = document.querySelector(`.lora-card[data-filepath="${filePath}"]`); + const loraCard = document.querySelector(`.model-card[data-filepath="${filePath}"]`); const currentPresets = parsePresets(loraCard?.dataset.usage_tips); currentPresets[key] = parseFloat(value); diff --git a/static/js/components/shared/PresetTags.js b/static/js/components/shared/PresetTags.js index 00d391ce..fb682ee8 100644 --- a/static/js/components/shared/PresetTags.js +++ b/static/js/components/shared/PresetTags.js @@ -52,7 +52,7 @@ window.removePreset = async function(key) { .querySelector('.file-path').textContent + document.querySelector('#modelModal .modal-content') .querySelector('#file-name').textContent + '.safetensors'; - const loraCard = document.querySelector(`.lora-card[data-filepath="${filePath}"]`); + const loraCard = document.querySelector(`.model-card[data-filepath="${filePath}"]`); const currentPresets = parsePresets(loraCard.dataset.usage_tips); delete currentPresets[key]; diff --git a/static/js/components/shared/RecipeTab.js b/static/js/components/shared/RecipeTab.js index 661d4169..17e38597 100644 --- a/static/js/components/shared/RecipeTab.js +++ b/static/js/components/shared/RecipeTab.js @@ -96,7 +96,7 @@ function renderRecipes(tabElement, recipes, loraName, loraHash) { // Create card element matching the structure in recipes.html const card = document.createElement('div'); - card.className = 'lora-card'; + card.className = 'model-card'; card.dataset.filePath = recipe.file_path || ''; card.dataset.title = recipe.title || ''; card.dataset.created = recipe.created_date || ''; diff --git a/static/js/managers/BulkManager.js b/static/js/managers/BulkManager.js index fc6b21e6..2ce9b0b2 100644 --- a/static/js/managers/BulkManager.js +++ b/static/js/managers/BulkManager.js @@ -105,7 +105,7 @@ export class BulkManager { // TODO: fix this, no DOM manipulation should be done here // Force a lightweight refresh of the cards to ensure proper display // This is less disruptive than a full resetAndReload() - document.querySelectorAll('.lora-card').forEach(card => { + document.querySelectorAll('.model-card').forEach(card => { // Re-apply normal display mode to all card actions const actions = card.querySelectorAll('.card-actions, .card-button'); actions.forEach(action => action.style.display = 'flex'); @@ -114,7 +114,7 @@ export class BulkManager { } clearSelection() { - document.querySelectorAll('.lora-card.selected').forEach(card => { + document.querySelectorAll('.model-card.selected').forEach(card => { card.classList.remove('selected'); }); state.selectedLoras.clear(); @@ -190,7 +190,7 @@ export class BulkManager { applySelectionState() { if (!state.bulkMode) return; - document.querySelectorAll('.lora-card').forEach(card => { + document.querySelectorAll('.model-card').forEach(card => { const filepath = card.dataset.filepath; if (state.selectedLoras.has(filepath)) { card.classList.add('selected'); @@ -502,7 +502,7 @@ export class BulkManager { deselectItem(filepath) { // Find and deselect the corresponding card if it's in the DOM - const card = document.querySelector(`.lora-card[data-filepath="${filepath}"]`); + const card = document.querySelector(`.model-card[data-filepath="${filepath}"]`); if (card) { card.classList.remove('selected'); } diff --git a/static/js/managers/SettingsManager.js b/static/js/managers/SettingsManager.js index f53eb81e..edaf4578 100644 --- a/static/js/managers/SettingsManager.js +++ b/static/js/managers/SettingsManager.js @@ -734,7 +734,7 @@ export class SettingsManager { applyFrontendSettings() { // Apply blur setting to existing content const blurSetting = state.global.settings.blurMatureContent; - document.querySelectorAll('.lora-card[data-nsfw="true"] .card-image').forEach(img => { + document.querySelectorAll('.model-card[data-nsfw="true"] .card-image').forEach(img => { if (blurSetting) { img.classList.add('nsfw-blur'); } else { diff --git a/static/js/utils/cardUpdater.js b/static/js/utils/cardUpdater.js index 938ee288..490ed83b 100644 --- a/static/js/utils/cardUpdater.js +++ b/static/js/utils/cardUpdater.js @@ -9,7 +9,7 @@ */ export function updateRecipeCard(recipeId, updates) { // Find the card with matching recipe ID - const recipeCard = document.querySelector(`.lora-card[data-id="${recipeId}"]`); + const recipeCard = document.querySelector(`.model-card[data-id="${recipeId}"]`); if (!recipeCard) return; // Get the recipe card component instance diff --git a/static/js/utils/modalUtils.js b/static/js/utils/modalUtils.js index 19a0edf5..25af1fbc 100644 --- a/static/js/utils/modalUtils.js +++ b/static/js/utils/modalUtils.js @@ -9,7 +9,7 @@ let pendingExcludePath = null; export function showDeleteModal(filePath) { pendingDeletePath = filePath; - const card = document.querySelector(`.lora-card[data-filepath="${filePath}"]`); + const card = document.querySelector(`.model-card[data-filepath="${filePath}"]`); const modelName = card ? card.dataset.name : filePath.split('/').pop(); const modal = modalManager.getModal('deleteModal').element; const modelInfo = modal.querySelector('.delete-model-info'); @@ -49,7 +49,7 @@ export function closeDeleteModal() { export function showExcludeModal(filePath) { pendingExcludePath = filePath; - const card = document.querySelector(`.lora-card[data-filepath="${filePath}"]`); + const card = document.querySelector(`.model-card[data-filepath="${filePath}"]`); const modelName = card ? card.dataset.name : filePath.split('/').pop(); const modal = modalManager.getModal('excludeModal').element; const modelInfo = modal.querySelector('.exclude-model-info'); diff --git a/static/js/utils/uiHelpers.js b/static/js/utils/uiHelpers.js index 7fd07f28..8a4866c8 100644 --- a/static/js/utils/uiHelpers.js +++ b/static/js/utils/uiHelpers.js @@ -168,13 +168,13 @@ function updateThemeToggleIcons(theme) { } function filterByFolder(folderPath) { - document.querySelectorAll('.lora-card').forEach(card => { + document.querySelectorAll('.model-card').forEach(card => { card.style.display = card.dataset.folder === folderPath ? '' : 'none'; }); } export function openCivitai(filePath) { - const loraCard = document.querySelector(`.lora-card[data-filepath="${filePath}"]`); + const loraCard = document.querySelector(`.model-card[data-filepath="${filePath}"]`); if (!loraCard) return; const metaData = JSON.parse(loraCard.dataset.meta);