schon/engine/core/templates/json_table_widget.html
Egor fureunoir Gorbunov dc94841f40 feat(core/blog): add support for product videos and blog post images
This commit introduces support for uploading optional video files to products and image files to blog posts. Enhanced admin interfaces were added to preview these files directly. Also includes adjustments to GraphQL types and serializers to expose the new fields.
2026-03-02 01:57:57 +03:00

112 lines
4.8 KiB
HTML

{% load i18n %}
{% with input_cls="border border-base-200 bg-white font-medium placeholder-base-400 rounded-default shadow-xs text-font-default-light text-sm focus:outline-2 focus:-outline-offset-2 focus:outline-primary-600 dark:bg-base-900 dark:border-base-700 dark:text-font-default-dark dark:scheme-dark px-3 py-2 w-full" %}
<div class="max-w-4xl">
<table class="w-full" id="table-{{ widget.attrs.id }}">
<thead>
<tr class="border-b border-base-200 dark:border-base-700">
<th class="text-left text-xs font-semibold uppercase tracking-wide text-font-important-light dark:text-font-important-dark pb-2 pr-4 w-5/12">{% trans "Key" %}</th>
<th class="text-left text-xs font-semibold uppercase tracking-wide text-font-important-light dark:text-font-important-dark pb-2 pr-4 w-5/12">{% trans "Value" %}</th>
<th class="pb-2 w-2/12"></th>
</tr>
</thead>
<tbody id="json-fields-{{ widget.attrs.id }}">
{% for key, val in widget.value.items %}
<tr class="border-b border-base-200 dark:border-base-700 group/row">
<td class="py-2 pr-3">
<input type="text"
name="{{ widget.name }}_key"
value="{{ key }}"
placeholder="{% trans "key" %}"
class="{{ input_cls }}">
</td>
<td class="py-2 pr-3">
<input type="text"
name="{{ widget.name }}_value"
value="{% if val is list %}{{ val|join:', ' }}{% else %}{{ val }}{% endif %}"
placeholder="{% trans "value" %}"
class="{{ input_cls }}">
</td>
<td class="py-2">
<button type="button"
class="delete-row-btn border border-transparent cursor-pointer font-medium px-2 py-2 rounded-default text-center bg-red-600 text-white text-sm leading-none opacity-60 group-hover/row:opacity-100 transition-opacity"
title="{% trans "Delete row" %}">&#x2715;</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="mt-3">
<button type="button"
class="add-row-btn border border-transparent cursor-pointer font-medium px-3 py-2 rounded-default text-center whitespace-nowrap bg-primary-600 text-white text-sm"
data-tbody="json-fields-{{ widget.attrs.id }}"
data-name="{{ widget.name }}"
data-input-cls="{{ input_cls }}">
+ {% trans "Add Row" %}
</button>
</div>
</div>
{% endwith %}
<script>
(function () {
function wireDeleteBtn(btn) {
btn.addEventListener("click", function () {
btn.closest("tr").remove();
});
}
function buildRow(name, inputCls) {
const tr = document.createElement("tr");
tr.className = "border-b border-base-200 dark:border-base-700 group/row";
const mkTd = (paddingCls) => {
const td = document.createElement("td");
td.className = paddingCls;
return td;
};
const mkInput = (fieldName, placeholder) => {
const inp = document.createElement("input");
inp.type = "text";
inp.name = fieldName;
inp.placeholder = placeholder;
inp.className = inputCls;
return inp;
};
const keyTd = mkTd("py-2 pr-3");
keyTd.appendChild(mkInput(name + "_key", "key"));
const valTd = mkTd("py-2 pr-3");
valTd.appendChild(mkInput(name + "_value", "value"));
const delTd = mkTd("py-2");
const delBtn = document.createElement("button");
delBtn.type = "button";
delBtn.className = "delete-row-btn border border-transparent cursor-pointer font-medium px-2 py-2 rounded-default text-center bg-red-600 text-white text-sm leading-none";
delBtn.title = "Delete row";
delBtn.textContent = "\u2715";
wireDeleteBtn(delBtn);
delTd.appendChild(delBtn);
tr.appendChild(keyTd);
tr.appendChild(valTd);
tr.appendChild(delTd);
return tr;
}
document.addEventListener("DOMContentLoaded", function () {
// Wire existing delete buttons
document.querySelectorAll(".delete-row-btn").forEach(wireDeleteBtn);
// Wire add-row buttons
document.querySelectorAll(".add-row-btn").forEach(function (btn) {
const tbody = document.getElementById(btn.dataset.tbody);
if (!tbody) return;
btn.addEventListener("click", function () {
tbody.appendChild(buildRow(btn.dataset.name, btn.dataset.inputCls));
});
});
});
}());
</script>