add: postgres support

chore: restructure
This commit is contained in:
trisua 2025-03-22 22:17:47 -04:00
parent cda879f6df
commit b6fe2fba37
58 changed files with 3403 additions and 603 deletions

View file

@ -0,0 +1,9 @@
{% extends "root.html" %} {% block body %}
<main class="flex flex-col gap-2" style="max-width: 25rem">
<h2 class="w-full text-center">{% block title %}{% endblock %}</h2>
<div class="card w-full flex flex-col gap-4 justify-center align-center">
{% block content %}{% endblock %}
</div>
{% block footer %}{% endblock %}
</main>
{% endblock %}

View file

@ -0,0 +1,33 @@
{% extends "auth/base.html" %} {% block head %}
<title>🐐 Login</title>
{% endblock %} {% block title %}Login{% endblock %} {% block content %}
<form class="w-full flex flex-col gap-4">
<div class="flex flex-col gap-1">
<label for="username"><b>Username</b></label>
<input
type="text"
placeholder="username"
required
name="username"
id="username"
/>
</div>
<div class="flex flex-col gap-1">
<label for="username"><b>Password</b></label>
<input
type="password"
placeholder="password"
required
name="password"
id="password"
/>
</div>
<button>Submit</button>
</form>
{% endblock %} {% block footer %}
<span class="small w-full text-center"
>Or, <a href="/auth/register">register</a></span
>
{% endblock %}

View file

@ -0,0 +1,62 @@
{% extends "auth/base.html" %} {% block head %}
<title>🐐 Register</title>
{% endblock %} {% block title %}Register{% endblock %} {% block content %}
<form class="w-full flex flex-col gap-4" onsubmit="register(event)">
<div class="flex flex-col gap-1">
<label for="username"><b>Username</b></label>
<input
type="text"
placeholder="username"
required
name="username"
id="username"
/>
</div>
<div class="flex flex-col gap-1">
<label for="username"><b>Password</b></label>
<input
type="password"
placeholder="password"
required
name="password"
id="password"
/>
</div>
<button>Submit</button>
</form>
<script>
function register(e) {
e.preventDefault();
fetch("/api/v1/auth/register", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
username: e.target.username.value,
password: e.target.password.value,
}),
})
.then((res) => res.json())
.then((res) => {
trigger("atto::toast", [
res.ok ? "sucesss" : "error",
res.message,
]);
if (res.ok) {
setTimeout(() => {
window.location.href = "/";
}, 150);
}
});
}
</script>
{% endblock %} {% block footer %}
<span class="small w-full text-center"
>Or, <a href="/auth/login">login</a></span
>
{% endblock %}

View file

@ -0,0 +1,45 @@
{% macro nav(selected="", show_lhs=true) -%}
<nav>
<div class="content_container">
<div class="flex nav_side">
<a href="/" class="button desktop title">
<b>{{ config.name }}</b>
</a>
{% if show_lhs %}
<a
href="/"
class="button {% if selected == 'home' %}active{% endif %}"
>Home</a
>
{% endif %}
</div>
<div class="flex nav_side">
{% if user %}
<div class="dropdown">
<button
class="flex-row title"
onclick="trigger('atto::hooks::dropdown', [event])"
exclude="dropdown"
style="gap: 0.25rem !important"
>
{{ macros::avatar(username=user.username, size="24px") }}
</button>
</div>
{% else %}
<a href="/auth/login" class="button">Login</a>
<a href="/auth/register" class="button">Register</a>
{% endif %}
</div>
</div>
</nav>
{%- endmacro %} {% macro avatar(username, size="24px") -%}
<img
title="{{ username }}'s avatar"
src="/api/v1/auth/profile/{{ username }}/avatar"
alt="@{{ username }}"
class="avatar shadow"
style="--size: {{ size }}"
/>
{%- endmacro %}

View file

@ -0,0 +1,23 @@
{% import "macros.html" as macros %} {% extends "root.html" %} {% block body %}
{{ macros::nav(selected="home") }}
<main class="flex flex-col gap-2">
<h1>Hello, world!</h1>
<div class="pillmenu">
<a class="active" href="#">A</a>
<a href="#">B</a>
<a href="#">C</a>
</div>
<div class="card w-full flex flex-col gap-2">
<div class="flex gap-2 flex-wrap">
<button>Hello, world!</button>
<button class="secondary">Hello, world!</button>
<button class="camo">Hello, world!</button>
</div>
<input type="text" placeholder="abcd" />
</div>
</main>
{% endblock %}

View file

@ -0,0 +1,73 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link rel="stylesheet" href="/css/style.css" />
<script src="/js/loader.js"></script>
<script defer async src="/js/atto.js"></script>
<script>
globalThis.ns_verbose = false;
globalThis.ns_config = {
root: "/js/",
verbose: globalThis.ns_verbose,
};
globalThis._app_base = {
name: "tetratto",
ns_store: {},
classes: {},
};
globalThis.no_policy = false;
</script>
<meta name="theme-color" content="{{ config.color }}" />
<meta name="description" content="{{ config.description }}" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="{{ config.name }}" />
<meta name="turbo-prefetch" content="false" />
<meta name="turbo-refresh-method" content="morph" />
<meta name="turbo-refresh-scroll" content="preserve" />
<script
src="https://unpkg.com/@hotwired/turbo@8.0.5/dist/turbo.es2017-esm.js"
type="module"
async
defer
></script>
{% block head %}{% endblock %}
</head>
<body>
<div id="toast_zone"></div>
{% block body %}{% endblock %}
<script data-turbo-permanent="true" id="init-script">
document.documentElement.addEventListener("turbo:load", () => {
const atto = ns("atto");
atto.disconnect_observers();
atto.clean_date_codes();
atto.link_filter();
atto["hooks::scroll"](document.body, document.documentElement);
atto["hooks::dropdown.init"](window);
atto["hooks::character_counter.init"]();
atto["hooks::long_text.init"]();
atto["hooks::alt"]();
// atto["hooks::ips"]();
atto["hooks::check_reactions"]();
atto["hooks::tabs"]();
atto["hooks::partial_embeds"]();
});
</script>
</body>
</html>