Switch icons from a webfont to self-hosted SVG masks — the webfont was the actual problem
Self-hosting Font Awesome's font files (previous commit) didn't fix it either: every icon in the picker still failed identically. That rules out CDN/network blocking specifically and points to something in the browser blocking custom webfont loading altogether regardless of origin (common with strict anti-fingerprinting protection, e.g. Brave's font blocking or certain privacy extensions — @font-face loading is a well-known fingerprinting vector). Replaced the whole mechanism: each of the 258 curated icons is now a real downloaded SVG file (static/icons/*.svg, sourced from Font Awesome 5 Free's official SVG package) displayed via CSS mask-image (.icon-svg in style.css) instead of a font glyph. A masked SVG isn't a font resource at all, so it isn't subject to webfont-blocking — and it still colors via the existing "color" style property (background-color:currentColor) and sizes via font-size (1em), so no change to how the widget's other controls work. The "Icône" widget now stores just the icon's slug (e.g. "trophy") in a dedicated attribute instead of a full CSS class string, rendered by a new special_render (render_icone.py). Updated the add-gallery and the properties-panel picker modal to use the same mask technique for their previews, and element_add.py to validate the slug against the curated list. Removed the now-unused self-hosted Font Awesome CSS/webfont files and the <link> tags — no font dependency left for icons at all. Verified end to end (gallery renders with real SVG previews, simulated add creates a correctly-attributed element, the SVG file is actually served, the per-element picker reflects the current icon). Full suite green (89).
This commit is contained in:
@@ -14,6 +14,7 @@ from .render_repeater import _render_repeater
|
||||
from .render_jauge import _render_jauge
|
||||
from .render_overlay import _render_overlay
|
||||
from .render_onglets import _render_onglets
|
||||
from .render_icone import _render_icone
|
||||
from .resolve_bound_row import _resolve_bound_row_ctx
|
||||
|
||||
|
||||
@@ -50,6 +51,8 @@ def render_element_html(el, slug=None, children_map=None, ctx=None, parent_flex_
|
||||
return _render_overlay(el, meta, slug, children_map, ctx, parent_flex_direction)
|
||||
if special == "onglets":
|
||||
return _render_onglets(el, meta, slug, children_map, ctx, parent_flex_direction)
|
||||
if special == "icone":
|
||||
return _render_icone(el, meta, slug, children_map, ctx, parent_flex_direction)
|
||||
|
||||
tag = meta.get("tag")
|
||||
if tag is None: # widget à balise dynamique (ex: "titre" -> h1/h2/h3)
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
from .visible_attrs import _visible_attrs
|
||||
from .style_string import _style_string
|
||||
from .attr_string import _attr_string
|
||||
from ..widgets.fontawesome_icons import FONTAWESOME_ICONS
|
||||
|
||||
|
||||
def _render_icone(el, meta, slug=None, children_map=None, ctx=None, parent_flex_direction=None):
|
||||
"""Widget Icône — un SVG affiché en silhouette via "mask-image" (voir
|
||||
.icon-svg dans style.css), pas une police d'icônes : certains
|
||||
navigateurs/extensions bloquent le chargement de polices web tierces
|
||||
(protection anti-fingerprinting), ce qui rendait les icônes Font Awesome
|
||||
invisibles quelle que soit leur source — un SVG posé en masque n'est
|
||||
jamais concerné. Se colore via "color" (couleur du texte, déjà un
|
||||
réglage existant), se dimensionne via "font-size" (le masque fait 1em)."""
|
||||
raw_attrs = el.get("attributes") or {}
|
||||
icon_slug = raw_attrs.get("_icon_slug") or "star"
|
||||
if icon_slug not in FONTAWESOME_ICONS:
|
||||
icon_slug = "star" # attribut corrompu/vidé : jamais d'icône cassée
|
||||
attrs = _visible_attrs(el, meta, ctx)
|
||||
existing_class = attrs.pop("class", "")
|
||||
attrs["class"] = (existing_class + " icon-svg").strip()
|
||||
icon_url = f"/static/icons/{icon_slug}.svg"
|
||||
style = _style_string(el, f" --icon-url:url('{icon_url}');", parent_flex_direction)
|
||||
return f"<i {_attr_string(attrs, style)}></i>"
|
||||
@@ -1,12 +1,13 @@
|
||||
# Sélection large mais CURATÉE d'icônes Font Awesome 5 Free (style "solid")
|
||||
# pour la galerie du widget Icône (voir bulma_controls.py/registry.py et la
|
||||
# section "Icônes" du panneau de propriétés dans screen_edit.html) —
|
||||
# volontairement PAS le catalogue Font Awesome 5 Free complet (~1500 icônes) :
|
||||
# une liste embarquée doit être garantie exacte (une classe qui n'existe pas
|
||||
# affiche une case vide dans la police), donc on limite ici aux icônes dont
|
||||
# le nom est sûr plutôt que de deviner l'exhaustif. N'importe quelle autre
|
||||
# icône Font Awesome 5 reste utilisable en tapant directement sa classe dans
|
||||
# le réglage "Icône" du panneau de propriétés.
|
||||
# Sélection large mais CURATÉE d'icônes Font Awesome 5 Free (style "solid"),
|
||||
# chacune un fichier SVG téléchargé une fois pour toutes dans static/icons/
|
||||
# (voir render_icone.py — affichées en silhouette via "mask-image", PAS une
|
||||
# police d'icônes : certains navigateurs/extensions bloquent le chargement
|
||||
# de polices web tierces par protection anti-fingerprinting, ce qui rendait
|
||||
# les icônes invisibles quelle que soit leur source — un SVG posé en masque
|
||||
# n'est jamais concerné). Volontairement PAS le catalogue Font Awesome 5
|
||||
# Free complet (~1500 icônes) : chaque entrée ici doit avoir un fichier SVG
|
||||
# réellement présent dans static/icons/, donc la liste reste bornée à ce qui
|
||||
# a été téléchargé plutôt que de deviner l'exhaustif.
|
||||
FONTAWESOME_ICONS = [
|
||||
"star", "heart", "check", "times", "plus", "minus", "search", "cog", "cogs", "wrench",
|
||||
"hammer", "tools", "trash", "trash-alt", "edit", "pen", "pencil-alt", "save", "download",
|
||||
|
||||
@@ -316,17 +316,19 @@ WIDGETS = {
|
||||
"controls": BULMA_TABS_CONTROLS,
|
||||
},
|
||||
"icone": {
|
||||
# La classe Font Awesome ("fa-solid fa-xxx") EST le contenu visuel de
|
||||
# ce widget — posée soit en cliquant/glissant une icône depuis la
|
||||
# galerie du panneau de propriétés (voir routes/elements/element_add.py,
|
||||
# qui pré-remplit ce réglage), soit tapée à la main ici pour n'importe
|
||||
# quelle icône Font Awesome 5 hors de la sélection curatée de la
|
||||
# galerie (voir fontawesome_icons.py).
|
||||
"label": "Icône", "icon": "🔤", "tag": "i", "has_content": False,
|
||||
# Un SVG affiché en silhouette via "mask-image" (voir .icon-svg dans
|
||||
# style.css et render_icone.py) plutôt qu'une police d'icônes —
|
||||
# certains navigateurs/extensions bloquent le chargement de polices
|
||||
# web tierces (protection anti-fingerprinting), ce qui rendait
|
||||
# invisible toute icône Font Awesome classique quelle que soit sa
|
||||
# source (CDN ou même hébergée ici). Le nom de l'icône (ex. "star")
|
||||
# est posé soit en cliquant/glissant depuis la galerie du panneau de
|
||||
# propriétés (voir routes/elements/element_add.py), soit choisi via
|
||||
# le sélecteur visuel du réglage "Icône" — jamais tapé à la main.
|
||||
"label": "Icône", "icon": "🔤", "tag": "i", "has_content": False, "special_render": "icone",
|
||||
"w": 15, "h": 15, "default_content": "",
|
||||
"controls": [
|
||||
c_text("icon_class", "Icône (classe Font Awesome 5)", "attr:class",
|
||||
default="fa-solid fa-star", placeholder="fa-solid fa-heart", group="Contenu"),
|
||||
c_text("icon_class", "Icône", "attr:_icon_slug", default="star", group="Contenu"),
|
||||
c_slider("font-size", "Taille", "style:font-size", min=10, max=160, default=32, group="Texte"),
|
||||
c_color("color", "Couleur", "style:color", "#e8eaf0", group="Texte"),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user