Merge commit '9919ae93c21395043f7f0eac6e54668a70cad146'

This commit is contained in:
Marie Birner
2025-08-02 21:35:29 +02:00
6 changed files with 93 additions and 99 deletions

2
README.md Normal file
View File

@@ -0,0 +1,2 @@
# TODOs
- [ ] limit names to 25(?) chars

View File

@@ -30,28 +30,34 @@ async fn index(State(backend): State<Arc<Backend>>, cookies: CookieJar) -> Respo
form {
fieldset role="group" {
input name="name" placeholder=(format!("Rename {}", client.get_display_name())) aria-label="Name";
input
name="name"
placeholder=(format!("Rename {}", client.get_display_name()))
aria-label="Name";
input type="submit" value="Save";
}
}
p { "You have found " (sightings.len()) "/" (amount_total_cameras) " cameras." }
p {
"You have found "
(sightings.len())
"/"
(amount_total_cameras)
" cameras."
progress value=(sightings.len()) max=(amount_total_cameras);
}
p {
h2 { "Highscore" }
ul.iterated {
@for rank in highscore {
li.card {
span {
span.font-headline.rank.text-muted {
(rank.rank)"."
}
@if rank.uuid == client.uuid { (PreEscaped("<mark>")) }
(rank.name)
@if rank.uuid == client.uuid { (PreEscaped("</mark>")) }
}
span.font-headline.cam {
(rank.amount)(PreEscaped("&nbsp;"))"📸"
span.font-headline.rank.text-muted { (rank.rank) "." }
@if rank.client == client { (PreEscaped("<mark>")) }
(rank.client.get_display_name())
@if rank.client == client { (PreEscaped("</mark>")) }
}
span.font-headline.cam { (rank.amount) (PreEscaped("&nbsp;")) "📸" }
}
}
}

View File

@@ -3,9 +3,7 @@ use maud::{html, Markup};
pub(super) async fn index() -> Markup {
new(html! {
h1 {
"Digital Shadows"
}
h1 { "Digital Shadows" }
hgroup {
h2 {
"Who owns your "
@@ -22,9 +20,7 @@ pub(super) async fn index() -> Markup {
blockquote {
"Digital Shadows confronts visitors with their digital self copied, measured, analyzed. An experiment on data power, visibility, and control in the digital age."
footer {
cite {
"— René Mayrhofer"
}
cite { "— René Mayrhofer" }
}
}
p {

View File

@@ -9,6 +9,12 @@ pub struct Client {
pub name: Option<String>,
}
impl PartialEq for Client {
fn eq(&self, other: &Self) -> bool {
self.uuid == other.uuid
}
}
impl Client {
pub(crate) fn get_display_name(&self) -> String {
match &self.name {

View File

@@ -1,40 +1,16 @@
use crate::{random_names::get_name_by_uuid, Backend};
struct RankDb {
pub(crate) rank: i64,
pub(crate) name: Option<String>,
pub(crate) uuid: String,
pub(crate) amount: i64,
}
use crate::{model::client::Client, Backend};
pub(crate) struct Rank {
pub(crate) rank: i64,
pub(crate) name: String,
pub(crate) uuid: String,
pub(crate) client: Client,
pub(crate) amount: i64,
}
impl From<RankDb> for Rank {
fn from(value: RankDb) -> Self {
let name = match value.name {
Some(name) => name,
None => get_name_by_uuid(&value.uuid).to_string(),
};
Self {
rank: value.rank,
name,
uuid: value.uuid,
amount: value.amount,
}
}
}
impl Backend {
pub(crate) async fn highscore(&self) -> Vec<Rank> {
match self {
Backend::Sqlite(db) => sqlx::query_as!(
RankDb,
Backend::Sqlite(db) => {
let rows = sqlx::query!(
"SELECT
RANK() OVER (ORDER BY COUNT(s.client_uuid) DESC) as rank,
c.name,
@@ -47,10 +23,20 @@ impl Backend {
)
.fetch_all(db)
.await
.unwrap_or_default()
.into_iter()
.unwrap_or_default();
rows.into_iter()
.map(|row| Rank {
rank: row.rank,
client: Client {
uuid: row.uuid,
name: row.name,
},
amount: row.amount,
})
.map(|r| r.into())
.collect(),
.collect()
}
}
}
}

View File

@@ -10,40 +10,38 @@ pub fn new(content: Markup) -> Markup {
meta name="viewport" content="width=device-width, initial-scale=1.0";
link rel="stylesheet" href="/static/pico.min.css";
link rel="stylesheet" href="/static/style.css";
title {
"Digital Shadows"
}
title { "Digital Shadows" }
}
body {
header.container {
nav {
ul {
li { a href="/" { strong { "Digital Shadows" } } }
li {
a href="/" {
strong { "Digital Shadows" }
}
}
}
ul {
li {
a href="/"{
span role="img" aria-label="home" {
"🏠"
}
a href="/" {
span role="img" aria-label="home" { "🏠" }
}
}
li {
a href="/game" {
span role="img" aria-label="camera" {
"📸"
span role="img" aria-label="camera" { "📸" }
}
}
li {
span id="theme_switcher" {}
}
li { span id="theme_switcher" {} }
}
}
}
main.container {
section {
(content)
}
section { (content) }
}
footer.container {