Add "<user> boosted" and "Replied to <user>"

This commit is contained in:
blankie 2023-11-24 00:29:55 +11:00
parent fb1f45817c
commit aa0c7806cb
Signed by: blankie
GPG Key ID: CC15FC822C7F61F5
3 changed files with 85 additions and 42 deletions

10
font_awesome.h Normal file
View File

@ -0,0 +1,10 @@
/*
* The icons here are from the free edition of Font Awesome, which are created
* by Fonticons, Inc. and is available under the CC-BY 4.0 license.
*
* https://fontawesome.com/license/free#icons
* https://creativecommons.org/licenses/by/4.0/
*/
const char fa_retweet[] = R"EOF(<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. --><path d="M272 416c17.7 0 32-14.3 32-32s-14.3-32-32-32H160c-17.7 0-32-14.3-32-32V192h32c12.9 0 24.6-7.8 29.6-19.8s2.2-25.7-6.9-34.9l-64-64c-12.5-12.5-32.8-12.5-45.3 0l-64 64c-9.2 9.2-11.9 22.9-6.9 34.9s16.6 19.8 29.6 19.8l32 0 0 128c0 53 43 96 96 96H272zM304 96c-17.7 0-32 14.3-32 32s14.3 32 32 32l112 0c17.7 0 32 14.3 32 32l0 128H416c-12.9 0-24.6 7.8-29.6 19.8s-2.2 25.7 6.9 34.9l64 64c12.5 12.5 32.8 12.5 45.3 0l64-64c9.2-9.2 11.9-22.9 6.9-34.9s-16.6-19.8-29.6-19.8l-32 0V192c0-53-43-96-96-96L304 96z"/></svg>)EOF";
const char fa_reply[] = R"EOF(<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. --><path d="M205 34.8c11.5 5.1 19 16.6 19 29.2v64H336c97.2 0 176 78.8 176 176c0 113.3-81.5 163.9-100.2 174.1c-2.5 1.4-5.3 1.9-8.1 1.9c-10.9 0-19.7-8.9-19.7-19.7c0-7.5 4.3-14.4 9.8-19.5c9.4-8.8 22.2-26.4 22.2-56.7c0-53-43-96-96-96H224v64c0 12.6-7.4 24.1-19 29.2s-25 3-34.4-5.4l-160-144C3.9 225.7 0 217.1 0 208s3.9-17.7 10.6-23.8l160-144c9.4-8.5 22.9-10.6 34.4-5.4z"/></svg>)EOF";

View File

