add: small littleweb browser changes
This commit is contained in:
parent
e7febc7c7e
commit
388ccbf58c
9 changed files with 194 additions and 21 deletions
|
@ -32,7 +32,7 @@
|
||||||
(input
|
(input
|
||||||
("type" "uri")
|
("type" "uri")
|
||||||
("class" "w-full")
|
("class" "w-full")
|
||||||
("true_value" "{{ path }}")
|
("true_value" "")
|
||||||
("name" "uri")
|
("name" "uri")
|
||||||
("id" "uri"))
|
("id" "uri"))
|
||||||
|
|
||||||
|
@ -121,10 +121,6 @@
|
||||||
uri = `${uri}/index.html`;
|
uri = `${uri}/index.html`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!uri.startsWith(\"atto://\")) {
|
|
||||||
uri = `atto://${uri}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
console.log(\"navigate\", uri);
|
console.log(\"navigate\", uri);
|
||||||
document.getElementById(\"browser_iframe\").src = `{{ config.lw_host|safe }}/api/v1/net/${uri}`;
|
document.getElementById(\"browser_iframe\").src = `{{ config.lw_host|safe }}/api/v1/net/${uri}`;
|
||||||
|
@ -152,7 +148,8 @@
|
||||||
if (data.event === \"change_url\") {
|
if (data.event === \"change_url\") {
|
||||||
const uri = new URL(data.target).pathname.slice(\"/api/v1/net/\".length);
|
const uri = new URL(data.target).pathname.slice(\"/api/v1/net/\".length);
|
||||||
window.history.pushState(null, null, `/net/${uri.replace(\"atto://\", \"\")}`);
|
window.history.pushState(null, null, `/net/${uri.replace(\"atto://\", \"\")}`);
|
||||||
document.getElementById(\"uri\").setAttribute(\"true_value\", uri);
|
document.getElementById(\"uri\").setAttribute(\"true_value\", `atto://${uri}`);
|
||||||
|
document.getElementById(\"uri\").value = uri.split(\"/\")[0];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -207,6 +204,7 @@
|
||||||
is_focused = false;
|
is_focused = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById(\"uri\").value = document.getElementById(\"uri\").getAttribute(\"true_value\").replace(\"atto://\", \"\").split(\"/\")[0]"))
|
// navigate
|
||||||
|
littleweb_navigate(\"{{ path|safe }}\");"))
|
||||||
|
|
||||||
(text "{% endblock %}")
|
(text "{% endblock %}")
|
||||||
|
|
|
@ -5,6 +5,17 @@
|
||||||
(text "{% endblock %} {% block body %} {{ macros::nav() }}")
|
(text "{% endblock %} {% block body %} {{ macros::nav() }}")
|
||||||
(main
|
(main
|
||||||
("class" "flex flex-col gap-2")
|
("class" "flex flex-col gap-2")
|
||||||
|
|
||||||
|
; viewing other user's domains warning
|
||||||
|
(text "{% if profile.id != user.id -%}")
|
||||||
|
(div
|
||||||
|
("class" "card w-full red flex gap-2 items-center")
|
||||||
|
(text "{{ icon \"skull\" }}")
|
||||||
|
(b
|
||||||
|
(text "Viewing other user's domains! Please be careful.")))
|
||||||
|
(text "{%- endif %}")
|
||||||
|
|
||||||
|
; ...
|
||||||
(text "{% if user -%}")
|
(text "{% if user -%}")
|
||||||
(div
|
(div
|
||||||
("class" "pillmenu")
|
("class" "pillmenu")
|
||||||
|
|
|
@ -5,6 +5,17 @@
|
||||||
(text "{% endblock %} {% block body %} {{ macros::nav() }}")
|
(text "{% endblock %} {% block body %} {{ macros::nav() }}")
|
||||||
(main
|
(main
|
||||||
("class" "flex flex-col gap-2")
|
("class" "flex flex-col gap-2")
|
||||||
|
|
||||||
|
; viewing other user's services warning
|
||||||
|
(text "{% if profile.id != user.id -%}")
|
||||||
|
(div
|
||||||
|
("class" "card w-full red flex gap-2 items-center")
|
||||||
|
(text "{{ icon \"skull\" }}")
|
||||||
|
(b
|
||||||
|
(text "Viewing other user's sites! Please be careful.")))
|
||||||
|
(text "{%- endif %}")
|
||||||
|
|
||||||
|
; ...
|
||||||
(text "{% if user -%}")
|
(text "{% if user -%}")
|
||||||
(div
|
(div
|
||||||
("class" "pillmenu")
|
("class" "pillmenu")
|
||||||
|
|
|
@ -50,6 +50,18 @@
|
||||||
(span
|
(span
|
||||||
("class" "notification")
|
("class" "notification")
|
||||||
(text "{{ profile.request_count }}")))
|
(text "{{ profile.request_count }}")))
|
||||||
|
(a
|
||||||
|
("href" "/services?id={{ profile.id }}")
|
||||||
|
("class" "button lowered")
|
||||||
|
(icon (text "globe"))
|
||||||
|
(span
|
||||||
|
(text "Sites")))
|
||||||
|
(a
|
||||||
|
("href" "/domains?id={{ profile.id }}")
|
||||||
|
("class" "button lowered")
|
||||||
|
(icon (text "globe"))
|
||||||
|
(span
|
||||||
|
(text "Domains")))
|
||||||
(button
|
(button
|
||||||
("class" "red lowered")
|
("class" "red lowered")
|
||||||
("onclick" "delete_account(event)")
|
("onclick" "delete_account(event)")
|
||||||
|
@ -155,6 +167,33 @@
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
globalThis.update_user_secondary_role = async (new_role) => {
|
||||||
|
if (
|
||||||
|
!(await trigger(\"atto::confirm\", [
|
||||||
|
\"Are you sure you would like to do this?\",
|
||||||
|
]))
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(`/api/v1/auth/user/{{ profile.id }}/role/2`, {
|
||||||
|
method: \"POST\",
|
||||||
|
headers: {
|
||||||
|
\"Content-Type\": \"application/json\",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
role: Number.parseInt(new_role),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((res) => {
|
||||||
|
trigger(\"atto::toast\", [
|
||||||
|
res.ok ? \"success\" : \"error\",
|
||||||
|
res.message,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
ui.refresh_container(element, [\"actions\"]);
|
ui.refresh_container(element, [\"actions\"]);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -178,6 +217,11 @@
|
||||||
\"{{ profile.permissions }}\",
|
\"{{ profile.permissions }}\",
|
||||||
\"input\",
|
\"input\",
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
[\"secondary_role\", \"Secondary permission level\"],
|
||||||
|
\"{{ profile.secondary_permissions }}\",
|
||||||
|
\"input\",
|
||||||
|
],
|
||||||
],
|
],
|
||||||
null,
|
null,
|
||||||
{
|
{
|
||||||
|
@ -194,6 +238,9 @@
|
||||||
role: (new_role) => {
|
role: (new_role) => {
|
||||||
return update_user_role(new_role);
|
return update_user_role(new_role);
|
||||||
},
|
},
|
||||||
|
secondary_role: (new_role) => {
|
||||||
|
return update_user_secondary_role(new_role);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}, 100);
|
}, 100);
|
||||||
|
@ -244,6 +291,24 @@
|
||||||
(div
|
(div
|
||||||
("class" "card lowered flex flex-col gap-2")
|
("class" "card lowered flex flex-col gap-2")
|
||||||
("id" "permission_builder")))
|
("id" "permission_builder")))
|
||||||
|
(div
|
||||||
|
("class" "card-nest w-full")
|
||||||
|
(div
|
||||||
|
("class" "card small flex items-center justify-between gap-2")
|
||||||
|
(div
|
||||||
|
("class" "flex items-center gap-2")
|
||||||
|
(text "{{ icon \"blocks\" }}")
|
||||||
|
(span
|
||||||
|
(text "{{ text \"mod_panel:label.permissions_level_builder\" }}")))
|
||||||
|
(button
|
||||||
|
("class" "small lowered")
|
||||||
|
("onclick" "update_user_secondary_role(Number.parseInt(document.getElementById('role').value))")
|
||||||
|
(text "{{ icon \"check\" }}")
|
||||||
|
(span
|
||||||
|
(text "{{ text \"general:action.save\" }}"))))
|
||||||
|
(div
|
||||||
|
("class" "card lowered flex flex-col gap-2")
|
||||||
|
("id" "secondary_permission_builder")))
|
||||||
(script
|
(script
|
||||||
(text "setTimeout(async () => {
|
(text "setTimeout(async () => {
|
||||||
const get_permissions_html = await trigger(
|
const get_permissions_html = await trigger(
|
||||||
|
@ -291,6 +356,30 @@
|
||||||
Number.parseInt(\"{{ profile.permissions }}\"),
|
Number.parseInt(\"{{ profile.permissions }}\"),
|
||||||
\"permission_builder\",
|
\"permission_builder\",
|
||||||
);
|
);
|
||||||
|
}, 250);
|
||||||
|
|
||||||
|
setTimeout(async () => {
|
||||||
|
const get_permissions_html = await trigger(
|
||||||
|
\"ui::generate_permissions_ui\",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
// https://trisuaso.github.io/tetratto/tetratto/model/permissions/struct.SecondaryPermission.html
|
||||||
|
DEFAULT: 1 << 0,
|
||||||
|
ADMINISTRATOR: 1 << 1,
|
||||||
|
MANAGE_DOMAINS: 1 << 2,
|
||||||
|
MANAGE_SECONDARY: 1 << 3,
|
||||||
|
},
|
||||||
|
\"secondary_role\",
|
||||||
|
\"add_permission_to_secondary_role\",
|
||||||
|
\"remove_permission_to_secondary_role\",
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
document.getElementById(\"secondary_permission_builder\").innerHTML =
|
||||||
|
get_permissions_html(
|
||||||
|
Number.parseInt(\"{{ profile.secondary_permissions }}\"),
|
||||||
|
\"secondary_permission_builder\",
|
||||||
|
);
|
||||||
}, 250);")))
|
}, 250);")))
|
||||||
|
|
||||||
(text "{% endblock %}")
|
(text "{% endblock %}")
|
||||||
|
|
|
@ -1069,7 +1069,13 @@ ${option.input_element_type === "textarea" ? `${option.value}</textarea>` : ""}
|
||||||
// permissions ui
|
// permissions ui
|
||||||
self.define(
|
self.define(
|
||||||
"generate_permissions_ui",
|
"generate_permissions_ui",
|
||||||
(_, permissions, field_id = "role") => {
|
(
|
||||||
|
_,
|
||||||
|
permissions,
|
||||||
|
field_id = "role",
|
||||||
|
add_name = "add_permission_to_role",
|
||||||
|
remove_name = "remove_permission_from_role",
|
||||||
|
) => {
|
||||||
function all_matching_permissions(role) {
|
function all_matching_permissions(role) {
|
||||||
const matching = [];
|
const matching = [];
|
||||||
const not_matching = [];
|
const not_matching = [];
|
||||||
|
@ -1099,7 +1105,7 @@ ${option.input_element_type === "textarea" ? `${option.value}</textarea>` : ""}
|
||||||
function get_permissions_html(role, id) {
|
function get_permissions_html(role, id) {
|
||||||
const [matching, not_matching] = all_matching_permissions(role);
|
const [matching, not_matching] = all_matching_permissions(role);
|
||||||
|
|
||||||
globalThis.remove_permission_from_role = (permission) => {
|
globalThis[remove_name] = (permission) => {
|
||||||
matching.splice(matching.indexOf(permission), 1);
|
matching.splice(matching.indexOf(permission), 1);
|
||||||
not_matching.push(permission);
|
not_matching.push(permission);
|
||||||
|
|
||||||
|
@ -1107,7 +1113,7 @@ ${option.input_element_type === "textarea" ? `${option.value}</textarea>` : ""}
|
||||||
get_permissions_html(rebuild_role(matching), id);
|
get_permissions_html(rebuild_role(matching), id);
|
||||||
};
|
};
|
||||||
|
|
||||||
globalThis.add_permission_to_role = (permission) => {
|
globalThis[add_name] = (permission) => {
|
||||||
not_matching.splice(not_matching.indexOf(permission), 1);
|
not_matching.splice(not_matching.indexOf(permission), 1);
|
||||||
matching.push(permission);
|
matching.push(permission);
|
||||||
|
|
||||||
|
@ -1120,14 +1126,14 @@ ${option.input_element_type === "textarea" ? `${option.value}</textarea>` : ""}
|
||||||
for (const match of matching) {
|
for (const match of matching) {
|
||||||
permissions_html += `<div class="card w-full secondary flex justify-between gap-2">
|
permissions_html += `<div class="card w-full secondary flex justify-between gap-2">
|
||||||
<span>${match} <code>${permissions[match]}</code></span>
|
<span>${match} <code>${permissions[match]}</code></span>
|
||||||
<button class="red lowered" onclick="remove_permission_from_role('${match}')">Remove</button>
|
<button class="red lowered" onclick="${remove_name}('${match}')">Remove</button>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const match of not_matching) {
|
for (const match of not_matching) {
|
||||||
permissions_html += `<div class="card w-full secondary flex justify-between gap-2">
|
permissions_html += `<div class="card w-full secondary flex justify-between gap-2">
|
||||||
<span>${match} <code>${permissions[match]}</code></span>
|
<span>${match} <code>${permissions[match]}</code></span>
|
||||||
<button class="green lowered" onclick="add_permission_to_role('${match}')">Add</button>
|
<button class="green lowered" onclick="${add_name}('${match}')">Add</button>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ function fix_atto_links() {
|
||||||
`atto://${path.replace("atto://", "").split("/")[0]}${x}`;
|
`atto://${path.replace("atto://", "").split("/")[0]}${x}`;
|
||||||
} else {
|
} else {
|
||||||
y[property] =
|
y[property] =
|
||||||
`/api/v1/net/atto://${path.replace("atto://", "").split("/")[0]}${x}`;
|
`/api/v1/net/${path.replace("atto://", "").split("/")[0]}${x}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,9 +110,14 @@ pub async fn delete_request(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_file_request(
|
pub async fn get_file_request(
|
||||||
Path(addr): Path<String>,
|
Path(mut addr): Path<String>,
|
||||||
Extension(data): Extension<State>,
|
Extension(data): Extension<State>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
|
if !addr.starts_with("atto://") {
|
||||||
|
addr = format!("atto://{addr}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let (subdomain, domain, tld, path) = Domain::from_str(&addr);
|
let (subdomain, domain, tld, path) = Domain::from_str(&addr);
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,22 @@
|
||||||
use super::render_error;
|
use super::render_error;
|
||||||
use crate::{assets::initial_context, get_lang, get_user_from_token, State};
|
use crate::{
|
||||||
|
assets::initial_context, get_lang, get_user_from_token,
|
||||||
|
routes::pages::misc::NotificationsProps, State,
|
||||||
|
};
|
||||||
use axum::{
|
use axum::{
|
||||||
response::{Html, IntoResponse},
|
response::{Html, IntoResponse},
|
||||||
extract::{Query, Path},
|
extract::{Query, Path},
|
||||||
Extension,
|
Extension,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use axum_extra::extract::CookieJar;
|
||||||
use tetratto_core::model::{littleweb::TLDS_VEC, Error};
|
use tetratto_core::model::{littleweb::TLDS_VEC, permissions::SecondaryPermission, Error};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
/// `/services`
|
/// `/services`
|
||||||
pub async fn services_request(
|
pub async fn services_request(
|
||||||
jar: CookieJar,
|
jar: CookieJar,
|
||||||
Extension(data): Extension<State>,
|
Extension(data): Extension<State>,
|
||||||
|
Query(props): Query<NotificationsProps>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = data.read().await;
|
let data = data.read().await;
|
||||||
let user = match get_user_from_token!(jar, data.0) {
|
let user = match get_user_from_token!(jar, data.0) {
|
||||||
|
@ -24,7 +28,26 @@ pub async fn services_request(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let list = match data.0.get_services_by_user(user.id).await {
|
let profile = if props.id != 0 {
|
||||||
|
match data.0.get_user_by_id(props.id).await {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => return Err(Html(render_error(e, &jar, &data, &None).await)),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
user.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
if profile.id != user.id
|
||||||
|
&& !user
|
||||||
|
.secondary_permissions
|
||||||
|
.check(SecondaryPermission::MANAGE_SERVICES)
|
||||||
|
{
|
||||||
|
return Err(Html(
|
||||||
|
render_error(Error::NotAllowed, &jar, &data, &None).await,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let list = match data.0.get_services_by_user(profile.id).await {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
|
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
|
||||||
};
|
};
|
||||||
|
@ -32,6 +55,7 @@ pub async fn services_request(
|
||||||
let lang = get_lang!(jar, data.0);
|
let lang = get_lang!(jar, data.0);
|
||||||
let mut context = initial_context(&data.0.0.0, lang, &Some(user)).await;
|
let mut context = initial_context(&data.0.0.0, lang, &Some(user)).await;
|
||||||
context.insert("list", &list);
|
context.insert("list", &list);
|
||||||
|
context.insert("profile", &profile);
|
||||||
|
|
||||||
// return
|
// return
|
||||||
Ok(Html(
|
Ok(Html(
|
||||||
|
@ -43,6 +67,7 @@ pub async fn services_request(
|
||||||
pub async fn domains_request(
|
pub async fn domains_request(
|
||||||
jar: CookieJar,
|
jar: CookieJar,
|
||||||
Extension(data): Extension<State>,
|
Extension(data): Extension<State>,
|
||||||
|
Query(props): Query<NotificationsProps>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = data.read().await;
|
let data = data.read().await;
|
||||||
let user = match get_user_from_token!(jar, data.0) {
|
let user = match get_user_from_token!(jar, data.0) {
|
||||||
|
@ -54,6 +79,25 @@ pub async fn domains_request(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let profile = if props.id != 0 {
|
||||||
|
match data.0.get_user_by_id(props.id).await {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => return Err(Html(render_error(e, &jar, &data, &None).await)),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
user.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
if profile.id != user.id
|
||||||
|
&& !user
|
||||||
|
.secondary_permissions
|
||||||
|
.check(SecondaryPermission::MANAGE_DOMAINS)
|
||||||
|
{
|
||||||
|
return Err(Html(
|
||||||
|
render_error(Error::NotAllowed, &jar, &data, &None).await,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
let list = match data.0.get_domains_by_user(user.id).await {
|
let list = match data.0.get_domains_by_user(user.id).await {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
|
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
|
||||||
|
@ -64,6 +108,7 @@ pub async fn domains_request(
|
||||||
|
|
||||||
context.insert("list", &list);
|
context.insert("list", &list);
|
||||||
context.insert("tlds", &*TLDS_VEC);
|
context.insert("tlds", &*TLDS_VEC);
|
||||||
|
context.insert("profile", &profile);
|
||||||
|
|
||||||
// return
|
// return
|
||||||
Ok(Html(
|
Ok(Html(
|
||||||
|
@ -99,7 +144,11 @@ pub async fn service_request(
|
||||||
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
|
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
|
||||||
};
|
};
|
||||||
|
|
||||||
if user.id != service.owner {
|
if user.id != service.owner
|
||||||
|
&& !user
|
||||||
|
.secondary_permissions
|
||||||
|
.check(SecondaryPermission::MANAGE_SERVICES)
|
||||||
|
{
|
||||||
return Err(Html(
|
return Err(Html(
|
||||||
render_error(Error::NotAllowed, &jar, &data, &None).await,
|
render_error(Error::NotAllowed, &jar, &data, &None).await,
|
||||||
));
|
));
|
||||||
|
@ -153,7 +202,11 @@ pub async fn domain_request(
|
||||||
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
|
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
|
||||||
};
|
};
|
||||||
|
|
||||||
if user.id != domain.owner {
|
if user.id != domain.owner
|
||||||
|
&& !user
|
||||||
|
.secondary_permissions
|
||||||
|
.check(SecondaryPermission::MANAGE_DOMAINS)
|
||||||
|
{
|
||||||
return Err(Html(
|
return Err(Html(
|
||||||
render_error(Error::NotAllowed, &jar, &data, &None).await,
|
render_error(Error::NotAllowed, &jar, &data, &None).await,
|
||||||
));
|
));
|
||||||
|
@ -204,7 +257,7 @@ pub async fn browser_request(
|
||||||
|
|
||||||
let lang = get_lang!(jar, data.0);
|
let lang = get_lang!(jar, data.0);
|
||||||
let mut context = initial_context(&data.0.0.0, lang, &user).await;
|
let mut context = initial_context(&data.0.0.0, lang, &user).await;
|
||||||
context.insert("path", &uri);
|
context.insert("path", &uri.replace("atto://", ""));
|
||||||
|
|
||||||
// return
|
// return
|
||||||
Html(data.1.render("littleweb/browser.html", &context).unwrap())
|
Html(data.1.render("littleweb/browser.html", &context).unwrap())
|
||||||
|
|
|
@ -194,7 +194,7 @@ macro_rules! define_domain_tlds {
|
||||||
define_domain_tlds!(
|
define_domain_tlds!(
|
||||||
Bunny, Tet, Cool, Qwerty, Boy, Girl, Them, Quack, Bark, Meow, Silly, Wow, Neko, Yay, Lol, Love,
|
Bunny, Tet, Cool, Qwerty, Boy, Girl, Them, Quack, Bark, Meow, Silly, Wow, Neko, Yay, Lol, Love,
|
||||||
Fun, Gay, City, Woah, Clown, Apple, Yaoi, Yuri, World, Wav, Zero, Evil, Dragon, Yum, Site, All,
|
Fun, Gay, City, Woah, Clown, Apple, Yaoi, Yuri, World, Wav, Zero, Evil, Dragon, Yum, Site, All,
|
||||||
Me, Bug, Slop, Retro, Eye, Neo, Spring
|
Me, Bug, Slop, Retro, Eye, Neo, Spring, Nurse, Pony
|
||||||
);
|
);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue