Skip to content

Commit 3d4e389

Browse files
committed
feat: improve multi-color SVG handling and accessibility
- Add detection for paths with different colors - Display warning when merging multi-colored SVGs - Apply fill-rule='evenodd' by default to preserve overlapping paths - Improve toast contrast for WCAG AAA compliance (warnings with dark text) - Update FAQ with multi-colored SVG behavior explanation - Update Schema.org structured data with new FAQ entry
1 parent 6adc6fa commit 3d4e389

2 files changed

Lines changed: 57 additions & 12 deletions

File tree

index.html

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,15 @@
8484
"name": "Will merging paths change my SVG appearance?",
8585
"acceptedAnswer": {
8686
"@type": "Answer",
87-
"text": "No, merging paths only combines the path data into a single element. The visual appearance remains exactly the same. However, if multiple paths have different fill or stroke colors, the merged path will inherit the fill or stroke color of the first path."
87+
"text": "In most cases, no. The visual appearance remains the same when paths use the same colors. However, if your SVG uses multiple fill or stroke colors, see the question about multi-colored SVGs."
88+
}
89+
},
90+
{
91+
"@type": "Question",
92+
"name": "What happens with multi-colored SVGs?",
93+
"acceptedAnswer": {
94+
"@type": "Answer",
95+
"text": "When merging paths with different colors, all paths will inherit the color of the first path. This means details with different colors may become less visible or disappear. The tool will warn you when this happens. For best results, use this tool with single-color SVGs or SVGs where overlapping paths create cutouts."
8896
}
8997
},
9098
{
@@ -273,7 +281,11 @@ <h3 class="font-semibold text-slate-900 dark:text-slate-100 mb-2">What is an SVG
273281
</div>
274282
<div>
275283
<h3 class="font-semibold text-slate-900 dark:text-slate-100 mb-2">Will merging paths change my SVG appearance?</h3>
276-
<p class="text-slate-600 dark:text-slate-400">No, merging paths only combines the path data into a single element. The visual appearance remains exactly the same. However, if multiple paths have different fill or stroke colors, the merged path will inherit the fill or stroke color of the first path.</p>
284+
<p class="text-slate-600 dark:text-slate-400">In most cases, no. The visual appearance remains the same when paths use the same colors. However, if your SVG uses multiple fill or stroke colors, see the question below about multi-colored SVGs.</p>
285+
</div>
286+
<div>
287+
<h3 class="font-semibold text-slate-900 dark:text-slate-100 mb-2">What happens with multi-colored SVGs?</h3>
288+
<p class="text-slate-600 dark:text-slate-400">When merging paths with different colors, all paths will inherit the color of the first path. This means details with different colors may become less visible or disappear. The tool will warn you when this happens. For best results, use this tool with single-color SVGs or SVGs where overlapping paths create cutouts (which will be preserved using <code class="text-slate-800 dark:text-slate-300">fill-rule="evenodd"</code>).</p>
277289
</div>
278290
<div>
279291
<h3 class="font-semibold text-slate-900 dark:text-slate-100 mb-2">Is this tool free to use?</h3>

src/main.js

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,14 @@ function handleInput() {
214214
});
215215

216216
// Merge paths
217-
const mergedSvg = mergePaths(svgElement, paths);
217+
const mergeResult = mergePaths(svgElement, paths);
218+
const mergedSvg = mergeResult.svg;
219+
220+
// Show warnings if any colors are lost
221+
if (mergeResult.warnings.length > 0) {
222+
const warningMessage = '⚠️ Note: ' + mergeResult.warnings.join(' ');
223+
showToast(warningMessage, 'warning');
224+
}
218225