@ -49,13 +49,17 @@ a:hover {
color: var(--bright-accent-color); color: var(--bright-accent-color);
} }
/* CUSTOM EMOJI */ /* CUSTOM EMOJI and FONT AWESOME ICONS */
.custom_emoji { .custom_emoji, svg {
height: 1em; height: 1em;
width: 1em; width: 1em;
/* https://stackoverflow.com/a/489394 */ /* https://stackoverflow.com/a/489394 */
vertical-align: middle; vertical-align: middle;
} }
/* FONT AWESOME ICONS */
svg {
filter: invert(1);
}
/* POST */ /* POST */
.post { .post {

View File

@ -4,6 +4,7 @@
#include <FastHash.h> #include <FastHash.h>
#include <curl/curl.h> #include <curl/curl.h>
#include "font_awesome.h"
#include "config.h" #include "config.h"
#include "models.h" #include "models.h"
#include "timeutils.h" #include "timeutils.h"
@ -17,6 +18,12 @@ static inline void preprocess_link(const httplib::Request& req, const std::strin
static inline bool should_fix_link(lxb_dom_element_t* element, const std::string& cls); static inline bool should_fix_link(lxb_dom_element_t* element, const std::string& cls);
static inline lxb_dom_node_t* emojify(lxb_dom_node_t* child, const std::vector<Emoji>& emojis); static inline lxb_dom_node_t* emojify(lxb_dom_node_t* child, const std::vector<Emoji>& emojis);
static inline std::vector<lxb_dom_node*> emojify(lxb_dom_document_t* document, std::string str, const std::vector<Emoji>& emojis); static inline std::vector<lxb_dom_node*> emojify(lxb_dom_document_t* document, std::string str, const std::vector<Emoji>& emojis);
struct PostStatus {
const char* icon_html;
Node info_node;
};
static Element serialize_post(const httplib::Request& req, const std::string& server, const Post& post, const std::optional<PostStatus>& post_status);
static inline Element serialize_media(const Media& media); static inline Element serialize_media(const Media& media);
class CurlUrlException : public std::exception { class CurlUrlException : public std::exception {
@ -169,47 +176,20 @@ Element serialize_post(const httplib::Request& req, const std::string& server, c
using namespace std::string_literals; using namespace std::string_literals;
if (post.reblog) { if (post.reblog) {
return serialize_post(req, server, *post.reblog); PostStatus post_status = {
fa_retweet,
preprocess_html(req, post.account.emojis, post.account.display_name + " boosted"),
};
return serialize_post(req, server, *post.reblog, post_status);
} else if (post.in_reply_to_id && post.in_reply_to_account_id && post.account.id == *post.in_reply_to_account_id) {
PostStatus post_status = {
fa_reply,
preprocess_html(req, post.account.emojis, "Replied to "s + post.account.display_name),
};
return serialize_post(req, server, post, post_status);
} else {
return serialize_post(req, server, post, std::nullopt);
} }
std::string time_title = post.edited_at < 0
? full_time(post.created_at)
: "Created: "s + full_time(post.created_at) + "\nEdited: " + full_time(post.edited_at);
const char* time_badge = post.edited_at < 0 ? "" : " (edited)";
Element contents("div", {preprocess_html(req, server, post.emojis, post.content)});
Element post_attachments("div", {{"class", "post-attachments"}}, {});
post_attachments.nodes.reserve(post.media_attachments.size());
for (const Media& media : post.media_attachments) {
post_attachments.nodes.push_back(serialize_media(media));
}
contents.nodes.push_back(std::move(post_attachments));
if (post.sensitive) {
std::string spoiler_text = !post.spoiler_text.empty() ? post.spoiler_text : "See more";
contents = Element("details", {
Element("summary", {preprocess_html(req, post.emojis, std::move(spoiler_text))}),
std::move(contents),
});
}
Element div("div", {{"class", "post"}}, {
Element("div", {{"class", "post-header"}}, {
Element("a", {{"href", get_origin(req) + '/' + server + "/@" + post.account.acct(false)}}, {
Element("img", {{"class", "post-avatar"}, {"alt", "User profile picture"}, {"src", post.account.avatar_static}}, {}),
Element("span", {
Element("b", {preprocess_html(req, post.account.emojis, post.account.display_name)}),
Element("br"), "@", post.account.acct(),
}),
}),
Element("a", {{"href", get_origin(req) + '/' + server + "/@" + post.account.acct(false) + '/' + post.id}, {"title", time_title}}, {
Element("time", {{"datetime", to_rfc3339(post.created_at)}}, {relative_time(post.created_at, current_time()), time_badge}),
}),
}),
contents,
});
return div;
} }
blankie::html::HTMLString preprocess_html(const httplib::Request& req, const std::string& domain_name, const std::vector<Emoji>& emojis, const blankie::html::HTMLString& str) { blankie::html::HTMLString preprocess_html(const httplib::Request& req, const std::string& domain_name, const std::vector<Emoji>& emojis, const blankie::html::HTMLString& str) {
@ -375,6 +355,55 @@ static inline std::vector<lxb_dom_node_t*> emojify(lxb_dom_document_t* document,
return res; return res;
} }
static Element serialize_post(const httplib::Request& req, const std::string& server, const Post& post, const std::optional<PostStatus>& post_status) {
using namespace std::string_literals;
std::string time_title = post.edited_at < 0
? full_time(post.created_at)
: "Created: "s + full_time(post.created_at) + "\nEdited: " + full_time(post.edited_at);
const char* time_badge = post.edited_at < 0 ? "" : " (edited)";
Element contents("div", {preprocess_html(req, server, post.emojis, post.content)});
Element post_attachments("div", {{"class", "post-attachments"}}, {});
post_attachments.nodes.reserve(post.media_attachments.size());
for (const Media& media : post.media_attachments) {
post_attachments.nodes.push_back(serialize_media(media));
}
contents.nodes.push_back(std::move(post_attachments));
if (post.sensitive) {
std::string spoiler_text = !post.spoiler_text.empty() ? post.spoiler_text : "See more";
contents = Element("details", {
Element("summary", {preprocess_html(req, post.emojis, std::move(spoiler_text))}),
std::move(contents),
});
}
Element div("div", {{"class", "post"}}, {
Element("div", {{"class", "post-header"}}, {
Element("a", {{"href", get_origin(req) + '/' + server + "/@" + post.account.acct(false)}}, {
Element("img", {{"class", "post-avatar"}, {"alt", "User profile picture"}, {"src", post.account.avatar_static}}, {}),
Element("span", {
Element("b", {preprocess_html(req, post.account.emojis, post.account.display_name)}),
Element("br"), "@", post.account.acct(),
}),
}),
Element("a", {{"href", get_origin(req) + '/' + server + "/@" + post.account.acct(false) + '/' + post.id}, {"title", time_title}}, {
Element("time", {{"datetime", to_rfc3339(post.created_at)}}, {relative_time(post.created_at, current_time()), time_badge}),
}),
}),
contents,
});
if (post_status) {
div.nodes.insert(div.nodes.begin(), Element("p", {
blankie::html::HTMLString(post_status->icon_html), " ", post_status->info_node,
}));
}
return div;
}
static inline Element serialize_media(const Media& media) { static inline Element serialize_media(const Media& media) {
Element element = [&]() { Element element = [&]() {
if (media.type == "image") { if (media.type == "image") {