mirror of
https://codeberg.org/demostf/frontend.git
synced 2026-06-03 18:24:12 +02:00
chat
This commit is contained in:
parent
1648eeffab
commit
82a82d2aff
7 changed files with 152 additions and 43 deletions
35
src/data/chat.rs
Normal file
35
src/data/chat.rs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
use crate::data::demo::Duration;
|
||||
use crate::Result;
|
||||
use sqlx::{query_as, Executor, Postgres};
|
||||
use tracing::instrument;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Chat {
|
||||
pub from: String,
|
||||
pub text: String,
|
||||
pub time: i32,
|
||||
}
|
||||
|
||||
impl Chat {
|
||||
#[instrument(skip(connection))]
|
||||
pub async fn for_demo(
|
||||
connection: impl Executor<'_, Database = Postgres>,
|
||||
id: u32,
|
||||
) -> Result<Vec<Chat>> {
|
||||
Ok(query_as!(
|
||||
Chat,
|
||||
r#"SELECT
|
||||
"from", text, time
|
||||
FROM chat
|
||||
WHERE demo_id = $1
|
||||
ORDER BY time ASC"#,
|
||||
id as i32
|
||||
)
|
||||
.fetch_all(connection)
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub fn time(&self) -> Duration {
|
||||
Duration(self.time)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
use crate::data::chat::Chat;
|
||||
use crate::data::player::Player;
|
||||
use crate::data::steam_id::SteamId;
|
||||
use crate::Result;
|
||||
|
|
@ -27,6 +28,7 @@ pub struct Demo {
|
|||
pub nick: String,
|
||||
pub player_count: i32,
|
||||
pub players: Vec<Player>,
|
||||
pub chat: Vec<Chat>,
|
||||
}
|
||||
|
||||
impl Demo {
|
||||
|
|
@ -76,6 +78,7 @@ impl Demo {
|
|||
};
|
||||
|
||||
let players = Player::for_demo(connection, id).await?;
|
||||
let chat = Chat::for_demo(connection, id).await?;
|
||||
|
||||
Ok(Some(Demo {
|
||||
id: raw.id,
|
||||
|
|
@ -96,6 +99,7 @@ impl Demo {
|
|||
nick: raw.nick,
|
||||
player_count: raw.player_count,
|
||||
players,
|
||||
chat,
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
@ -117,6 +121,22 @@ impl Demo {
|
|||
.or(self.uploader_name.as_deref())
|
||||
.unwrap_or("unknown")
|
||||
}
|
||||
|
||||
pub fn duration(&self) -> Duration {
|
||||
Duration(self.duration)
|
||||
}
|
||||
|
||||
pub fn viewer_url(&self) -> ViewerUrl {
|
||||
ViewerUrl(self.id)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ViewerUrl(i32);
|
||||
|
||||
impl Render for ViewerUrl {
|
||||
fn render_to(&self, buffer: &mut String) {
|
||||
write!(buffer, "/viewer/{}", self.0).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, FromRow)]
|
||||
|
|
@ -232,7 +252,7 @@ impl Render for DemoFormat {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Duration(i32);
|
||||
pub struct Duration(pub i32);
|
||||
|
||||
impl Render for Duration {
|
||||
fn render_to(&self, buffer: &mut String) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
pub mod chat;
|
||||
pub mod demo;
|
||||
pub mod player;
|
||||
pub mod steam_id;
|
||||
|
|
|
|||
|
|
@ -89,6 +89,28 @@ impl Page for DemoPage {
|
|||
}
|
||||
}
|
||||
}
|
||||
p.demo-info {
|
||||
span { (self.demo.map) }
|
||||
span.time { (self.demo.duration()) }
|
||||
}
|
||||
p.demo-download {
|
||||
a.button.button-primary href = (self.demo.url) download = (self.demo.name) { "Download" }
|
||||
a.button href = (self.demo.viewer_url()) { "View" }
|
||||
details.chat {
|
||||
summary.button.button-tertiary { "Toggle Chat" }
|
||||
div {
|
||||
table.chat {
|
||||
@for chat in &self.demo.chat {
|
||||
tr {
|
||||
td.user { (chat.from) }
|
||||
td.message { (chat.text) }
|
||||
td.duration { (chat.time()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -216,3 +216,40 @@ table.players {
|
|||
background-color: #5b818f66;
|
||||
}
|
||||
}
|
||||
|
||||
table.chat {
|
||||
& td {
|
||||
padding: 0 6px;
|
||||
}
|
||||
|
||||
& td.user {
|
||||
white-space: nowrap;
|
||||
vertical-align: top;
|
||||
width: 20%;
|
||||
color: var(--text-secondary);
|
||||
text-align: right;
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
|
||||
& td.message {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
& td.duration {
|
||||
width: 80px;
|
||||
text-align: right;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
details.chat {
|
||||
margin-top: -55px;
|
||||
|
||||
& > summary {
|
||||
float: right;
|
||||
}
|
||||
|
||||
& > div {
|
||||
padding-top: 45px;
|
||||
}
|
||||
}
|
||||
35
style/pure.css
Normal file
35
style/pure.css
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
.button {
|
||||
border-radius: 0;
|
||||
min-width: 150px;
|
||||
display: inline-block;
|
||||
zoom: 1;
|
||||
line-height: normal;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
-webkit-user-drag: none;
|
||||
font-family: inherit;
|
||||
font-size: 100%;
|
||||
padding: .5em 1em;
|
||||
color: var(--text-primary);
|
||||
background-color: #E6E6E6;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(rgba(0, 0, 0, 0.1)), to(rgba(0, 0, 0, 0.1)));
|
||||
background-image: -webkit-linear-gradient(rgba(0, 0, 0, 0.1) 40%, rgba(0, 0, 0, 0.1));
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.1));
|
||||
}
|
||||
|
||||
.button-primary {
|
||||
background-color: var(--button-primary);
|
||||
}
|
||||
|
||||
.button-tertiary, .button-tertiary:hover {
|
||||
color: var(--text-secondary);
|
||||
background-color: transparent;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
@import 'header.css';
|
||||
@import 'footer.css';
|
||||
@import 'pure.css';
|
||||
|
||||
@import 'pages/index.css';
|
||||
@import 'pages/demo.css';
|
||||
|
|
@ -154,48 +155,6 @@ pre {
|
|||
float: right;
|
||||
}
|
||||
|
||||
.pure-button {
|
||||
border-radius: 0;
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.pure-button-primary, .pure-button-selected, a.pure-button-primary, a.pure-button-selected {
|
||||
background-color: var(--button-primary);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.pure-button {
|
||||
display: inline-block;
|
||||
zoom: 1;
|
||||
line-height: normal;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
-webkit-user-drag: none;
|
||||
font-family: inherit;
|
||||
font-size: 100%;
|
||||
padding: .5em 1em;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
background-color: #E6E6E6;
|
||||
text-decoration: none;
|
||||
min-width: 150px;
|
||||
|
||||
&.pure-button-tertiary {
|
||||
background-color: transparent;
|
||||
text-decoration: underline;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.pure-button:hover {
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#1a000000', endColorstr='#1a000000', GradientType=0);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(rgba(0, 0, 0, 0.1)), to(rgba(0, 0, 0, 0.1)));
|
||||
background-image: -webkit-linear-gradient(rgba(0, 0, 0, 0.1) 40%, rgba(0, 0, 0, 0.1));
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.1));
|
||||
}
|
||||
|
||||
.button-delete {
|
||||
background: var(--button-critical);
|
||||
color: var(--primary-color);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue