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"
},
"targets": {
"part_s1": "#s1",
"part_s2": "#s2",
"part_l": "#l"
"part_s": "#s",
"part_s_stroke": "#s&stroke",
"part_l": "#l",
"part_l_stroke": "#l&stroke"
},
"sets": {
"light": {
"part_s1": "red",
"part_s2": "red",
"part_l": "white"
"part_s": "red",
"part_l": "white",
"part_l_stroke": "black",
"part_s_stroke": "black"
},
"dark": {
"part_s1": "red",
"part_s2": "red",
"part_l": "black"
"part_s": "red",
"part_l": "black",
"part_l_stroke": "white",
"part_s_stroke": "white"
},
"uk": {
"part_s1": "uk_red",
"part_s2": "uk_red",
"part_l": "uk_blue"
},
"ua": {
"part_s1": "ua_blue",
"part_s2": "ua_blue",
"part_l": "ua_yellow"
"part_s": "ua_blue",
"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",
"format": "SVG",
"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">
<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" />
<g stroke="#eee" stroke-width="0" stroke-miterlimit="10">
<path id="s1" fill="#dc2108" 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" />
<g id="s" fill="#dc2108" stroke="none" stroke-width="2" stroke-miterlimit="10">
<path d="m161.2 500 106.1-100.8-39-37.2-66.9 63.6z" />
<path d="m275 174.3-113.8 108.9 113.8 108.9v-73.6l-37-35.3 37-36.3z" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 485 B

After

Width:  |  Height:  |  Size: 461 B

View File

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

View File

@@ -23,12 +23,41 @@
// For SVG source code display
let svgSource = "";
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) {
return logo && logo.format && logo.format.toLowerCase() === "svg";
}
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 {
navigator.clipboard.writeText(svgSource);
return true;
@@ -41,14 +70,18 @@
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 =
logo && typeof logo.colorConfig === "object" && logo.colorConfig.selector
? logo.colorConfig
: undefined;
// Only fetch SVG source when displayed
$: getLogoThemeColor = (logo) => getDefaultLogoColor(logo.colors, theme);
$: if (show && logo) {
if (logo.format === "SVG" && !svgSource) {
isFetchingSvgSource = true;
@@ -106,6 +139,7 @@
<div class="preview-container" use:removeSvgSize>
{#if isSvgLogo(logo)}
<InlineSvg
bind:this={inlineSvgRef}
path={logo.path}
color={logo.colors
? logo._activeColor || getLogoThemeColor(logo)
@@ -132,10 +166,18 @@
role="button"
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;"
on:click|stopPropagation={() => (logo._activeColor = undefined)}
on:keydown|stopPropagation={(e) =>
(e.key === "Enter" || e.key === " ") &&
(logo._activeColor = undefined)}
on:click|stopPropagation={() => {
logo._activeColor = undefined;
logo._activeSet = undefined; // Reset activeSet too
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
width="100%"
@@ -160,6 +202,7 @@
i % Object.keys(logo.colors).length
];
logo._activeSet = setName;
setTimeout(updateSvgSource, 100); // Update SVG source after color change
}}
on:keydown|stopPropagation={(e) => {
if (e.key === "Enter" || e.key === " ") {
@@ -167,6 +210,7 @@
i % Object.keys(logo.colors).length
];
logo._activeSet = setName;
setTimeout(updateSvgSource, 100); // Update SVG source after color change
}
}}
style="padding: 0; overflow: hidden;"
@@ -182,11 +226,18 @@
style={`background:${colorValue}`}
tabindex="0"
role="button"
on:click|stopPropagation={() =>
(logo._activeColor = colorValue)}
on:keydown|stopPropagation={(e) =>
(e.key === "Enter" || e.key === " ") &&
(logo._activeColor = colorValue)}
on:click|stopPropagation={() => {
logo._activeColor = colorValue;
logo._activeSet = undefined; // Clear any active set when setting individual color
setTimeout(updateSvgSource, 100); // Update SVG source after color change
}}
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>
{/each}
{/if}

View File

@@ -9,6 +9,7 @@
export let colors = null;
export let alt = "";
let svgHtml = "";
let svgSource = ""; // Store the updated SVG source code
async function fetchAndColorSvg() {
const res = await fetch(path);
@@ -58,37 +59,69 @@
// Remove all <style> elements
styleEls.forEach((styleEl) => styleEl.remove());
// 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
const colorAssignments = sets[activeSet];
// Apply each target-color pair
for (const [targetName, colorName] of Object.entries(colorAssignments)) {
if (targets[targetName] && colors && colors[colorName]) {
// Get the selector for this target
const selector = targets[targetName];
// Get the selector and determine if it's for fill or stroke
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);
// Get the actual color value for this target
const targetColor = colors[colorName];
// Apply the color to all elements matching this selector
targetElements.forEach(el => {
// Always override fill and stroke unless they are 'none'
if (el.hasAttribute("fill") && el.getAttribute("fill") !== "none") {
if (colorName === "none") {
// Special case for 'none' value
el.setAttribute(attribute, "none");
} else if (attribute === 'fill') {
el.setAttribute("fill", targetColor);
}
if (el.hasAttribute("stroke") && el.getAttribute("stroke") !== "none") {
} else if (attribute === 'stroke') {
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;
// 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();