diff --git a/crates/app/src/assets.rs b/crates/app/src/assets.rs index 43c8fd1..1b348b3 100644 --- a/crates/app/src/assets.rs +++ b/crates/app/src/assets.rs @@ -52,6 +52,7 @@ pub const COMMUNITIES_FEED: &str = include_str!("./public/html/communities/feed. pub const COMMUNITIES_POST: &str = include_str!("./public/html/communities/post.html"); pub const COMMUNITIES_SETTINGS: &str = include_str!("./public/html/communities/settings.html"); pub const COMMUNITIES_MEMBERS: &str = include_str!("./public/html/communities/members.html"); +pub const COMMUNITIES_SEARCH: &str = include_str!("./public/html/communities/search.html"); pub const TIMELINES_HOME: &str = include_str!("./public/html/timelines/home.html"); pub const TIMELINES_FOLLOWING: &str = include_str!("./public/html/timelines/following.html"); @@ -180,6 +181,7 @@ pub(crate) async fn write_assets(config: &Config) -> PathBufD { write_template!(html_path->"communities/post.html"(crate::assets::COMMUNITIES_POST) --config=config); write_template!(html_path->"communities/settings.html"(crate::assets::COMMUNITIES_SETTINGS) --config=config); write_template!(html_path->"communities/members.html"(crate::assets::COMMUNITIES_MEMBERS) --config=config); + write_template!(html_path->"communities/search.html"(crate::assets::COMMUNITIES_SEARCH) --config=config); write_template!(html_path->"timelines/home.html"(crate::assets::TIMELINES_HOME) -d "timelines" --config=config); write_template!(html_path->"timelines/following.html"(crate::assets::TIMELINES_FOLLOWING) --config=config); diff --git a/crates/app/src/langs/en-US.toml b/crates/app/src/langs/en-US.toml index 839bf95..0713af7 100644 --- a/crates/app/src/langs/en-US.toml +++ b/crates/app/src/langs/en-US.toml @@ -80,6 +80,10 @@ version = "1.0.0" "communities:label.repost" = "Repost" "communities:label.quote_post" = "Quote post" "communities:label.expand_original" = "Expand original" +"communities:label.search" = "Search" +"communities:label.search_results" = "Search results" +"communities:label.query" = "Query" +"communities:label.join_new" = "Join new" "notifs:action.mark_as_read" = "Mark as read" "notifs:action.mark_as_unread" = "Mark as unread" diff --git a/crates/app/src/public/css/style.css b/crates/app/src/public/css/style.css index 442b1f4..bf366ef 100644 --- a/crates/app/src/public/css/style.css +++ b/crates/app/src/public/css/style.css @@ -157,6 +157,10 @@ p { margin-bottom: 0; } +.no_p_margin img { + display: block !important; +} + .name { max-width: 250px; overflow: hidden; diff --git a/crates/app/src/public/html/communities/list.html b/crates/app/src/public/html/communities/list.html index 8a6191b..31f0b66 100644 --- a/crates/app/src/public/html/communities/list.html +++ b/crates/app/src/public/html/communities/list.html @@ -33,9 +33,16 @@ {% endif %}
-
- {{ icon "award" }} - {{ text "communities:label.my_communities" }} +
+
+ {{ icon "award" }} + {{ text "communities:label.my_communities" }} +
+ + + {{ icon "search" }} + {{ text "communities:label.join_new" }} +
@@ -45,9 +52,16 @@
-
- {{ icon "trending-up" }} - {{ text "communities:label.popular_communities" }} +
+
+ {{ icon "trending-up" }} + {{ text "communities:label.popular_communities" }} +
+ + + {{ icon "search" }} + {{ text "communities:label.search" }} +
diff --git a/crates/app/src/public/html/communities/search.html b/crates/app/src/public/html/communities/search.html new file mode 100644 index 0000000..d54cb15 --- /dev/null +++ b/crates/app/src/public/html/communities/search.html @@ -0,0 +1,45 @@ +{% extends "root.html" %} {% block head %} +Search communities - {{ config.name }} +{% endblock %} {% block body %} {{ macros::nav(selected="communities") }} +
+
+
+ {{ icon "search" }} + {{ text "communities:label.search" }} +
+ +
+
+ + +
+ + +
+
+ +
+
+ {{ icon "book-marked" }} + {{ text "communities:label.search_results" }} +
+ + +
+ {% for item in list %} + {{ components::community_listing_card(community=item) }} + {% endfor %} + + {{ components::pagination(page=page, items=list|length, key="&text=", value=text) }} +
+
+
+{% endblock %} diff --git a/crates/app/src/public/html/components.html b/crates/app/src/public/html/components.html index 093fd5e..4c70d79 100644 --- a/crates/app/src/public/html/components.html +++ b/crates/app/src/public/html/components.html @@ -392,17 +392,23 @@ show_community and post.community != config.town_square %}
-{%- endmacro %} {% macro pagination(page=0, items=0) -%} +{%- endmacro %} {% macro pagination(page=0, items=0, key="", value="") -%}
{% if page > 0 %} - + {{ icon "arrow-left" }} {{ text "general:link.previous" }} {% else %}
{% endif %} {% if items != 0 %} - + {{ text "general:link.next" }} {{ icon "arrow-right"}} diff --git a/crates/app/src/public/html/timelines/home.html b/crates/app/src/public/html/timelines/home.html index 2b89e6f..6a596a7 100644 --- a/crates/app/src/public/html/timelines/home.html +++ b/crates/app/src/public/html/timelines/home.html @@ -11,8 +11,14 @@ ✨ Welcome to {{ config.name }}!
-
- Join some communities to populate your home timeline! +
+

