Files
indiekit-endpoint-activitypub/views/activitypub-profile.njk
Ricardo bf386e0c41 chore: phase 2 convention alignment — onerror/onclick removal, CSS stacking avatar fallback (v2.8.1)
- Replace inline onerror handlers with CSS stacking + event delegation for avatar fallback
- Replace inline onclick with event delegation for profile link removal
- Replace hardcoded border values with design tokens in reader-links.css
- Add data-avatar-fallback pattern: fallback initials always visible, img layered on top

Confab-Link: http://localhost:8080/sessions/bb4a6ec4-b711-48cd-b3d7-942ec2a9851d
2026-03-13 12:32:14 +01:00

187 lines
6.7 KiB
Plaintext

{% extends "document.njk" %}
{% from "heading/macro.njk" import heading with context %}
{% from "input/macro.njk" import input with context %}
{% from "textarea/macro.njk" import textarea with context %}
{% from "checkboxes/macro.njk" import checkboxes with context %}
{% from "radios/macro.njk" import radios with context %}
{% from "button/macro.njk" import button with context %}
{% from "notification-banner/macro.njk" import notificationBanner with context %}
{% from "prose/macro.njk" import prose with context %}
{% block content %}
{% if result %}
{{ notificationBanner({ type: result.type, text: result.text }) }}
{% endif %}
{{ prose({ text: __("activitypub.profile.intro") }) }}
<form method="post" novalidate>
{{ input({
name: "name",
label: __("activitypub.profile.nameLabel"),
hint: __("activitypub.profile.nameHint"),
value: profile.name
}) }}
{{ textarea({
name: "summary",
label: __("activitypub.profile.summaryLabel"),
hint: __("activitypub.profile.summaryHint"),
value: profile.summary,
rows: 4
}) }}
{{ input({
name: "url",
label: __("activitypub.profile.urlLabel"),
hint: __("activitypub.profile.urlHint"),
value: profile.url,
type: "url"
}) }}
{{ input({
name: "icon",
label: __("activitypub.profile.iconLabel"),
hint: __("activitypub.profile.iconHint"),
value: profile.icon,
type: "url"
}) }}
{{ input({
name: "image",
label: __("activitypub.profile.imageLabel"),
hint: __("activitypub.profile.imageHint"),
value: profile.image,
type: "url"
}) }}
{{ radios({
name: "actorType",
fieldset: {
legend: __("activitypub.profile.actorTypeLabel")
},
hint: __("activitypub.profile.actorTypeHint"),
items: [{
label: "Person",
value: "Person"
}, {
label: "Service",
value: "Service"
}, {
label: "Organization",
value: "Organization"
}],
values: [profile.actorType or "Person"]
}) }}
<fieldset class="fieldset" style="margin-block-end: var(--space-l);">
<legend class="label">{{ __("activitypub.profile.linksLabel") }}</legend>
<p class="hint">{{ __("activitypub.profile.linksHint") }}</p>
<div id="profile-links">
{% if profile.attachments and profile.attachments.length > 0 %}
{% for att in profile.attachments %}
<div class="profile-link-row" style="display: grid; grid-template-columns: 1fr 2fr auto; gap: var(--space-s); align-items: end; margin-block-end: var(--space-s);">
<div>
<label class="label" for="link_name_{{ loop.index }}">{{ __("activitypub.profile.linkNameLabel") }}</label>
<input class="input" type="text" id="link_name_{{ loop.index }}" name="link_name[]" value="{{ att.name }}" placeholder="Website">
</div>
<div>
<label class="label" for="link_value_{{ loop.index }}">{{ __("activitypub.profile.linkValueLabel") }}</label>
<input class="input" type="url" id="link_value_{{ loop.index }}" name="link_value[]" value="{{ att.value }}" placeholder="https://example.com">
</div>
<button type="button" class="button button--small profile-link-remove" style="margin-block-end: 4px;">{{ __("activitypub.profile.removeLink") }}</button>
</div>
{% endfor %}
{% endif %}
</div>
<button type="button" class="button button--small" id="add-link-btn">{{ __("activitypub.profile.addLink") }}</button>
</fieldset>
{{ checkboxes({
name: "manuallyApprovesFollowers",
items: [
{
label: __("activitypub.profile.manualApprovalLabel"),
value: "true",
hint: __("activitypub.profile.manualApprovalHint")
}
],
values: ["true"] if profile.manuallyApprovesFollowers else []
}) }}
{{ checkboxes({
name: "authorizedFetch",
items: [
{
label: __("activitypub.profile.authorizedFetchLabel"),
value: "true",
hint: __("activitypub.profile.authorizedFetchHint")
}
],
values: ["true"] if profile.authorizedFetch else []
}) }}
{{ button({ text: __("activitypub.profile.save") }) }}
</form>
<script>
(function() {
document.getElementById('profile-links').addEventListener('click', function(e) {
var btn = e.target.closest('.profile-link-remove');
if (btn) btn.closest('.profile-link-row').remove();
});
var linkCount = {{ (profile.attachments.length if profile.attachments) or 0 }};
document.getElementById('add-link-btn').addEventListener('click', function() {
linkCount++;
var container = document.getElementById('profile-links');
var row = document.createElement('div');
row.className = 'profile-link-row';
row.style.cssText = 'display: grid; grid-template-columns: 1fr 2fr auto; gap: var(--space-s); align-items: end; margin-block-end: var(--space-s);';
var nameDiv = document.createElement('div');
var nameLabel = document.createElement('label');
nameLabel.className = 'label';
nameLabel.setAttribute('for', 'link_name_' + linkCount);
nameLabel.textContent = 'Label';
var nameInput = document.createElement('input');
nameInput.className = 'input';
nameInput.type = 'text';
nameInput.id = 'link_name_' + linkCount;
nameInput.name = 'link_name[]';
nameInput.placeholder = 'Website';
nameDiv.appendChild(nameLabel);
nameDiv.appendChild(nameInput);
var valueDiv = document.createElement('div');
var valueLabel = document.createElement('label');
valueLabel.className = 'label';
valueLabel.setAttribute('for', 'link_value_' + linkCount);
valueLabel.textContent = 'URL';
var valueInput = document.createElement('input');
valueInput.className = 'input';
valueInput.type = 'url';
valueInput.id = 'link_value_' + linkCount;
valueInput.name = 'link_value[]';
valueInput.placeholder = 'https://example.com';
valueDiv.appendChild(valueLabel);
valueDiv.appendChild(valueInput);
var removeBtn = document.createElement('button');
removeBtn.type = 'button';
removeBtn.className = 'button button--small profile-link-remove';
removeBtn.style.cssText = 'margin-block-end: 4px;';
removeBtn.textContent = 'Remove';
row.appendChild(nameDiv);
row.appendChild(valueDiv);
row.appendChild(removeBtn);
container.appendChild(row);
});
})();
</script>
{% endblock %}