Nuevo diseño atributos - Bsale-IO/template-docs GitHub Wiki

Para dar nuevo diseño a la selección de atributos tanto en la vista de los productos como en los filtros de las colecciones. Se debe reemplazar el codigo actual por los presentados a continuación.

Nueva estructura de datos de los atributos

En Colección

El dato json que llega al componente ahora se contiene dos nuevos atributos isColor y attrDetails. El primero indicando si el atributo es de tipo color (1 si, 0 no), y el segundo los colores del atributo (nombre y codigo hexadecimal).

{
  color: {
   name: "color",
   code: "attr_color",
     values: ["azul","rojo","verde"],
     **isColor**: 1,
     **attrDetails**: [
   	{ "name": "azul", "code": "#2661DE" },
        { "name": "rojo", "code": "#DE2C26" },
        { "name": "verde", "code": "#29DE26" }
     ]
   },
   talla: {
      name: "Talla",
      code: "attr_talla",
      values: ["S","M","L"],
      isColor: 0,
      attrDetails: []
   }
}

En producto

El dato json que llega al componente se ve modificado en attributes donde se agregan los atributos isColor y colors

attributes: [
  {
   name: "Color",
   values: ["azul","rojo"],
   isColor: 1,
   required: 1
   colors: [
   	{ "name": "azul", "code": "#2661DE" },
        { "name": "rojo", "code": "#DE2C26" },
        { "name": "verde", "code": "#29DE26" }
     ]
   }, {
   name: "Marca",
   values: ["L", "M"],
   isColor: 0,
   required: 1,   
   colors: []
   }
]

Elementos a reemplazar

1. Archivo style-attributes.css

Crear este archivo dentro del menu archivos y copia el siguiente código

/*************************************
Pantalla de producto SELECTORES
**************************************/

/* variables de personalizacion 
    
    copia estas variables en variables.css 

    --disabled-color:       silver;
    --selected-color:       var(--primary-color);
    --selected-contrast:    var(--primary-contrast);

    --product-select-btn-padding:   0.75rem 1.25rem;
    --product-select-btn-border:    2px silver solid;
    --product-select-btn-bg:        transparent;
    --product-select-btn-border-selected:  2px solid var(--selected-color);
    --product-select-btn-border-disabled:  2px dashed var(--disabled-color);

    --select-attr-text:     "selecciona una opción"; 
    --disabled-attr-text:   "No Disponible";
*/
:root{
    --check-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26l2.974 2.99L8 2.193z'/%3e%3c/svg%3e");
}

/*dropdown*/
.attr-dropdown{
    border:1px solid silver;
    border-radius:var(--default-border-radius);
    margin-bottom:1rem;
}
.attr-dropdown .dropdown-toggle{
    width:100%;
    text-align:left;
    display:flex;
    align-items:center;
}
.attr-dropdown .dropdown-toggle::after{
    display: inline-block;
    margin-left: 0.255em;
    vertical-align: 0.255em;
    content: "";
    border-top: 0.3em solid;
    border-right: 0.3em solid transparent;
    border-bottom: 0;
    border-left: 0.3em solid transparent;
}
.attr-dropdown .bs-product__label__attr{
    margin:0;
    width:100%
}
.attr-dropdown .dropdown-menu{
    max-height: 280px;
    overflow-y: auto;
}
.attr-dropdown .dropdown-item{
    display:flex;
    align-items:center;
}
.attr-dropdown .dropdown-item.attr-none-stock,
.attr-dropdown .dropdown-item.attr-disabled{
    color: silver;
}
.attr-dropdown .dropdown-item.attr-none-stock::after,
.attr-dropdown .dropdown-item.attr-disabled::after{
    content: var(--disabled-attr-text,"No Disponible");
    display:inline-block;
    padding:4px;
    border-radius:var(--default-border-radius);
    background:var(--disabled-color, silver);
    color:white;
    font-size:80%;
    margin-left:auto;

}
.attr-dropdown .attr-color-ball{
    margin-right:.5rem;
}

