Copy environment

Item Filter

<div class="item-filter  " data-query="">

    <div class="content-section content-section--sticky item-filter__font-col">
        <div class="content-section__title text-button">
            <div class="item-filter__font-title">
                <div class="item-filter__font-title-text">
                    recent fonts
                </div>

                <button type="button" class="button  item-filter__burger-open ">

                    <span class="button__inner" data-text="filter and sort">
                        <span class="button__text">
                            filter and sort

                        </span>
                    </span>
                </button>
            </div>
        </div>
        <div class="content-section__content">
            <div class="item-list item-filter__item-list ">

                <div class="item-cell  item-list__cell" data-font="" data-id="">
                    <a class="item-cell__content" href="#">
                        <div class="item-cell__main-text">
                            Väike mölder hüppas rongile.
                        </div>
                        <span class="item-cell__sub-text text-small">
                            Flex 0.1
                        </span>
                    </a>
                </div>

                <div class="item-cell  item-list__cell" data-font="" data-id="">
                    <a class="item-cell__content" href="#">
                        <div class="item-cell__main-text">
                            Eriti väike mölder hüppas rongile.
                        </div>
                        <span class="item-cell__sub-text text-small">
                            Flex 0.1
                        </span>
                    </a>
                </div>

                <div class="item-cell  item-list__cell" data-font="" data-id="">
                    <a class="item-cell__content" href="#">
                        <div class="item-cell__main-text">
                            Kõige väiksem mölder hüppas rongile.
                        </div>
                        <span class="item-cell__sub-text text-small">
                            Flex 0.1
                        </span>
                    </a>
                </div>

                <div class="item-cell  item-list__cell" data-font="" data-id="">
                    <a class="item-cell__content" href="#">
                        <div class="item-cell__main-text">
                            Väike mölder hüppas eriti suurele rongile.
                        </div>
                        <span class="item-cell__sub-text text-small">
                            Flex 0.1
                        </span>
                    </a>
                </div>
            </div>

        </div>
    </div>

    <div class="content-section content-section--sticky item-filter__filter-col">
        <div class="content-section__title text-button">

            <div class="textfield select ">
                <div class="textfield__inner">
                    <select name="sort" id="sort" class="textfield__input select__input" data-text="Sort by">
                        <option value="1" selected>added (newest first)</option>
                        <option value="1">added (oldest first)</option>
                        <option value="1">name (a-z)</option>
                        <option value="1">name (z-a)</option>
                        <option value="1">year (newest first)</option>
                        <option value="1">year (oldest first)</option>
                    </select>
                    <svg class="icon  select__icon">
                        <use xlink:href="../../inc/svg/global.49d3f64de1a3f5ccf16c763316702027.svg#chevron-bottom"></use>
                    </svg>

                    <label class="textfield__label text-button select__label" for="sort">
                        Sort by
                    </label>
                </div>
            </div>
        </div>
        <div class="content-section__content">

            <div class="content-section  item-filter__sort-content">
                <div class="content-section__title text-button">filter by</div>
                <div class="content-section__content">

                    <fieldset class="choice-group item-filter__filter-list">
                        <legend class="choice-group__label"></legend>
                        <div class="choice-group__inner">

                            <div class="check choice-group__item">
                                <input type="checkbox" id="latin" name="filter" value="" class="check__input">
                                <label for="latin" class="check__label">
                                    <span class="check__indicator">
                                        <svg class="icon  check__icon">
                                            <use xlink:href="../../inc/svg/global.49d3f64de1a3f5ccf16c763316702027.svg#checkbox-crossed-big"></use>
                                        </svg>
                                    </span>
                                    <span class="check__text">Latin</span>
                                </label>
                            </div>

                            <div class="check choice-group__item">
                                <input type="checkbox" id="sans" name="filter" value="" class="check__input">
                                <label for="sans" class="check__label">
                                    <span class="check__indicator">
                                        <svg class="icon  check__icon">
                                            <use xlink:href="../../inc/svg/global.49d3f64de1a3f5ccf16c763316702027.svg#checkbox-crossed-big"></use>
                                        </svg>
                                    </span>
                                    <span class="check__text">Sans Serif</span>
                                </label>
                            </div>

                            <div class="check choice-group__item">
                                <input type="checkbox" id="display" name="filter" value="" class="check__input">
                                <label for="display" class="check__label">
                                    <span class="check__indicator">
                                        <svg class="icon  check__icon">
                                            <use xlink:href="../../inc/svg/global.49d3f64de1a3f5ccf16c763316702027.svg#checkbox-crossed-big"></use>
                                        </svg>
                                    </span>
                                    <span class="check__text">Display</span>
                                </label>
                            </div>

                            <div class="check choice-group__item">
                                <input type="checkbox" id="serif" name="filter" value="" class="check__input">
                                <label for="serif" class="check__label">
                                    <span class="check__indicator">
                                        <svg class="icon  check__icon">
                                            <use xlink:href="../../inc/svg/global.49d3f64de1a3f5ccf16c763316702027.svg#checkbox-crossed-big"></use>
                                        </svg>
                                    </span>
                                    <span class="check__text">Serif</span>
                                </label>
                            </div>
                        </div>
                    </fieldset>

                </div>
            </div>
            <div class="item-filter__burger-heading">switch colors</div>
            <div class="theme-switcher  item-filter__theme-switcher">
                <button data-theme="theme-beige" class="theme-switcher__button theme-switcher__button--beige">
                    <span class="theme-switcher__icon-cross"></span>
                </button>
                <button data-theme="theme-gray" class="theme-switcher__button theme-switcher__button--gray">
                    <span class="theme-switcher__icon-cross"></span>
                </button>
                <button data-theme="theme-yellow" class="theme-switcher__button theme-switcher__button--yellow">
                    <span class="theme-switcher__icon-cross"></span>
                </button>
                <button data-theme="theme-green" class="theme-switcher__button theme-switcher__button--green">
                    <span class="theme-switcher__icon-cross"></span>
                </button>
                <button data-theme="theme-dark" class="theme-switcher__button theme-switcher__button--dark">
                    <span class="theme-switcher__icon-cross"></span>
                </button>
            </div>

        </div>
    </div>
    <div class="item-filter__burger-header">

        <button type="button" class="button button--icon item-filter__burger-close ">
            <span class="button__pseudo-icon">
                <svg class="icon  button__icon">
                    <use xlink:href="../../inc/svg/global.49d3f64de1a3f5ccf16c763316702027.svg#exit"></use>
                </svg>

            </span>

            <span class="button__inner" data-text="">
                <span class="button__text">

                    <svg class="icon  button__icon">
                        <use xlink:href="../../inc/svg/global.49d3f64de1a3f5ccf16c763316702027.svg#exit"></use>
                    </svg>

                </span>
            </span>
        </button>
    </div>
