{# ---------- PAC-INFO MACROS ---------- #}
{# These macros render semantic HTML with light class hooks. #}
{%- macro key_value_table(pairs) -%}
{# pairs: iterable of (key, value) 2-tuples - NOT a dict.items()-only call, so
callers with non-unique/empty labels (e.g. several attributes sharing a blank
label) don't silently lose rows the way collapsing into a dict first would. #}
{% if display_label %}
{# The card above is the primary content; the label is always a real link
too, on top of it - route_pac_id_url_for lets an issuer route it through
their own page instead of linking straight to the PAC-ID's own URL. #}
{% if route_pac_id_url_for is defined %}
{{ label or value }}
{% else %}
{{ label or value }}
{% endif %}
{% endif %}
{% if pac_card_url_for is defined %}
{% endif %}
{%- endmacro %}
{# A PacInfo.Document (name, key, url) - the uniform shape safety_data_sheet/
certificate_of_analysis return regardless of whether the source was an attribute
or a user handover Service. Distinct from attribute_row() since Document has no
.value_list/.label to match that macro's Attribute-shaped interface. #}
{%- macro document_row(document) -%}
{% for value in a.value_list%}
{%- if is_image(value) -%}
{{ label }}
{%- elif is_reference(value) -%}
{# Checked before is_url - a PAC-ID is itself a valid URL, so a
bare (non-pyReference) PAC-ID string would otherwise always hit
the generic link branch below and never reach the card. #}
{{ reference(value)}}
{%- elif is_url(value) -%}
{# Same icon+label format as service_links' elements -
reuses its classes rather than a parallel set, since the look is
meant to be identical. #}
{{ value }}
{%- else -%}
{{ render_text(value) }}
{%- endif -%}
{% if not loop.last %} {% endif %}
{% endfor%}
{%- for name, trex in attached_data.items() -%}
{{ attached_data_trex(name, trex) }}
{%- endfor -%}
{%- endmacro -%}
{# One pictogram for a GHS0x code, using the bundled static image.
resolve_static_image() only searches flat filenames directly in the static
root (Path(base_name).stem strips any directory component before it even
searches) - no subdirectory, no extension needed, it tries svg/png/jpg/jpeg/
webp itself. Supplier-provided images (see PacInfo.explicit_pictogram_image_urls)
aren't matched to a particular code - they're rendered as their own separate
images by pictogram_strip below. #}
{%- macro pictogram_image(code) -%}
{%- endmacro -%}
{# Shown once above the hazard/precautionary statement table (see
PacInfo.safety_pictogram_codes) rather than repeated per row - a hazard statement's
pictogram is a property of the substance as a whole, and several codes
commonly share the same one (e.g. H300/H310/H330 are all Skull-and-crossbones).
explicit_image_urls are supplier-provided pictogram images (Resource-valued
GHS_PICTOGRAM attribute values) - rendered in addition to the code-derived
images, not matched against any particular code. #}
{%- macro pictogram_strip(codes, explicit_image_urls=[]) -%}
{%- if codes or explicit_image_urls -%}
{%- for code in codes -%}
{{ pictogram_image(code) }}
{%- endfor -%}
{%- for url in explicit_image_urls -%}
{%- endfor -%}
{%- endif -%}
{%- endmacro -%}
{# GHS hazard/precautionary statement rows - code beside its full text. Resolution
(code extraction + labfreed/utilities/ghs/ghs_statements.json lookup) now happens
in PacInfo.hazard_statements/precautionary_statements, not here - these macros
just render the already-resolved HazardStatement/PrecautionaryStatement (code,
text, text_origin). text is None when the code isn't in that table (e.g. an
EU-specific EUH code, not part of the UN GHS document it was sourced from) and
text_origin is always 'Predefined' for now - falls back to the bare code until
attribute-delivered text is wired up - see developer-docs/design-choices.md. #}
{# th/td classes match every other key/value table (key_value_table, attribute_row) -
same 1/3-2/3 column widths and label bolding from .lf-table--kv, for free, no
GHS-specific CSS needed. #}
{%- macro hazard_statement_row(statement) -%}