working on the profile page

This commit is contained in:
Artemis 2025-01-23 18:07:37 +01:00
parent 33d952d511
commit c2621bbc0f
9 changed files with 317 additions and 215 deletions

4
Cargo.lock generated
View file

@ -237,7 +237,10 @@ checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"serde",
"wasm-bindgen",
"windows-targets 0.52.6",
]
@ -449,6 +452,7 @@ dependencies = [
name = "dolltags"
version = "0.1.0"
dependencies = [
"chrono",
"rand",
"regex",
"rocket",

View file

@ -12,5 +12,6 @@ sqlx = { version = "0.7", default-features = false, features = [
"macros",
"chrono",
] }
chrono = { version = "0.4", features = ["serde"] }
regex = "1.11"
rand = "0.8"

View file

@ -1,172 +1,234 @@
:root {
font-family: sans-serif, sans-serif;
/** Dark theme primary colors */
--clr-primary-a0: #813d9c;
--clr-primary-a10: #9052a7;
--clr-primary-a20: #9e68b2;
--clr-primary-a30: #ac7cbd;
--clr-primary-a40: #ba92c8;
--clr-primary-a50: #c8a7d3;
font-family: sans-serif, sans-serif;
/** Dark theme primary colors */
--clr-primary-a0: #813d9c;
--clr-primary-a10: #9052a7;
--clr-primary-a20: #9e68b2;
--clr-primary-a30: #ac7cbd;
--clr-primary-a40: #ba92c8;
--clr-primary-a50: #c8a7d3;
/** Dark theme surface colors */
--clr-surface-a0: #000000;
--clr-surface-a10: #1e1e1e;
--clr-surface-a20: #353535;
--clr-surface-a30: #4e4e4e;
--clr-surface-a40: #696969;
--clr-surface-a50: #858585;
/** Dark theme surface colors */
--clr-surface-a0: #000000;
--clr-surface-a10: #1e1e1e;
--clr-surface-a20: #353535;
--clr-surface-a30: #4e4e4e;
--clr-surface-a40: #696969;
--clr-surface-a50: #858585;
/** Dark theme tonal surface colors */
--clr-surface-tonal-a0: #130b15;
--clr-surface-tonal-a10: #28232a;
--clr-surface-tonal-a20: #3f3a41;
--clr-surface-tonal-a30: #585359;
--clr-surface-tonal-a40: #716d72;
--clr-surface-tonal-a50: #8c888d;
/** Dark theme tonal surface colors */
--clr-surface-tonal-a0: #130b15;
--clr-surface-tonal-a10: #28232a;
--clr-surface-tonal-a20: #3f3a41;
--clr-surface-tonal-a30: #585359;
--clr-surface-tonal-a40: #716d72;
--clr-surface-tonal-a50: #8c888d;
--clr-txt-on-dark: #fff;
--clr-txt-on-light: #000;
--clr-txt-on-dark: #fff;
--clr-txt-on-light: #000;
font-size: 1.2em;
color: var(--clr-txt-on-dark);
background-color: var(--clr-surface-tonal-a0);
font-size: 1.2em;
color: var(--clr-txt-on-dark);
background-color: var(--clr-surface-tonal-a0);
}
* {
box-sizing: border-box;
box-sizing: border-box;
}
body {
margin-bottom: 2em;
margin-bottom: 2em;
}
h1>a {
text-decoration: none;
color: var(--clr-txt-on-dark);
text-decoration: none;
color: var(--clr-txt-on-dark);
}
input,
select,
button,
a.btn {
border: 2pt solid var(--clr-surface-tonal-a50);
border-radius: 4pt;
padding: 4pt 8pt;
color: var(--clr-txt-on-dark);
background-color: var(--clr-surface-tonal-a10);
text-decoration: none;
.btn {
border: 2pt solid var(--clr-surface-tonal-a50);
border-radius: 4pt;
padding: 4pt 8pt;
background-color: var(--clr-surface-tonal-a10);
}
input,
select,
button,
.btn,
.btn a {
color: var(--clr-txt-on-dark);
text-decoration: none;
}
p.btn {
display: inline-block;
}
input:hover,
select:hover,
button:hover,
a.btn:hover {
border-color: var(--clr-primary-a0);
.btn:hover {
border-color: var(--clr-primary-a0);
}
header,
header.padded,
main {
padding-left: 1em;
padding-right: 1em;
padding-left: 1em;
padding-right: 1em;
}
header {
display: flex;
justify-content: space-between;
align-items: center;
display: flex;
justify-content: space-between;
align-items: center;
}
section {
margin-top: 2em;
margin-top: 2em;
}
.split {
display: flex;
flex-direction: row;
text-align: center;
align-items: center;
display: flex;
flex-direction: row;
text-align: center;
align-items: center;
}
.split>* {
flex: 1;
padding-left: 2em;
padding-right: 2em;
flex: 1;
padding-left: 2em;
padding-right: 2em;
}
.split>*:not(:first-child) {
border-left: 2pt solid var(--clr-primary-a0);
.split.bordered>*:not(:first-child) {
border-left: 2pt solid var(--clr-primary-a0);
}
div.dual-fields {
display: flex;
display: flex;
}
.dual-fields>* {
flex: 1;
flex: 1;
}
.dual-fields>*:first-child {
margin-right: 1em;
margin-right: 1em;
}
.dual-fields>*:last-child {
margin-left: 1em;
margin-left: 1em;
}
.raised {
background-color: var(--clr-surface-tonal-a10);
padding: 1em;
border-radius: 4pt;
background-color: var(--clr-surface-tonal-a10);
padding: 1em;
border-radius: 4pt;
}
.fields>*:not(:last-child) {
margin-bottom: 1em;
margin-bottom: 1em;
}
.fields>* * {
display: block;
width: 100%
display: block;
width: 100%
}
.fields label {
font-weight: bold;
margin-bottom: 4pt;
font-weight: bold;
margin-bottom: 4pt;
}
.checkbox>* {
display: inline-block;
width: unset;
display: inline-block;
width: unset;
}
input.pronoun {
display: inline-block;
width: 10ch;
display: inline-block;
width: 10ch;
}
p.note {
margin: 2pt 0 0 0;
font-size: .9em;
margin: 2pt 0 0 0;
font-size: .9em;
}
button.submit {
margin: 2em auto;
font-size: 1.2em;
display: block;
margin: 2em auto;
font-size: 1.2em;
display: block;
}
#stray-form {
display: flex;
flex-direction: column;
align-items: center;
gap: 1em;
display: flex;
flex-direction: column;
align-items: center;
gap: 1em;
}
#stray-form>h2 {
margin-bottom: 0;
margin-bottom: 0;
}
input#ident {
font-family: monospace;
width: 6ch;
font-size: 1.6em;
box-sizing: content-box;
font-family: monospace;
width: 6ch;
font-size: 1.6em;
box-sizing: content-box;
}
#pregen_ids>button {
font-family: monospace;
font-size: 1.6em;
margin: 2pt;
font-family: monospace;
font-size: 1.6em;
margin: 2pt;
}
#stray-form>button {
font-size: 1em;
font-size: 1em;
}
.profile p,
.profile h2,
.profile h3 {
margin: 0;
}
.profile h2 {
margin-bottom: .8em;
text-align: center;
}
.profile .ident,
.handler {
text-transform: uppercase;
font-size: .8em;
color: var(--clr-primary-a50);
}
.ident>.id {
font-family: monospace, monospace;
font-size: 1.1em;
font-weight: bold;
letter-spacing: .2ch;
color: var(--clr-txt-on-dark);
}
.handler-info {
color: var(--clr-txt-on-dark);
}
.pronouns {
text-transform: uppercase;
font-size: .8em;
letter-spacing: .1ch;
}
.profile h2 {
font-size: 2em;
}

