fix: Update collection label retrieval to support titles and improve SVG error handling

This commit is contained in:
sHa
2025-06-18 16:49:05 +03:00
parent 5baa4bfab4
commit 83dd8245a8
2 changed files with 106 additions and 93 deletions

View File

@@ -45,7 +45,8 @@
dropdownOpen = false; dropdownOpen = false;
} }
$: currentLabel = (collections.find(c => c.name === collection)?.label || "Logo Gallery").replace(/s$/, ""); $: currentCollectionObj = collections.find(c => c.name === collection);
$: currentLabel = (currentCollectionObj?.title || currentCollectionObj?.label || "Logo Gallery").replace(/s$/, "");
</script> </script>
<header class="main-header"> <header class="main-header">
@@ -55,7 +56,7 @@
<img src="favicon.svg" alt="Logo Gallery icon" /> <img src="favicon.svg" alt="Logo Gallery icon" />
</div> </div>
<button class="collection-title-btn" on:click={handleTitleClick} aria-haspopup="listbox" aria-expanded={dropdownOpen}> <button class="collection-title-btn" on:click={handleTitleClick} aria-haspopup="listbox" aria-expanded={dropdownOpen}>
{currentLabel} Gallery <span class="triangle"></span> {currentLabel} <span class="triangle"></span>
</button> </button>
{#if dropdownOpen} {#if dropdownOpen}
<ul class="collection-dropdown" role="listbox"> <ul class="collection-dropdown" role="listbox">
@@ -72,7 +73,7 @@
handleCollectionSelect(c.name); handleCollectionSelect(c.name);
} }
}} }}
>{c.label} Gallery</li> >{c.title} Gallery</li>
{/each} {/each}
</ul> </ul>
{/if} {/if}
@@ -107,6 +108,7 @@
{getTagObj} {getTagObj}
{compactMode} {compactMode}
{setCompactMode} {setCompactMode}
collection={currentCollectionObj}
/> />
<ListViewSwitcher <ListViewSwitcher
{viewMode} {viewMode}

View File