</div>
{% set itemListTitle %}
    <div class="item-filter__font-title">
        {% if data.listTitle %}
            <div class="item-filter__font-title-text">
                {{ data.listTitle }}
            </div>
        {% endif %}
        {% if data.burgerButton %}
            {% include '@button' with {class: "item-filter__burger-open", data: data.burgerButton} %}
        {% endif %}
    </div>
{% endset %}

{% set itemListContent %}
    {% if data.itemList %}
        {% include '@item-list' with {class: "item-filter__item-list", data: data.itemList} %}
    {% endif %}
{% endset %}

{% set sortTitle %}
    {% if data.sort %}
        {% include '@select' with {data: data.sort} %}
    {% endif %}
    {% if data.filters and not data.sort %}
        <div class="item-filter__filter-text">{{ data.filterTitle }}</div>
    {% endif %}
{% endset %}

{% set filterContent %}
    {% if data.filters %}
        {% include '@choice-group' with {class: "item-filter__filter-list", data: data.filters} %}
    {% endif %}
{% endset %}

{% set sortContent %}
    {% if data.sort %}
        {% include '@content-section' with {class: "item-filter__sort-content", data: {title: data.filterTitle, content: filterContent}} %}
    {% else %}
        {% include '@content-section' with {class: "item-filter__sort-content item-filter__sort-content--small-top", data: {content: filterContent}} %}
    {% endif %}
    {% if data.themeSwitcherTitle %}
        <div class="item-filter__burger-heading">{{ data.themeSwitcherTitle }}</div>
    {% endif %}
    {% if data.themeSwitcher %}
        {% include '@theme-switcher' with {class: "item-filter__theme-switcher", data: data.themeSwitcher} %}
    {% endif %}
{% endset %}

<div class="item-filter {{ class }} {{ modifier }}" data-query="{{ data.initialQuery }}">
    {% include '@content-section' with {class: "item-filter__font-col", modifier: "content-section--sticky", data: {title: itemListTitle, content: itemListContent}} %}
    {% include '@content-section' with {class: "item-filter__filter-col", modifier: "content-section--sticky", data: {title: sortTitle, content: sortContent}} %}
    <div class="item-filter__burger-header">
        {% include '@button' with {class: "item-filter__burger-close", modifier: "button--icon", data: {icon: "exit"}} %}
    </div>
