Compare commits

...

4 Commits

8 changed files with 115 additions and 55 deletions

View File

@ -15,3 +15,10 @@ This list is not exhaustive, nor does it mean that these are being worked on.
- No search - No search
- No ability to login - No ability to login
- No ability to see comments or like counts - No ability to see comments or like counts
# Miscellaneous Information
In a page containing a list of illustrations (e.g. a user's illustrations page
or a search results page), illustrations containing multiple images will have a
badge indicating the amount of images inside. Illustrations that are marked as
being AI-generated will have a badge with a red background.

View File

@ -120,6 +120,7 @@ void from_json(const nlohmann::json& j, Illust& illust) {
} else { } else {
illust.images = {get_illust_image(illust_details)}; illust.images = {get_illust_image(illust_details)};
} }
illust.page_count = to_ull(illust_details.at("page_count").get_ref<const nlohmann::json::string_t&>());
} }
void from_json(const nlohmann::json& j, Illusts& illusts) { void from_json(const nlohmann::json& j, Illusts& illusts) {
@ -167,7 +168,8 @@ void from_json(const nlohmann::json& j, SearchResults& search_results) {
.comment = std::nullopt, .comment = std::nullopt,
.tags = std::move(tags), .tags = std::move(tags),
.images = {get_illust_image(i)} .images = {get_illust_image(i)},
.page_count = i.at("pageCount").get<size_t>()
}; };
search_results.illusts.illusts.push_back(illust); search_results.illusts.illusts.push_back(illust);
} }

View File

