#!/usr/bin/env python3 """ SVG Beautifier - Updates all SVG diagrams for perfect readability on all devices with beautiful colors that work in both color and black/white modes. """ import os import re from pathlib import Path # Beautiful color palette that works in grayscale COLORS = { # Primary colors with good contrast 'primary_blue': '#2563EB', # Bright blue - appears as dark gray in B&W 'primary_green': '#059669', # Emerald green - medium gray in B&W 'primary_purple': '#7C3AED', # Purple - medium-dark gray in B&W 'primary_orange': '#EA580C', # Orange - medium gray in B&W 'primary_red': '#DC2626', # Red - dark gray in B&W 'primary_teal': '#0891B2', # Teal - medium gray in B&W # Text colors for maximum readability 'text_primary': '#1F2937', # Almost black - perfect for main text 'text_secondary': '#4B5563', # Dark gray - for secondary text 'text_accent': '#2563EB', # Blue for emphasis - dark in B&W # Background and border colors 'bg_light': '#F9FAFB', # Very light gray background 'border_primary': '#2563EB', # Blue borders - visible in B&W 'border_secondary': '#9CA3AF', # Gray borders # Status colors 'success': '#059669', # Green - medium gray in B&W 'warning': '#EA580C', # Orange - medium gray in B&W 'error': '#DC2626', # Red - dark gray in B&W 'info': '#2563EB', # Blue - dark gray in B&W } # Consistent font sizes for all devices (matching documentation) FONT_SIZES = { 'title': '24', # Main diagram titles 'subtitle': '20', # Section titles 'heading': '18', # Component headings 'body': '16', # Main text (matches doc font size) 'label': '14', # Labels and annotations 'small': '12', # Small details (minimum for mobile) } # Standard margins and padding LAYOUT = { 'margin': 40, # Outer margin 'padding': 20, # Inner padding 'spacing': 15, # Element spacing 'corner_radius': 8, # Rounded corners } def create_improved_svg(content, filename): """ Transform SVG content with improved styling for all devices. """ # Extract viewBox or width/height viewbox_match = re.search(r'viewBox="([^"]+)"', content) width_match = re.search(r'width="(\d+)"', content) height_match = re.search(r'height="(\d+)"', content) if viewbox_match: viewbox = viewbox_match.group(1) vb_parts = viewbox.split() width = int(vb_parts[2]) height = int(vb_parts[3]) elif width_match and height_match: width = int(width_match.group(1)) height = int(height_match.group(1)) else: width, height = 800, 600 # Default size # Add responsive margins new_width = width + (LAYOUT['margin'] * 2) new_height = height + (LAYOUT['margin'] * 2) # Create new SVG header with responsive sizing new_header = f''' ''' # Process the content content = re.sub(r']*>', '', content) content = re.sub(r'', '', content) # Update font sizes to be mobile-friendly and consistent content = re.sub(r'font-size="(\d+)"', lambda m: update_font_size(m), content) content = re.sub(r'font-size:\s*(\d+)(?:px)?', lambda m: f"font-size:{update_font_size_style(m)}", content) # Update text colors for better contrast content = re.sub(r'fill="#[A-Fa-f0-9]{6}"', lambda m: update_text_color(m), content) content = re.sub(r'stroke="#[A-Fa-f0-9]{6}"', lambda m: update_stroke_color(m), content) # Improve rectangles with better styling content = re.sub(r']+)>', lambda m: improve_rect(m), content) # Update text elements with better positioning and styling content = re.sub(r']*)>(.*?)', lambda m: improve_text(m), content) # Add font family consistency content = re.sub(r'font-family="[^"]*"', 'font-family="-apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, \'Helvetica Neue\', Arial, sans-serif"', content) # Close the container and SVG new_footer = ''' ''' return new_header + content + new_footer def update_font_size(match): """Update font sizes to be mobile-friendly.""" size = int(match.group(1)) if size >= 20: return f'font-size="{FONT_SIZES["title"]}"' elif size >= 16: return f'font-size="{FONT_SIZES["heading"]}"' elif size >= 14: return f'font-size="{FONT_SIZES["body"]}"' elif size >= 12: return f'font-size="{FONT_SIZES["label"]}"' else: return f'font-size="{FONT_SIZES["small"]}"' def update_font_size_style(match): """Update font sizes in style attributes.""" size = int(match.group(1)) if size >= 20: return FONT_SIZES["title"] elif size >= 16: return FONT_SIZES["heading"] elif size >= 14: return FONT_SIZES["body"] elif size >= 12: return FONT_SIZES["label"] else: return FONT_SIZES["small"] def update_text_color(match): """Update text fill colors for better contrast.""" color = match.group(0) # Check if it's a light color (rough heuristic) if any(light in color.lower() for light in ['fff', 'fef', 'efe', 'fee', 'eee', 'ddd', 'ccc']): return f'fill="{COLORS["text_primary"]}"' # Keep dark colors but ensure they're dark enough elif any(dark in color.lower() for dark in ['000', '111', '222', '333', '444']): return f'fill="{COLORS["text_primary"]}"' else: # For other colors, use our palette return f'fill="{COLORS["text_secondary"]}"' def update_stroke_color(match): """Update stroke colors to use our palette.""" color = match.group(0) # Map to our color palette for consistency if 'blue' in color.lower() or '4a90e2' in color.lower() or '63b3ed' in color.lower(): return f'stroke="{COLORS["primary_blue"]}"' elif 'green' in color.lower() or '48bb78' in color.lower() or '68d391' in color.lower(): return f'stroke="{COLORS["primary_green"]}"' elif 'purple' in color.lower() or 'b794f4' in color.lower() or '9f7aea' in color.lower(): return f'stroke="{COLORS["primary_purple"]}"' elif 'orange' in color.lower() or 'f6ad55' in color.lower() or 'ed8936' in color.lower(): return f'stroke="{COLORS["primary_orange"]}"' elif 'red' in color.lower() or 'e53e3e' in color.lower() or 'fc8181' in color.lower(): return f'stroke="{COLORS["primary_red"]}"' else: return f'stroke="{COLORS["border_primary"]}"' def improve_rect(match): """Improve rectangle elements with better styling.""" rect = match.group(0) # Add rounded corners if not present if 'rx=' not in rect: rect = rect[:-1] + f' rx="{LAYOUT["corner_radius"]}">' # Add subtle shadow for depth if 'filter=' not in rect: rect = rect[:-1] + ' filter="url(#shadow)">' # Ensure proper stroke width rect = re.sub(r'stroke-width="[^"]*"', 'stroke-width="2"', rect) return rect def improve_text(match): """Improve text elements with better styling.""" text_tag = match.group(1) text_content = match.group(2) # Add text shadow for better readability if 'filter=' not in text_tag: text_tag += ' filter="url(#textShadow)"' # Ensure text has proper weight for readability if 'font-weight=' not in text_tag and any(word in text_content.lower() for word in ['title', 'process', 'flow', 'system']): text_tag += ' font-weight="600"' return f'{text_content}' def process_all_svgs(): """Process all SVG files in the docs directory.""" docs_dir = Path('docs') # Find all SVG files svg_files = list(docs_dir.glob('**/*.svg')) print(f"Found {len(svg_files)} SVG files to beautify") for svg_file in svg_files: # Skip font files if 'fontawesome' in str(svg_file).lower() or 'favicon' in str(svg_file).lower(): print(f"Skipping font/favicon file: {svg_file}") continue print(f"Beautifying: {svg_file}") try: # Read the original content with open(svg_file, 'r', encoding='utf-8') as f: content = f.read() # Skip if already processed if 'Beautiful gradient definitions' in content: print(f" Already beautified, skipping...") continue # Create improved version improved = create_improved_svg(content, svg_file.name) # Save the improved version with open(svg_file, 'w', encoding='utf-8') as f: f.write(improved) print(f" ✓ Successfully beautified!") except Exception as e: print(f" ✗ Error processing {svg_file}: {e}") if __name__ == "__main__": print("=" * 60) print("SVG BEAUTIFIER - Making diagrams beautiful for all devices") print("=" * 60) print("\nFeatures:") print("• Consistent text sizing matching documentation") print("• Proper margins and padding for mobile") print("• Beautiful colors that work in black & white") print("• Responsive design for all screen sizes") print("• Enhanced readability with shadows and gradients") print("\nStarting beautification process...\n") process_all_svgs() print("\n" + "=" * 60) print("✨ Beautification complete!") print("All SVGs now have:") print("• Mobile-friendly text sizes (min 12px)") print("• Consistent font family") print("• Proper margins (40px) and padding (20px)") print("• High contrast colors readable in B&W") print("• Responsive viewBox settings") print("=" * 60)