Reworked icons generation

This commit is contained in:
2025-11-10 13:49:17 +01:00
parent 5cb628099a
commit 3d46e092aa
16 changed files with 28672 additions and 86923 deletions

View File

@@ -17,5 +17,15 @@ Update the root folder in `update_icons.py` to point to the root folder of the i
##
```sh
python update_icons.py
```
python manage_icons.py --help
```
To list
```sh
python manage_icons.py list
```
To generate icons
```sh
python manage_icons.py generate --no-dry-run --suppress-suffix
```

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,150 @@
import os
from pathlib import Path
import typer
ROOT_FOLDER = "/home/kodjo/Dev/MyDocManager/src/frontend/node_modules/@sicons"
MAX_SIZE = 2000000
import re
def pascal_to_snake(name: str) -> str:
"""Convert a PascalCase or CamelCase string to snake_case."""
# Insert underscore before capital letters (except the first one)
s1 = re.sub(r'(.)([A-Z][a-z]+)', r'\1_\2', name)
# Handle consecutive capital letters (like 'HTTPServer' -> 'http_server')
s2 = re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', s1)
return s2.lower()
app = typer.Typer()
def list_sources(source_folder: str):
return os.listdir(source_folder)
def list_icons_from_source(source_folder: str, source: str):
res = []
for f in os.listdir(f"{source_folder}/{source}"):
if f.endswith(".svg"):
res.append(f)
return res
def read_content(source_folder: str, source: str, file_name: str):
with open(f"{source_folder}/{source}/{file_name}", "r") as f:
return f.read().strip()
def get_dir_size(path: str | Path) -> int:
p = Path(path)
if p.is_file():
return p.stat().st_size
elif p.is_dir():
return sum(f.stat().st_size for f in p.rglob('*') if f.is_file())
else:
raise FileNotFoundError(f"Path not found: {path}")
def sizeof_fmt(num, suffix="B"):
for unit in ["", "K", "M", "G", "T"]:
if abs(num) < 1024.0:
return f"{num:3.1f}{unit}{suffix}"
num /= 1024.0
return f"{num:.1f}P{suffix}"
def init_buffer(source_folder: str, source: str):
buffer = ""
readme_file_path = f"{source_folder}/{source}/README.md"
if os.path.exists(readme_file_path):
with open(readme_file_path, "r") as f_readme:
for line in f_readme:
if line.startswith("#"):
buffer += line
else:
buffer += f"# {line}"
buffer += "\n\n"
buffer += "from fastcore.basics import NotStr\n\n"
return buffer
def flush(dry_run, suppress_suffix, source_folder: str, target_folder: str, buffer: str, size: int, part: int, source: str):
suffix = '' if suppress_suffix else f"_test"
outfile = f"{source}{suffix}.py" if part == 0 else f"{source}_p{part}{suffix}.py"
if not dry_run:
output_path = f"{target_folder}/{outfile}" if part == 0 else f"{target_folder}/{outfile}"
with open(output_path, "w") as f:
f.write(buffer)
typer.echo(f" Generated {source} as {outfile} ({sizeof_fmt(size)}, max={sizeof_fmt(MAX_SIZE)})")
return init_buffer(source_folder, source), 0, part + 1
@app.command("list")
def list_icons(
source: str = typer.Argument(None, help="The source file to list icons from"),
source_folder: str = typer.Option(ROOT_FOLDER, help="The source folder containing icons"),
count: bool = typer.Option(False, help="Counts the number of items"),
size: bool = typer.Option(False, help="Gets the size of the items"),
):
res = []
if source:
res.extend(list_icons_from_source(source_folder, source))
else:
res.extend(list_sources(source_folder))
if count:
typer.echo(len(res))
return
if size:
path = f"{source_folder}/{source}" if source else f"{source_folder}"
size = get_dir_size(path)
typer.echo(sizeof_fmt(size))
return
for r in res:
typer.echo(r)
@app.command("generate")
def generate_icons(
source: str = typer.Argument(None, help="The source file to list icons from"),
source_folder: str = typer.Option(ROOT_FOLDER, help="The source folder containing icons"),
target_folder: str = typer.Option(".", help="The folder where to create the python files."),
top: int = typer.Option(0, help="The number of top items to generate"),
dry_run: bool = typer.Option(True, help="Does not generate the icons"),
suppress_suffix: bool = typer.Option(False, help="Does not add the suffix to the icon names"),
):
sources = [source] if source else list_sources(source_folder)
for current_source in sources:
typer.echo(f"Generating icons for {current_source}")
buffer = init_buffer(source_folder, current_source)
size = 0
part = 0
for index, svg_file in enumerate(list_icons_from_source(source_folder, current_source)):
if 0 < top <= index:
break
icon_name = os.path.splitext(os.path.basename(svg_file))[0]
svg_content = read_content(source_folder, current_source, svg_file)
svg_content = svg_content.replace("<svg ", f'<svg name="{current_source}-{icon_name}" ').replace("\n", "")
content = f"{pascal_to_snake(icon_name)} = NotStr('''{svg_content}''')"
buffer += f"{content}\n"
size += len(content)
if size > MAX_SIZE:
buffer, size, part = flush(dry_run, suppress_suffix, source_folder, target_folder, buffer, size, part,
current_source)
flush(dry_run, suppress_suffix, source_folder, target_folder, buffer, size, part, current_source)
if __name__ == "__main__":
app()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff