diff --git a/app/admin/forms.py b/app/admin/forms.py index 51c52e6d..dea99c6c 100644 --- a/app/admin/forms.py +++ b/app/admin/forms.py @@ -47,14 +47,14 @@ class EditCommunityForm(FlaskForm): icon_file = FileField(_('Icon image')) banner_file = FileField(_('Banner image')) rules = TextAreaField(_l('Rules')) - nsfw = BooleanField('Porn community') - local_only = BooleanField('Only accept posts from current instance') - restricted_to_mods = BooleanField('Only moderators can post') - new_mods_wanted = BooleanField('New moderators wanted') - show_home = BooleanField('Posts show on home page') - show_popular = BooleanField('Posts can be popular') - show_all = BooleanField('Posts show in All list') - low_quality = BooleanField("Low quality / toxic - upvotes in here don't add to reputation") + nsfw = BooleanField(_l('Porn community')) + local_only = BooleanField(_l('Only accept posts from current instance')) + restricted_to_mods = BooleanField(_l('Only moderators can post')) + new_mods_wanted = BooleanField(_l('New moderators wanted')) + show_home = BooleanField(_l('Posts show on home page')) + show_popular = BooleanField(_l('Posts can be popular')) + show_all = BooleanField(_l('Posts show in All list')) + low_quality = BooleanField(_l("Low quality / toxic - upvotes in here don't add to reputation")) options = [(-1, _l('Forever')), (7, _l('1 week')), (14, _l('2 weeks')), @@ -69,6 +69,10 @@ class EditCommunityForm(FlaskForm): ] content_retention = SelectField(_l('Retain content'), choices=options, default=1, coerce=int) topic = SelectField(_l('Topic'), coerce=int, validators=[Optional()]) + layouts = [('', _l('List')), + ('masonry', _l('Masonry')), + ('masonry_wide', _l('Wide masonry'))] + default_layout = SelectField(_l('Layout'), coerce=str, choices=layouts, validators=[Optional()]) submit = SubmitField(_l('Save')) def validate(self, extra_validators=None): @@ -93,8 +97,8 @@ class EditTopicForm(FlaskForm): class EditUserForm(FlaskForm): about = TextAreaField(_l('Bio'), validators=[Optional(), Length(min=3, max=5000)]) matrix_user_id = StringField(_l('Matrix User ID'), validators=[Optional(), Length(max=255)]) - profile_file = FileField(_('Avatar image')) - banner_file = FileField(_('Top banner image')) + profile_file = FileField(_l('Avatar image')) + banner_file = FileField(_l('Top banner image')) bot = BooleanField(_l('This profile is a bot')) newsletter = BooleanField(_l('Subscribe to email newsletter')) ignore_bots = BooleanField(_l('Hide posts by bots')) diff --git a/app/admin/routes.py b/app/admin/routes.py index 7445ef23..59b13498 100644 --- a/app/admin/routes.py +++ b/app/admin/routes.py @@ -241,6 +241,7 @@ def admin_community_edit(community_id): community.low_quality = form.low_quality.data community.content_retention = form.content_retention.data community.topic_id = form.topic.data if form.topic.data != 0 else None + community.default_layout = form.default_layout.data icon_file = request.files['icon_file'] if icon_file and icon_file.filename != '': if community.icon_id: @@ -276,6 +277,7 @@ def admin_community_edit(community_id): form.low_quality.data = community.low_quality form.content_retention.data = community.content_retention form.topic.data = community.topic_id if community.topic_id else None + form.default_layout.data = community.default_layout return render_template('admin/edit_community.html', title=_('Edit community'), form=form, community=community, moderating_communities=moderating_communities(current_user.get_id()), joined_communities=joined_communities(current_user.get_id()) diff --git a/app/community/routes.py b/app/community/routes.py index 71d282ab..671a4f35 100644 --- a/app/community/routes.py +++ b/app/community/routes.py @@ -105,6 +105,8 @@ def show_community(community: Community): page = request.args.get('page', 1, type=int) sort = request.args.get('sort', '' if current_user.is_anonymous else current_user.default_sort) + low_bandwidth = request.cookies.get('low_bandwidth', '0') == '1' + post_layout = request.args.get('layout', community.default_layout if not low_bandwidth else '') # If nothing has changed since their last visit, return HTTP 304 current_etag = f"{community.id}{sort}_{hash(community.last_active)}" @@ -138,7 +140,12 @@ def show_community(community: Community): posts = posts.order_by(desc(Post.posted_at)) elif sort == 'active': posts = posts.order_by(desc(Post.last_active)) - posts = posts.paginate(page=page, per_page=100, error_out=False) + per_page = 100 + if post_layout == 'masonry': + per_page = 200 + elif post_layout == 'masonry_wide': + per_page = 300 + posts = posts.paginate(page=page, per_page=per_page, error_out=False) if community.topic_id: related_communities = Community.query.filter_by(topic_id=community.topic_id).\ @@ -159,11 +166,11 @@ def show_community(community: Community): og_image=og_image, POST_TYPE_IMAGE=POST_TYPE_IMAGE, POST_TYPE_LINK=POST_TYPE_LINK, SUBSCRIPTION_PENDING=SUBSCRIPTION_PENDING, SUBSCRIPTION_MEMBER=SUBSCRIPTION_MEMBER, SUBSCRIPTION_OWNER=SUBSCRIPTION_OWNER, SUBSCRIPTION_MODERATOR=SUBSCRIPTION_MODERATOR, etag=f"{community.id}{sort}_{hash(community.last_active)}", related_communities=related_communities, - next_url=next_url, prev_url=prev_url, low_bandwidth=request.cookies.get('low_bandwidth', '0') == '1', + next_url=next_url, prev_url=prev_url, low_bandwidth=low_bandwidth, rss_feed=f"https://{current_app.config['SERVER_NAME']}/community/{community.link()}/feed", rss_feed_name=f"{community.title} posts on PieFed", content_filters=content_filters, moderating_communities=moderating_communities(current_user.get_id()), joined_communities=joined_communities(current_user.get_id()), sort=sort, - inoculation=inoculation[randint(0, len(inoculation) - 1)]) + inoculation=inoculation[randint(0, len(inoculation) - 1)], post_layout=post_layout) # RSS feed of the community diff --git a/app/models.py b/app/models.py index b5b8a28e..bf26c46b 100644 --- a/app/models.py +++ b/app/models.py @@ -146,6 +146,7 @@ class Community(db.Model): private_key = db.Column(db.Text) content_retention = db.Column(db.Integer, default=-1) topic_id = db.Column(db.Integer, db.ForeignKey('topic.id'), index=True) + default_layout = db.Column(db.String(15)) ap_id = db.Column(db.String(255), index=True) ap_profile_id = db.Column(db.String(255), index=True) diff --git a/app/static/structure.css b/app/static/structure.css index ba5bda3e..0e71c9b1 100644 --- a/app/static/structure.css +++ b/app/static/structure.css @@ -597,6 +597,83 @@ fieldset legend { font-size: 80%; } +.post_list_masonry, .post_list_masonry_wide { + -webkit-column-count: 2; + -moz-column-count: 2; + column-count: 2; + -webkit-column-gap: 5px; + -moz-column-gap: 5px; + column-gap: 5px; + clear: both; +} +@media (min-width: 992px) { + .post_list_masonry, .post_list_masonry_wide { + -webkit-column-count: 4; + -moz-column-count: 4; + column-count: 4; + -webkit-column-gap: 5px; + -moz-column-gap: 5px; + column-gap: 5px; + } +} +.post_list_masonry .post_teaser, .post_list_masonry_wide .post_teaser { + margin-bottom: 5px; + position: relative; +} +.post_list_masonry .post_teaser img, .post_list_masonry_wide .post_teaser img { + width: 100%; + height: auto; +} +.post_list_masonry .post_teaser .masonry_info, .post_list_masonry_wide .post_teaser .masonry_info { + position: absolute; + bottom: 0; + background-color: rgba(0, 0, 0, 0.2); + width: 100%; + text-align: center; +} +.post_list_masonry .post_teaser .masonry_info p, .post_list_masonry_wide .post_teaser .masonry_info p { + margin-bottom: 0; +} +.post_list_masonry .post_teaser .masonry_info p a, .post_list_masonry_wide .post_teaser .masonry_info p a { + color: white; + text-decoration: none; + line-height: 40px; +} +@media (min-width: 1280px) { + .post_list_masonry .post_teaser .masonry_info p a, .post_list_masonry_wide .post_teaser .masonry_info p a { + line-height: 30px; + } +} +.post_list_masonry .post_teaser .masonry_info_no_image, .post_list_masonry_wide .post_teaser .masonry_info_no_image { + background-color: rgba(0, 0, 0, 0.2); + width: 100%; + text-align: center; +} +.post_list_masonry .post_teaser .masonry_info_no_image p, .post_list_masonry_wide .post_teaser .masonry_info_no_image p { + margin-bottom: 0; +} +.post_list_masonry .post_teaser .masonry_info_no_image p a, .post_list_masonry_wide .post_teaser .masonry_info_no_image p a { + color: var(--bs-body-color); + text-decoration: none; +} + +@media (min-width: 992px) { + .post_list_masonry_wide { + -webkit-column-count: 5; + -moz-column-count: 5; + column-count: 5; + -webkit-column-gap: 5px; + -moz-column-gap: 5px; + column-gap: 5px; + } +} + +@media (min-width: 992px) { + .layout_switcher { + float: right; + } +} + .url_thumbnail { float: right; margin-top: -6px; diff --git a/app/static/structure.scss b/app/static/structure.scss index ad827ab3..deda15d5 100644 --- a/app/static/structure.scss +++ b/app/static/structure.scss @@ -218,6 +218,86 @@ nav, etc which are used site-wide */ } } +.post_list_masonry, .post_list_masonry_wide { + -webkit-column-count: 2; + -moz-column-count: 2; + column-count: 2; + -webkit-column-gap: 5px; + -moz-column-gap: 5px; + column-gap: 5px; + clear: both; + + @include breakpoint(tablet) { + -webkit-column-count: 4; + -moz-column-count: 4; + column-count: 4; + -webkit-column-gap: 5px; + -moz-column-gap: 5px; + column-gap: 5px; + } + + .post_teaser { + margin-bottom: 5px; + position: relative; + img { + width: 100%; + height: auto; + } + + .masonry_info { + position: absolute; + bottom: 0; + background-color: rgba(0, 0, 0, 0.2); + width: 100%; + text-align: center; + p { + margin-bottom: 0; + + a { + color: white; + text-decoration: none; + line-height: 40px; + @include breakpoint(laptop) { + line-height: 30px; + } + } + } + } + + .masonry_info_no_image { + background-color: rgba(0, 0, 0, 0.2); + width: 100%; + text-align: center; + p { + margin-bottom: 0; + + a { + color: var(--bs-body-color); + text-decoration: none; + } + } + } + } +} + +.post_list_masonry_wide { + @include breakpoint(tablet) { + -webkit-column-count: 5; + -moz-column-count: 5; + column-count: 5; + -webkit-column-gap: 5px; + -moz-column-gap: 5px; + column-gap: 5px; + } + +} + +.layout_switcher { + @include breakpoint(tablet) { + float: right; + } +} + .url_thumbnail { float: right; margin-top: -6px; diff --git a/app/templates/admin/edit_community.html b/app/templates/admin/edit_community.html index d91989e2..c800ba89 100644 --- a/app/templates/admin/edit_community.html +++ b/app/templates/admin/edit_community.html @@ -46,6 +46,7 @@ {{ render_field(form.low_quality) }} {{ render_field(form.content_retention) }} {{ render_field(form.topic) }} + {{ render_field(form.default_layout) }} {% if not community.is_local() %} {% endif %} diff --git a/app/templates/base.html b/app/templates/base.html index 201dcdd5..a21b4564 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -94,7 +94,7 @@ {% block navbar %}