diff --git a/static/js/components/shared/ModelModal.js b/static/js/components/shared/ModelModal.js
index f530a09a..4e333aa0 100644
--- a/static/js/components/shared/ModelModal.js
+++ b/static/js/components/shared/ModelModal.js
@@ -360,6 +360,11 @@ export async function showModelModal(model, modelType) {
const viewOnCivitaiAction = modelWithFullData.from_civitai ? `
${translate('modals.model.actions.viewOnCivitaiText', {}, 'View on Civitai')}
+
`.trim() : '';
+ const escapedHfUrl = modelWithFullData.hf_url ? escapeAttribute(modelWithFullData.hf_url) : '';
+ const viewOnHuggingFaceAction = escapedHfUrl ? `
+
+ ${translate('modals.model.actions.viewOnHuggingFaceText', {}, 'View on Hugging Face')}
`.trim() : '';
const creatorInfoAction = modelWithFullData.civitai?.creator ? `
@@ -377,6 +382,9 @@ export async function showModelModal(model, modelType) {
if (viewOnCivitaiAction) {
creatorActionItems.push(indentMarkup(viewOnCivitaiAction, 24));
}
+ if (viewOnHuggingFaceAction) {
+ creatorActionItems.push(indentMarkup(viewOnHuggingFaceAction, 24));
+ }
if (creatorInfoAction) {
creatorActionItems.push(indentMarkup(creatorInfoAction, 24));
}
@@ -869,6 +877,11 @@ function setupEventHandlers(filePath, modelType) {
case 'view-civitai':
openCivitai(target.dataset.filepath);
break;
+ case 'view-huggingface':
+ if (target.dataset.hfUrl) {
+ window.open(target.dataset.hfUrl, '_blank', 'noopener,noreferrer');
+ }
+ break;
case 'view-creator':
const username = target.dataset.username;
if (username) {
diff --git a/static/js/utils/uiHelpers.js b/static/js/utils/uiHelpers.js
index 961d1042..4df7bf56 100644
--- a/static/js/utils/uiHelpers.js
+++ b/static/js/utils/uiHelpers.js
@@ -319,6 +319,15 @@ export function openCivitai(filePath) {
openCivitaiByMetadata(civitaiId, versionId, modelName);
}
+/**
+ * Open a Hugging Face model page in a new tab
+ * @param {string} hfUrl - The Hugging Face URL
+ */
+export function openHuggingFace(hfUrl) {
+ if (!hfUrl) return;
+ window.open(hfUrl, '_blank', 'noopener,noreferrer');
+}
+
/**
* Dynamically positions the search options panel and filter panel
* based on the current layout and folder tags container height