#!/usr/bin/env python3 """ Generate favicon variants with status indicators (compiled, compiling, error) Usage: python generate_favicons.py favicon.svg """ import sys from pathlib import Path def create_compiled_icon(size): """Create a green checkmark icon""" circle = f'' check_path = f'' return f'{circle}{check_path}' def create_compiling_icon(size): """Create rotating arrows icon (circular progress)""" circle = f'' r = size * 0.3 cx, cy = size/2, size/2 stroke_w = size * 0.06 arrow_len = stroke_w * 2 # Two SHORT arcs with arrow heads, forming an open circle # Arc 1: short arc at top-right (about 90 degrees) arc1 = f'' # Arrow head for arc1 (pointing downward/clockwise at right side) arrow1 = f'' # Arc 2: short arc at bottom-left (about 90 degrees) arc2 = f'' # Arrow head for arc2 (pointing upward/clockwise at left side) arrow2 = f'' return f'{circle}{arc1}{arrow1}{arc2}{arrow2}' def create_error_icon(size): """Create a red X icon""" circle = f'' x1 = f'' x2 = f'' return f'{circle}{x1}{x2}' def extract_dimensions(svg_content): """Extract width and height from SVG content""" # Try to find viewBox if 'viewBox=' in svg_content: start = svg_content.find('viewBox=') quote = svg_content[start + 8] start = start + 9 end = svg_content.find(quote, start) viewbox = svg_content[start:end] parts = viewbox.split() return float(parts[2]), float(parts[3]) # Try to find width and height attributes width = 100 height = 100 if 'width=' in svg_content: start = svg_content.find('width=') quote = svg_content[start + 6] start = start + 7 end = svg_content.find(quote, start) width = float(svg_content[start:end].replace('px', '')) if 'height=' in svg_content: start = svg_content.find('height=') quote = svg_content[start + 7] start = start + 8 end = svg_content.find(quote, start) height = float(svg_content[start:end].replace('px', '')) return width, height def add_overlay_to_svg(input_file, output_file, overlay_creator): """Add an overlay icon to the SVG in the lower right corner""" with open(input_file, 'r') as f: svg_content = f.read() # Extract dimensions width, height = extract_dimensions(svg_content) # Calculate overlay size and position (1/3 of the icon size) overlay_size = min(width, height) / 3 overlay_x = width - overlay_size - (overlay_size * 0.1) overlay_y = height - overlay_size - (overlay_size * 0.1) # Create overlay group overlay_svg = f'\n {overlay_creator(overlay_size)}\n' # Find the closing tag and insert overlay before it closing_tag = '' insert_pos = svg_content.rfind(closing_tag) if insert_pos == -1: print(f"Error: Could not find closing tag in {input_file}") return # Insert the overlay new_content = svg_content[:insert_pos] + overlay_svg + '\n' + svg_content[insert_pos:] # Write output with open(output_file, 'w') as f: f.write(new_content) print(f"Created: {output_file}") def main(): if len(sys.argv) != 2: print("Usage: python generate_favicons.py favicon.svg") sys.exit(1) input_file = Path(sys.argv[1]) if not input_file.exists(): print(f"Error: {input_file} not found") sys.exit(1) base_name = input_file.stem output_dir = input_file.parent # Generate the three variants add_overlay_to_svg( input_file, output_dir / f"{base_name}-compiled.svg", create_compiled_icon ) add_overlay_to_svg( input_file, output_dir / f"{base_name}-compiling.svg", create_compiling_icon ) add_overlay_to_svg( input_file, output_dir / f"{base_name}-error.svg", create_error_icon ) print("\nAll favicon variants created successfully!") if __name__ == "__main__": main()