</div>
{
  "language": "en-US",
  "data": {
    "listTitle": "recent fonts",
    "itemList": {
      "items": [
        {
          "mainText": "Väike mölder hüppas rongile.",
          "subText": "Flex 0.1",
          "link": "#"
        },
        {
          "mainText": "Eriti väike mölder hüppas rongile.",
          "subText": "Flex 0.1",
          "link": "#"
        },
        {
          "mainText": "Kõige väiksem mölder hüppas rongile.",
          "subText": "Flex 0.1",
          "link": "#"
        },
        {
          "mainText": "Väike mölder hüppas eriti suurele rongile.",
          "subText": "Flex 0.1",
          "link": "#"
        }
      ]
    },
    "filterTitle": "filter by",
    "sort": {
      "label": "Sort by",
      "id": "sort",
      "name": "sort",
      "options": [
        {
          "name": "added (newest first)",
          "value": "1",
          "isSelected": true
        },
        {
          "name": "added (oldest first)",
          "value": "1"
        },
        {
          "name": "name (a-z)",
          "value": "1"
        },
        {
          "name": "name (z-a)",
          "value": "1"
        },
        {
          "name": "year (newest first)",
          "value": "1"
        },
        {
          "name": "year (oldest first)",
          "value": "1"
        }
      ]
    },
    "themeSwitcherTitle": "switch colors",
    "themeSwitcher": {
      "palettes": [
        {
          "class": "beige"
        },
        {
          "class": "gray"
        },
        {
          "class": "yellow"
        },
        {
          "class": "green"
        },
        {
          "class": "dark"
        }
      ]
    },
    "burgerButton": {
      "text": "filter and sort"
    },
    "burgerCloseButton": {
      "text": null,
      "icon": "exit"
    },
    "filters": {
      "type": "check",
      "choices": [
        {
          "id": "latin",
          "label": "Latin",
          "name": "filter"
        },
        {
          "id": "sans",
          "label": "Sans Serif",
          "name": "filter"
        },
        {
          "id": "display",
          "label": "Display",
          "name": "filter"
        },
        {
          "id": "serif",
          "label": "Serif",
          "name": "filter"
        }
      ]
    }
  }
}
  • Content:
    .item-filter {
        display: flex;
        flex: 1 1 auto;
    }
    
    .item-filter__font-col {
        max-width: 100%;
    
        @include bp(md-min) {
            @include gridcol(max-width, 17, $grid-cols-md);
            @include gridcol(min-width, 17, $grid-cols-md);
            @include gridcol(flex-basis, 17, $grid-cols-md);
        }
    
        @include bp(lg-min) {
            @include gridcol(max-width, 18, $grid-cols-md);
            @include gridcol(min-width, 18, $grid-cols-md);
            @include gridcol(flex-basis, 18, $grid-cols-md);
        }
    }
    
    .item-filter__font-title {
        display: flex;
        overflow: hidden;
        min-height: 38px;
    
        @include bp(md-min) {
            min-height: 58px;
        }
    }
    
    .item-filter__font-title-text {
        padding: 8px 16px;
        flex-grow: 1;
        border-right: 1px solid var(--color-brand);
        transition: border-right-color $transition-duration $transition-easing;
    
        @include bp(sm-min) {
            padding: 15px 32px;
        }
    
        @include bp(md-min) {
            padding: 14px 32px;
            border: none;
        }
    }
    
    .item-filter__burger-open {
        @include bp(md-min) {
            display: none;
        }
    }
    
    .item-filter__sort-content {
        box-shadow: none;
        border: none;
        top: 120px;
        display: flex;
        flex-direction: column;
        flex-grow: 1;
    
        @include bp(md-min) {
            position: sticky; /* stylelint-disable-line plugin/no-unsupported-browser-features */
            display: block;
            flex-grow: 0;
        }
    
        &.item-filter__sort-content--small-top {
            margin: 0;
        }
    }
    
    .item-filter__filter-list {
        text-transform: uppercase;
        padding: 26px 18px;
    
        @include bp(md-min) {
            padding: 35px 26px;
        }
    }
    
    .item-filter__burger-heading {
        border-top: 1px solid var(--color-brand);
        border-bottom: 1px solid var(--color-brand);
        text-transform: uppercase;
        padding: 6px 16px;
        margin-top: 40px;
        transition: $transition-duration $transition-easing;
        transition-property: border-bottom-color, border-top-color;
    
        @include bp(md-min) {
            display: none;
        }
    }
    
    .item-filter__burger-header {
        display: flex;
        position: fixed;
        top: 0;
        left: 0;
        justify-content: flex-end;
        width: 100%;
        height: 40px;
        background: var(--color-background);
        border-bottom: 1px solid var(--color-brand);
        transform: translateX(-101%);
        z-index: map_get($zindex, header);
        transition: $transition-duration $transition-easing;
        transition-property: background-color, border-bottom-color, transform;
    
        @include bp(sm-min) {
            height: 60px;
        }
    
        @include bp(md-min) {
            display: none;
        }
    
        .item-filter__filter-col.is-burger-visible + & {
            transform: translateX(0);
        }
    }
    
    .item-filter__burger-close {
        margin-right: -1px;
        box-shadow: none;
        border-left: 1px solid var(--color-brand);
        border-right: 1px solid var(--color-brand);
    }
    
    .item-filter__theme-switcher {
        padding: 27px 17px 44px;
        justify-content: flex-start;
    
        @include bp(md-min) {
            display: none;
        }
    }
    
    .item-filter__filter-col {
        display: flex;
        position: fixed;
        flex-direction: column;
        top: 0;
        left: 0;
        margin: 0;
        padding-top: 39px;
        width: 100%;
        height: var(--app-height);
        z-index: map_get($zindex, itemListBurgerMenu);
        border-bottom: 1px solid var(--color-brand);
        background: var(--color-background);
        transition: $transition-duration $transition-easing;
        transition-property: background-color, border, transform, box-shadow;
        transform: translateY(-101%);
        overflow: hidden;
        overflow-y: auto;
    
        @include bp(sm-min) {
            padding-top: 59px;
        }
    
        @include bp(md-min) {
            position: relative;
            overflow: visible;
            height: auto;
            z-index: map_get($zindex, default);
            border-left: 1px solid var(--color-brand);
            transform: translateY(0);
            margin: 0;
            padding-top: 0;
        }
    
        &.is-burger-visible {
            transform: translateY(0);
        }
    }
    
    .item-filter__filter-text {
        border: none;
        padding: 8px 16px;
    
        @include bp(sm-min) {
            padding: 14px 26px;
        }
    }
    
    .theme-switcher {
        .item-filter__burger & {
            justify-content: flex-start;
            margin: 24px 16px 33px;
        }
    }
    
    .content-section__title {
        .item-filter__font-col > &,
        .item-filter__filter-col > & {
            min-height: 40px;
            padding: 0;
    
            @include bp(sm-min) {
                min-height: 60px;
            }
        }
    
        .item-filter__filter-col > & {
            position: static;
    
            @include bp(md-min) {
                position: sticky; /* stylelint-disable-line plugin/no-unsupported-browser-features */
            }
        }
    
        .item-filter__sort-content & {
            z-index: map_get($zindex, default);
            margin-top: 40px;
    
            @include bp(sm-min) {
                margin-top: 60px;
            }
    
            @include bp(md-min) {
                margin: 0;
            }
        }
    }
    
    .content-section__content {
        .item-filter__filter-col > & {
            display: flex;
            flex-direction: column;
            flex: 1 1;
        }
    
        .item-filter__sort-content > & {
            box-shadow: none;
        }
    }
    
    .select__inner {
        .item-filter__filter-col & {
            border: none;
    
            @include bp(md-min) {
                padding-left: 26px;
            }
        }
    }
    
    .choice-group__item {
        .item-filter__filter-list & {
            padding-bottom: 20px;
            margin: 0;
    
            @include bp(md-min) {
                padding-bottom: 30px;
            }
        }
    }
    
  • URL: /components/raw/item-filter/item-filter.scss
  • Filesystem Path: src/patterns/modules/item-filter/item-filter.scss
  • Size: 5.5 KB
  • Content:
    import './item-filter.scss';
    import Component from '@component';
    import Helpers from '@helpers';
    import Ajax, {IAjaxPostParams} from '@ajax';
    
    interface IItemFilterSettings {
        isVisibleClass: string;
        burgerOpenClass: string;
        burgerCloseClass: string;
        burgerMenuClass: string;
        fontItemClass: string;
        fontListClass: string;
        filtersClass: string;
    }
    
    interface ISearchParams {
        filters?: string[];
        authors?: string[];
        names?: string[];
    }
    
    export default class ItemFilter extends Component {
        static initSelector: string = '.item-filter';
    
        settings: IItemFilterSettings;
        burgerMenu: JQuery;
        openButton: JQuery;
        closeButton: JQuery;
        fontList: JQuery;
        filters: JQuery;
        waitingResponse: boolean;
        loadedPages: number;
        activeFilters: string[];
        defaultQuery: string;
    
        constructor(element: HTMLElement) {
            super(element);
    
            this.settings = {
                burgerCloseClass: 'item-filter__burger-close',
                burgerMenuClass: 'item-filter__filter-col',
                burgerOpenClass: 'item-filter__burger-open',
                filtersClass: 'item-filter__filter-list',
                fontItemClass: 'item-list__cell',
                fontListClass: 'item-filter__item-list',
                isVisibleClass: 'is-burger-visible',
            };
    
            this.burgerMenu = this.element.find('.' + this.settings.burgerMenuClass);
            this.openButton = this.element.find('.' + this.settings.burgerOpenClass);
            this.closeButton = this.element.find('.' + this.settings.burgerCloseClass);
            this.fontList = this.element.find('.' + this.settings.fontListClass);
            this.filters = this.element.find('.' + this.settings.filtersClass);
            this.waitingResponse = false;
            this.loadedPages = 1;
            this.activeFilters = [];
            this.defaultQuery = this.element.data('query');
    
            this.init();
        }
    
        init(): void {
            this.openButton.on('click', this.openBurger.bind(this));
            this.closeButton.on('click', this.closeBurger.bind(this));
            this.filters.on('change', this.filterHandler.bind(this));
            document.addEventListener('scroll', this.scrollHandler.bind(this));
            window.addEventListener('resize', this.resizeHandler.bind(this));
            const hashes : string[] = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
    
            if (window.location.href.indexOf('?') === -1) {
                this.loadFonts();
            } else {
                const search: string = hashes[0].split('=')[1].replace('+', '-');
    
                this.loadFonts(search);
            }
        }
    
        filterHandler(): void {
            const checkedFilters: string[] = [];
    
            this.filters.find('input').each((index: number, element: HTMLInputElement): void => {
                if (element.checked) {
                    checkedFilters.push(element.value);
                }
            });
    
            this.activeFilters = checkedFilters;
            this.clearFonts();
            this.loadFonts();
        }
    
        scrollHandler(): void {
            const fontItems: JQuery = this.element.find('.' + this.settings.fontItemClass).last();
    
            if (fontItems.length > 0) {
                const percent: number = fontItems[0].getBoundingClientRect().bottom / window.innerHeight;
    
                if (percent < 0.7 && !this.waitingResponse) {
                    this.loadFonts();
                }
            } else {
    
                if (!this.waitingResponse) {
                    this.loadFonts();
                }
            }
        }
    
        clearFonts(): void {
            if (!this.waitingResponse) {
                Helpers.clearFontFaces();
                this.fontList.children().remove();
                this.loadedPages = 1;
            }
        }
    
        loadFonts(search: string = ''): void {
            const searchParams: Record<string, string[]> = {};
    
            if (this.defaultQuery !== '') {
                const params: string[] = this.defaultQuery.split(';');
                const keyValuePairs: { key: string, value: string[] }[] = params.map((param: string): { key: string, value: string[] } => {
                    const split: string[] = param.split('=');
                    const key: string = split[0];
                    const values: string[] = split[1].split(',');
    
                    return {
                        key,
                        value: values,
                    };
                });
    
                keyValuePairs.forEach((pair: { key: string, value: string[] }): void => {
                    searchParams[pair.key] = pair.value;
                });
            }
            searchParams.filters = this.activeFilters;
    
            const formData: IAjaxPostParams = {
                action: 'loadList',
                page: this.loadedPages,
                searchParams,
            };
    
            if (search !== '') {
                formData.search = search;
            }
    
            this.waitingResponse = true;
            Ajax.post(formData).then((response: {items: string[]}) => {
                response.items.forEach((font: string): void => {
                    const item: JQuery = this.fontList.append(font).children().last();
    
                    const fontFamily: string = Helpers.addFontFace(item.data('font'), item.data('id'));
    
                    item.children().children().first().css('font-family', fontFamily);
                });
                this.loadedPages++;
                this.waitingResponse = false;
            });
        }
    
        resizeHandler(): void {
            if (window.matchMedia('only screen and (min-width: 1024px)').matches) {
                this.closeBurger();
            }
        }
    
        openBurger(): void {
            this.burgerMenu.addClass(this.settings.isVisibleClass);
            Helpers.disableScroll();
        }
    
        closeBurger(): void {
            this.burgerMenu.removeClass(this.settings.isVisibleClass);
            Helpers.enableScroll();
        }
    }
    
  • URL: /components/raw/item-filter/item-filter.ts
  • Filesystem Path: src/patterns/modules/item-filter/item-filter.ts
  • Size: 5.7 KB