/* buttons */
.bs-product__label__attr{
    display:block;
}
.bs-product__label__attr::after{
    content: attr(data-info);
    font-weight: var(--font-bold);
    text-transform:capitalize;
}

.bs-product__label__attr[data-info=""]::after{
    content: var(--select-attr-text,"");
    font-weight:inherit;
    text-transform:inherit;
    opacity:.6;
}
.bs-product__label__attr.is-invalid{
    color: var(--danger-color);
    font-weight: var(--font-bold);
}
.btn-attr{
    border:none;
    position:relative;
    display:flex;
    justify-content:center;
    padding: var(--product-select-btn-padding,0.75rem 1.25rem);
    color:inherit;
    border-radius: var(--default-border-radius);
    border: var(--product-select-btn-border, 2px solid silver);
    background: var(--product-select-btn-bg, transparent);
}

button.btn-attr.attr-selected,
button.btn-attr.attr-selected:focus{
    border-color: var(--selected-color ,var(--primary-color)) !important;

}
.btn-attr.attr-selected::after{
    content:"";
    width:1rem;
    height:1rem;
    display:block;
    position:absolute;
    bottom:-2px;
    right:-2px;
    background-image: var(--check-icon);
    background-repeat: no-repeat;
    background-position:center center;
    background-color:var(--selected-color ,var(--primary-color, black));
    border-radius:var(--default-border-radius);
    border: 2px solid white;
}


.btn-attr:not(.btn-color).attr-selected::after{
    border-color:var(--selected-color ,var(--primary-color, black));
}
.btn-color{
    padding:2px;
    border-radius:3rem;
}
.attr-color-ball{
    width:var(--product-attr-color-size, 3rem);
    height:var(--product-attr-color-size, 3rem);
}
.attr-color-ball::after{
    width:var(--product-attr-color-size, 3rem);
    height:var(--product-attr-color-size, 3rem);
    content:"";
    background: var(--color-attr);
    box-shadow: 0px 0px 0px 2px rgba(0,0,0,0.5) inset;
    
    border-radius:3rem;
    display:flex;
    align-items:center;
    justify-content:center; 
}
.dropdown-item .attr-color-ball{
    position:relative;
}

.dropdown-item .attr-color-ball,
.dropdown-item .attr-color-ball::after{
    width:2rem;
    height:2rem;
}
.attr-dropdown .dropdown-item.attr-selected.attr-selected{
    background:var(--selected-color ,var(--primary-color, silver));
    color:var(--selected-contrast ,var(--primary-contrast, black));
}
.dropdown-item.attr-selected .attr-color-ball::before{
    content:"";
    width:1rem;
    height:1rem;
    display:block;
    position:absolute;
    bottom:-2px;
    right:-2px;
    z-index:1000;
    background-image: var(--check-icon);
    background-repeat: no-repeat;
    background-position:center center;
    background-color:var(--selected-color ,var(--primary-color, black));
    border-radius:var(--default-border-radius);
    border: 2px solid white;
}

.btn-color.attr-none-stock::before,
.btn-color.attr-disabled::before{
    content:"";
    border-top: solid var(--disabled-color, silver); 2px;
    display: block;
    width:100%;
    position:absolute;
    transform: rotate(-45deg);
    top:50%;
}
.btn-attr.attr-disabled,
.btn-attr.attr-none-stock{
    border-style: dashed !important;
    color:var(--disabled-color, silver);
}
.attr-disabled > .attr-color-ball::after,
.attr-none-stock > .attr-color-ball::after{
    opacity:0.5;
}
/*********** 
tooltip 
************/
.attr-color-ball{
    position:relative;
    display:flex;
    justify-content:center;
}

