add: littleweb full
This commit is contained in:
parent
3fc0872867
commit
d67e7c9c33
32 changed files with 1699 additions and 71 deletions
274
crates/app/src/public/html/littleweb/domain.lisp
Normal file
274
crates/app/src/public/html/littleweb/domain.lisp
Normal file
|
@ -0,0 +1,274 @@
|
|||
(text "{% extends \"root.html\" %} {% block head %}")
|
||||
(title
|
||||
(text "My services - {{ config.name }}"))
|
||||
|
||||
(text "{% endblock %} {% block body %} {{ macros::nav() }}")
|
||||
(main
|
||||
("class" "flex flex-col gap-2")
|
||||
(text "{% if user -%}")
|
||||
(div
|
||||
("class" "pillmenu")
|
||||
(a ("href" "/services") (str (text "littleweb:label.services")))
|
||||
(a ("href" "/domains") ("class" "active") (str (text "littleweb:label.domains"))))
|
||||
|
||||
(div
|
||||
("class" "card-nest")
|
||||
(div
|
||||
("class" "card small")
|
||||
(b
|
||||
(text "{{ domain.name }}.{{ domain.tld|lower }}")))
|
||||
(div
|
||||
("class" "flex flex-col gap-2 card")
|
||||
(code
|
||||
("class" "w-content")
|
||||
(a
|
||||
("href" "atto://{{ domain.name }}.{{ domain.tld|lower }}")
|
||||
(text "atto://{{ domain.name }}.{{ domain.tld|lower }}")))
|
||||
(div
|
||||
("class" "flex gap-2 flex-wrap")
|
||||
(button
|
||||
("class" "red lowered")
|
||||
("onclick" "delete_domain()")
|
||||
(icon (text "trash"))
|
||||
(str (text "general:action.delete"))))))
|
||||
(text "{%- endif %}")
|
||||
(div
|
||||
("class" "card-nest w-full")
|
||||
(div
|
||||
("class" "card small flex flex-col gap-2")
|
||||
(div
|
||||
("class" "flex items-center justify-between gap-2")
|
||||
(div
|
||||
("class" "flex items-center gap-2")
|
||||
(icon (text "panel-top"))
|
||||
(span
|
||||
(str (text "littleweb:label.domain_data"))))
|
||||
|
||||
(div
|
||||
("class" "flex gap-2")
|
||||
(button
|
||||
("class" "small lowered")
|
||||
("title" "Help")
|
||||
("onclick" "document.getElementById('domain_help').classList.toggle('hidden')")
|
||||
(icon (text "circle-question-mark")))
|
||||
|
||||
(button
|
||||
("class" "small")
|
||||
("onclick" "document.getElementById('add_data').classList.toggle('hidden')")
|
||||
(icon (text "plus"))
|
||||
(str (text "littleweb:action.add")))))
|
||||
|
||||
(div
|
||||
("class" "card w-full lowered flex flex-col gap-2 hidden no_p_margin")
|
||||
("id" "domain_help")
|
||||
(p (text "To link your domain to a site, go to the site and press \"Copy ID\"."))
|
||||
(p (text "After you have the site's ID, click \"Add\" on this page, then paste the ID into the \"value\" field."))
|
||||
(p (text "If you've ever managed a real domain's DNS, this should be familiar."))))
|
||||
(div
|
||||
("class" "card flex flex-col gap-2")
|
||||
; add data
|
||||
(form
|
||||
("id" "add_data")
|
||||
("class" "card hidden w-full lowered flex flex-col gap-2")
|
||||
("onsubmit" "add_data_from_form(event)")
|
||||
(div
|
||||
("class" "flex gap-2")
|
||||
(div
|
||||
("class" "flex w-full flex-col gap-1")
|
||||
(label
|
||||
("for" "name")
|
||||
(str (text "littleweb:label.type")))
|
||||
(select
|
||||
("type" "text")
|
||||
("name" "type")
|
||||
("id" "type")
|
||||
("placeholder" "type")
|
||||
("required" "")
|
||||
(option ("value" "Service") (text "Site ID"))
|
||||
(option ("value" "Text") (text "Text"))))
|
||||
(div
|
||||
("class" "flex w-full flex-col gap-1")
|
||||
(label
|
||||
("for" "name")
|
||||
(str (text "littleweb:label.name")))
|
||||
(input
|
||||
("type" "text")
|
||||
("name" "name")
|
||||
("id" "name")
|
||||
("placeholder" "name")
|
||||
("minlength" "1")
|
||||
("maxlength" "32"))
|
||||
(span ("class" "fade") (text "Use \"@\" for root.")))
|
||||
(div
|
||||
("class" "flex w-full flex-col gap-1")
|
||||
(label
|
||||
("for" "value")
|
||||
(str (text "littleweb:label.value")))
|
||||
(input
|
||||
("type" "text")
|
||||
("name" "value")
|
||||
("id" "value")
|
||||
("placeholder" "value")
|
||||
("required" "")
|
||||
("minlength" "2")
|
||||
("maxlength" "256"))))
|
||||
(div
|
||||
("class" "flex w-full justify-between")
|
||||
(div)
|
||||
(button
|
||||
(icon (text "check"))
|
||||
(str (text "general:action.save")))))
|
||||
; data
|
||||
(table
|
||||
(thead
|
||||
(tr
|
||||
(th (text "Name"))
|
||||
(th (text "Type"))
|
||||
(th (text "Value"))
|
||||
(th (text "Actions"))))
|
||||
|
||||
(tbody
|
||||
(text "{% for item in domain.data -%}")
|
||||
(tr
|
||||
(td (text "{{ item[0] }}"))
|
||||
(text "{% for k,v in item[1] -%}")
|
||||
(td (text "{{ k }}"))
|
||||
(td (text "{{ v }}"))
|
||||
(text "{%- endfor %}")
|
||||
(td
|
||||
("style" "overflow: auto")
|
||||
(div
|
||||
("class" "dropdown")
|
||||
(button
|
||||
("class" "camo small")
|
||||
("onclick" "trigger('atto::hooks::dropdown', [event])")
|
||||
("exclude" "dropdown")
|
||||
(icon (text "ellipsis")))
|
||||
(div
|
||||
("class" "inner")
|
||||
(button
|
||||
("onclick" "rename_data('{{ item[0] }}')")
|
||||
(icon (text "pencil"))
|
||||
(str (text "littleweb:action.rename")))
|
||||
|
||||
(button
|
||||
("class" "red")
|
||||
("onclick" "remove_data('{{ item[0] }}')")
|
||||
(icon (text "trash"))
|
||||
(str (text "general:action.delete")))))))
|
||||
(text "{%- endfor %}"))))))
|
||||
|
||||
(script ("id" "domain_data") ("type" "application/json") (text "{{ domain.data|json_encode()|safe }}"))
|
||||
(script
|
||||
(text "globalThis.DOMAIN_DATA = JSON.parse(document.getElementById(\"domain_data\").innerText);
|
||||
async function save_data() {
|
||||
await trigger(\"atto::debounce\", [\"domains::update_data\"]);
|
||||
fetch(\"/api/v1/domains/{{ domain.id }}/data\", {
|
||||
method: \"POST\",
|
||||
headers: {
|
||||
\"Content-Type\": \"application/json\",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
data: DOMAIN_DATA,
|
||||
}),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
async function add_data_from_form(e) {
|
||||
e.preventDefault();
|
||||
await trigger(\"atto::debounce\", [\"domains::add_data\"]);
|
||||
|
||||
const x = {};
|
||||
x[e.target.type.selectedOptions[0].value] = e.target.value.value;
|
||||
|
||||
if (e.target.name.value === \"\") {
|
||||
e.target.name.value = \"@\";
|
||||
}
|
||||
|
||||
const name = e.target.name.value.replace(\" \", \"_\");
|
||||
if (DOMAIN_DATA.find((x) => x[0] === name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DOMAIN_DATA.push([name, x]);
|
||||
await save_data();
|
||||
e.target.reset();
|
||||
}
|
||||
|
||||
async function delete_data(name) {
|
||||
e.preventDefault();
|
||||
await trigger(\"atto::debounce\", [\"domains::delete_data\"]);
|
||||
|
||||
delete DOMAIN_DATA.find((x) => x[0] === name);
|
||||
await save_data();
|
||||
}
|
||||
|
||||
async function delete_domain() {
|
||||
await trigger(\"atto::debounce\", [\"domains::delete\"]);
|
||||
|
||||
if (
|
||||
!(await trigger(\"atto::confirm\", [
|
||||
\"Are you sure you would like to do this?\",
|
||||
]))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(\"/api/v1/domains/{{ domain.id }}\", {
|
||||
method: \"DELETE\",
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
async function rename_data(selector) {
|
||||
await trigger(\"atto::debounce\", [\"domains::rename_data\"]);
|
||||
|
||||
let name = await trigger(\"atto::prompt\", [\"New name:\"]);
|
||||
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
|
||||
DOMAIN_DATA.find((x) => x[0] === selector)[0] = name.replaceAll(\" \", \"_\");
|
||||
await save_data();
|
||||
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 150);
|
||||
}
|
||||
|
||||
async function remove_data(name) {
|
||||
await trigger(\"atto::debounce\", [\"domains::remove_data\"]);
|
||||
|
||||
if (
|
||||
!(await trigger(\"atto::confirm\", [
|
||||
\"Are you sure you would like to do this?\",
|
||||
]))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
let i = 0;
|
||||
DOMAIN_DATA.find((x) => {
|
||||
i += 1;
|
||||
return x[0] === name;
|
||||
});
|
||||
|
||||
DOMAIN_DATA.splice(i - 1, 1);
|
||||
await save_data();
|
||||
}"))
|
||||
|
||||
(text "{% endblock %}")
|
Loading…
Add table
Add a link
Reference in a new issue