diff --git a/static/css/components/lora-modal/versions.css b/static/css/components/lora-modal/versions.css index 86e6e2c0..1eaa9eac 100644 --- a/static/css/components/lora-modal/versions.css +++ b/static/css/components/lora-modal/versions.css @@ -107,6 +107,10 @@ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08); } +.model-version-row.is-clickable { + cursor: pointer; +} + .model-version-row.is-current { border-color: var(--lora-accent); box-shadow: 0 0 0 1px color-mix(in oklch, var(--lora-accent) 65%, transparent), diff --git a/static/js/components/shared/ModelVersionsTab.js b/static/js/components/shared/ModelVersionsTab.js index a3232640..7def4d76 100644 --- a/static/js/components/shared/ModelVersionsTab.js +++ b/static/js/components/shared/ModelVersionsTab.js @@ -7,6 +7,20 @@ import { formatFileSize } from './utils.js'; const VIDEO_EXTENSIONS = ['.mp4', '.webm', '.mov', '.mkv']; +function buildCivitaiVersionUrl(modelId, versionId) { + if (modelId == null || versionId == null) { + return null; + } + const normalizedModelId = String(modelId).trim(); + const normalizedVersionId = String(versionId).trim(); + if (!normalizedModelId || !normalizedVersionId) { + return null; + } + const encodedModelId = encodeURIComponent(normalizedModelId); + const encodedVersionId = encodeURIComponent(normalizedVersionId); + return `https://civitai.com/models/${encodedModelId}?modelVersionId=${encodedVersionId}`; +} + function escapeHtml(value) { if (value == null) { return ''; @@ -176,7 +190,7 @@ function renderMediaMarkup(version) { } function renderRow(version, options) { - const { latestLibraryVersionId, currentVersionId } = options; + const { latestLibraryVersionId, currentVersionId, modelId: parentModelId } = options; const isCurrent = currentVersionId && version.versionId === currentVersionId; const isNewer = typeof latestLibraryVersionId === 'number' && @@ -201,8 +215,8 @@ function renderRow(version, options) { const deleteLabel = translate('modals.model.versions.actions.delete', {}, 'Delete'); const ignoreLabel = translate( version.shouldIgnore - ? 'modals.model.versions.actions.unignore' - : 'modals.model.versions.actions.ignore', + ? 'modals.model.versions.actions.unignore' + : 'modals.model.versions.actions.ignore', {}, version.shouldIgnore ? 'Unignore' : 'Ignore' ); @@ -223,12 +237,37 @@ function renderRow(version, options) { }">${escapeHtml(ignoreLabel)}` ); + const versionName = + version.name || + translate('modals.model.versions.labels.unnamed', {}, 'Untitled Version'); + const linkTarget = buildCivitaiVersionUrl( + version.modelId || parentModelId, + version.versionId + ); + const civitaiTooltip = translate( + 'modals.model.actions.viewOnCivitai', + {}, + 'View on Civitai' + ); + const versionNameMarkup = linkTarget + ? `${escapeHtml(versionName)}` + : `${escapeHtml(versionName)}`; + + const rowAttributes = [ + `class="model-version-row${isCurrent ? ' is-current' : ''}${linkTarget ? ' is-clickable' : ''}"`, + `data-version-id="${escapeHtml(version.versionId)}"`, + ]; + if (linkTarget) { + rowAttributes.push(`data-civitai-url="${escapeHtml(linkTarget)}"`); + rowAttributes.push(`title="${escapeHtml(civitaiTooltip)}"`); + } + return ` -