Fix SVG sprites: convert classes to inline styles, prefix IDs
- Convert Adobe Illustrator .st0/.st1 classes to inline styles - Prefix all IDs (defs, clipPaths) with icon name to avoid conflicts - Fix clip-path references in both attributes and inline styles - Keep defs/clipPaths intact for proper rendering Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,79 @@ $paymentShapes = ['icon', 'square', 'rectangle', 'text-only'];
|
||||
// Social shapes
|
||||
$socialShapes = ['icon', 'full-logo', 'text-only'];
|
||||
|
||||
/**
|
||||
* Convert class-based styles to inline styles and clean up SVG
|
||||
*/
|
||||
function processIcon(string $content, string $iconId): string
|
||||
{
|
||||
// Extract style definitions
|
||||
$styles = [];
|
||||
if (preg_match('/<style[^>]*>(.*?)<\/style>/s', $content, $styleMatch)) {
|
||||
// Parse CSS rules like .st0{fill:#FF0000;}
|
||||
preg_match_all('/\.([a-zA-Z0-9_-]+)\s*\{([^}]+)\}/', $styleMatch[1], $rules, PREG_SET_ORDER);
|
||||
foreach ($rules as $rule) {
|
||||
$className = $rule[1];
|
||||
$cssProps = trim($rule[2]);
|
||||
// Convert CSS to inline style format
|
||||
$styles[$className] = $cssProps;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove style block
|
||||
$content = preg_replace('/<style[^>]*>.*?<\/style>/s', '', $content);
|
||||
|
||||
// Remove XML declaration
|
||||
$content = preg_replace('/<\?xml[^>]+\?>/', '', $content);
|
||||
|
||||
// Remove comments
|
||||
$content = preg_replace('/<!--.*?-->/s', '', $content);
|
||||
|
||||
// Extract defs content for later re-insertion with prefixed IDs
|
||||
$defsContent = '';
|
||||
if (preg_match('/<defs>(.*?)<\/defs>/s', $content, $defsMatch)) {
|
||||
$defsContent = $defsMatch[1];
|
||||
// Prefix IDs in defs
|
||||
$defsContent = preg_replace('/id="([^"]+)"/', 'id="' . $iconId . '_$1"', $defsContent);
|
||||
$content = preg_replace('/<defs>.*?<\/defs>/s', '', $content);
|
||||
}
|
||||
|
||||
// Update clipPath references to use prefixed IDs (both attribute and inline style)
|
||||
$content = preg_replace('/clip-path="url\(#([^)]+)\)"/', 'clip-path="url(#' . $iconId . '_$1)"', $content);
|
||||
$content = preg_replace('/clip-path:\s*url\(#([^)]+)\)/', 'clip-path:url(#' . $iconId . '_$1)', $content);
|
||||
|
||||
// Update xlink:href references
|
||||
$content = preg_replace('/xlink:href="#([^"]+)"/', 'xlink:href="#' . $iconId . '_$1"', $content);
|
||||
|
||||
// Update clipPath IDs themselves
|
||||
$content = preg_replace('/<clipPath id="([^"]+)"/', '<clipPath id="' . $iconId . '_$1"', $content);
|
||||
|
||||
// Replace class attributes with inline styles
|
||||
foreach ($styles as $className => $cssProps) {
|
||||
// Find elements with this class and add inline style
|
||||
$content = preg_replace_callback(
|
||||
'/class="([^"]*\b' . preg_quote($className, '/') . '\b[^"]*)"/',
|
||||
function ($match) use ($cssProps) {
|
||||
return 'style="' . $cssProps . '"';
|
||||
},
|
||||
$content
|
||||
);
|
||||
}
|
||||
|
||||
// Extract inner content (everything between <svg> and </svg>)
|
||||
if (preg_match('/<svg[^>]*>(.*)<\/svg>/s', $content, $match)) {
|
||||
$innerContent = trim($match[1]);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Re-add defs with prefixed IDs if there were any
|
||||
if (!empty($defsContent)) {
|
||||
$innerContent = '<defs>' . $defsContent . '</defs>' . $innerContent;
|
||||
}
|
||||
|
||||
return $innerContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a sprite from a directory of SVG files
|
||||
*/
|
||||
@@ -47,35 +120,15 @@ function buildSprite(string $sourceDir, string $outputFile, string $modeSuffix):
|
||||
preg_match('/viewBox="([^"]+)"/', $content, $viewBoxMatch);
|
||||
$viewBox = $viewBoxMatch[1] ?? '0 0 45 45';
|
||||
|
||||
// Extract width/height if present
|
||||
preg_match('/width="([^"]+)"/', $content, $widthMatch);
|
||||
preg_match('/height="([^"]+)"/', $content, $heightMatch);
|
||||
$width = $widthMatch[1] ?? null;
|
||||
$height = $heightMatch[1] ?? null;
|
||||
// Process the icon (convert styles, prefix IDs)
|
||||
$innerContent = processIcon($content, $filename);
|
||||
|
||||
// Remove XML declaration and outer SVG tags
|
||||
$content = preg_replace('/<\?xml[^>]+\?>/', '', $content);
|
||||
$content = preg_replace('/<!--[^>]*-->/', '', $content);
|
||||
|
||||
// Extract inner content (everything between <svg> and </svg>)
|
||||
if (preg_match('/<svg[^>]*>(.*)<\/svg>/s', $content, $match)) {
|
||||
$innerContent = trim($match[1]);
|
||||
} else {
|
||||
if (empty($innerContent)) {
|
||||
echo " Warning: Could not parse $filename\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
// Clean up the inner content - remove defs with clip-paths that reference unique IDs
|
||||
// and inline styles where possible
|
||||
$innerContent = preg_replace('/<defs>.*?<\/defs>/s', '', $innerContent);
|
||||
$innerContent = preg_replace('/clip-path="url\([^)]+\)"/', '', $innerContent);
|
||||
$innerContent = preg_replace('/<clipPath[^>]*>.*?<\/clipPath>/s', '', $innerContent);
|
||||
$innerContent = preg_replace('/<g[^>]*>\s*<\/g>/', '', $innerContent);
|
||||
|
||||
// Use filename as ID (already includes mode suffix like visa_lm)
|
||||
$id = $filename;
|
||||
|
||||
$symbols[] = " <symbol id=\"$id\" viewBox=\"$viewBox\">$innerContent</symbol>";
|
||||
$symbols[] = " <symbol id=\"$filename\" viewBox=\"$viewBox\">$innerContent</symbol>";
|
||||
}
|
||||
|
||||
if (empty($symbols)) {
|
||||
@@ -83,7 +136,7 @@ function buildSprite(string $sourceDir, string $outputFile, string $modeSuffix):
|
||||
return;
|
||||
}
|
||||
|
||||
$sprite = "<svg xmlns=\"http://www.w3.org/2000/svg\" style=\"display:none\">\n";
|
||||
$sprite = "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" style=\"display:none\">\n";
|
||||
$sprite .= implode("\n", $symbols) . "\n";
|
||||
$sprite .= "</svg>\n";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user