@ -44,6 +44,7 @@ struct Illust {
std::optional<std::string> comment; std::optional<std::string> comment;
std::vector<Tag> tags; std::vector<Tag> tags;
std::vector<Images> images; std::vector<Images> images;
size_t page_count;
}; };
struct Illusts { struct Illusts {

View File

@ -59,7 +59,7 @@ static inline Element generate_user_link(const httplib::Request& req, const Conf
std::string user_link = get_origin(req, config) + "/users/" + std::to_string(illust.user_id); std::string user_link = get_origin(req, config) + "/users/" + std::to_string(illust.user_id);
return Element("a", {{"class", "usermetadata"}, {"href", std::move(user_link)}}, { return Element("a", {{"class", "usermetadata"}, {"href", std::move(user_link)}}, {
Element("img", {{"class", "smallprofilepicture"}, {"loading", "lazy"}, {"src", std::move(profile_picture)}}, {}), Element("img", {{"class", "profilepicture small"}, {"loading", "lazy"}, {"src", std::move(profile_picture)}}, {}),
Element("b", {illust.user_display_name}) Element("b", {illust.user_display_name})
}); });
} }
@ -67,7 +67,7 @@ static inline Element generate_user_link(const httplib::Request& req, const Conf
static inline Element generate_images(const httplib::Request& req, const Config& config, const Illust& illust) { static inline Element generate_images(const httplib::Request& req, const Config& config, const Illust& illust) {
using namespace std::string_literals; using namespace std::string_literals;
Element div("div", {{"class", "illust"}}, {}); Element div("div", {{"class", "illustimages"}}, {});
bool show_pages = illust.images.size() > 1; bool show_pages = illust.images.size() > 1;
if (show_pages) { if (show_pages) {

View File

@ -8,6 +8,9 @@ void css_route(const httplib::Request& req, httplib::Response& res) {
--background-color: black; --background-color: black;
--text-color: white; --text-color: white;
--illust-badge-background-color: rgba(0, 0, 0, .5);
--illust-badge-ai-background-color: rgba(255, 0, 0, .5);
--error-background-color: rgb(100, 0, 0); --error-background-color: rgb(100, 0, 0);
--error-border-color: red; --error-border-color: red;
--error-text-color: white; --error-text-color: white;
@ -22,6 +25,14 @@ void css_route(const httplib::Request& req, httplib::Response& res) {
color: var(--text-color); color: var(--text-color);
font-family: sans-serif; font-family: sans-serif;
} }
img {
object-fit: cover;
max-width: 100%;
}
.center {
text-align: center;
display: block;
}
a { a {
color: var(--accent-color); color: var(--accent-color);
@ -32,67 +43,72 @@ void css_route(const httplib::Request& req, httplib::Response& res) {
text-decoration: underline; text-decoration: underline;
} }
img { /* ILLUSTRATIONS GRID and ILLUSTRATION PREVIEW PAGE */
object-fit: cover;
max-width: 100%;
}
.center {
text-align: center;
display: block;
}
/* USER PAGE (and a tiny bit for illustrations page) */
.cover {
width: 100%;
height: 50vh;
margin-bottom: 1em;
}
.profilepicture, .smallprofilepicture {
margin-right: .5em;
}
.profilepicture {
width: 5em;
height: 5em;
}
.smallprofilepicture {
width: 2.5em;
height: 2.5em;
}
.usermetadata {
display: flex;
align-items: center;
margin-left: .5em;
}
/* USER ILLUSTRATIONS PAGE (and illustrations page) */
.grid { .grid {
gap: 1em;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 1em;
justify-content: center; justify-content: center;
} }
.grid img { .grid img {
width: 15em; width: 15em;
height: 15em; height: 15em;
} }
/* ILLUSTRATIONS GRID (used in user illustrations page and search results page) */
.grid p { .grid p {
width: 15em; width: 15em;
} }
.illustsgriditem {
position: relative;
}
.illustbadge {
position: absolute;
top: .25em;
right: .25em;
padding: .25em;
color: var(--text-color);
background-color: var(--illust-badge-background-color);
text-decoration: none !important;
}
.illustbadge.ai {
background-color: var(--illust-badge-ai-background-color);
}
/* ILLUSTRATIONS PAGE */ /* ILLUSTRATIONS PAGE */
.profilepicture.small {
width: 2.5em;
height: 2.5em;
}
.illustimages {
display: grid;
text-align: center;
}
.illustimages .landmark {
padding-top: 1em;
padding-bottom: 1em;
}
.illusttags { .illusttags {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 0 1em; gap: 0 1em;
} }
.illust {
display: grid; /* USER PAGE */
text-align: center; .profilecover {
width: 100%;
height: 50vh;
margin-bottom: 1em;
} }
.illust .landmark { .profilepicture {
padding-top: 1em; margin-right: .5em;
padding-bottom: 1em; width: 5em;
height: 5em;
}
.usermetadata {
display: flex;
align-items: center;
margin-left: .5em;
} }
/* SEARCH RESULTS PAGE */ /* SEARCH RESULTS PAGE */

View File

@ -39,6 +39,12 @@ void home_route(const httplib::Request& req, httplib::Response& res, const Confi
Element("li", {"Can only search for newest and oldest illustrations"}), Element("li", {"Can only search for newest and oldest illustrations"}),
Element("li", {"No ability to login"}), Element("li", {"No ability to login"}),
Element("li", {"No ability to see comments or like counts"}), Element("li", {"No ability to see comments or like counts"}),
}),
Element("h2", {"Miscellaneous Information"}),
Element("p", {
"In a page containing a list of illustrations (e.g. a user's illustrations page or a search results page), "
"illustrations containing multiple images will have a badge indicating the amount of images inside. "
"Illustrations that are marked as being AI-generated will have a badge with a red background."
}) })
}); });
serve(req, res, config, "Pixwhile", std::move(body)); serve(req, res, config, "Pixwhile", std::move(body));

View File

@ -11,7 +11,7 @@ Element generate_user_header(const User& user, const Config& config) {
std::string cover_original = proxy_image_url(config, user.cover_images->original_or_thumbnail()); std::string cover_original = proxy_image_url(config, user.cover_images->original_or_thumbnail());
std::string cover_thumbnail = proxy_image_url(config, user.cover_images->thumbnail_or_original()); std::string cover_thumbnail = proxy_image_url(config, user.cover_images->thumbnail_or_original());
header.nodes.push_back(Element("a", {{"href", std::move(cover_original)}}, { header.nodes.push_back(Element("a", {{"href", std::move(cover_original)}}, {
Element("img", {{"class", "cover"}, {"loading", "lazy"}, {"src", std::move(cover_thumbnail)}}, {}) Element("img", {{"class", "profilecover"}, {"loading", "lazy"}, {"src", std::move(cover_thumbnail)}}, {})
})); }));
} }

