Backup before syncing server scripts

This commit is contained in:
Hamza-Ayed
2026-08-16 13:17:56 +03:00
parent dc9d546733
commit 32865e78df
26 changed files with 3919 additions and 2123 deletions
+94
View File
@@ -0,0 +1,94 @@
#!/usr/bin/env python3
"""
build-sprite.py — يبني sprite sheet لـ MapLibre من مجلد SVG.
لماذا: MapLibre لا يقرأ ملفات SVG مفردة. يحتاج صورة PNG واحدة تُرصف فيها كل
الآيقونات + فهرس JSON يحدد موضع وحجم كل واحدة. كان الستايل يشير إلى
demotiles.maplibre.org (خادم تجريبي)، وحين يفشل تحميله يرسم MapLibre النص
بلا آيقونة وبصمت — فتبدو الخريطة بأسماء بلا رموز.
الاستخدام:
pip install cairosvg pillow
python3 infrastructure/scripts/build-sprite.py
المخرجات في apps/web/public/:
sprite.png / sprite.json (1x)
sprite@2x.png / sprite@2x.json (شاشات Retina — MapLibre يطلبها تلقائياً)
ثم في الستايل: "sprite": "https://map-saas.intaleqapp.com/sprite"
(بلا امتداد — MapLibre يضيف .png/.json و@2x بنفسه)
"""
import json
import os
import sys
try:
import cairosvg
from PIL import Image
except ImportError:
sys.exit("ينقص: pip install cairosvg pillow")
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
ICONS_DIR = os.path.join(ROOT, "apps", "web", "public", "icons")
OUT_DIR = os.path.join(ROOT, "apps", "web", "public")
BASE_SIZE = 24 # بكسل للآيقونة عند 1x
PADDING = 2 # فاصل يمنع نزّ ألوان الجيران عند التصغير (bleeding)
def build(scale: int, suffix: str) -> None:
size = BASE_SIZE * scale
pad = PADDING * scale
svgs = sorted(f for f in os.listdir(ICONS_DIR) if f.endswith(".svg"))
if not svgs:
sys.exit(f"لا توجد ملفات SVG في {ICONS_DIR}")
rendered = []
for fname in svgs:
name = os.path.splitext(fname)[0]
png_bytes = cairosvg.svg2png(
url=os.path.join(ICONS_DIR, fname),
output_width=size,
output_height=size,
)
import io
rendered.append((name, Image.open(io.BytesIO(png_bytes)).convert("RGBA")))
# شبكة مربعة تقريباً: أقل هدراً من صف واحد طويل
cols = max(1, int(len(rendered) ** 0.5 + 0.999))
rows = (len(rendered) + cols - 1) // cols
sheet = Image.new(
"RGBA",
(cols * (size + pad) - pad, rows * (size + pad) - pad),
(0, 0, 0, 0),
)
index = {}
for i, (name, img) in enumerate(rendered):
x = (i % cols) * (size + pad)
y = (i // cols) * (size + pad)
sheet.paste(img, (x, y))
index[name] = {
"x": x, "y": y,
"width": size, "height": size,
"pixelRatio": scale,
"sdf": False,
}
sheet.save(os.path.join(OUT_DIR, f"sprite{suffix}.png"))
with open(os.path.join(OUT_DIR, f"sprite{suffix}.json"), "w") as fh:
json.dump(index, fh, indent=2)
print(f"✅ sprite{suffix}: {len(index)} آيقونة، {sheet.width}×{sheet.height}px")
return list(index)
if __name__ == "__main__":
names = build(1, "")
build(2, "@2x")
print("\nالآيقونات المتاحة لـ icon-image:")
print(" " + ", ".join(names))
print("\n⚠️ طبقات الستايل تطلب أسماء قد لا تكون موجودة أعلاه")
print(" (college, rail, tourist ...) — راجعها أو أضف SVG مقابلاً لكل ناقص.")