diff --git a/scripts/TEMPLATE.md b/scripts/TEMPLATE.md
new file mode 100644
index 00000000..4af14e0a
--- /dev/null
+++ b/scripts/TEMPLATE.md
@@ -0,0 +1,12 @@
+![jsDelivr hits (GitHub)](https://img.shields.io/jsdelivr/gh/hy/walkxcode/dashboard-icons?style=flat-square&color=%23A020F0)
+
+## Dashboard Icons
+
+The best source for dashboard icons.
+[**← Back to repository**](https://github.com/walkxcode/dashboard-icons/)
+
+
+
+
+
+
\ No newline at end of file
diff --git a/scripts/convert_svg_assets.py b/scripts/convert_svg_assets.py
new file mode 100644
index 00000000..cad2a6f9
--- /dev/null
+++ b/scripts/convert_svg_assets.py
@@ -0,0 +1,157 @@
+import os
+import re
+import hashlib
+from pathlib import Path
+from PIL import Image
+import cairosvg
+
+# Define paths
+ROOT_DIR = Path(__file__).resolve().parent.parent
+SVG_DIR = ROOT_DIR / "svg"
+PNG_DIR = ROOT_DIR / "png"
+WEBP_DIR = ROOT_DIR / "webp"
+
+# Ensure the output folders exist
+PNG_DIR.mkdir(parents=True, exist_ok=True)
+WEBP_DIR.mkdir(parents=True, exist_ok=True)
+
+# Track results
+failed_files = []
+converted_pngs = 0
+converted_webps = 0
+total_icons = 0
+
+def file_size_readable(size_bytes):
+ """Convert bytes to a human-readable format."""
+ for unit in ['B', 'KB', 'MB', 'GB']:
+ if size_bytes < 1024:
+ return f"{size_bytes:.2f} {unit}"
+ size_bytes /= 1024
+
+def hash_file(file_path):
+ """Generate an MD5 hash for a file."""
+ hash_md5 = hashlib.md5()
+ with open(file_path, "rb") as f:
+ for chunk in iter(lambda: f.read(4096), b""):
+ hash_md5.update(chunk)
+ return hash_md5.hexdigest()
+
+def convert_to_kebab_case(name):
+ """Convert a filename to kebab-case."""
+ cleaned = re.sub(r'[^a-zA-Z0-9\s-]', '', name)
+ kebab_case_name = re.sub(r'[\s_]+', '-', cleaned).lower()
+ return kebab_case_name
+
+def rename_if_needed(file_path):
+ """Ensure the filename is in kebab-case; rename if necessary."""
+ new_name = convert_to_kebab_case(file_path.stem) + file_path.suffix
+ new_path = file_path.parent / new_name
+
+ if new_path != file_path:
+ if new_path.exists():
+ raise FileExistsError(f"File conflict: {new_path} already exists.")
+ file_path.rename(new_path)
+ print(f"Renamed: {file_path} -> {new_path}")
+
+ return new_path
+
+def needs_conversion(output_file, data=None):
+ """Check if a file needs to be converted or overwritten."""
+ if output_file.exists():
+ if data:
+ existing_hash = hash_file(output_file)
+ new_hash = hashlib.md5(data).hexdigest()
+ return existing_hash != new_hash
+ return False
+ return True
+
+def convert_svg_to_png(svg_path, png_path):
+ """Convert SVG to PNG."""
+ global converted_pngs
+ try:
+ png_data = cairosvg.svg2png(url=str(svg_path), output_height=512)
+
+ if needs_conversion(png_path, png_data):
+ with open(png_path, 'wb') as f:
+ f.write(png_data)
+ print(f"Converted PNG: {png_path} ({file_size_readable(png_path.stat().st_size)})")
+ converted_pngs += 1
+ else:
+ print(f"PNG already up-to-date: {png_path}")
+
+ except Exception as e:
+ print(f"Failed to convert {svg_path} to PNG: {e}")
+ failed_files.append(svg_path)
+
+def convert_png_to_webp(png_path, webp_path):
+ """Convert PNG to WEBP."""
+ global converted_webps
+ try:
+ image = Image.open(png_path)
+
+ if needs_conversion(webp_path):
+ image.save(webp_path, format='WEBP')
+ print(f"Converted WEBP: {webp_path} ({file_size_readable(webp_path.stat().st_size)})")
+ converted_webps += 1
+ else:
+ print(f"WEBP already up-to-date: {webp_path}")
+
+ except Exception as e:
+ print(f"Failed to convert {png_path} to WEBP: {e}")
+ failed_files.append(png_path)
+
+def clean_up_files(folder, valid_basenames):
+ """Remove files that no longer have corresponding SVG files."""
+ removed_files = 0
+ for file_path in folder.glob('*'):
+ if file_path.stem not in valid_basenames:
+ file_path.unlink()
+ print(f"Removed: {file_path}")
+ removed_files += 1
+ return removed_files
+
+if __name__ == "__main__":
+ # Track valid basenames (existing SVG files)
+ valid_basenames = set()
+
+ # Process all SVG files
+ for svg_file in SVG_DIR.glob("*.svg"):
+ total_icons += 1
+
+ # Ensure the filename is in kebab-case
+ try:
+ svg_path = rename_if_needed(svg_file)
+ except Exception as e:
+ print(f"Error renaming {svg_file}: {e}")
+ failed_files.append(svg_file)
+ continue
+
+ valid_basenames.add(svg_path.stem)
+
+ # Set paths for PNG and WEBP
+ png_path = PNG_DIR / f"{svg_path.stem}.png"
+ webp_path = WEBP_DIR / f"{svg_path.stem}.webp"
+
+ # Convert SVG to PNG
+ convert_svg_to_png(svg_path, png_path)
+
+ # Convert PNG to WEBP
+ if png_path.exists():
+ convert_png_to_webp(png_path, webp_path)
+
+ # Clean up unused files
+ removed_pngs = clean_up_files(PNG_DIR, valid_basenames)
+ removed_webps = clean_up_files(WEBP_DIR, valid_basenames)
+
+ # Display summary
+ if converted_pngs == 0 and converted_webps == 0 and removed_pngs == 0 and removed_webps == 0:
+ print("\nAll icons are already up-to-date.")
+ else:
+ print(f"\nConverted {converted_pngs} PNGs and {converted_webps} WEBPs out of {total_icons} icons.")
+ print(f"Removed {removed_pngs} PNGs and {removed_webps} WEBPs.")
+
+ # Display any failed conversions
+ if failed_files:
+ print("\nThe following files failed to convert:")
+ for file in failed_files:
+ print(file)
\ No newline at end of file
diff --git a/scripts/generate_file_tree.py b/scripts/generate_file_tree.py
new file mode 100644
index 00000000..bc23aa73
--- /dev/null
+++ b/scripts/generate_file_tree.py
@@ -0,0 +1,37 @@
+import os
+import json
+import sys
+from pathlib import Path
+
+def generate_folder_tree(paths):
+ tree = {}
+ for path in paths:
+ resolved_path = Path(path).resolve()
+ base_folder = resolved_path.name or Path.cwd().name
+ for root, _, files in os.walk(resolved_path):
+ relative_path = os.path.relpath(root, resolved_path)
+ key = base_folder if relative_path == '.' else os.path.join(base_folder, relative_path)
+ if files:
+ tree[key] = sorted(files) # Sort the list of files alphabetically
+ return tree
+
+if __name__ == "__main__":
+ # Adjust paths to be one level up
+ folder_paths = sys.argv[1:]
+ folder_paths = [str(Path(path).resolve()) for path in folder_paths]
+
+ if not folder_paths:
+ print("Please provide at least one folder path.")
+ sys.exit(1)
+
+ # Generate the combined folder tree
+ folder_tree = generate_folder_tree(folder_paths)
+
+ # Write the JSON structure to 'tree.json' in the root folder
+ root_dir = Path(__file__).resolve().parent.parent # Assuming script is in 'scripts' folder
+ tree_json_path = root_dir / 'tree.json'
+
+ with open(tree_json_path, 'w') as f:
+ json.dump(folder_tree, f, indent=4, sort_keys=True) # Sort the keys in the JSON output
+
+ print(f"Folder tree successfully written to '{tree_json_path}'.")
\ No newline at end of file
diff --git a/scripts/generate_icons_page.py b/scripts/generate_icons_page.py
new file mode 100644
index 00000000..945385e9
--- /dev/null
+++ b/scripts/generate_icons_page.py
@@ -0,0 +1,38 @@
+import pathlib
+from pathlib import Path
+import sys
+
+def generate_img_tag(file):
+ return (
+ f''
+ f''
+ )
+
+if __name__ == "__main__":
+ root = pathlib.Path(__file__).parent.resolve()
+ template_path = root / "TEMPLATE.md"
+ icons_md_path = root.parent / "ICONS.md"
+
+ imgs = sorted((root.parent / "webp").glob("*.webp"))
+ img_tags = [generate_img_tag(x) for x in imgs]
+
+ # Read the template file
+ with open(template_path, "r", encoding="UTF-8") as f:
+ lines = f.readlines()
+
+ # Find the line that starts with ""
+ try:
+ line_number = lines.index("\n")
+ except ValueError:
+ print(" placeholder not found in TEMPLATE.md")
+ sys.exit(1)
+
+ # Insert the icons after the placeholder
+ lines.insert(line_number + 1, " ".join(img_tags) + "\n")
+
+ # Write the new ICONS.md file
+ with open(icons_md_path, "w", encoding="UTF-8") as f:
+ f.writelines(lines)
+
+ print("ICONS.md has been successfully generated.")
\ No newline at end of file