View file

@ -1,3 +1,4 @@
use rocket::serde::Serialize;
use rocket_db_pools::{Connection, Database};
use sqlx::types::chrono;
@ -7,7 +8,8 @@ pub struct DollTags(sqlx::SqlitePool);
pub type DollTagsDb = Connection<DollTags>;
// Doll Profiles stuff
#[derive(Debug, Serialise)]
#[derive(Debug, Serialize)]
#[serde(crate = "rocket::serde")]
pub struct DollProfile {
pub id: i64,
pub created_at: chrono::NaiveDateTime,

View file

@ -105,11 +105,10 @@ async fn handle_register(db: DollTagsDb, tag: Form<TagForm<'_>>) -> Template {
#[get("/profile?<ident>")]
async fn show_profile(db: DollTagsDb, ident: &str) -> Result<Template, Redirect> {
let internal_id = id_public_to_db(ident).ok_or_else(|| Redirect::to(uri!("/")))?;
let profile = doll::get(db, internal_id).await.expect("fuck");
if let None = profile {
return Err(Redirect::to(uri!("/")));
}
let profile = doll::get(db, internal_id)
.await
.expect("fuck")
.ok_or(Redirect::to(uri!("/")))?;
println!("{:?}", profile);
Ok(Template::render(

View file

@ -1,22 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<link rel=stylesheet href="/assets/site.css" />
<title>{% block title %}{% endblock title %}Doll.Tags</title>
</head>
<body>
<header>
<h1><a href="/">Doll.Tags</a></h1>
<head>
<link rel=stylesheet href="/assets/site.css" />
<title>{% block title %}{% endblock title %}Doll.Tags</title>
</head>
<nav>
<p><a class="btn" href="/register">New tag</a></p>
</nav>
</header>
<body>
<header class="padded">
<h1><a href="/">Doll.Tags</a></h1>
<main>
{% block main %}
{% endblock main %}
</main>
</body>
</html>
<nav>
<p><a class="btn" href="/register">New tag</a></p>
</nav>
</header>
<main>
{% block main %}
{% endblock main %}
</main>
</body>
</html>

View file

@ -2,10 +2,11 @@
{% block title %}Found a stray? - {% endblock title %}
{% block main %}
<form action="/profile" id="stray-form">
<h2>Found a stray?</h2>
<label for="ident">Enter the 6-digit ID you found:</label>
<input type="text" inputmode="numeric" pattern="\d{6}" id="ident" name="ident" required size="6" placeholder="000000" autofocus />
<h2>Found a stray?</h2>
<label for="ident">Enter the 6-digit ID you found:</label>
<input type="text" inputmode="numeric" pattern="\d{6}" id="ident" name="ident" required size="6"
placeholder="000000" autofocus />
<button type="submit">Search the database</button>
<button type="submit">Search the database</button>
</form>
{% endblock main %}
{% endblock main %}

View file

@ -4,114 +4,120 @@
<h2>Register a new tag</h2>
<aside>
<h3>A foreword</h3>
<p>
Registering a tag for your entity can be a pretty fun and intimate moment,
but remember that this current version of <code>Doll.Tags</code> doesn't offer any private field.<br/>
<b>Anynull guessing your tag or finding it by mistake will have access to the info you enter.</b><br/>
In that sense, we recommend you to avoid entering personally identifiable information.
</p>
<h3>A foreword</h3>
<p>
Registering a tag for your entity can be a pretty fun and intimate moment,
but remember that this current version of <code>Doll.Tags</code> doesn't offer any private field.<br />
<b>Anynull guessing your tag or finding it by mistake will have access to the info you enter.</b><br />
In that sense, we recommend you to avoid entering personally identifiable information.
</p>
</aside>
<section>
<h3>Now, to the registration!</h3>
<h3>Now, to the registration!</h3>
<form method="POST">
<section>
<h4>Firstly, the tag's ID</h4>
<p>
You may enter your own, but in case of collision it will not be usable.<br/>
To that end, here's a few free ones you may also pick from.
</p>
<form method="POST">
<section>
<h4>Firstly, the tag's ID</h4>
<p>
You may enter your own, but in case of collision it will not be usable.<br />
To that end, here's a few free ones you may also pick from.
</p>
<div class="split raised">
<div>
<p><label for="ident">Enter your ID</label></p>
<input type="text" inputmode="numeric" pattern="\d{6}" id="ident" name="ident" required size="6" placeholder="000000" />
</div>
<div>
<p>Or pick one of those pre-generated ones</p>
<div class="split bordered raised">
<div>
<p><label for="ident">Enter your ID</label></p>
<input type="text" inputmode="numeric" pattern="\d{6}" id="ident" name="ident" required size="6"
placeholder="000000" />
</div>
<div>
<p>Or pick one of those pre-generated ones</p>
<div id="pregen_ids">
<button type="button">720-812</button>
<button type="button">423-158</button>
<button type="button">863-633</button>
<button type="button">139-317</button>
<button type="button">848-339</button>
</div>
</div>
</div>
</section>
<div id="pregen_ids">
<button type="button">720-812</button>
<button type="button">423-158</button>
<button type="button">863-633</button>
<button type="button">139-317</button>
<button type="button">848-339</button>
</div>
</div>
</div>
</section>
<section>
<h4>Names and contact info</h4>
<section>
<h4>Names and contact info</h4>
<div class="fields raised">
<div>
<label for="name">The entity's name and pronouns (required)</label>
<div class="dual-fields">
<div>
<input type="text" name="name" id="name" required placeholder="A name or callsign" />
<p class="note">Remember: names only mean what you want them to!</p>
</div>
<div>
<input class="pronoun" type="text" name="pronoun_subject" required maxlength="255" placeholder="they" /> /
<input class="pronoun" type="text" name="pronoun_object" required maxlength="255" placeholder="them" /> /
<input class="pronoun" type="text" name="pronoun_possessive" required maxlength="255" placeholder="theirs" />
</div>
</div>
</div>
<div>
<label for="handler_name">The handler's name (required) and contact</label>
<div class="dual-fields">
<div>
<input type="text" name="handler_name" id="handler_name" required placeholder="Another name or callsign" />
</div>
<div>
<input type="url" name="handler_link" id="handler_link" placeholder="E-mails can be entered using mailto:" />
<p class="note">Optional, will make the handler's name clickable.</p>
</div>
</div>
</div>
</div>
</section>
<div class="fields raised">
<div>
<label for="name">The entity's name and pronouns (required)</label>
<div class="dual-fields">
<div>
<input type="text" name="name" id="name" required placeholder="A name or callsign" />
<p class="note">Remember: names only mean what you want them to!</p>
</div>
<div>
<input class="pronoun" type="text" name="pronoun_subject" required maxlength="255"
placeholder="they" /> /
<input class="pronoun" type="text" name="pronoun_object" required maxlength="255"
placeholder="them" /> /
<input class="pronoun" type="text" name="pronoun_possessive" required maxlength="255"
placeholder="theirs" />
</div>
</div>
</div>
<div>
<label for="handler_name">The handler's name (required) and contact</label>
<div class="dual-fields">
<div>
<input type="text" name="handler_name" id="handler_name" required
placeholder="Another name or callsign" />
</div>
<div>
<input type="url" name="handler_link" id="handler_link"
placeholder="E-mails can be entered using mailto:" />
<p class="note">Optional, will make the handler's name clickable.</p>
</div>
</div>
</div>
</div>
</section>
<section>
<h4>Entity description and notable features</h4>
<p>
Have fun with those inputs; empty ones will not be shown so you can selectively fill them.<br/>
You can poke me if you'd like me to add more.
</p>
<section>
<h4>Entity description and notable features</h4>
<p>
Have fun with those inputs; empty ones will not be shown so you can selectively fill them.<br />
You can poke me if you'd like me to add more.
</p>
<div class="fields raised">
<div class="dual-fields">
<div>
<label for="kind">What kind of entity?</label>
<input type="text" name="kind" id="kind" placeholder="Something" />
</div>
<div>
<label for="breed">What breed is it?</label>
<input type="text" name="breed" id="breed" placeholder="Mutt :3" />
</div>
</div>
<div class="dual-fields">
<div>
<label for="behaviour">Its general behaviour</label>
<input type="text" name="behaviour" id="behaviour" placeholder="Totally independent" />
</div>
<div>
</div>
</div>
</div>
</section>
<div class="fields raised">
<div class="dual-fields">
<div>
<label for="kind">What kind of entity?</label>
<input type="text" name="kind" id="kind" placeholder="Something" />
</div>
<div>
<label for="breed">What breed is it?</label>
<input type="text" name="breed" id="breed" placeholder="Mutt :3" />
</div>
</div>
<div class="dual-fields">
<div>
<label for="behaviour">Its general behaviour</label>
<input type="text" name="behaviour" id="behaviour" placeholder="Totally independent" />
</div>
<div>
</div>
</div>
</div>
</section>
<button class="submit" type="submit">Register this tag!</button>
</form>
<button class="submit" type="submit">Register this tag!</button>
</form>
</section>
<script>
const $ident = document.getElementById("ident");
const $pregen_ids = document.getElementById("pregen_ids");
$pregen_ids.addEventListener("click", ev => $ident.value = ev.target.innerText.split("-").join(""));
const $ident = document.getElementById("ident");
const $pregen_ids = document.getElementById("pregen_ids");
$pregen_ids.addEventListener("click", ev => $ident.value = ev.target.innerText.split("-").join(""));
</script>
{% endblock main %}
{% endblock main %}

View file

@ -1,3 +1,28 @@
{% extends "base" %}
{% block title %}{{ profile.name }} - {% endblock title %}
{% block main %}
{% endblock main %}
<section class="raised profile">
<header>
<p class="ident">Tag ID <span class="id">{{profile.id}}</span></p>
<p class="pronouns">{{profile.pronouns}}</p>
</header>
<h2>{{profile.name}}</h2>
<hr>
<div class="split">
<p>
<span class="handler">Handler</span><br />
<span class="handler-info">{{profile.handler_name}}</span>
</p>
{% if profile.handler_url %}
<div>
<p class="btn"><a href="{{profile.handler_url}}">Contact the handler</a></p>
</div>
{% endif %}
</div>
</section>
<section>
<h2>Identifying information</h2>
</section>
{% endblock main %}