ayb 0.1.12

ayb makes it easy to create, host, and share embedded databases like SQLite and DuckDB
Documentation
<style>
/* Profile edit mode toggle styles */
.profile-section .edit-mode { display: none; }
.profile-section .view-mode { display: block; }
.profile-section .view-mode.flex { display: flex; }

/* When editing, swap visibility */
.profile-section.editing .edit-mode { display: block; }
.profile-section.editing .edit-mode.flex { display: flex; }
.profile-section.editing .view-mode { display: none; }

/* HTMX loading indicator styles */
.htmx-request .htmx-indicator { opacity: 1; }
#profile-edit-form.htmx-request .save-text { visibility: hidden; }
</style>

<div class="uk-card profile-section" id="profile-section">
    <form id="profile-edit-form"
          hx-post="/{{ entity }}/update_profile"
          hx-target="#profile-section"
          hx-target-400="#profile-update-error"
          hx-swap="outerHTML">
        <div class="uk-card-header space-y-2">
            <h1 class="uk-h2 view-mode">{{ name }}</h1>
            <input type="text" name="display_name" value="{{ name }}" class="edit-mode p-2 border rounded focus:border-blue-500 w-full uk-h2" placeholder="Display Name">
            <p class="text-muted-foreground view-mode">{{ description }}</p>
            <input type="text" name="description" value="{{ description }}" class="edit-mode p-2 border rounded focus:border-blue-500 w-full" placeholder="Description">
        </div>
        <div class="uk-card-body space-y-2">
            {% if organization %}
            <div class="flex items-center view-mode">
                <uk-icon icon="building" class="mr-1"></uk-icon> {{ organization }}
            </div>
            {% endif %}
            <div class="flex items-start edit-mode">
                <uk-icon icon="building" class="mr-1 mt-2 flex-shrink-0"></uk-icon>
                <input type="text" name="organization" value="{{ organization }}" class="p-2 border rounded focus:border-blue-500 w-full" placeholder="Organization">
            </div>

            {% if location %}
            <div class="flex items-center view-mode">
                <uk-icon icon="map-pin" class="mr-1"></uk-icon> {{ location }}
            </div>
            {% endif %}
            <div class="flex items-start edit-mode">
                <uk-icon icon="map-pin" class="mr-1 mt-2 flex-shrink-0"></uk-icon>
                <input type="text" name="location" value="{{ location }}" class="p-2 border rounded focus:border-blue-500 w-full" placeholder="Location">
            </div>

            <div class="mt-3 view-mode">
                {% for link in links %}
                <div class="flex items-center">
                    <uk-icon icon="link" class="mr-1"></uk-icon>
                    <a href="{{ link.url }}" rel="nofollow me">{{ link.url }}</a>
                </div>
                {% endfor %}
            </div>
            <div class="mt-3 edit-mode">
                <div id="profile-links-container">
                    {% for link in links %}
                    <div class="flex items-start mb-2 link-input-group">
                        <uk-icon icon="link" class="mr-1 mt-2 flex-shrink-0"></uk-icon>
                        <input type="text" name="links[]" value="{{ link.url }}" class="p-2 border rounded focus:border-blue-500 w-full link-url" placeholder="Link URL">
                        <button type="button" class="uk-btn uk-btn-danger uk-btn-sm ml-2 flex-shrink-0" onclick="removeLink(this)">
                            <uk-icon icon="trash"></uk-icon>
                        </button>
                    </div>
                    {% endfor %}
                </div>
                <button type="button" class="uk-btn uk-btn-default uk-btn-sm" onclick="addLink()">
                    <uk-icon icon="plus"></uk-icon> Add link
                </button>
            </div>

            {% if logged_in_entity == entity %}
            <div class="mt-4 view-mode">
                <button type="button" class="uk-btn uk-btn-default uk-btn-sm w-full text-center" onclick="enableProfileEdit()">
                    Edit profile
                </button>
            </div>
            <div class="mt-4 edit-mode">
                <button type="button" class="uk-btn uk-btn-default uk-btn-sm" onclick="cancelProfileEdit()">
                    Cancel
                </button>
                <button type="submit" class="uk-btn uk-btn-primary uk-btn-sm ml-2" style="min-width: 70px; position: relative;">
                    <span class="save-text">Save</span>
                    <span class="htmx-indicator opacity-0 transition-opacity duration-200 ease-in inline-block absolute left-1/2 top-1/2 transform -translate-x-1/2" style="transform: translate(-50%, calc(-50% + 1px));">
                        <div uk-spinner="ratio: 0.6"></div>
                    </span>
                </button>
            </div>
            <div id="profile-update-error" class="mt-2"></div>
            {% endif %}
        </div>
    </form>
</div>

<script>
function enableProfileEdit() {
    document.getElementById('profile-section').classList.add('editing');
    // Clear any previous errors
    document.getElementById('profile-update-error').innerHTML = '';
}

function cancelProfileEdit() {
    document.getElementById('profile-section').classList.remove('editing');
    // Reset form to original values
    document.getElementById('profile-edit-form').reset();
}

function addLink() {
    const container = document.getElementById('profile-links-container');
    const linkDiv = document.createElement('div');
    linkDiv.className = 'flex items-start mb-2 link-input-group';
    linkDiv.innerHTML = `
        <uk-icon icon="link" class="mr-1 mt-2 flex-shrink-0"></uk-icon>
        <input type="text" name="links[]" value="" class="p-2 border rounded focus:border-blue-500 w-full link-url" placeholder="Link URL">
        <button type="button" class="uk-btn uk-btn-danger uk-btn-sm ml-2 flex-shrink-0" onclick="removeLink(this)">
            <uk-icon icon="trash"></uk-icon>
        </button>
    `;
    container.appendChild(linkDiv);
}

function removeLink(button) {
    button.closest('.link-input-group').remove();
}

// Handle form submission preparation
document.body.addEventListener('htmx:configRequest', function(event) {
    if (event.detail.elt.id === 'profile-edit-form') {
        // Collect links into JSON format
        const linkInputs = event.detail.elt.querySelectorAll('input[name="links[]"]');
        const links = Array.from(linkInputs)
            .map(input => input.value.trim())
            .filter(url => url.length > 0)
            .map(url => ({ url: url }));

        // Add links as JSON string to the parameters
        event.detail.parameters.links = JSON.stringify(links);

        // Remove the individual link inputs from submission
        delete event.detail.parameters['links[]'];
    }
});
</script>