Join some communities to populate your home timeline!

+

+ You can get started by + searching for a community to join! +

{% else %} diff --git a/crates/app/src/routes/pages/communities.rs b/crates/app/src/routes/pages/communities.rs index 1276d8f..b9eabcb 100644 --- a/crates/app/src/routes/pages/communities.rs +++ b/crates/app/src/routes/pages/communities.rs @@ -1,4 +1,4 @@ -use super::{PaginatedQuery, render_error}; +use super::{render_error, PaginatedQuery, SearchedQuery}; use crate::{assets::initial_context, get_lang, get_user_from_token, sanitize::clean_context, State}; use axum::{ Extension, @@ -166,6 +166,44 @@ pub async fn list_request(jar: CookieJar, Extension(data): Extension) -> )) } +/// `/communities/search` +pub async fn search_request( + jar: CookieJar, + Extension(data): Extension, + Query(req): Query, +) -> impl IntoResponse { + let data = data.read().await; + let user = match get_user_from_token!(jar, data.0) { + Some(ua) => ua, + None => { + return Err(Html( + render_error(Error::NotAllowed, &jar, &data, &None).await, + )); + } + }; + + let communities = match data + .0 + .get_communities_searched(&req.text, 12, req.page) + .await + { + Ok(p) => p, + Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)), + }; + + let lang = get_lang!(jar, data.0); + let mut context = initial_context(&data.0.0, lang, &Some(user)).await; + + context.insert("list", &communities); + context.insert("page", &req.page); + context.insert("text", &req.text); + + // return + Ok(Html( + data.1.render("communities/search.html", &context).unwrap(), + )) +} + pub fn community_context( context: &mut Context, community: &Community, diff --git a/crates/app/src/routes/pages/mod.rs b/crates/app/src/routes/pages/mod.rs index 52eb6a1..43cac0e 100644 --- a/crates/app/src/routes/pages/mod.rs +++ b/crates/app/src/routes/pages/mod.rs @@ -45,6 +45,7 @@ pub fn routes() -> Router { .route("/@{username}/followers", get(profile::followers_request)) // communities .route("/communities", get(communities::list_request)) + .route("/communities/search", get(communities::search_request)) .route("/community/{title}", get(communities::feed_request)) .route( "/community/{title}/manage", @@ -74,3 +75,11 @@ pub struct PaginatedQuery { #[serde(default)] pub page: usize, } + +#[derive(Deserialize)] +pub struct SearchedQuery { + #[serde(default)] + pub text: String, + #[serde(default)] + pub page: usize, +} diff --git a/crates/core/src/database/communities.rs b/crates/core/src/database/communities.rs index 1d11c26..3d50d85 100644 --- a/crates/core/src/database/communities.rs +++ b/crates/core/src/database/communities.rs @@ -145,6 +145,33 @@ impl DataManager { Ok(res.unwrap()) } + /// Get all communities, filtering their title. + /// Communities are sorted by popularity first, creation date second. + pub async fn get_communities_searched( + &self, + query: &str, + batch: usize, + page: usize, + ) -> Result> { + let conn = match self.connect().await { + Ok(c) => c, + Err(e) => return Err(Error::DatabaseConnection(e.to_string())), + }; + + let res = query_rows!( + &conn, + "SELECT * FROM communities WHERE title LIKE $1 ORDER BY member_count DESC, created DESC LIMIT $2 OFFSET $3", + params![&format!("%{query}%"), &(batch as i64), &(page as i64)], + |x| { Self::get_community_from_row(x) } + ); + + if res.is_err() { + return Err(Error::GeneralNotFound("communities".to_string())); + } + + Ok(res.unwrap()) + } + /// Create a new community in the database. /// /// # Arguments