Files
ComfyUI-Lora-Manager/templates/recipes.html
2025-03-16 16:56:33 +08:00

169 lines
7.5 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<title>LoRA Recipes</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/loras_static/css/style.css">
<link rel="stylesheet" href="/loras_static/css/components/recipe-card.css">
<link rel="stylesheet" href="/loras_static/css/components/recipe-modal.css">
<link rel="stylesheet" href="/loras_static/css/components/import-modal.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" crossorigin="anonymous" referrerpolicy="no-referrer">
<link rel="icon" type="image/png" sizes="32x32" href="/loras_static/images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/loras_static/images/favicon-16x16.png">
<link rel="manifest" href="/loras_static/images/site.webmanifest">
<!-- Preload critical resources -->
<link rel="preload" href="/loras_static/css/style.css" as="style">
<link rel="preload" href="/loras_static/js/recipes.js" as="script" crossorigin="anonymous">
<!-- Optimize font loading -->
<link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/webfonts/fa-solid-900.woff2" as="font" type="font/woff2" crossorigin>
<!-- Performance monitoring -->
<script>
performance.mark('page-start');
window.addEventListener('load', () => {
performance.mark('page-end');
performance.measure('page-load', 'page-start', 'page-end');
});
</script>
<!-- Security meta tags -->
<meta http-equiv="Cross-Origin-Opener-Policy" content="same-origin">
<meta http-equiv="Cross-Origin-Embedder-Policy" content="require-corp">
<!-- Resource loading strategy -->
<link rel="preconnect" href="https://cdnjs.cloudflare.com">
</head>
<body>
{% include 'components/header.html' %}
<div class="page-content">
{% include 'components/modals.html' %}
{% include 'components/loading.html' %}
{% include 'components/context_menu.html' %}
{% include 'components/import_modal.html' %}
{% include 'components/recipe_modal.html' %}
<div class="container">
{% if is_initializing %}
<div class="initialization-notice">
<div class="notice-content">
<div class="loading-spinner"></div>
<h2>Initializing Recipe Manager</h2>
<p>Scanning and building recipe cache. This may take a few moments...</p>
</div>
</div>
{% else %}
<!-- Recipe controls - can reuse structure from loras controls -->
<div class="controls">
<div class="action-buttons">
<div title="Import recipes" class="control-group">
<button onclick="importRecipes()"><i class="fas fa-file-import"></i> Import</button>
</div>
</div>
</div>
<!-- Recipe grid - similar to lora grid -->
<div class="card-grid recipe-grid" id="recipeGrid">
{% if recipes and recipes|length > 0 %}
{% for recipe in recipes %}
<div class="recipe-card" data-file-path="{{ recipe.file_path }}" data-title="{{ recipe.title }}" data-created="{{ recipe.created_date }}">
<div class="recipe-indicator" title="Recipe">R</div>
<div class="card-preview">
<img src="{{ recipe.file_url }}" alt="{{ recipe.title }}">
<div class="card-header">
<div class="base-model-wrapper">
{% if recipe.base_model %}
<span class="base-model-label" title="{{ recipe.base_model }}">
{{ recipe.base_model }}
</span>
{% endif %}
</div>
<div class="card-actions">
<i class="fas fa-share-alt" title="Share Recipe"></i>
<i class="fas fa-copy" title="Copy Recipe"></i>
<i class="fas fa-trash" title="Delete Recipe"></i>
</div>
</div>
<div class="card-footer">
<div class="model-info">
<span class="model-name">{{ recipe.title }}</span>
</div>
<div class="lora-count" title="Number of LoRAs in this recipe">
<i class="fas fa-layer-group"></i> {{ recipe.loras|length }}
</div>
</div>
</div>
</div>
{% endfor %}
{% else %}
<div class="placeholder-message">
<p>No recipes found</p>
<p>Add recipe images to your recipes folder to see them here.</p>
</div>
{% endif %}
</div>
{% endif %}
</div>
</div>
<script type="module" src="/loras_static/js/recipes.js"></script>
{% if is_initializing %}
<script>
// Check initialization status and set auto-refresh
async function checkInitStatus() {
try {
const response = await fetch('/api/recipes?page=1&page_size=1');
if (response.ok) {
// If data successfully retrieved, initialization is complete, refresh the page
window.location.reload();
} else {
// If not yet complete, continue polling
setTimeout(checkInitStatus, 2000); // Check every 2 seconds
}
} catch (error) {
// If error, continue polling
setTimeout(checkInitStatus, 2000);
}
}
// Start status checking
checkInitStatus();
</script>
{% endif %}
<!-- Recipe page specific scripts -->
<script>
// Refresh recipes
function refreshRecipes() {
// Will be implemented in recipes.js
window.location.reload();
}
// Placeholder for recipe filter manager
const recipeFilterManager = {
toggleFilterPanel() {
const panel = document.getElementById('filterPanel');
panel.classList.toggle('hidden');
},
closeFilterPanel() {
document.getElementById('filterPanel').classList.add('hidden');
},
clearFilters() {
// Clear filters and reset UI
document.querySelectorAll('.filter-tags .tag.active').forEach(tag => {
tag.classList.remove('active');
});
document.getElementById('activeFiltersCount').style.display = 'none';
// Reapply default view
refreshRecipes();
}
};
</script>
</body>
</html>