actix-admin 0.8.0

An admin interface for actix-web
Documentation
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ navbar_title }}</title>

{% if custom_css_paths %}
{% for custom_css_path in custom_css_paths %}
<link rel="stylesheet" href="{{ custom_css_path }}">
{% endfor %}
{% else %}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.0/css/bulma.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
{% endif %}

{% if custom_js_paths %}
{% for custom_js_path in custom_js_paths %}
<link rel="stylesheet" href="{{ custom_js_path }}">
{% endfor %}
{% else %}
<script src="https://unpkg.com/htmx.org@1.9.12"></script>
{% endif %}

<link href="https://cdn.jsdelivr.net/npm/tom-select@2.3.1/dist/css/tom-select.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/tom-select@2.3.1/dist/js/tom-select.complete.min.js"></script>

<script>
    document.onkeydown = function (e) {
        if (document.activeElement.tagName.toLowerCase() !== 'input') {
            switch (e.which) {
                case 37: // left
                    let left_el = document.getElementsByClassName('left-arrow-click').item(0);
                    if (left_el) { left_el.click(); };
                    break;

                //case 38: // up
                //    break;

                case 39: // right
                    let right_el = document.getElementsByClassName('right-arrow-click').item(0);
                    if (right_el) { right_el.click(); };
                    break;

                //case 40: // down
                //    break;

                default: return; // exit this handler for other keys
            }
            e.preventDefault(); // prevent the default action (scroll / move caret)
        }
    };

    function checkAll(bx) {
        var cbs = document.getElementsByTagName('input');
        for (var i = 0; i < cbs.length; i++) {
            if (cbs[i].type == 'checkbox') {
                cbs[i].checked = bx.checked;
            }
        }
    }

    function sort_by(column) {
        current_sort_order = document.getElementsByName("sort_order")[0].value;
        if (current_sort_order == "Asc") {
            document.getElementsByName("sort_order").forEach((e) => e.value = "Desc");
        } else {
            document.getElementsByName("sort_order").forEach((e) => e.value = "Asc");
        }
        document.getElementsByName("sort_by").forEach((e) => e.value = column);
        document.getElementById('table_form').requestSubmit();
    }

    function toggle_hidden(element_name) {
        el = document.getElementById(element_name);
        if (el) {
            if (el.classList.contains("is-hidden")) {
                el.classList.remove("is-hidden");
            } else {
                el.classList.add("is-hidden");
            }
        }
    }

    function disableButton(form) {
        let button = form.elements["submitBtn"];
        button.disabled = true;
        button.classList.add("is-loading");
    }

    document.addEventListener('DOMContentLoaded', () => {
        // Get all "navbar-burger" elements
        const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);

        // Add a click event on each of them
        $navbarBurgers.forEach(el => {
            el.addEventListener('click', () => {

                // Get the target from the "data-target" attribute
                const target = el.getAttribute('data-target');
                const $target = document.getElementById(target);

                // Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
                el.classList.toggle('is-active');
                $target.classList.toggle('is-active');

            });
        });
    });

    let error = "<div class=\"notification mb-4 is-light is-danger\"><button class=\"delete\" onclick=\"this.parentElement.remove()\"></button>An Error occurred</div>";
    htmx.on("htmx:responseError", function () {
        document.getElementById("notifications").insertAdjacentHTML("afterend", error)
    });
    htmx.on("htmx:sendError", function () {
        document.getElementById("notifications").insertAdjacentHTML("afterend", error)
    });
</script>

<style>
    .loader-wrapper {
        position: absolute;
        height: 50%;
        width: 100%;
        display: flex;
        justify-content: center;
        border-radius: 6px;
        align-items: center;
        z-index: 6;
        pointer-events: none
    }

    .opaque-rounded-background {
        background: rgba(255, 255, 255, 0.3);
        padding: 10px;
        border-radius: 10px;
    }
</style>