Add search suggestions

This commit is contained in:
blankie 2023-05-02 15:24:27 +07:00
parent 4586931adf
commit 2ecfe10584
Signed by: blankie
GPG Key ID: CC15FC822C7F61F5
2 changed files with 76 additions and 5 deletions

View File

@ -95,6 +95,14 @@ void css_route(const httplib::Request& req, httplib::Response& res) {
padding-bottom: 1em; padding-bottom: 1em;
} }
/* SEARCH RESULTS PAGE */
.searchsuggestions {
text-align: left;
display: inline-block;
margin-top: .5em;
margin-bottom: 0;
}
/* ERROR PAGE */ /* ERROR PAGE */
.error { .error {
text-align: center; text-align: center;

View File

@ -4,10 +4,14 @@
#include "../pixivclient.h" #include "../pixivclient.h"
static inline Element generate_header(const httplib::Request& req, const Config& config, static inline Element generate_header(const httplib::Request& req, const Config& config,
const SearchResults& search_results, const std::string& query, const std::vector<std::string>& tags, const std::string& order); const SearchResults& search_results, const std::string& query, const std::vector<std::string>& tags, const std::string& order,
const std::vector<SearchSuggestion>& search_suggestions);
static inline Element generate_search_suggestions(const httplib::Request& req, const Config& config,
const std::vector<std::string>& tags, const std::vector<SearchSuggestion>& search_suggestions, bool open_by_default);
static std::string tags_to_string(const std::unordered_map<std::string, std::string>& tag_translations, const std::vector<std::string>& tags); static std::string tags_to_string(const std::unordered_map<std::string, std::string>& tag_translations, const std::vector<std::string>& tags);
static inline std::vector<std::string> split(const std::string& str, char c); static inline std::vector<std::string> split(const std::string& str, char c);
static inline std::string join(const std::vector<std::string>& items, char c);
void tags_route(const httplib::Request& req, httplib::Response& res, const Config& config, PixivClient& pixiv_client) { void tags_route(const httplib::Request& req, httplib::Response& res, const Config& config, PixivClient& pixiv_client) {
std::string query = blankie::murl::unescape(req.matches.str(1)); std::string query = blankie::murl::unescape(req.matches.str(1));
@ -29,9 +33,17 @@ void tags_route(const httplib::Request& req, httplib::Response& res, const Confi
serve_error(req, res, config, "500: Internal server error", "Failed to search for illusts", e.what()); serve_error(req, res, config, "500: Internal server error", "Failed to search for illusts", e.what());
return; return;
} }
std::vector<SearchSuggestion> search_suggestions;
try {
search_suggestions = pixiv_client.get_search_suggestions(tags.back());
} catch (const std::exception& e) {
res.status = 500;
serve_error(req, res, config, "500: Internal server error", "Failed to get search suggestions", e.what());
return;
}
Element body("body", { Element body("body", {
generate_header(req, config, search_results, query, tags, order), generate_header(req, config, search_results, query, tags, order, search_suggestions),
Element("br"), Element("br"),
generate_illusts_pager(req, config, search_results.illusts, page, "illusts") generate_illusts_pager(req, config, search_results.illusts, page, "illusts")
}); });
@ -41,7 +53,8 @@ void tags_route(const httplib::Request& req, httplib::Response& res, const Confi
static inline Element generate_header(const httplib::Request& req, const Config& config, static inline Element generate_header(const httplib::Request& req, const Config& config,
const SearchResults& search_results, const std::string& query, const std::vector<std::string>& tags, const std::string& order) { const SearchResults& search_results, const std::string& query, const std::vector<std::string>& tags, const std::string& order,
const std::vector<SearchSuggestion>& search_suggestions) {
auto sort_element = [&](const char* title, const char* new_order) { auto sort_element = [&](const char* title, const char* new_order) {
std::string url = get_origin(req, config) + "/tags/" + blankie::murl::escape(query) + "/illustrations?order=" + new_order; std::string url = get_origin(req, config) + "/tags/" + blankie::murl::escape(query) + "/illustrations?order=" + new_order;
Element ret("a", {{"href", std::move(url)}}, {title}); Element ret("a", {{"href", std::move(url)}}, {title});
@ -56,9 +69,13 @@ static inline Element generate_header(const httplib::Request& req, const Config&
Element("input", {{"name", "q"}, {"required", ""}, {"value", query}}, {}), Element("input", {{"name", "q"}, {"required", ""}, {"value", query}}, {}),
" ", " ",
Element("button", {"Search for illustrations"}) Element("button", {"Search for illustrations"})
}), })
Element("br")
}); });
if (!search_suggestions.empty()) {
header.nodes.push_back(generate_search_suggestions(req, config, tags, search_suggestions, search_results.illusts.total_illusts == 0));
}
header.nodes.push_back(Element("br"));
if (search_results.illusts.total_illusts != 1) { if (search_results.illusts.total_illusts != 1) {
header.nodes.push_back("There are "); header.nodes.push_back("There are ");
header.nodes.push_back(std::to_string(search_results.illusts.total_illusts)); header.nodes.push_back(std::to_string(search_results.illusts.total_illusts));
@ -78,6 +95,39 @@ static inline Element generate_header(const httplib::Request& req, const Config&
return header; return header;
} }
static inline Element generate_search_suggestions(const httplib::Request& req, const Config& config,
const std::vector<std::string>& tags, const std::vector<SearchSuggestion>& search_suggestions, bool open_by_default) {
std::vector<blankie::html::Node> ul_nodes;
ul_nodes.reserve(search_suggestions.size());
for (const SearchSuggestion& search_suggestion : search_suggestions) {
std::string text = search_suggestion.tag;
if (search_suggestion.english_tag) {
text += " (";
text += *search_suggestion.english_tag;
text += ')';
}
std::vector<std::string> new_tags = tags;
new_tags.pop_back();
new_tags.push_back(search_suggestion.tag);
std::string url = get_origin(req, config) + "/tags/" + blankie::murl::escape(join(new_tags, ' '));
ul_nodes.push_back(Element("li", {
Element("a", {{"href", std::move(url)}}, {std::move(text)})
}));
}
Element details("details", {
Element("summary", {"Search suggestions"}),
Element("ul", {{"class", "searchsuggestions"}}, ul_nodes)
});
if (open_by_default) {
details.attributes.push_back({"open", ""});
}
return details;
}
static std::string tags_to_string(const std::unordered_map<std::string, std::string>& tag_translations, const std::vector<std::string>& tags) { static std::string tags_to_string(const std::unordered_map<std::string, std::string>& tag_translations, const std::vector<std::string>& tags) {
@ -112,3 +162,16 @@ static inline std::vector<std::string> split(const std::string& str, char c) {
return ret; return ret;
} }
static inline std::string join(const std::vector<std::string>& items, char c) {
std::string ret;
for (size_t i = 0; i < items.size(); i++) {
if (i) {
ret += c;
}
ret += items[i];
}
return ret;
}