Reworked icons generation
This commit is contained in:
@@ -14,11 +14,12 @@ from myfasthtml.controls.BaseCommands import BaseCommands
|
|||||||
from myfasthtml.controls.BaseControl import BaseControl
|
from myfasthtml.controls.BaseControl import BaseControl
|
||||||
from myfasthtml.controls.helpers import mk
|
from myfasthtml.controls.helpers import mk
|
||||||
from myfasthtml.core.commands import Command
|
from myfasthtml.core.commands import Command
|
||||||
from myfasthtml.icons.fluent import icon_panel_left_expand20_regular as left_drawer_icon
|
from myfasthtml.icons.fluent import panel_left_expand20_regular as left_drawer_icon
|
||||||
from myfasthtml.icons.fluent import icon_panel_right_expand20_regular as right_drawer_icon
|
from myfasthtml.icons.fluent_p2 import panel_right_expand20_regular as right_drawer_icon
|
||||||
|
|
||||||
logger = logging.getLogger("LayoutControl")
|
logger = logging.getLogger("LayoutControl")
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class LayoutState:
|
class LayoutState:
|
||||||
left_drawer_open: bool = True
|
left_drawer_open: bool = True
|
||||||
|
|||||||
@@ -17,5 +17,15 @@ Update the root folder in `update_icons.py` to point to the root folder of the i
|
|||||||
|
|
||||||
##
|
##
|
||||||
```sh
|
```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
2712
src/myfasthtml/icons/fluent_p1.py
Normal file
2712
src/myfasthtml/icons/fluent_p1.py
Normal file
File diff suppressed because it is too large
Load Diff
2705
src/myfasthtml/icons/fluent_p2.py
Normal file
2705
src/myfasthtml/icons/fluent_p2.py
Normal file
File diff suppressed because it is too large
Load Diff
1986
src/myfasthtml/icons/fluent_p3.py
Normal file
1986
src/myfasthtml/icons/fluent_p3.py
Normal file
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
150
src/myfasthtml/icons/manage_icons.py
Normal file
150
src/myfasthtml/icons/manage_icons.py
Normal 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
3892
src/myfasthtml/icons/material_p1.py
Normal file
3892
src/myfasthtml/icons/material_p1.py
Normal file
File diff suppressed because it is too large
Load Diff
2748
src/myfasthtml/icons/material_p2.py
Normal file
2748
src/myfasthtml/icons/material_p2.py
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user