219226
// Display output
220227
outputSvg.value = formatSvg(mergedSvg);
@@ -236,19 +243,26 @@ function handleInput() {
236243
* Merges all path elements into a single path
237244
* @param {SVGElement} svgElement - The SVG element
238245
* @param {NodeList} paths - Collection of path elements
239-
* @returns {string} - The merged SVG string
246+
* @returns {Object} - Object containing merged SVG string and warnings
240247
*/
241248
function mergePaths(svgElement, paths) {
242249
// Clone the SVG element
243250
const clonedSvg = svgElement.cloneNode(true);
244251

245-
// Collect all path data
252+
// Collect all path data and check for different colors
246253
const pathDataArray = [];
247-
const transforms = [];
254+
const fills = new Set();
255+
const strokes = new Set();
256+
const warnings = [];
248257

249258
paths.forEach(path => {
250259
const d = path.getAttribute('d');
251260
const transform = path.getAttribute('transform');
261+
const fill = path.getAttribute('fill') || 'none';
262+
const stroke = path.getAttribute('stroke') || 'none';
263+
264+
if (fill !== 'none') fills.add(fill);
265+
if (stroke !== 'none') strokes.add(stroke);
252266

253267
if (d) {
254268
// If path has a transform, we need to apply it
@@ -260,6 +274,14 @@ function mergePaths(svgElement, paths) {
260274
}
261275
});
262276

277+
// Check if there are multiple colors
278+
if (fills.size > 1) {
279+
warnings.push(`Multiple fill colors detected (${fills.size} different colors). All paths will use the first color found.`);
280+
}
281+
if (strokes.size > 1) {
282+
warnings.push(`Multiple stroke colors detected (${strokes.size} different colors). All paths will use the first stroke found.`);
283+
}
284+
263285
// Combine all path data
264286
const mergedPathData = pathDataArray.join(' ');
265287

@@ -275,16 +297,24 @@ function mergePaths(svgElement, paths) {
275297
const fill = firstPath.getAttribute('fill');
276298
const stroke = firstPath.getAttribute('stroke');
277299
const strokeWidth = firstPath.getAttribute('stroke-width');
300+
const fillRule = firstPath.getAttribute('fill-rule');
278301

279302
if (fill) newPath.setAttribute('fill', fill);
280303
if (stroke) newPath.setAttribute('stroke', stroke);
281304
if (strokeWidth) newPath.setAttribute('stroke-width', strokeWidth);
282305

306+
// Set fill-rule to evenodd to handle overlapping paths correctly
307+
// This allows overlapping shapes to create visual cutouts
308+
newPath.setAttribute('fill-rule', fillRule || 'evenodd');
309+
283310
// Append the new path to the SVG
284311
clonedSvg.appendChild(newPath);
285312

286-
// Return the serialized SVG
287-
return new XMLSerializer().serializeToString(clonedSvg);
313+
// Return the serialized SVG and warnings
314+
return {
315+
svg: new XMLSerializer().serializeToString(clonedSvg),
316+
warnings: warnings
317+
};
288318
}
289319

290320
/**
@@ -603,14 +633,17 @@ function clearInput() {
603633
function showToast(message, type = 'success') {
604634
toast.textContent = message;
605635

606-
let bgColor = 'bg-green-500 dark:bg-green-600'; // success
636+
let bgColor = 'bg-green-700 dark:bg-green-900'; // success
637+
let textColor = 'text-white'; // default white text
638+
607639
if (type === 'error') {
608-
bgColor = 'bg-red-500 dark:bg-red-600';
640+
bgColor = 'bg-red-700 dark:bg-red-900';
609641
} else if (type === 'warning') {
610-
bgColor = 'bg-yellow-500 dark:bg-yellow-600';
642+
bgColor = 'bg-yellow-50 dark:bg-yellow-900';
643+
textColor = 'text-slate-900 dark:text-slate-200'; // dark text for better contrast
611644
}
612645

613-
toast.className = `fixed bottom-8 right-8 px-6 py-4 rounded-lg shadow-custom-lg font-medium transition-all duration-300 ${bgColor} text-white opacity-0 translate-y-4 pointer-events-none`;
646+
toast.className = `fixed bottom-8 right-8 px-6 py-4 rounded-lg shadow-custom-lg font-medium transition-all duration-300 ${bgColor} ${textColor} opacity-0 translate-y-4 pointer-events-none`;
614647

615648
// Trigger reflow to restart animation
616649
void toast.offsetWidth;

0 commit comments

Comments
 (0)