fix: OS gallery accordion layout and remove broken remote icon fetching
- Replace flat category display with collapsible accordion (first category expanded, rest collapsed with click-to-toggle) - Remove VirtFusion remote icon fetching (icons are behind auth/404) — use brand-colored letter badges instead - Add accordion header CSS with category icon, template count, and arrow indicator - Update checkout page gallery (hooks.php) with matching accordion behavior - Flush Redis OS template cache on deploy Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -208,16 +208,40 @@ add_hook('ClientAreaFooterOutput', 1, function ($vars) {
|
||||
galleryContainer.style.marginTop = '8px';
|
||||
|
||||
if (osGalleryData.categories && osGalleryData.categories.length > 0) {
|
||||
osGalleryData.categories.forEach(function(cat) {
|
||||
osGalleryData.categories.forEach(function(cat, ci) {
|
||||
var section = document.createElement('div');
|
||||
section.className = 'vf-os-category';
|
||||
var title = document.createElement('h5');
|
||||
title.className = 'vf-os-category-title';
|
||||
title.textContent = cat.name;
|
||||
section.appendChild(title);
|
||||
|
||||
var header = document.createElement('div');
|
||||
header.className = 'vf-os-category-header';
|
||||
var catColor = getBrandColor(cat.name);
|
||||
|
||||
var catIcon = document.createElement('span');
|
||||
catIcon.className = 'vf-os-category-icon';
|
||||
catIcon.style.background = catColor;
|
||||
catIcon.textContent = (cat.name || '?')[0].toUpperCase();
|
||||
|
||||
var catTitle = document.createElement('span');
|
||||
catTitle.textContent = cat.name + ' (' + cat.templates.length + ')';
|
||||
|
||||
var arrow = document.createElement('span');
|
||||
arrow.className = 'vf-os-category-arrow';
|
||||
arrow.textContent = ci === 0 ? '\u25BC' : '\u25B6';
|
||||
|
||||
header.appendChild(catIcon);
|
||||
header.appendChild(catTitle);
|
||||
header.appendChild(arrow);
|
||||
section.appendChild(header);
|
||||
|
||||
var grid = document.createElement('div');
|
||||
grid.className = 'vf-os-grid';
|
||||
if (ci !== 0) grid.style.display = 'none';
|
||||
|
||||
header.addEventListener('click', function() {
|
||||
var isOpen = grid.style.display !== 'none';
|
||||
grid.style.display = isOpen ? 'none' : '';
|
||||
arrow.textContent = isOpen ? '\u25B6' : '\u25BC';
|
||||
});
|
||||
|
||||
cat.templates.forEach(function(tpl) {
|
||||
var fullLabel = tpl.name + (tpl.version ? ' ' + tpl.version : '') + (tpl.variant ? ' ' + tpl.variant : '');
|
||||
@@ -228,23 +252,10 @@ add_hook('ClientAreaFooterOutput', 1, function ($vars) {
|
||||
|
||||
var iconDiv = document.createElement('div');
|
||||
iconDiv.className = 'vf-os-icon';
|
||||
iconDiv.style.background = getBrandColor(cat.name || tpl.name);
|
||||
if (tpl.icon && osGalleryData.baseUrl) {
|
||||
var img = document.createElement('img');
|
||||
img.src = osGalleryData.baseUrl + '/storage/os/' + encodeURIComponent(tpl.icon);
|
||||
img.alt = '';
|
||||
img.onerror = function() {
|
||||
this.parentNode.textContent = '';
|
||||
var sp = document.createElement('span');
|
||||
sp.textContent = (tpl.name || '?')[0].toUpperCase();
|
||||
this.parentNode.appendChild(sp);
|
||||
};
|
||||
iconDiv.appendChild(img);
|
||||
} else {
|
||||
var sp = document.createElement('span');
|
||||
sp.textContent = (tpl.name || '?')[0].toUpperCase();
|
||||
iconDiv.appendChild(sp);
|
||||
}
|
||||
iconDiv.style.background = catColor;
|
||||
var sp = document.createElement('span');
|
||||
sp.textContent = (tpl.name || '?')[0].toUpperCase();
|
||||
iconDiv.appendChild(sp);
|
||||
card.appendChild(iconDiv);
|
||||
|
||||
var labelDiv = document.createElement('div');
|
||||
|
||||
@@ -263,24 +263,49 @@
|
||||
}
|
||||
|
||||
/* OS Template Gallery */
|
||||
.vf-os-category-title {
|
||||
text-transform: uppercase;
|
||||
.vf-os-category-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 10px 12px;
|
||||
margin-top: 6px;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-weight: 700;
|
||||
font-size: 0.9rem;
|
||||
user-select: none;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
.vf-os-category:first-child .vf-os-category-header {
|
||||
margin-top: 0;
|
||||
}
|
||||
.vf-os-category-header:hover {
|
||||
background: rgba(0,0,0,0.03);
|
||||
}
|
||||
.vf-os-category-icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
font-size: 0.85rem;
|
||||
letter-spacing: 0.5px;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
padding-bottom: 6px;
|
||||
margin-top: 16px;
|
||||
margin-bottom: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.vf-os-category:first-child .vf-os-category-title {
|
||||
margin-top: 0;
|
||||
.vf-os-category-arrow {
|
||||
margin-left: auto;
|
||||
font-size: 0.7rem;
|
||||
color: #888;
|
||||
}
|
||||
.vf-os-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
padding: 10px 0;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.vf-os-card {
|
||||
width: 120px;
|
||||
|
||||
@@ -317,32 +317,37 @@ function vfRenderOsGallery(container, data, hiddenInput) {
|
||||
return;
|
||||
}
|
||||
|
||||
var baseUrl = data.baseUrl || "";
|
||||
|
||||
$.each(data.categories, function (ci, category) {
|
||||
var section = $('<div class="vf-os-category"></div>').attr("data-category", ci);
|
||||
var title = $('<h5 class="vf-os-category-title"></h5>').text(category.name);
|
||||
section.append(title);
|
||||
var brandColor = vfGetBrandColor(category.name);
|
||||
|
||||
// Accordion header
|
||||
var header = $('<div class="vf-os-category-header"></div>');
|
||||
var iconSpan = $('<span class="vf-os-category-icon"></span>').css("background", brandColor).text((category.name || "?")[0].toUpperCase());
|
||||
var titleSpan = $('<span></span>').text(category.name + " (" + category.templates.length + ")");
|
||||
var arrow = $('<span class="vf-os-category-arrow">' + (ci === 0 ? '▼' : '▶') + '</span>');
|
||||
header.append(iconSpan).append(titleSpan).append(arrow);
|
||||
section.append(header);
|
||||
|
||||
// Collapsible grid — first category open by default
|
||||
var grid = $('<div class="vf-os-grid"></div>');
|
||||
if (ci !== 0) grid.hide();
|
||||
|
||||
header.on("click", function () {
|
||||
var isVisible = grid.is(":visible");
|
||||
grid.slideToggle(200);
|
||||
arrow.html(isVisible ? '▶' : '▼');
|
||||
});
|
||||
|
||||
$.each(category.templates, function (ti, tpl) {
|
||||
var label = tpl.name + (tpl.version ? " " + tpl.version : "") + (tpl.variant ? " " + tpl.variant : "");
|
||||
var brandColor = vfGetBrandColor(category.name || tpl.name);
|
||||
var card = $('<div class="vf-os-card"></div>')
|
||||
.attr("data-id", tpl.id)
|
||||
.attr("data-search", label.toLowerCase());
|
||||
if (tpl.eol) card.addClass("vf-os-card-eol");
|
||||
|
||||
var iconDiv = $('<div class="vf-os-icon"></div>').css("background", brandColor);
|
||||
if (tpl.icon && baseUrl) {
|
||||
var img = $('<img alt="">').attr("src", baseUrl + "/storage/os/" + encodeURIComponent(tpl.icon));
|
||||
img.on("error", function () {
|
||||
$(this).parent().empty().append($('<span></span>').text((tpl.name || "?")[0].toUpperCase()));
|
||||
});
|
||||
iconDiv.append(img);
|
||||
} else {
|
||||
iconDiv.append($('<span></span>').text((tpl.name || "?")[0].toUpperCase()));
|
||||
}
|
||||
iconDiv.append($('<span></span>').text((tpl.name || "?")[0].toUpperCase()));
|
||||
|
||||
card.append(iconDiv);
|
||||
card.append($('<div class="vf-os-label"></div>').text(tpl.name));
|
||||
|
||||
Reference in New Issue
Block a user