demo list and page

This commit is contained in:
Robin Appelman 2023-04-08 17:07:40 +02:00
commit 667f5eae04
32 changed files with 4784 additions and 5 deletions

96
src/pages/demo.rs Normal file
View file

@ -0,0 +1,96 @@
use crate::data::demo::Demo;
use crate::data::player::{Player, Team};
use crate::pages::Page;
use itertools::{EitherOrBoth, Itertools};
use maud::{html, Markup};
use std::borrow::Cow;
pub struct DemoPage {
pub demo: Demo,
}
impl Page for DemoPage {
fn title(&self) -> Cow<'static, str> {
format!("{} - demos.tf", self.demo.name).into()
}
fn render(&self) -> Markup {
html! {
h2 { (self.demo.server) " - " (self.demo.red) " vs " (self.demo.blu) }
h3 { (self.demo.name) }
p {
"Demo uploaded by "
a href = (self.demo.uploader_steam_id().uploads_link()) { (self.demo.uploader_name()) }
" "
span title = (self.demo.date()) { (self.demo.relative_date()) }
}
.teams {
.red {
span.name { (self.demo.red) }
span.score { (self.demo.score_red) }
}
.blue {
span.name { (self.demo.blu) }
span.score { (self.demo.score_blue) }
}
.clearfix {}
}
table.players {
thead {
th.team.red {}
th.name.red { "Name" }
th.stat.red { "K" }
th.stat.red { "A" }
th.stat.red { "D" }
th.class {}
th.class {}
th.stat.blue { "D" }
th.stat.blue { "A" }
th.stat.blue { "K" }
th.name.blue { "Name" }
th.team.blue {}
}
tbody {
@for player_pair in player_pairs(&self.demo.players) {
tr {
td.team.red {}
@if let Some(player) = player_pair.as_ref().left() {
td.name.red { (player.name) }
td.stat.red { (player.kills.unwrap_or_default()) }
td.stat.red { (player.assists.unwrap_or_default()) }
td.stat.red { (player.deaths.unwrap_or_default()) }
td.class.red.(player.class) {}
} @else {
td.name.red {}
td.stat.red {}
td.stat.red {}
td.stat.red {}
td.class {}
}
@if let Some(player) = player_pair.as_ref().right() {
td.class.blue.(player.class) {}
td.stat.blue { (player.deaths.unwrap_or_default()) }
td.stat.blue { (player.assists.unwrap_or_default()) }
td.stat.blue { (player.kills.unwrap_or_default()) }
td.name.blue { (player.name) }
} @else {
td.class {}
td.stat.blue {}
td.stat.blue {}
td.stat.blue {}
td.name.blue {}
}
td.team.blue {}
}
}
}
}
}
}
}
fn player_pairs(players: &[Player]) -> impl IntoIterator<Item = EitherOrBoth<&Player, &Player>> {
let red = players.iter().filter(|player| player.team == Team::Red);
let blue = players.iter().filter(|player| player.team == Team::Blue);
red.zip_longest(blue)
}

44
src/pages/index.rs Normal file
View file

@ -0,0 +1,44 @@
use crate::data::demo::ListDemo;
use crate::pages::Page;
use maud::{html, Markup};
use std::borrow::Cow;
pub struct Index {
pub demos: Vec<ListDemo>,
}
impl Page for Index {
fn title(&self) -> Cow<'static, str> {
"Demos - demos.tf".into()
}
fn render(&self) -> Markup {
html! {
h1 { "Demos" }
table.demolist {
thead {
tr {
th .title { "Title" }
th .format { "Format" }
th .map { "Map" }
th .duration { "Duration" }
th .date { "Date" }
}
}
tbody {
@for demo in &self.demos {
tr {
td .title {
a href = (demo.url()) { (demo.server) " - " (demo.red) " vs " (demo.blu) }
}
td .format { (demo.format()) }
td .map { (demo.map) }
td .duration { (demo.duration()) }
td .date title = (demo.date()) { (demo.relative_date()) }
}
}
}
}
}
}
}

39
src/pages/mod.rs Normal file
View file

@ -0,0 +1,39 @@
pub mod demo;
pub mod index;
use maud::{html, Markup, DOCTYPE};
use std::borrow::Cow;
pub trait Page {
fn title(&self) -> Cow<'static, str>;
fn render(&self) -> Markup;
}
pub fn render<T: Page>(page: T) -> Markup {
html! {
(DOCTYPE)
html {
head {
title { (page.title()) }
link rel="stylesheet" type="text/css" href="/style.css";
}
body {
header {
span .main {
a href = "/" { "demos.tf" }
}
span { a href = "/about" { "about" } }
span { a href = "/viewer" { "viewer" } }
span.beta { a href = "/editor" { "editor" } }
span.right { a.steam-login href = "/login" { "Sign in through Steam" } }
}
.page { (page.render()) }
}
footer {
"©"
a href = "https://steamcommunity.com/id/icewind1991" { "Icewind" }
" 2017."
}
}
}
}