kevinpapst / TablerBundle

Tabler.io bundle for Symfony 6 - admin theme for easy integration, coming with Bootstrap 5.3, Webpack-Encore integration and many more features...
MIT License
93 stars 19 forks source link

Macro utilities ? #85

Closed cavasinf closed 2 years ago

cavasinf commented 2 years ago

Due to #84

I was searching in the Bundle, what is the best way to handle custom attr for components.

I really like the button component way. https://github.com/kevinpapst/TablerBundle/blob/ea98cb05ce72cc3314ecc1572126e4bc5bdd7af1/templates/components/button.html.twig#L49-L53

But the code is "heavy" to copy pasta between component and child component.

I was implementing a macro for this component only, but it will be nice if we do utilities that can be called between all components. Twig Filter or Function is maybe overpower.

Maybe a simple twig file under /templates/components/macros.html.twig

Example macro:


{% macro attr_to_html(attr) %}
    {%- if attr is not empty %}
        {% for name, value in attr %}
            {{ ' ' ~ name }}={% if '"' in value %}'{{ value|raw }}'{% else %}"{{ value|raw }}"{% endif %}
        {% endfor %}
    {% endif %}
{% endmacro %}

Usage will be:

<div class="steps {{ _counter ? 'steps-counter' : '' }} {{ 'steps-'~_color }}" {{ attr_to_html(_attr) }}>
cavasinf commented 2 years ago

Example with steps component. Look for # ---- HERE --- #}

{% macro steps(steps, options) %}

    {% set _tooltip = options.tooltip ?? false %}
    {% set _color = options.color ?? 'primary' %}
    {% set _counter = options.counter ?? false %}
    {% set _attr = options.attr ?? {} %}

    <div 
           class="steps {{ _counter ? 'steps-counter' : '' }} {{ 'steps-'~_color }}" 
           {{ _self.attr_to_html(_attr) }}    {# ---- HERE --- #}
     > 

        {% set activeStepProcessed = false %}

        {% for step in steps %}
            {% set _type = (step.clickable ?? not activeStepProcessed) ? 'a' : 'span' %}
            {% set _title = step.title ?? '' %}
            {% set _description = step.description ?? _title %}
            {% set _active = step.active ?? false %}
            {% set _attr = step.attr ?? {} %}

            <{{ _type|raw }}
                class="step-item {{ _active ? 'active' : '' }}"
                href="{{ step.href ?? '#' }}"
                {%- if _tooltip -%} data-bs-toggle="tooltip" {%- endif -%}
                title="{{ _description }}"
                {{ _self.attr_to_html(_attr) }} {# ---- HERE --- #}
            >
                {{ _title }}
            </{{ _type|raw }}>

            {% if _active %}
                {% set activeStepProcessed = true %}
            {% endif %}

        {% endfor %}
    </div>
{% endmacro %}

{% macro attr_to_html(attr) %}
    {%- if attr is not empty %}
        {% for name, value in attr %}
            {{ ' ' ~ name }}={% if '"' in value %}'{{ value|raw }}'{% else %}"{{ value|raw }}"{% endif %}
        {% endfor %}
    {% endif %}
{% endmacro %}
kevinpapst commented 2 years ago

Sounds good! Create it in includes/utils.html.twig? And then we should improve it with the escape filter (?) like so:

{{ ' ' ~ name }}={% if '"' in value %}'{{ value|e('html_attr') }}'{% else %}"{{ value|e('html_attr') }}"{% endif %}
cavasinf commented 2 years ago

OK I'll simplify it as:

{% macro attr_to_html(attr) %}
    {%- if attr is not empty %}
        {% for name, value in attr %}
            {{ name|e('html_attr') }}={{ value|e('html_attr') }}
        {% endfor %}
    {% endif %}
{% endmacro %}
kevinpapst commented 2 years ago

Hm, I think the attribute name should never need escaping, otherwise there is a bug.

cavasinf commented 2 years ago

I've check what is happening with special name, it will break code if name contains:

kevinpapst commented 2 years ago

Alright 👍