Skip to content

Commit b66ce55

Browse files
authored
Add pagination only if max_number_of_topics > number_of_topics (#65)
Adds a new theme component setting called max_number_of_topics, defaulting to 0. Unless this is set to a number greater than the number_of_topics setting, behavior should be unchanged. If it's set to a higher number AND there are enough featured topics to have more than one page, page arrows will appear allowing the user to cycle through pages of featured topics with each page having number_of_topics topics displayed. The left/right arrow buttons should only display if there are additional pages in that direction. Tries to play nicely with the show_all_always setting and handles small screen sizes in the same way (lowering the number of displayed topics as the screen shrinks, but still allowing all topics included by max_number_of_topics to be paged through).
1 parent 3d7d416 commit b66ce55

File tree

7 files changed

+2510
-1132
lines changed

7 files changed

+2510
-1132
lines changed

common/common.scss

Lines changed: 90 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -33,97 +33,121 @@ html.homepage-featured-topics {
3333
margin-bottom: 1.5em;
3434
}
3535

36-
.featured-topics {
36+
.featured-topics-controls {
3737
display: flex;
38-
justify-content: center;
39-
align-items: flex-start;
38+
align-items: center;
39+
justify-content: space-between;
4040

41-
.featured-topic {
42-
flex: 1 1 30%;
43-
max-width: 500px;
41+
.page-button-container {
42+
flex: 0 0 2.2em;
43+
}
44+
45+
.page-button {
46+
height: min-content;
47+
padding: 0.3em;
48+
}
49+
50+
.left-page-button {
51+
margin-right: 0.4em;
52+
}
53+
54+
.right-page-button {
55+
margin-left: 0.4em;
56+
}
57+
58+
.featured-topics {
59+
flex: 1;
4460
display: flex;
45-
flex-wrap: wrap;
46-
align-items: center;
4761
justify-content: center;
62+
align-items: flex-start;
4863

49-
@media screen and (width >= 451px) {
50-
margin: 0 1.25em;
64+
.featured-topic {
65+
flex: 1 1 30%;
66+
max-width: 500px;
67+
display: flex;
68+
flex-wrap: wrap;
69+
align-items: center;
70+
justify-content: center;
5171

52-
&:first-of-type:not(:last-of-type) {
53-
margin-left: 0;
54-
}
72+
@media screen and (width >= 451px) {
73+
margin: 0 1.25em;
5574

56-
&:last-of-type:not(:first-of-type) {
57-
margin-right: 0;
58-
}
59-
}
75+
&:first-of-type:not(:last-of-type) {
76+
margin-left: 0;
77+
}
6078

61-
@media screen and (width <= 999px) {
62-
&:nth-of-type(4) {
63-
margin-right: 0;
79+
&:last-of-type:not(:first-of-type) {
80+
margin-right: 0;
81+
}
6482
}
6583

66-
&:nth-of-type(n + 5) {
67-
display: none;
68-
}
69-
}
84+
@media screen and (width <= 999px) {
85+
&:nth-of-type(4) {
86+
margin-right: 0;
87+
}
7088

71-
@media screen and (width <= 800px) {
72-
&:nth-of-type(3) {
73-
margin-right: 0;
89+
&:nth-of-type(n + 5) {
90+
display: none;
91+
}
7492
}
7593

76-
&:nth-of-type(n + 4) {
77-
display: none;
94+
@media screen and (width <= 800px) {
95+
&:nth-of-type(3) {
96+
margin-right: 0;
97+
}
98+
99+
&:nth-of-type(n + 4) {
100+
display: none;
101+
}
78102
}
79-
}
80103

81-
@media screen and (width <= 600px) {
82-
width: 100%;
104+
@media screen and (width <= 600px) {
105+
width: 100%;
83106

84-
&:nth-of-type(2) {
85-
margin-right: 0;
86-
}
107+
&:nth-of-type(2) {
108+
margin-right: 0;
109+
}
87110

88-
&:nth-of-type(n + 3) {
89-
display: none;
111+
&:nth-of-type(n + 3) {
112+
display: none;
113+
}
90114
}
91-
}
92115

93-
@media screen and (width <= 450px) {
94-
width: 100%;
116+
@media screen and (width <= 450px) {
117+
width: 100%;
95118

96-
&:nth-of-type(n + 2) {
97-
display: none;
119+
&:nth-of-type(n + 2) {
120+
display: none;
121+
}
98122
}
99-
}
100123

101-
h3 {
102-
margin: 0;
103-
font-size: var(--font-up-2);
104-
padding: 0.5em 1em 1em 1em;
105-
106-
a {
107-
display: -webkit-box;
108-
overflow: hidden;
109-
text-overflow: ellipsis;
110-
word-wrap: break-word;
111-
-webkit-line-clamp: 2;
112-
-webkit-box-orient: vertical;
124+
h3 {
125+
margin: 0;
126+
font-size: var(--font-up-2);
127+
padding: 0.5em 1em 1em 1em;
128+
129+
a {
130+
display: -webkit-box;
131+
overflow: hidden;
132+
text-overflow: ellipsis;
133+
word-wrap: break-word;
134+
-webkit-line-clamp: 2;
135+
-webkit-box-orient: vertical;
136+
}
113137
}
114-
}
115-
116-
.featured-topic-image {
117-
height: 200px;
118-
max-width: 450px;
119-
width: 100%;
120-
background-size: cover;
121-
background-position: center center;
122138

123-
a {
124-
display: block;
139+
.featured-topic-image {
140+
height: 200px;
141+
max-width: 450px;
125142
width: 100%;
126-
height: 100%;
143+
background-size: cover;
144+
background-position: center center;
145+
146+
a {
147+
display: block;
148+
width: 100%;
149+
height: 100%;
150+
}
127151
}
128152
}
129153
}

javascripts/discourse/components/featured-homepage-topics.gjs

Lines changed: 114 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,20 @@ export default class FeaturedHomepageTopics extends Component {
2828
toggleTopics =
2929
this.keyValueStore.getItem("toggleTopicsState") === "true" || false;
3030

31+
@tracked currentFeaturedTopic = 0;
32+
@tracked featuredTopicsAvailable = 0;
33+
@tracked actualTopicsDisplayed = 0;
34+
3135
constructor() {
3236
super(...arguments);
3337
this.router.on("routeDidChange", this.checkShowHere);
38+
window.addEventListener("resize", this.getBannerTopics);
3439
}
3540

3641
willDestroy() {
3742
super.willDestroy(...arguments);
3843
this.router.off("routeDidChange", this.checkShowHere);
44+
window.removeEventListener("resize", this.getBannerTopics);
3945
}
4046

4147
@action
@@ -119,6 +125,20 @@ export default class FeaturedHomepageTopics extends Component {
119125
return;
120126
}
121127

128+
this.actualTopicsDisplayed = settings.number_of_topics;
129+
if (!settings.show_all_always) {
130+
// Sizes here are based on the existing resize boundaries in the CSS
131+
if (window.innerWidth <= 450) {
132+
this.actualTopicsDisplayed = Math.min(this.actualTopicsDisplayed, 1);
133+
} else if (window.innerWidth <= 600) {
134+
this.actualTopicsDisplayed = Math.min(this.actualTopicsDisplayed, 2);
135+
} else if (window.innerWidth <= 800) {
136+
this.actualTopicsDisplayed = Math.min(this.actualTopicsDisplayed, 3);
137+
} else if (window.innerWidth <= 999) {
138+
this.actualTopicsDisplayed = Math.min(this.actualTopicsDisplayed, 4);
139+
}
140+
}
141+
122142
const sortOrder = settings.sort_by_created ? "created" : "activity";
123143
const topicList = await this.store.findFiltered("topicList", {
124144
filter: "latest",
@@ -128,12 +148,58 @@ export default class FeaturedHomepageTopics extends Component {
128148
},
129149
});
130150

131-
this.featuredTagTopics = topicList.topics
151+
const filteredTopics = topicList.topics
132152
.filter(
133153
(topic) =>
134154
topic.image_url && (!settings.hide_closed_topics || !topic.closed)
135155
)
136-
.slice(0, settings.number_of_topics);
156+
.slice(
157+
0,
158+
Math.max(settings.number_of_topics, settings.max_number_of_topics)
159+
);
160+
161+
this.featuredTopicsAvailable = filteredTopics.length;
162+
163+
this.featuredTagTopics = filteredTopics.slice(
164+
this.currentFeaturedTopic,
165+
this.currentFeaturedTopic + this.actualTopicsDisplayed
166+
);
167+
}
168+
169+
get showPageArrows() {
170+
return (
171+
settings.max_number_of_topics > settings.number_of_topics &&
172+
this.featuredTopicsAvailable > settings.number_of_topics
173+
);
174+
}
175+
176+
get showLeftArrow() {
177+
return this.currentFeaturedTopic > 0;
178+
}
179+
180+
get showRightArrow() {
181+
return (
182+
this.currentFeaturedTopic <
183+
this.featuredTopicsAvailable - this.actualTopicsDisplayed - 1
184+
);
185+
}
186+
187+
@action
188+
pageLeft() {
189+
this.currentFeaturedTopic = Math.max(
190+
this.currentFeaturedTopic - this.actualTopicsDisplayed,
191+
0
192+
);
193+
this.getBannerTopics();
194+
}
195+
196+
@action
197+
pageRight() {
198+
this.currentFeaturedTopic = Math.min(
199+
this.currentFeaturedTopic + this.actualTopicsDisplayed,
200+
this.featuredTopicsAvailable - 1
201+
);
202+
this.getBannerTopics();
137203
}
138204

139205
<template>
@@ -175,30 +241,54 @@ export default class FeaturedHomepageTopics extends Component {
175241
</h2>
176242
{{/if}}
177243

178-
<div class="featured-topics">
179-
{{#each this.featuredTagTopics as |t|}}
180-
<div class="featured-topic">
181-
<div
182-
class="featured-topic-image"
183-
style={{htmlSafe
184-
(concat "background-image: url(" t.image_url ")")
185-
}}
186-
>
187-
{{! template-lint-disable no-invalid-link-text }}
188-
<a href={{this.topicHref t}}></a>
189-
</div>
190-
<h3>
191-
<a
192-
href={{this.topicHref t}}
193-
role="heading"
194-
aria-level="2"
195-
data-topic-id={{t.id}}
244+
<div class="featured-topics-controls">
245+
{{#if this.showPageArrows}}
246+
<div class="page-button-container">
247+
{{#if this.showLeftArrow}}
248+
<DButton
249+
class="page-button left-page-button"
250+
@action={{this.pageLeft}}
251+
@icon="angle-left"
252+
/>
253+
{{/if}}
254+
</div>
255+
{{/if}}
256+
<div class="featured-topics">
257+
{{#each this.featuredTagTopics as |t|}}
258+
<div class="featured-topic">
259+
<div
260+
class="featured-topic-image"
261+
style={{htmlSafe
262+
(concat "background-image: url(" t.image_url ")")
263+
}}
196264
>
197-
{{htmlSafe (this.emojiTitle t.fancy_title)}}
198-
</a>
199-
</h3>
265+
{{! template-lint-disable no-invalid-link-text }}
266+
<a href={{this.topicHref t}}></a>
267+
</div>
268+
<h3>
269+
<a
270+
href={{this.topicHref t}}
271+
role="heading"
272+
aria-level="2"
273+
data-topic-id={{t.id}}
274+
>
275+
{{htmlSafe (this.emojiTitle t.fancy_title)}}
276+
</a>
277+
</h3>
278+
</div>
279+
{{/each}}
280+
</div>
281+
{{#if this.showPageArrows}}
282+
<div class="page-button-container">
283+
{{#if this.showRightArrow}}
284+
<DButton
285+
class="page-button right-page-button"
286+
@action={{this.pageRight}}
287+
@icon="angle-right"
288+
/>
289+
{{/if}}
200290
</div>
201-
{{/each}}
291+
{{/if}}
202292
</div>
203293
</div>
204294
</div>

locales/en.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ en:
33
theme_metadata:
44
settings:
55
number_of_topics: Display up to 5 topics at max-width
6+
max_number_of_topics: Maximum number of featured topics. If set higher than number_of_topics then arrows will be displayed for paging through the topics.
67
hide_featured_tag: When enabled the tag "featured tag" set above will be invisible to normal users when viewing topics.
78
show_on: top_menu refers to pages set in the <a href="%{base_path}/admin/site_settings/category/all_results?filter=top_menu">top menu site setting</a>
89
make_collapsible: Make the entire component collapsible

0 commit comments

Comments
 (0)