.btn-color:hover .attr-color-ball::before,
.attr-disabled:not(.btn-color):hover::before,
.attr-none-stock:not(.btn-color):hover::before{  
    position:absolute;
    top:100%;
    font-size:80%;
    background:black;
    color:white;
    z-index:1000;
    white-space: pre;
    padding:4px;
    border-radius:var(--default-border-radius);
}
.btn-color:hover .attr-color-ball::before{
    content:attr(tooltip);
}
.attr-disabled:not(.btn-color):not(.dropdown-item):hover::before,
.attr-none-stock:not(.btn-color):not(.dropdown-item):hover::before{
    content:var(--disabled-attr-text,"No Disponible");;
}
.btn-color.attr-none-stock:hover .attr-color-ball::before,
.btn-color.attr-disabled:hover .attr-color-ball::before{
    content:attr(tooltip) "\a" var(--disabled-attr-text,"No Disponible");;
}

.bs-error-stock{
    display:inline-block;
}

/* selector de variante radio button */
.bs-variant-select{
    display:inline-block;
}
.bs-variant-select .bs-variant-select__input{
    display:none;
}
.bs-variant-select__label{
    padding: var(--product-select-btn-padding,0.75rem 1.25rem);
    border: var(--product-select-btn-border, 2px solid silver);
    border-radius: var(--default-border-radius);
    position:relative;
    background: var(--product-select-btn-bg, transparent);
}

.bs-variant-select .bs-variant-select__input.disabled +.bs-variant-select__label{
    color: var(--disabled-color, silver);
    border: var(--product-select-btn-border-disabled,2px dashed var(--disabled-color, silver)) !important;
}
.bs-variant-select .bs-variant-select__input:checked +.bs-variant-select__label,
.bs-variant-select .bs-variant-select__input.disabled:checked +.bs-variant-select__label{
    border-color:var(--selected-color ,var(--primary-color, black)) !important;   
}
.bs-variant-select .bs-variant-select__input:checked +.bs-variant-select__label::after{
    content:"";
    width:1rem;
    height:1rem;
    display:block;
    position:absolute;
    bottom:-2px;
    right:-2px;
    background-image: var(--check-icon); 
    background-repeat: no-repeat;
    background-position:center center;
    background-color:var(--selected-color ,var(--primary-color, black));
    border-radius:var(--default-border-radius);
}


/*************************************
Pantalla de coleccion: FILTROS
**************************************/

.bs-filter-color-input{
    display:none;
}
.bs-filter-color-label{
    max-width:300px;
    display:flex;
    position:relative;
    align-items:center;
    margin:0;
}
.bs-filter-color-label::before{
    content:"";
    background: var(--attr-code);/*lo define el componente*/ 
    display:block;
    width:var(--filter-attr-color-size, 2rem);
    height:var(--filter-attr-color-size, 2rem);
    border-radius:var(--filter-attr-color-size, 2rem);
    position:relative;
    box-shadow: 0px 0px 0px 2px rgba(0,0,0,0.5) inset;
    margin-right:.5rem;
}

.bs-filter-color-input:checked+.bs-filter-color-label::after{
    content:"";
    width:1rem;
    height:1rem;
    display:block;
    position:absolute;
    bottom:0;
    left:1rem;
    background-image: var(--check-icon); 
    background-repeat: no-repeat;
    background-position:center center;
    background-color:var(--selected-color ,var(--primary-color, black));
    outline:2px solid white;
    border-radius:4px;
}

2. Inserta la libreria en el componente style css

Copia este codigo dentro de componente style css

<!-- style attributes --><link rel="stylesheet" media="all" href="{{ 'style-attributes.css' | asset_url }}">

3. Componente Producto > detalle > atributos

Copia y pega el siguiente codigo en el componente

{% assign mostrar_selector_atributos = true %}          <!-- true = dibuja atributos, false = oculta atributos -->
{% assign mostrar_selector_atributos_desde = 1 %} <!-- para que se muestren siempre atributos dejar en 1, sino dejar en 2 -->
{% assign Button_selector_variante = true %}
{% assign Button_selector_atributos = true %}
{% assign Button_selector_colores = true %}

