feat: enhance SVG handling by updating color targets and adding SVG source retrieval; refactor Actions and InlineSvg components for improved functionality

This commit is contained in:
sHa
2025-05-16 12:25:33 +03:00
parent cd753de3db
commit 6b4bada5f4
5 changed files with 143 additions and 57 deletions

View File

@@ -1544,30 +1544,33 @@
"ua_yellow": "#FFDD00" "ua_yellow": "#FFDD00"
}, },
"targets": { "targets": {
"part_s1": "#s1", "part_s": "#s",
"part_s2": "#s2", "part_s_stroke": "#s&stroke",
"part_l": "#l" "part_l": "#l",
"part_l_stroke": "#l&stroke"
}, },
"sets": { "sets": {
"light": { "light": {
"part_s1": "red", "part_s": "red",
"part_s2": "red", "part_l": "white",
"part_l": "white" "part_l_stroke": "black",
"part_s_stroke": "black"
}, },
"dark": { "dark": {
"part_s1": "red", "part_s": "red",
"part_s2": "red", "part_l": "black",
"part_l": "black" "part_l_stroke": "white",
"part_s_stroke": "white"
}, },
"uk": { "uk": {
"part_s1": "uk_red",
"part_s2": "uk_red", "part_s2": "uk_red",
"part_l": "uk_blue" "part_l": "uk_blue"
}, },
"ua": { "ua": {
"part_s1": "ua_blue", "part_s": "ua_blue",
"part_s2": "ua_blue", "part_l": "ua_yellow",
"part_l": "ua_yellow" "part_l_stroke": "none",
"part_s_stroke": "none"
} }
} }
}, },
@@ -1582,7 +1585,7 @@
] ]
}, },
{ {
"name": "Shkafnik Logo", "name": "Shkafnik",
"path": "logos/shkafnik_logo.svg", "path": "logos/shkafnik_logo.svg",
"format": "SVG", "format": "SVG",
"disable": false, "disable": false,

View File

@@ -1,8 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" height="510" width="510" viewBox="0 0 510 510"> <svg xmlns="http://www.w3.org/2000/svg" height="510" width="510" viewBox="0 0 510 510">
<path id="l" d="m286.7 401.2 61.9 60.2v-389.4l-62.4-60.6z" fill="currentColor" stroke="#eee" stroke-width="0" <path id="l" d="m286.7 401.2 61.9 60.2v-389.4l-62.4-60.6z" fill="currentColor" stroke="none" stroke-width="2"
stroke-miterlimit="10" /> stroke-miterlimit="10" />
<g stroke="#eee" stroke-width="0" stroke-miterlimit="10"> <g id="s" fill="#dc2108" stroke="none" stroke-width="2" stroke-miterlimit="10">
<path id="s1" fill="#dc2108" d="m161.2 500 106.1-100.8-39-37.2-66.9 63.6z" /> <path d="m161.2 500 106.1-100.8-39-37.2-66.9 63.6z" />
<path id="s2" fill="#dc2108" d="m275 174.3-113.8 108.9 113.8 108.9v-73.6l-37-35.3 37-36.3z" /> <path d="m275 174.3-113.8 108.9 113.8 108.9v-73.6l-37-35.3 37-36.3z" />
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 485 B

After

Width:  |  Height:  |  Size: 461 B

View File

@@ -393,7 +393,7 @@
top: 110%; top: 110%;
right: auto; right: auto;
left: 0; left: 0;
min-width: 200px; /* Increased width from 160px */ min-width: 200px;
background: var(--color-card, #fff); background: var(--color-card, #fff);
color: var(--color-text, #222); color: var(--color-text, #222);
border: 1px solid var(--color-border, #ddd); border: 1px solid var(--color-border, #ddd);
@@ -407,7 +407,6 @@
pointer-events: auto; pointer-events: auto;
} }
/* Dropdown menus are positioned with JavaScript instead of CSS */
.dropdown-item { .dropdown-item {
background: none; background: none;
color: var(--color-text, #222); color: var(--color-text, #222);
@@ -439,7 +438,7 @@
padding-left: 5px; padding-left: 5px;
white-space: nowrap; white-space: nowrap;
} }
/* Notification styles moved to Notification.svelte */
.notification-overlay { .notification-overlay {
position: fixed; position: fixed;
top: 20px; top: 20px;

View File

@@ -23,12 +23,41 @@
// For SVG source code display // For SVG source code display
let svgSource = ""; let svgSource = "";
let isFetchingSvgSource = false; let isFetchingSvgSource = false;
let inlineSvgRef; // Reference to the InlineSvg component
// Watch for color changes and update SVG source
function updateSvgSource() {
if (inlineSvgRef && typeof inlineSvgRef.getSvgSource === 'function') {
const newSource = inlineSvgRef.getSvgSource();
if (newSource) {
svgSource = newSource;
}
}
}
function isSvgLogo(logo) { function isSvgLogo(logo) {
return logo && logo.format && logo.format.toLowerCase() === "svg"; return logo && logo.format && logo.format.toLowerCase() === "svg";
} }
function copySvgSourceFromTextarea() { function copySvgSourceFromTextarea() {
if (svgSource) { if (inlineSvgRef && typeof inlineSvgRef.getSvgSource === 'function') {
// Get the updated SVG source with all color changes applied
const updatedSource = inlineSvgRef.getSvgSource();
try {
const tempEl = document.createElement('textarea');
tempEl.value = updatedSource || svgSource;
document.body.appendChild(tempEl);
tempEl.select();
document.execCommand('copy');
document.body.removeChild(tempEl);
return true;
} catch (err) {
console.error("Error copying SVG source:", err);
window.prompt("Copy the SVG source code:", updatedSource || svgSource);
return false;
}
} else if (svgSource) {
// Fallback to the original source if component reference is not available
try { try {
navigator.clipboard.writeText(svgSource); navigator.clipboard.writeText(svgSource);
return true; return true;
@@ -41,14 +70,18 @@
return false; return false;
} }
$: getLogoThemeColor = (logo) => getDefaultLogoColor(logo.colors, theme); // Update SVG source every time the component rerenders with new colors
$: if (logo && (logo._activeColor || (logo && logo._activeSet))) {
// Use a small delay to ensure the SVG has been rendered with the new colors
setTimeout(updateSvgSource, 100);
}
$: validColorConfig = $: validColorConfig =
logo && typeof logo.colorConfig === "object" && logo.colorConfig.selector logo && typeof logo.colorConfig === "object" && logo.colorConfig.selector
? logo.colorConfig ? logo.colorConfig
: undefined; : undefined;
// Only fetch SVG source when displayed $: getLogoThemeColor = (logo) => getDefaultLogoColor(logo.colors, theme);
$: if (show && logo) { $: if (show && logo) {
if (logo.format === "SVG" && !svgSource) { if (logo.format === "SVG" && !svgSource) {
isFetchingSvgSource = true; isFetchingSvgSource = true;
@@ -106,6 +139,7 @@
<div class="preview-container" use:removeSvgSize> <div class="preview-container" use:removeSvgSize>
{#if isSvgLogo(logo)} {#if isSvgLogo(logo)}
<InlineSvg <InlineSvg
bind:this={inlineSvgRef}
path={logo.path} path={logo.path}
color={logo.colors color={logo.colors
? logo._activeColor || getLogoThemeColor(logo) ? logo._activeColor || getLogoThemeColor(logo)
@@ -132,10 +166,18 @@
role="button" role="button"
aria-label="Reset to theme color" aria-label="Reset to theme color"
style="background: none; width: 24px; height: 24px; display: inline-flex; align-items: center; justify-content: center; padding: 0; margin: 0; border: none;" style="background: none; width: 24px; height: 24px; display: inline-flex; align-items: center; justify-content: center; padding: 0; margin: 0; border: none;"
on:click|stopPropagation={() => (logo._activeColor = undefined)} on:click|stopPropagation={() => {
on:keydown|stopPropagation={(e) => logo._activeColor = undefined;
(e.key === "Enter" || e.key === " ") && logo._activeSet = undefined; // Reset activeSet too
(logo._activeColor = undefined)} setTimeout(updateSvgSource, 100); // Update SVG source after color reset
}}
on:keydown|stopPropagation={(e) => {
if (e.key === "Enter" || e.key === " ") {
logo._activeColor = undefined;
logo._activeSet = undefined;
setTimeout(updateSvgSource, 100);
}
}}
> >
<svg <svg
width="100%" width="100%"
@@ -160,6 +202,7 @@
i % Object.keys(logo.colors).length i % Object.keys(logo.colors).length
]; ];
logo._activeSet = setName; logo._activeSet = setName;
setTimeout(updateSvgSource, 100); // Update SVG source after color change
}} }}
on:keydown|stopPropagation={(e) => { on:keydown|stopPropagation={(e) => {
if (e.key === "Enter" || e.key === " ") { if (e.key === "Enter" || e.key === " ") {
@@ -167,6 +210,7 @@
i % Object.keys(logo.colors).length i % Object.keys(logo.colors).length
]; ];
logo._activeSet = setName; logo._activeSet = setName;
setTimeout(updateSvgSource, 100); // Update SVG source after color change
} }
}} }}
style="padding: 0; overflow: hidden;" style="padding: 0; overflow: hidden;"
@@ -182,11 +226,18 @@
style={`background:${colorValue}`} style={`background:${colorValue}`}
tabindex="0" tabindex="0"
role="button" role="button"
on:click|stopPropagation={() => on:click|stopPropagation={() => {
(logo._activeColor = colorValue)} logo._activeColor = colorValue;
on:keydown|stopPropagation={(e) => logo._activeSet = undefined; // Clear any active set when setting individual color
(e.key === "Enter" || e.key === " ") && setTimeout(updateSvgSource, 100); // Update SVG source after color change
(logo._activeColor = colorValue)} }}
on:keydown|stopPropagation={(e) => {
if (e.key === "Enter" || e.key === " ") {
logo._activeColor = colorValue;
logo._activeSet = undefined; // Clear any active set
setTimeout(updateSvgSource, 100); // Update SVG source after color change
}
}}
></span> ></span>
{/each} {/each}
{/if} {/if}

View File

@@ -9,6 +9,7 @@
export let colors = null; export let colors = null;
export let alt = ""; export let alt = "";
let svgHtml = ""; let svgHtml = "";
let svgSource = ""; // Store the updated SVG source code
async function fetchAndColorSvg() { async function fetchAndColorSvg() {
const res = await fetch(path); const res = await fetch(path);
@@ -58,37 +59,69 @@
// 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 && sets[activeSet]) { if (targets && sets && activeSet && typeof activeSet === 'string' && sets[activeSet]) {
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 for this target // Get the selector and determine if it's for fill or stroke
const selector = targets[targetName]; const targetInfo = targets[targetName];
// Parse the selector to extract the target and attribute (fill/stroke)
let selector, attribute;
if (typeof targetInfo === 'string') {
if (targetInfo.includes('&stroke')) {
// Format: "#element&stroke" - target stroke attribute
selector = targetInfo.split('&stroke')[0];
attribute = 'stroke';
} else if (targetInfo.includes('&fill')) {
// Format: "#element&fill" - target fill attribute
selector = targetInfo.split('&fill')[0];
attribute = 'fill';
} else {
// Default is fill if not specified
selector = targetInfo;
attribute = 'fill';
}
} else {
// Fallback for older format
selector = targetInfo;
attribute = 'fill';
}
// Proceed with selecting elements and applying colors
const targetElements = doc.querySelectorAll(selector); const targetElements = doc.querySelectorAll(selector);
// Get the actual color value for this target
const targetColor = colors[colorName]; const targetColor = colors[colorName];
// Apply the color to all elements matching this selector // Apply the color to all elements matching this selector
targetElements.forEach(el => { targetElements.forEach(el => {
// Always override fill and stroke unless they are 'none' if (colorName === "none") {
if (el.hasAttribute("fill") && el.getAttribute("fill") !== "none") { // Special case for 'none' value
el.setAttribute(attribute, "none");
} else if (attribute === 'fill') {
el.setAttribute("fill", targetColor); el.setAttribute("fill", targetColor);
} } else if (attribute === 'stroke') {
if (el.hasAttribute("stroke") && el.getAttribute("stroke") !== "none") {
el.setAttribute("stroke", targetColor); el.setAttribute("stroke", targetColor);
} }
if (!el.hasAttribute("fill") && !el.hasAttribute("stroke")) {
// If neither, prefer fill
el.setAttribute("fill", targetColor);
}
}); });
} }
} }
} catch (err) {
console.error("Error applying color set:", err);
}
} }
svgHtml = doc.documentElement.outerHTML; 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 function getSvgSource() {
return svgSource;
} }
$: path, color, colorConfig, targets, sets, activeSet, colors, fetchAndColorSvg(); $: path, color, colorConfig, targets, sets, activeSet, colors, fetchAndColorSvg();