@@ -12,111 +12,122 @@
let svgSource = ""; // Store the updated SVG source code let svgSource = ""; // Store the updated SVG source code
async function fetchAndColorSvg() { async function fetchAndColorSvg() {
const res = await fetch(path); try {
let text = await res.text(); const res = await fetch(path);
if (!color) { if (!res.ok) {
// No user-selected color, add currentColor to ensure theme colors are applied svgHtml = `<svg width='100%' height='100%' viewBox='0 0 64 64' fill='none' xmlns='http://www.w3.org/2000/svg'><rect width='64' height='64' fill='#eee'/><line x1='16' y1='16' x2='48' y2='48' stroke='#888' stroke-width='4'/><line x1='48' y1='16' x2='16' y2='48' stroke='#888' stroke-width='4'/></svg>`;
svgSource = svgHtml;
return;
}
let text = await res.text();
if (!color) {
// No user-selected color, add currentColor to ensure theme colors are applied
const parser = new DOMParser();
const doc = parser.parseFromString(text, "image/svg+xml");
const svg = doc.documentElement;
// Set currentColor on SVG element if no fill is specified
if (!svg.hasAttribute("fill")) {
svg.setAttribute("fill", "currentColor");
}
svgHtml = doc.documentElement.outerHTML;
return;
}
// Parse and update color only if user selected
const parser = new DOMParser(); const parser = new DOMParser();
const doc = parser.parseFromString(text, "image/svg+xml"); const doc = parser.parseFromString(text, "image/svg+xml");
const svg = doc.documentElement; // 1. Parse <style> rules and apply as inline attributes before removing <style>
const styleEls = Array.from(doc.querySelectorAll("style"));
// Set currentColor on SVG element if no fill is specified styleEls.forEach((styleEl) => {
if (!svg.hasAttribute("fill")) { const css = styleEl.textContent;
svg.setAttribute("fill", "currentColor"); // Only handle simple .class { ... } rules
} const regex = /\.([\w-]+)\s*{([^}]*)}/g;
let match;
svgHtml = doc.documentElement.outerHTML; while ((match = regex.exec(css))) {
return; const className = match[1];
} const rules = match[2];
// Parse and update color only if user selected // Find all elements with this class
const parser = new DOMParser(); doc.querySelectorAll("." + className).forEach((el) => {
const doc = parser.parseFromString(text, "image/svg+xml"); rules.split(";").forEach((rule) => {
// 1. Parse <style> rules and apply as inline attributes before removing <style> const [prop, value] = rule.split(":").map((s) => s && s.trim());
const styleEls = Array.from(doc.querySelectorAll("style")); if (prop && value) {
styleEls.forEach((styleEl) => { // Apply all style properties, not just fill/stroke
const css = styleEl.textContent; el.setAttribute(
// Only handle simple .class { ... } rules prop.replace(/-([a-z])/g, (g) => g[1].toUpperCase()),
const regex = /\.([\w-]+)\s*{([^}]*)}/g; value,
let match; );
while ((match = regex.exec(css))) { }
const className = match[1]; });
const rules = match[2];
// Find all elements with this class
doc.querySelectorAll("." + className).forEach((el) => {
rules.split(";").forEach((rule) => {
const [prop, value] = rule.split(":").map((s) => s && s.trim());
if (prop && value) {
// Apply all style properties, not just fill/stroke
el.setAttribute(
prop.replace(/-([a-z])/g, (g) => g[1].toUpperCase()),
value,
);
}
}); });
}); }
} });
}); // Remove all <style> elements
// Remove all <style> elements styleEls.forEach((styleEl) => styleEl.remove());
styleEls.forEach((styleEl) => styleEl.remove()); // Handle the new format with targets and sets if available
// Handle the new format with targets and sets if available if (targets && sets && activeSet && typeof activeSet === 'string' && sets[activeSet]) {
if (targets && sets && activeSet && typeof activeSet === 'string' && sets[activeSet]) { try {
try { // Get the color assignments from the active set
// Get the color assignments from the active set const colorAssignments = sets[activeSet];
const colorAssignments = sets[activeSet];
// Apply each target-color pair // Apply each target-color pair
for (const [targetName, colorName] of Object.entries(colorAssignments)) { for (const [targetName, colorName] of Object.entries(colorAssignments)) {
if (targets[targetName] && colors && colors[colorName]) { if (targets[targetName] && colors && colors[colorName]) {
// Get the selector and determine if it's for fill or stroke // Get the selector and determine if it's for fill or stroke
const targetInfo = targets[targetName]; const targetInfo = targets[targetName];
// Parse the selector to extract the target and attribute (fill/stroke) // Parse the selector to extract the target and attribute (fill/stroke)
let selector, attribute; let selector, attribute;
if (typeof targetInfo === 'string') { if (typeof targetInfo === 'string') {
if (targetInfo.includes('&stroke')) { if (targetInfo.includes('&stroke')) {
// Format: "#element&stroke" - target stroke attribute // Format: "#element&stroke" - target stroke attribute
selector = targetInfo.split('&stroke')[0]; selector = targetInfo.split('&stroke')[0];
attribute = 'stroke'; attribute = 'stroke';
} else if (targetInfo.includes('&fill')) { } else if (targetInfo.includes('&fill')) {
// Format: "#element&fill" - target fill attribute // Format: "#element&fill" - target fill attribute
selector = targetInfo.split('&fill')[0]; selector = targetInfo.split('&fill')[0];
attribute = 'fill'; attribute = 'fill';
} else {
// Default is fill if not specified
selector = targetInfo;
attribute = 'fill';
}
} else { } else {
// Default is fill if not specified // Fallback for older format
selector = targetInfo; selector = targetInfo;
attribute = 'fill'; attribute = 'fill';
} }
} else {
// Fallback for older format // Proceed with selecting elements and applying colors
selector = targetInfo; const targetElements = doc.querySelectorAll(selector);
attribute = 'fill'; const targetColor = colors[colorName];
// Apply the color to all elements matching this selector
targetElements.forEach(el => {
if (colorName === "none") {
// Special case for 'none' value
el.setAttribute(attribute, "none");
} else if (attribute === 'fill') {
el.setAttribute("fill", targetColor);
} else if (attribute === 'stroke') {
el.setAttribute("stroke", targetColor);
}
});
} }
// Proceed with selecting elements and applying colors
const targetElements = doc.querySelectorAll(selector);
const targetColor = colors[colorName];
// Apply the color to all elements matching this selector
targetElements.forEach(el => {
if (colorName === "none") {
// Special case for 'none' value
el.setAttribute(attribute, "none");
} else if (attribute === 'fill') {
el.setAttribute("fill", targetColor);
} else if (attribute === 'stroke') {
el.setAttribute("stroke", targetColor);
}
});
} }
} catch (err) {
console.error("Error applying color set:", err);
} }
} catch (err) {
console.error("Error applying color set:", err);
} }
svgHtml = doc.documentElement.outerHTML;
// Update the svgSource property to store the modified SVG code
svgSource = doc.documentElement.outerHTML;
} catch (error) {
console.error("Error fetching or processing SVG:", error);
svgHtml = `<svg width='100%' height='100%' viewBox='0 0 64 64' fill='none' xmlns='http://www.w3.org/2000/svg'><rect width='64' height='64' fill='#eee'/><line x1='16' y1='16' x2='48' y2='48' stroke='#888' stroke-width='4'/><line x1='48' y1='16' x2='16' y2='48' stroke='#888' stroke-width='4'/></svg>`;
svgSource = svgHtml;
} }
svgHtml = doc.documentElement.outerHTML;
// Update the svgSource property to store the modified SVG code
svgSource = doc.documentElement.outerHTML;
} }
// Export the svgSource so it can be accessed from outside // Export the svgSource so it can be accessed from outside