Identity profile metadata input with dynamic form (#280)
This commit is contained in:
parent
b63ad40f54
commit
aa2ace9b68
|
@ -434,6 +434,7 @@ p.authorization-code {
|
||||||
font-size: 140%;
|
font-size: 140%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Icon menus */
|
/* Icon menus */
|
||||||
|
|
||||||
.icon-menu .option {
|
.icon-menu .option {
|
||||||
|
@ -870,6 +871,35 @@ button:hover,
|
||||||
.right-column .button {
|
.right-column .button {
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
}
|
}
|
||||||
|
form .field.multi-option {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
form .field.multi-option {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
form .option.option-row {
|
||||||
|
margin: 0px 0px 5px 0px;
|
||||||
|
}
|
||||||
|
.option-row .right {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
form .option-row .option-field {
|
||||||
|
vertical-align: middle;
|
||||||
|
display: inline-block;
|
||||||
|
line-height: normal;
|
||||||
|
width: 40%;
|
||||||
|
min-width: 30px;
|
||||||
|
padding-left: 0px;
|
||||||
|
padding-right: 7px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
form .option-row .right button {
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-top: 0px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Logged out homepage */
|
/* Logged out homepage */
|
||||||
|
|
||||||
|
@ -933,6 +963,32 @@ h1.identity small {
|
||||||
margin: 0 0 10px 0;
|
margin: 0 0 10px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.identity-metadata .metadata-pair {
|
||||||
|
display: block;
|
||||||
|
margin: 0px 0 10px 0;
|
||||||
|
background: var(--color-bg-box);
|
||||||
|
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.1);
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border: 2px solid rgba(255, 255, 255, 0);
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.identity-metadata .metadata-pair .metadata-name {
|
||||||
|
display: inline-block;
|
||||||
|
min-width: 80px;
|
||||||
|
margin-right: 15px;
|
||||||
|
text-align: right;
|
||||||
|
color: var(--color-text-dull);
|
||||||
|
}
|
||||||
|
.identity-metadata .metadata-pair .metadata-name::after {
|
||||||
|
padding-left: 3px;
|
||||||
|
|
||||||
|
color: var(--color-text-dull);
|
||||||
|
}
|
||||||
|
|
||||||
.system-note {
|
.system-note {
|
||||||
background: var(--color-bg-menu);
|
background: var(--color-bg-menu);
|
||||||
color: var(--color-text-dull);
|
color: var(--color-text-dull);
|
||||||
|
@ -1602,3 +1658,7 @@ form .post {
|
||||||
.debug-section .hidden {
|
.debug-section .hidden {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.field .hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
{% with name_one=field_name_one|default:"name" name_two=field_name_two|default:"value" %}
|
||||||
|
|
||||||
|
<script type="text/hyperscript">
|
||||||
|
def {{ field.name }}.collect{{ field.name|title }}Fields()
|
||||||
|
set newdata to []
|
||||||
|
for item in <div.{{ field.name }}-row/>
|
||||||
|
get the (value of the first <input.{{ field.name }}-{{ name_one }}/> in item)
|
||||||
|
set n to it
|
||||||
|
get the (value of the last <input.{{ field.name }}-{{ name_two }}/> in item)
|
||||||
|
set val to it
|
||||||
|
if n != '' and val != '' then
|
||||||
|
append {'{{ name_one }}': n, '{{ name_two }}': val} to newdata
|
||||||
|
end
|
||||||
|
set #id_{{ field.name }}@value to newdata as JSON
|
||||||
|
end
|
||||||
|
|
||||||
|
def {{ field.name }}.addEmptyField()
|
||||||
|
get #blank_{{ field.name }}'s outerHTML
|
||||||
|
put it before #new_{{ field.name }}
|
||||||
|
get #new_{{ field.name }}'s previousSibling
|
||||||
|
set foo to it
|
||||||
|
set foo@id to ''
|
||||||
|
remove .hidden from foo
|
||||||
|
add .{{ field.name }}-row to foo
|
||||||
|
return foo
|
||||||
|
end
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{% include "forms/_field.html" %}
|
||||||
|
|
||||||
|
<div class="field multi-option">
|
||||||
|
<section class="icon-menu">
|
||||||
|
<span id="new_{{ field.name }}" stlye="display: none"
|
||||||
|
_="on load
|
||||||
|
get the (value of #id_{{ field.name }}) as Object
|
||||||
|
set items to it
|
||||||
|
for item in items
|
||||||
|
set f to {{ field.name }}.addEmptyField()
|
||||||
|
set one to the first <input.{{ field.name }}-{{ name_one }}/> in f then
|
||||||
|
set one@value to item.{{ name_one }}
|
||||||
|
|
||||||
|
set two to the first <input.{{ field.name }}-{{ name_two }}/> in f then
|
||||||
|
set two@value to item.{{ name_two }}
|
||||||
|
end
|
||||||
|
"></span>
|
||||||
|
|
||||||
|
<div class="option">
|
||||||
|
<span class="option-field">
|
||||||
|
<button class="fa-solid fa-add" _="on click {{ field.name }}.addEmptyField() then halt"></button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="blank_{{ field.name }}" class="option option-row hidden">
|
||||||
|
<span class="option-field">
|
||||||
|
<input type=text class="{{ field.name }}-{{ name_one }}" name="{{ field.name }}_{{ name_one }}" value="">
|
||||||
|
</span>
|
||||||
|
<span class="option-field">
|
||||||
|
<input type=text class="{{ field.name }}-{{ name_two }}" name="{{ field.name }}_{{ name_two }}" value="">
|
||||||
|
</span>
|
||||||
|
<div class="right">
|
||||||
|
<button class="fa-solid fa-trash delete"
|
||||||
|
_="on click remove (closest parent .option)
|
||||||
|
then {{ field.name }}.collect{{ field.name|title }}Fields()
|
||||||
|
then halt" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endwith %}
|
|
@ -68,14 +68,14 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if identity.metadata %}
|
{% if identity.metadata %}
|
||||||
<table class="metadata">
|
<div class="identity-metadata">
|
||||||
{% for entry in identity.safe_metadata %}
|
{% for entry in identity.safe_metadata %}
|
||||||
<tr>
|
<div class="metadata-pair">
|
||||||
<th>{{ entry.name }}</td>
|
<span class="metadata-name">{{ entry.name }}</span>
|
||||||
<td>{{ entry.value }}</td>
|
<span class="metadata-value">{{ entry.value }}</span>
|
||||||
</tr>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if identity.local and identity.config_identity.visible_follows %}
|
{% if identity.local and identity.config_identity.visible_follows %}
|
||||||
|
|
|
@ -3,15 +3,19 @@
|
||||||
{% block subtitle %}Profile{% endblock %}
|
{% block subtitle %}Profile{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<form action="." method="POST" enctype="multipart/form-data" >
|
<form action="." method="POST" enctype="multipart/form-data"
|
||||||
|
_="on submit metadata.collectMetadataFields()">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Details</legend>
|
<legend>Details</legend>
|
||||||
{% include "forms/_field.html" with field=form.name %}
|
{% include "forms/_field.html" with field=form.name %}
|
||||||
{% include "forms/_field.html" with field=form.summary %}
|
{% include "forms/_field.html" with field=form.summary %}
|
||||||
|
{% include "forms/_json_name_value_list.html" with field=form.metadata %}
|
||||||
{% include "forms/_field.html" with field=form.discoverable %}
|
{% include "forms/_field.html" with field=form.discoverable %}
|
||||||
{% include "forms/_field.html" with field=form.visible_follows %}
|
{% include "forms/_field.html" with field=form.visible_follows %}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Images</legend>
|
<legend>Images</legend>
|
||||||
{% include "forms/_field.html" with field=form.icon %}
|
{% include "forms/_field.html" with field=form.icon %}
|
||||||
|
|
|
@ -47,6 +47,12 @@ class ProfilePage(FormView):
|
||||||
widget=forms.Select(choices=[(True, "Visible"), (False, "Hidden")]),
|
widget=forms.Select(choices=[(True, "Visible"), (False, "Hidden")]),
|
||||||
required=False,
|
required=False,
|
||||||
)
|
)
|
||||||
|
metadata = forms.JSONField(
|
||||||
|
label="Profile Metadata Fields",
|
||||||
|
help_text="These values will appear on your profile below your Bio",
|
||||||
|
widget=forms.HiddenInput,
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
identity = self.request.identity
|
identity = self.request.identity
|
||||||
|
@ -57,6 +63,7 @@ class ProfilePage(FormView):
|
||||||
"image": identity.image and identity.image.url,
|
"image": identity.image and identity.image.url,
|
||||||
"discoverable": identity.discoverable,
|
"discoverable": identity.discoverable,
|
||||||
"visible_follows": identity.config_identity.visible_follows,
|
"visible_follows": identity.config_identity.visible_follows,
|
||||||
|
"metadata": identity.metadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
|
@ -78,6 +85,9 @@ class ProfilePage(FormView):
|
||||||
image.name,
|
image.name,
|
||||||
resize_image(image, size=(1500, 500)),
|
resize_image(image, size=(1500, 500)),
|
||||||
)
|
)
|
||||||
|
metadata = form.cleaned_data.get("metadata")
|
||||||
|
if metadata:
|
||||||
|
identity.metadata = metadata
|
||||||
identity.save()
|
identity.save()
|
||||||
identity.transition_perform(IdentityStates.edited)
|
identity.transition_perform(IdentityStates.edited)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue