ff2747eb7785ad4f822b379b83077153498504d9 / frogue / src / views / notes.rs
Raw
use super::components;
use maud::{Markup, Render, html};
use url::Url;
pub struct NoteAuthor {
pub display_name: String,
pub handle: NoteAuthorHandle,
}
impl Render for NoteAuthor {
fn render(&self) -> Markup {
html! {
span class="note-author" {
span class="note-author-display-name" {(self.display_name)}
(self.handle)
}
}
}
}
pub enum NoteAuthorHandle {
Local { username: String },
Remote { username: String, host: String },
}
impl Render for NoteAuthorHandle {
fn render(&self) -> Markup {
html! {
span class="note-author-handle" {
(match self {
Self::Local { username } => {
format!("@{username}")
},
Self::Remote { username, host } => {
format!("@{username}@{host}")
}
})}
}
}
}
pub struct Note {
id: i64,
author: NoteAuthor,
content_html: String,
created_at: components::DateTime,
updated_at: Option<components::DateTime>,
permalink: Url,
reacted: bool,
boosted: bool,
logged_in_viewer: Option<String>,
}
impl Render for Note {
fn render(&self) -> Markup {
html! {
article class="note" {
header{
(self.author)
span class="note-time" {
(self.created_at)
@if let Some(updated_at) = &self.updated_at {
(updated_at)
}
}
}
main {
(self.content_html)
}
footer {
a href=(self.permalink) { "permalink" }
@if self.logged_in_viewer.is_some() {
@if self.reacted {
form method="post" action=(format!("/remote-notes/{}/unreact", self.id)) {
button type="submit" class="react-button reacted" { "❤️ Unreact" }
}
} @else {
form method="post" action=(format!("/remote-notes/{}/react", self.id)) {
button type="submit" class="react-button" { "❤️ React" }
}
}
@if self.boosted {
form method="post" action=(format!("/remote-notes/{}/unannounce", self.id)) {
button type="submit" class="react-button reacted" { "🔁 Unboost" }
}
} @else {
form method="post" action=(format!("/remote-notes/{}/announce", self.id)) {
button type="submit" class="react-button" { "🔁 Boost" }
}
}
}
}
}
}
}
}
#[cfg(test)]
mod tests {
use chrono::Utc;
use super::*;
#[test]
fn test_sample_note() {
let note = Note {
id: 1,
author: NoteAuthor {
display_name: "Alice In Wonderland".to_string(),
handle: NoteAuthorHandle::Local {
username: "alice".to_string(),
},
},
content_html: "<h1>hiiiiiiiii!</h1><p>Sample note content.</p>".to_string(),
created_at: components::DateTime::from(&Utc::now()),
updated_at: None,
permalink: Url::try_from("http://localhost/notes/1").expect("Could not parse URL"),
reacted: false,
boosted: false,
logged_in_viewer: None,
};
let res = note.render().into_string();
const EXPECTED: &str = "<article class=\"note\">
<header>
<span class=\"note-author\">
<span class=\"note-author-display-name\">Alice In Wonderland</span>
<span class=\"note-author-handle\">@alice</span>
</span>
<span class=\"note-time\">
<time datetime=\"2026-10-22T10:06:21.083097274+00:00\">2026-10-22T10:06:21.083097274+00:00</time>
</span>
</header>
<main><h1>hiiiiiiiii!</h1><p>Sample note content.</p></main>
<footer><a href=\"http://localhost/notes/1\">permalink</a></footer>
</article>";
assert_eq!(res, EXPECTED.replace("\n", ""));
}
}