{% comment %} NO MODIFICAR ESTA VARIABLE {% endcomment %}
{% assign atributosRequeridos = 0 %}
{% for sizeAttr in product.attributes %}
    {% if sizeAttr[1].required == 1 %}
        {% comment %} si el atributo es requerido se suma {% endcomment %}
        {% assign atributosRequeridos = atributosRequeridos | plus : 1 %}
    {% endif %}
{% endfor %}

<div class="form mt-2" id="bs-product-form"> 
    {% comment %} si tiene al menos un atributo requerido y tiene definido mostrar atributos {% endcomment %}
    {%if atributosRequeridos >= mostrar_selector_atributos_desde and mostrar_selector_atributos == true %}
        {% for pAttr in product.attributes%}
            {% if pAttr[1].required > 0 %}
                {% if pAttr[1].isColor == 1 %}
                    {% comment %} ES COLOR {% endcomment %}
                    {% if Button_selector_colores == false %}
                        <div class="dropdown attr-dropdown">
                            <button class="btn dropdown-toggle" data-toggle="dropdown">
                                <label  class="bs-product__label__attr" 
                                        data-bs="{{pAttr[0]}}" data-info="" 
                                        class-labelError="is-invalid" >
                                        {{pAttr[0] | capitalize}}:
                                </label>
                            </button>
                            <div class="dropdown-menu">
                                {% for val in  pAttr[1].colors %}
                                        <button
                                            class="dropdown-item"
                                            data-bs="product.attributes"
                                            class-selected="attr-selected"
                                            class-disable="attr-disabled"
                                            data-info="{{pAttr[0]}}"
                                            value='{{val.name}}'
                                        >
                                        <span class="attr-color-ball" style="--color-attr: {{val.code}};"></span> {{val.name | capitalize}}
                                        </button>
                                {% endfor %}
                            </div>
                        </div>
                    {% else %}
                        <div class="form-group row mx-0 " >
                            <label class="bs-product__label__attr col-12 px-1 mb-1" data-bs="{{pAttr[0]}}" data-info="" class-labelError="is-invalid">
                                {{pAttr[0] | capitalize}}:
                            </label>
                            {% for val in  pAttr[1].colors %}
                                <div class="col-auto px-1 pb-1 ">
                                    <button
                                        class="btn-attr btn-color"
                                        data-bs="product.attributes"
                                        class-selected="attr-selected"
                                        class-disable="attr-disabled"                                  
                                        data-info="{{pAttr[0]}}"
                                        value='{{val.name}}'
                                    >
                                    <span class="attr-color-ball" tooltip="{{val.name | capitalize }}" style="--color-attr: {{val.code}};"></span>
                                    </button>
                                </div>
                            {% endfor %} 
                        </div>
                    {% endif %}
                {% else %}
                    {% comment %} NO ES COLOR {% endcomment %}
                    {% if Button_selector_atributos == false %}
                        <div class="dropdown  attr-dropdown">
                            <button class="btn dropdown-toggle" data-toggle="dropdown">
                                <label  class="bs-product__label__attr " 
                                        data-bs="{{pAttr[0]}}" data-info="" 
                                        class-labelError="is-invalid" >
                                        {{pAttr[0] | capitalize}}:
                                </label>
                            </button>
                            <div class="dropdown-menu">
                                    {% for val in  pAttr[1].values %}
                                            <button
                                                class="dropdown-item"
                                                data-bs="product.attributes"
                                                class-selected="attr-selected"
                                                class-disable="attr-disabled"
                                                data-info="{{pAttr[0]}}"
                                                value='{{val}}'
                                            >
                                            {{val}}
                                            </button>
                                    {% endfor %}
                            </div>
                        </div>
                    {% else %}
                        <div class="form-group row mx-0 " >
                            <label class="bs-product__label__attr col-12 px-1 mb-1" data-bs="{{pAttr[0]}}" data-info="" class-labelError="is-invalid">
                                {{pAttr[0] | capitalize}}:
                            </label>
                            {% for val in  pAttr[1].values %}
                                <div class="col-auto px-1 pb-1 ">
                                    <button
                                        class="btn-attr"
                                        data-bs="product.attributes"
                                        class-selected="attr-selected"
                                        class-disable="attr-disabled" 
                                        data-info="{{pAttr[0]}}"
                                        value='{{val}}'
                                    >
                                        {{val}}
                                    </button>
                                </div>
                            {% endfor %}
                        </div>
                    {%endif%}
                {% endif %}
            {% endif %}
        {% endfor %}
    {% elsif variant.size > 1 %}
        {%comment%} ES VARIANTE {%endcomment%}
        {% if Button_selector_variante == true %}
            {%comment%} ES BOTON {%endcomment%}
            {% for var in variant %}
                <div class="bs-variant-select col-auto px-1 pb-1">
                    <input 
                        data-bs="product.variant"
                        data-info="{{var.id}}"
                        type="radio" 
                        value="{{ forloop.index }}" 
                        id="var{{forloop.index}}"
                        name="variantes"
                        {% if var.id == product.variantId %} checked {% endif %}
                        class="bs-variant-select__input {% if products.classification != 1 %}{% unless var.unlimitedStock > 0 or var.allowNegativeStock > 0 %}{% assign st = var.id | get_stock_variant %}{% if st <= 0 %}disabled{% endif %}{% endunless %}{% endif %}"
                    >
                    <label class="bs-variant-select__label" for="var{{forloop.index}}">
                        {% if var.title.size > 0 %}{{var.title}}{% else %}{{var.sku}}{%endif%}
                    </label>
                </div>
            {% endfor %}
        {% else %}
            {%comment%} ES SELECT {%endcomment%}
                <div class="form-group">
                    <label class="bs-product__label">Opciones</label>
                    <select data-bs="product.variant" class="form-control">
                        {% for var in variant %}
                            <option
                                {% assign outStock = false %}
                                {% if products.classification != 1 %}{% unless var.unlimitedStock > 0 or var.allowNegativeStock > 0 %}{% assign st = var.id | get_stock_variant %}{% if st <= 0 %}class="disabled"{% assign outStock = true %}{% endif %}{% endunless %}{% endif %}
                            
                                data-info='{{var.id}}'
                                value="{{ forloop.index }}"
                                {% if var.id == product.variantId %} selected {% endif %}>
                                {% if var.title.size > 0 %}{{var.title}}{% else %}{{var.sku}}{%endif%}
                                {% if outStock %} × Sin Stock {%endif %} 
                            </option>
                        {% endfor %}
                    </select>
                </div>
        {% endif %}
    {% endif %}
</div>

4. Componente Coleccion Buscador Marca > Filtros

{% assign deleteAttibutes = "atributo 1,atributo oculto 2" | split: ',' %}

{% comment %} VERSION DICIEMBRE 2022 {% endcomment %}
<aside class="bs-collection-filter col-lg-3">
    <form id="bs-collection-filter-form">
        <section class="row">
            <div class="col-12 h3 d-none d-lg-block">
                    Filtros
            </div>
            <div class="col-12 d-flex d-lg-block align-items-center justify-content-between mb-1">
                <a  class="btn btn-secondary order-lg-2"
                    href="{{ paginate.link }}">
                    <i class="fas fa-undo-alt"></i>
                    <span class="d-none d-sm-inline">Limpiar</span>
                </a>
                <a class="d-lg-none btn btn-link collapsed" href="#filter-toggle" data-toggle="collapse" role="button" title="Filtros">
                        Filtros
                        <i class="fas fa-caret-down"></i>
                </a>
                
                <button class="btn btn-secondary" type="submit">
                    <i class="d-none d-lg-inline fas fa-filter"></i>
                    Filtrar
                </button>
            </div>
        </section>
        <section class="collapse d-lg-block" id="filter-toggle" >
            {% if collection.limitPrice.minPrice != collection.limitPrice.maxPrice %}
                <div id="bs-collection-filter-price" class=" my-1">
                    <ul class="list-group">
                        <li class="list-group-item">
                            <div
                                data-bs="filter.range"
                                data-min="{{ collection.limitPrice.minPrice }}"
                                data-max="{{ collection.limitPrice.maxPrice }}"
                        >
                            </div>
                        </li>
                    </ul>
                </div>
            {% endif%}
        
            {% for attr in collection.attributes %}
                {%assign flagAttr = false %}
                {% for del in deleteAttibutes %}
                    {% if attr[1].name == del %}
                        {%assign flagAttr = true %}
                        {{break}}
                    {% endif %}
                {% endfor %}
                <!-- elimina marca si esta en la url /brand/ -->
                {% if attr[0] == "Brands" and current_url contains "/brand/" %}
                    {% assign flagAttr == true %}
                {% endif %}
                <!---------------------------->
                {% if flagAttr == false %}
                    {% if attr[1].values.size > 0 %}
                            <div class="panel-heading my-1">
                                <a
                                    class="btn d-flex justify-content-between align-items-center bs-filter-btn collapsed" 
                                    data-toggle="collapse" 
                                    href="#{{ attr[1].code }}{{ attr[0] }}">
                                    {{ attr[1].name }}<i class="fas fa-angle-down"></i>
                                </a>
                            </div>
                            <div id="{{ attr[1].code }}{{ attr[0] }}" class="panel-collapse collapse my-1 {% if attr[1].isColor == 1 %} panel-color{%endif%}">

                            {% if attr[1].isColor == 1 %}
                                
                                <ul class="list-group">
                                {% for color in attr[1].attrDetails %}
                                    <li class="list-group-item py-2">
                                        <input id="{{ attr[1].code | url_encode}}-{{ forloop.index }}"
                                                class="bs-collection-filter-input bs-filter-color-input"
                                                type="checkbox"
                                                value="{{ color.name | url_encode }}"
                                                title="{{ color.name | capitalize }}"
                                                data-filter="{{ attr[1].code | url_encode }}[]">
                                        <label class="bs-filter-color-label" style="--attr-code:{{color.code}}" for="{{ attr[1].code | url_encode}}-{{ forloop.index }}" data-tooltip="{{ color.name | capitalize }}">
                                        {{ color.name | capitalize }} {{color.id_color}}
                                        </label>      
                                {% endfor %}
                                    </li>
                                </ul>
                            {% else %}
                                <ul class="list-group">
                                    {% assign data = attr[1].code %}
                                    {% for item in attr[1].values %}
                                        {% if item.size > 0 %}
                                            <li class="list-group-item py-2">
                                                <div class="custom-control custom-checkbox">
                                                    <input
                                                        id="{{ attr[1].code | url_encode}}-{{ forloop.index }}-{{ attr[0] }}"
                                                        class="custom-control-input bs-collection-filter-input"
                                                        type="checkbox"
                                                        value="{{ item | url_encode }}"
                                                        data-filter="{{ attr[1].code | url_encode }}[]">
                                                    <label class="custom-control-label" for="{{ attr[1].code | url_encode }}-{{ forloop.index }}-{{ attr[0] }}">
                                                        {{ item }}
                                                    </label>
                                                </div>
                                            </li>
                                        {% endif %}
                                    {% endfor %}
                                </ul>
                            {% endif %}
                            </div>
                   
                    {% endif %}
                {% endif %}
                {%assign flagAttr = false %}
            {%endfor%}
        </section>
    </form>
</aside>
⚠️ **GitHub.com Fallback** ⚠️