{% apply spaceless %}
{% set keyPrefix = keyPrefix ?? '' %}
{% set isTopLevel = not keyPrefix %}

{% if isTopLevel %}
    {% set elementInstance = craft.app.elements.createElement(elementType) %}
    {% set baseSortOptions = elementInstance.sortOptions()|map((option, key) => {
        label: option.label ?? option,
        attr: option.attribute ?? option.orderBy ?? key,
        defaultDir: option.defaultDir ?? 'asc',
    })|values %}
    {% set tableColumns = craft.app.elementSources.getAvailableTableAttributes(elementType) %}
{% endif %}

{% macro sourceLink(key, source, isTopLevel, elementType, baseSortOptions, tableColumns) %}
    {{ tag('a', {
        data: {
            key: key,
            'has-thumbs': (source.hasThumbs ?? false) ? true : false,
            'has-structure': (source.structureId ?? null)|boolean,
            'default-sort': source.defaultSort ?? false,
            'sort-opts': isTopLevel
                ? baseSortOptions
                    |merge(craft.app.elementSources.getSourceSortOptions(elementType, key)|map(option => {
                        label: option.label,
                        attr: option.attribute ?? option.orderBy,
                        defaultDir: option.defaultDir ?? 'asc'
                    })|values)
                : false,
            'table-col-opts': isTopLevel
                ? tableColumns
                    |merge(craft.app.elementSources.getSourceTableAttributes(elementType, key))
                    |map((a, key) => a|merge({attr: key}))
                    |values
                : false,
            'default-table-cols': isTopLevel
                ? craft.app.elementSources.getTableAttributes(elementType, key)
                    |map(a => a[0])
                    |filter(a => a != 'title')
                    |values
                : false,
            'default-source-path': (source.defaultSourcePath ?? false) ? source.defaultSourcePath|json_encode : false,
            sites: (source.sites ?? false) ? source.sites|join(',') : false,
            'override-status': (source.criteria.status ?? false) ? true : false,
            disabled: source.disabled ?? false,
        }|merge(source.data ?? {}),
        html: _self.sourceInnerHtml(source)
    }) }}
{% endmacro %}

{% macro sourceInnerHtml(source) %}
    {% if source.status is defined %}
        <span class="status {{ source.status }}"></span>
    {% elseif source.icon is defined %}
        <span class="icon">
            {{ (svg(source.icon, sanitize=true, namespace=true) ?: "<span data-icon='#{source.icon}'></span>")|raw }}
        </span>
    {% elseif source.iconMask is defined %}
        <span class="icon icon-mask">
            {{ (svg(source.iconMask, sanitize=true, namespace=true) ?: "<span data-icon='#{source.iconMask}'></span>")|raw }}
        </span>
    {% endif %}
    <span class="label">{{ source.label|trim is not same as('') ? source.label : '(blank)'|t('app') }}</span>
    {% if source.badgeCount is defined %}
        <span class="badge" aria-hidden="true">{{ source.badgeCount|number(decimals=0) }}</span>
        {{ tag('span', {
            class: 'visually-hidden',
            data: {
                notification: true,
            },
            text: '{num, number} {num, plural, =1{notification} other{notifications}}'|t('app', {
                num: source.badgeCount,
            }),
        }) }}
    {% endif %}
{% endmacro %}

{% set nestedUnderHeading = false %}

{% tag 'ul' with {
    class: keyPrefix ? 'nested' : null,
} %}
    {% for source in sources %}
        {% if (source.type ?? null) == 'heading' %}
            {% if nestedUnderHeading %}
                    </ul>
                </li>
            {% endif %}
            <li class="heading">
                <span>{{ source.heading|t('site') }}</span>
                <ul>
            {% set nestedUnderHeading = true %}
        {% else %}
            {% set key = source.keyPath ?? (keyPrefix ~ source.key) %}
            {% tag 'li' with {
                class: [
                    (source.disabled ?? false) ? 'hidden' : null,
                ]|filter,
            } %}
                {{ _self.sourceLink(key, source, isTopLevel, elementType, baseSortOptions ?? null, tableColumns ?? null) }}
                {% if source.nested is defined and source.nested is not empty %}
                    <button class="toggle" aria-expanded="false" aria-label="{{ 'Show nested sources'|t('app') }}"></button>
                    {% include "_elements/sources" with {
                        keyPrefix: key ~ '/',
                        sources: source.nested
                    } %}
                {% endif %}
            {% endtag %}
        {% endif %}
    {% endfor %}
    {% if nestedUnderHeading %}
            </ul>
        </li>
    {% endif %}
{% endtag %}
{% endapply %}