View File

@ -5,7 +5,9 @@
#include "servehelper.h" #include "servehelper.h"
static Element generate_pager(const Illusts& illusts, size_t page, const char* id); static Element generate_pager(const Illusts& illusts, size_t page, const char* id);
static inline Element generate_content(const httplib::Request& req, const Config& config, const Illusts& illusts); static inline Element generate_illusts_grid(const httplib::Request& req, const Config& config, const Illusts& illusts);
static inline Element generate_illusts_grid_item(const httplib::Request& req, const Config& config, const Illust& illust);
static inline Element generate_illust_badge(const Illust& illust, const std::string& illust_url);
void serve(const httplib::Request& req, httplib::Response& res, const Config& config, std::string title, Element element) { void serve(const httplib::Request& req, httplib::Response& res, const Config& config, std::string title, Element element) {
using namespace std::string_literals; using namespace std::string_literals;
@ -104,7 +106,7 @@ Element generate_illusts_pager(const httplib::Request& req, const Config& config
return Element("div", {{"id", id}}, { return Element("div", {{"id", id}}, {
generate_pager(illusts, page, id), generate_pager(illusts, page, id),
Element("br"), Element("br"),
generate_content(req, config, illusts), generate_illusts_grid(req, config, illusts),
generate_pager(illusts, page, id) generate_pager(illusts, page, id)
}); });
} }
@ -132,19 +134,45 @@ static Element generate_pager(const Illusts& illusts, size_t page, const char* i
}); });
} }
static inline Element generate_content(const httplib::Request& req, const Config& config, const Illusts& illusts) { static inline Element generate_illusts_grid(const httplib::Request& req, const Config& config, const Illusts& illusts) {
Element div("div", {{"class", "grid"}}, {}); Element div("div", {{"class", "grid"}}, {});
div.nodes.reserve(illusts.illusts.size()); div.nodes.reserve(illusts.illusts.size());
for (const Illust& i : illusts.illusts) { for (const Illust& i : illusts.illusts) {
std::string illust_url = get_origin(req, config) + "/artworks/" + std::to_string(i.illust_id); div.nodes.push_back(generate_illusts_grid_item(req, config, i));
std::string image_url = proxy_image_url(config, i.images[0].thumbnail_or_original(1));
div.nodes.push_back(Element("a", {{"href", {std::move(illust_url)}}}, {
Element("img", {{"loading", "lazy"}, {"src", std::move(image_url)}}, {}),
Element("p", {i.title})
}));
} }
return div; return div;
} }
static inline Element generate_illusts_grid_item(const httplib::Request& req, const Config& config, const Illust& illust) {
std::string illust_url = get_origin(req, config) + "/artworks/" + std::to_string(illust.illust_id);
std::string image_url = proxy_image_url(config, illust.images[0].thumbnail_or_original(1));
Element div("div", {{"class", "illustsgriditem"}}, {
Element("a", {{"href", illust_url}}, {
Element("img", {{"loading", "lazy"}, {"src", std::move(image_url)}}, {}),
Element("p", {illust.title})
})
});
if (illust.page_count > 1 || illust.ai_generated) {
div.nodes.push_back(generate_illust_badge(illust, std::move(illust_url)));
}
return div;
}
static inline Element generate_illust_badge(const Illust& illust, const std::string& illust_url) {
const char* css_class = !illust.ai_generated ? "illustbadge" : "illustbadge ai";
if (illust.page_count > 1) {
return Element("a", {{"class", css_class}, {"href", illust_url + "?preview=1"}}, {
std::to_string(illust.page_count), " pages"
});
} else {
return Element("span", {{"class", css_class}}, {
"AI"
});
}
}