Compare commits

..

2 Commits

Author SHA1 Message Date
bdf7d44ee5 Merge branch 'main' of ssh://git.hofer.link:2222/philipp/aef-website 2025-08-03 10:23:50 +02:00
d0b4247ed1 add language 2025-08-03 10:23:42 +02:00
3 changed files with 139 additions and 121 deletions

View File

@@ -1,6 +1,7 @@
use crate::{page::new, Backend};
use crate::{language::language, page::new, Backend};
use axum::{
extract::{Path, State},
http::HeaderMap,
response::{IntoResponse, Redirect, Response},
routing::get,
Router,
@@ -10,77 +11,85 @@ use maud::{html, Markup, PreEscaped};
use std::sync::Arc;
use uuid::Uuid;
async fn index(State(backend): State<Arc<Backend>>, cookies: CookieJar) -> Response {
let (cookies, client) = backend.client(cookies).await;
async fn index(
State(backend): State<Arc<Backend>>,
cookies: CookieJar,
headers: HeaderMap,
) -> Response {
let (cookies, req) = backend.client_full(cookies, &headers).await;
let client = req.client;
let sightings = backend.sightings_for_client(&client).await;
let amount_total_cameras = backend.amount_total_cameras().await;
let highscore = backend.highscore().await;
let markup = new(html! {
hgroup {
h1 { "Who finds the most cameras?" }
}
p {
mark { "TODO: Explanation of AEF / digital shadows / search game" }
}
p {
mark { "TODO: Show optional SUCC message" }
}
div {
(client.get_display_name())
", do you want to be named something different? No worries, change here 👇"
}
form {
fieldset role="group" {
input
name="name"
placeholder="✨ Your new name starts here ✨"
aria-label="Name";
input type="submit" value="Save";
let markup = new(
html! {
hgroup {
h1 { "Who finds the most cameras?" }
}
p {
mark { "TODO: Explanation of AEF / digital shadows / search game" }
}
p {
mark { "TODO: Show optional SUCC message" }
}
}
p {
"You have found "
(sightings.len())
"/"
(amount_total_cameras)
" cameras:"
progress value=(sightings.len()) max=(amount_total_cameras);
}
p {
ul.iterated {
@for (idx, sighting) in sightings.iter().enumerate() {
li.card {
span {
span.font-headline.rank.text-muted { (idx+1) }
(sighting.camera.name)
div {
(client.get_display_name())
", do you want to be named something different? No worries, change here 👇"
}
form {
fieldset role="group" {
input
name="name"
placeholder="✨ Your new name starts here ✨"
aria-label="Name";
input type="submit" value="Save";
}
}
p {
"You have found "
(sightings.len())
"/"
(amount_total_cameras)
" cameras:"
progress value=(sightings.len()) max=(amount_total_cameras);
}
p {
ul.iterated {
@for (idx, sighting) in sightings.iter().enumerate() {
li.card {
span {
span.font-headline.rank.text-muted { (idx+1) }
(sighting.camera.name)
}
}
}
}
}
p {
h2 { "Highscore" }
ul.iterated {
@for rank in highscore {
li.card {
span {
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.font-lg { (rank.amount) (PreEscaped("&nbsp;")) "📸" }
}
}
}
}
}
p {
h2 { "Highscore" }
ul.iterated {
@for rank in highscore {
li.card {
span {
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.font-lg { (rank.amount) (PreEscaped("&nbsp;")) "📸" }
}
}
}
}
});
},
req.lang,
);
(cookies, markup).into_response()
}
@@ -88,16 +97,17 @@ async fn index(State(backend): State<Arc<Backend>>, cookies: CookieJar) -> Respo
async fn game(
State(backend): State<Arc<Backend>>,
cookies: CookieJar,
headers: HeaderMap,
Path(uuid): Path<String>,
) -> Result<Redirect, Response> {
let (cookies, client) = backend.client(cookies).await;
let Ok(uuid) = Uuid::parse_str(&uuid) else {
return Err(not_found().await.into_response());
return Err(not_found(cookies, headers).await.into_response());
};
let Some(camera) = backend.get_camera(&uuid).await else {
return Err(not_found().await.into_response());
return Err(not_found(cookies, headers).await.into_response());
};
let succ = backend.client_found_camera(&client, &camera).await;
@@ -106,10 +116,14 @@ async fn game(
Ok(Redirect::to("/game"))
}
async fn not_found() -> Markup {
new(html! {
h1 { "uups" }
})
async fn not_found(cookies: CookieJar, headers: HeaderMap) -> Markup {
let lang = language(&cookies, &headers);
new(
html! {
h1 { "uups" }
},
lang,
)
}
pub(super) fn routes() -> Router<Arc<Backend>> {

View File

@@ -8,69 +8,72 @@ pub(super) async fn index(cookies: CookieJar, headers: HeaderMap) -> Markup {
rust_i18n::set_locale(lang.to_locale());
new(html! {
h1 { (t!("digital_shadows")) }
hgroup {
h2 {
"Who owns your "
mark { "data" }
"?"
new(
html! {
h1 { (t!("digital_shadows")) }
hgroup {
h2 {
"Who owns your "
mark { "data" }
"?"
}
p {
"What happens when your digital shadow takes shape: tangible, interrogative, observant?"
}
}
p {
"What happens when your digital shadow takes shape: tangible, interrogative, observant?"
"Artists: René Mayrhofer (AT), Philipp Hofer (AT), Laura Poulbot (FR), Airan Berg (AT), Andrea Hummer (AT), Ilona Roth (DE/AT), Linda Huber (AT), Gisela Klammsteiner (AT), Sara Koniarek (AT), Simon Sharkey (GB), Valerio Iurato (IT), Doris Roth (DE), Alina Lugovskaya (UA/RU), Selina Nowak (AT), JeanClaude Grieco (AR/AT), Florian Böttcher (AT), Ethem Saygieder-Fischer (AT)"
span.easteregg {
", Marie Birner (Couch)"
}
}
}
p {
"Artists: René Mayrhofer (AT), Philipp Hofer (AT), Laura Poulbot (FR), Airan Berg (AT), Andrea Hummer (AT), Ilona Roth (DE/AT), Linda Huber (AT), Gisela Klammsteiner (AT), Sara Koniarek (AT), Simon Sharkey (GB), Valerio Iurato (IT), Doris Roth (DE), Alina Lugovskaya (UA/RU), Selina Nowak (AT), JeanClaude Grieco (AR/AT), Florian Böttcher (AT), Ethem Saygieder-Fischer (AT)"
span.easteregg {
", Marie Birner (Couch)"
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 { "— Digital Shadow Team" }
}
}
}
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 { "— Digital Shadow Team" }
}
}
p {
"Digital Shadows invites the participants to experience questions of digital and physical identity, data security, and control. In immersive zones woven with choreographic elements, visitors encounter themselves mirrored, copied, measured and simultaneously lose themselves in a system that knows more about them than they intend to reveal. Between play and analysis, concealment and transparency, a reflection emerges on identity in the age of facial recognition, deepfakes, and algorithmic profiling. How does one fool a camera? How visible do I want to be? Who owns what I leave behind, and who profits from it? This experiment is a collaborative endeavor between science and art, making power, visibility, and self-determination in digital space tangible. Through an exploration of digital materiality and algorithmic intelligence, a sometimes absurd, always immediate reflection unfolds on our role in data-driven worlds until we face our digital dilemma, and the choice is still ours to make."
}
h2 {
"What to do with this information?"
}
div.grid.gap-lg {
article {
header {
"Visit our booth"
p {
"Digital Shadows invites the participants to experience questions of digital and physical identity, data security, and control. In immersive zones woven with choreographic elements, visitors encounter themselves mirrored, copied, measured and simultaneously lose themselves in a system that knows more about them than they intend to reveal. Between play and analysis, concealment and transparency, a reflection emerges on identity in the age of facial recognition, deepfakes, and algorithmic profiling. How does one fool a camera? How visible do I want to be? Who owns what I leave behind, and who profits from it? This experiment is a collaborative endeavor between science and art, making power, visibility, and self-determination in digital space tangible. Through an exploration of digital materiality and algorithmic intelligence, a sometimes absurd, always immediate reflection unfolds on our role in data-driven worlds until we face our digital dilemma, and the choice is still ours to make."
}
"We will be delighted to see you at our booth in the Post City Linz, where our team will show you, what happens when your Digital Shadow becomes allmighty. "
a href="https://www.jku.at/ars-electronica-2025-panic-yes-no/digital-shadows/" target="_blank" title="Go to JKU Information Page" {
"Find out more"
h2 {
"What to do with this information?"
}
footer {
"Where: Postcity Linz"
}
}
article {
header {
"Play our game"
}
div.grid.gap-lg {
article {
header {
"Visit our booth"
}
"Ever wandered through Linz with the aim to find (hidden) cameras? Well, if you are that kind of person than our 'Discover cameras' game will be ideal for you! "
"We will be delighted to see you at our booth in the Post City Linz, where our team will show you, what happens when your Digital Shadow becomes allmighty. "
a href="/game" title="Go to Game Page" {
"Find out more"
}
a href="https://www.jku.at/ars-electronica-2025-panic-yes-no/digital-shadows/" target="_blank" title="Go to JKU Information Page" {
"Find out more"
}
footer {
"Where: all over Linz"
footer {
"Where: Postcity Linz"
}
}
article {
header {
"Play our game"
}
"Ever wandered through Linz with the aim to find (hidden) cameras? Well, if you are that kind of person than our 'Discover cameras' game will be ideal for you! "
a href="/game" title="Go to Game Page" {
"Find out more"
}
footer {
"Where: all over Linz"
}
}
}
}
}
})
},
lang,
)
}

View File

@@ -1,8 +1,9 @@
use crate::Language;
use maud::{html, Markup, DOCTYPE};
// TODO: set dynamic meta lang attribute
pub fn new(content: Markup) -> Markup {
pub fn new(content: Markup, lang: Language) -> Markup {
html! {
(DOCTYPE)
head {