|
|
<!DOCTYPE html> |
|
|
<html lang="en" data-theme="light"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title data-i18n="nav.title">HF Space Deployer</title> |
|
|
|
|
|
|
|
|
<link href="https://cdn.jsdelivr.net/npm/daisyui@4.6.0/dist/full.min.css" rel="stylesheet" type="text/css" /> |
|
|
<script src="https://cdn.tailwindcss.com"></script> |
|
|
|
|
|
|
|
|
<link href="/static/style.css" rel="stylesheet" type="text/css" /> |
|
|
|
|
|
|
|
|
<script src="https://unpkg.com/htmx.org@1.9.10"></script> |
|
|
|
|
|
|
|
|
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.js"></script> |
|
|
|
|
|
|
|
|
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script> |
|
|
|
|
|
|
|
|
<script src="/static/i18n.js"></script> |
|
|
|
|
|
<style> |
|
|
.loading-spinner { |
|
|
animation: spin 2s linear infinite; |
|
|
} |
|
|
@keyframes spin { |
|
|
from { transform: rotate(0deg); } |
|
|
to { transform: rotate(360deg); } |
|
|
} |
|
|
.fade-in { |
|
|
animation: fadeIn 0.5s ease-in-out; |
|
|
} |
|
|
@keyframes fadeIn { |
|
|
from { opacity: 0; transform: translateY(10px); } |
|
|
to { opacity: 1; transform: translateY(0); } |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body class="min-h-screen bg-base-100"> |
|
|
|
|
|
<div class="navbar bg-primary text-primary-content shadow-lg sticky top-0 z-50"> |
|
|
<div class="container mx-auto"> |
|
|
<div class="flex-1"> |
|
|
<a href="/" class="btn btn-ghost text-xl font-bold"> |
|
|
<i data-lucide="rocket" class="w-6 h-6 mr-2"></i> |
|
|
<span data-i18n="nav.title">HF Space Deployer</span> |
|
|
</a> |
|
|
</div> |
|
|
<div class="flex-none space-x-2"> |
|
|
<button |
|
|
class="btn btn-ghost btn-circle" |
|
|
onclick="toggleLanguage()" |
|
|
data-i18n-title="nav.language" |
|
|
title="Language" |
|
|
> |
|
|
<span class="text-lg font-bold lang-icon">EN</span> |
|
|
</button> |
|
|
<button |
|
|
class="btn btn-ghost btn-circle" |
|
|
onclick="toggleTheme()" |
|
|
data-i18n-title="nav.theme" |
|
|
title="Toggle Theme" |
|
|
> |
|
|
<i data-lucide="sun" class="w-5 h-5 theme-icon"></i> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="toast-container" class="fixed top-20 right-4 z-50 space-y-2"></div> |
|
|
|
|
|
|
|
|
<main class="container mx-auto px-4 py-8 max-w-6xl"> |
|
|
{% block content %}{% endblock %} |
|
|
</main> |
|
|
|
|
|
|
|
|
<footer class="footer footer-center p-8 bg-base-200 text-base-content mt-16"> |
|
|
<div> |
|
|
<p class="font-bold text-lg" data-i18n="footer.title">HF Space Deployer</p> |
|
|
<p class="text-sm opacity-70" data-i18n="footer.desc">Quick deployment tool</p> |
|
|
</div> |
|
|
<div class="flex items-center space-x-4 text-sm"> |
|
|
<a href="https://github.com/kfcx/HFSpaceDeploy.git" target="_blank" class="link link-hover">GitHub</a> |
|
|
<span>•</span> |
|
|
<a href="https://huggingface.co" target="_blank" class="link link-hover">HuggingFace</a> |
|
|
</div> |
|
|
</footer> |
|
|
|
|
|
<script> |
|
|
|
|
|
function updateLanguageIcon() { |
|
|
const langIcon = document.querySelector('.lang-icon'); |
|
|
langIcon.textContent = currentLang === 'en' ? 'EN' : '中'; |
|
|
} |
|
|
|
|
|
|
|
|
if (typeof window.originalToggleLanguage === 'undefined') { |
|
|
window.originalToggleLanguage = toggleLanguage; |
|
|
window.toggleLanguage = function() { |
|
|
window.originalToggleLanguage(); |
|
|
updateLanguageIcon(); |
|
|
}; |
|
|
} |
|
|
|
|
|
|
|
|
function toggleTheme() { |
|
|
const currentTheme = document.documentElement.getAttribute('data-theme'); |
|
|
const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; |
|
|
setTheme(newTheme); |
|
|
} |
|
|
|
|
|
function setTheme(theme) { |
|
|
document.documentElement.setAttribute('data-theme', theme); |
|
|
localStorage.setItem('theme', theme); |
|
|
|
|
|
|
|
|
const themeIcon = document.querySelector('.theme-icon'); |
|
|
if (theme === 'dark') { |
|
|
themeIcon.setAttribute('data-lucide', 'moon'); |
|
|
} else { |
|
|
themeIcon.setAttribute('data-lucide', 'sun'); |
|
|
} |
|
|
lucide.createIcons(); |
|
|
} |
|
|
|
|
|
|
|
|
const savedTheme = localStorage.getItem('theme') || 'light'; |
|
|
setTheme(savedTheme); |
|
|
|
|
|
|
|
|
lucide.createIcons(); |
|
|
|
|
|
|
|
|
document.body.addEventListener('htmx:afterRequest', function(evt) { |
|
|
|
|
|
lucide.createIcons(); |
|
|
|
|
|
updatePageTranslations(); |
|
|
}); |
|
|
|
|
|
|
|
|
function copyToClipboard(text) { |
|
|
navigator.clipboard.writeText(text).then(function() { |
|
|
showToast(t('toast.copied'), 'success'); |
|
|
}).catch(function(err) { |
|
|
showToast(t('toast.copyFailed'), 'error'); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
function showToast(message, type = 'info') { |
|
|
const toastContainer = document.getElementById('toast-container'); |
|
|
const toast = document.createElement('div'); |
|
|
toast.className = `alert alert-${type} shadow-lg fade-in min-w-[300px]`; |
|
|
|
|
|
const icons = { |
|
|
'success': 'check-circle', |
|
|
'error': 'x-circle', |
|
|
'warning': 'alert-triangle', |
|
|
'info': 'info' |
|
|
}; |
|
|
|
|
|
toast.innerHTML = ` |
|
|
<i data-lucide="${icons[type]}" class="w-5 h-5"></i> |
|
|
<span>${message}</span> |
|
|
`; |
|
|
|
|
|
toastContainer.appendChild(toast); |
|
|
lucide.createIcons(); |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
toast.style.opacity = '0'; |
|
|
toast.style.transform = 'translateY(-10px)'; |
|
|
setTimeout(() => toast.remove(), 300); |
|
|
}, 3000); |
|
|
} |
|
|
|
|
|
|
|
|
document.body.addEventListener('htmx:responseError', function(evt) { |
|
|
showToast(t('toast.requestFailed'), 'error'); |
|
|
}); |
|
|
|
|
|
|
|
|
document.addEventListener('show-toast', function(event) { |
|
|
const { message, type } = event.detail; |
|
|
showToast(message, type); |
|
|
}); |
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
|
|
|
if (typeof lucide !== 'undefined') { |
|
|
lucide.createIcons(); |
|
|
} |
|
|
|
|
|
|
|
|
updateLanguageIcon(); |
|
|
}); |
|
|
|
|
|
|
|
|
if (typeof Alpine !== 'undefined') { |
|
|
document.addEventListener('alpine:init', () => { |
|
|
console.log('Alpine.js initialized'); |
|
|
}); |
|
|
} |
|
|
</script> |
|
|
</body> |
|
|
</html> |