diff --git a/app/assets/javascripts/discourse/app/components/topic-map/topic-map-summary.gjs b/app/assets/javascripts/discourse/app/components/topic-map/topic-map-summary.gjs index 38ec0eea1c8..0979302d0d1 100644 --- a/app/assets/javascripts/discourse/app/components/topic-map/topic-map-summary.gjs +++ b/app/assets/javascripts/discourse/app/components/topic-map/topic-map-summary.gjs @@ -91,18 +91,11 @@ export default class TopicMapSummary extends Component { if (this.args.topic.has_summary) { return false; } - - return ( - [this.hasViews, this.hasLikes, this.hasUsers, this.hasLinks].filter( - Boolean - ).length === 1 - ); + return [this.hasLikes, this.hasUsers, this.hasLinks].every((stat) => !stat); } get manyStats() { - return [this.hasViews, this.hasLikes, this.hasUsers, this.hasLinks].every( - Boolean - ); + return [this.hasLikes, this.hasUsers, this.hasLinks].every(Boolean); } get shouldShowViewsChart() { @@ -127,10 +120,6 @@ export default class TopicMapSummary extends Component { return !this.allLinksShown && this.linksCount > TRUNCATED_LINKS_LIMIT; } - get hasViews() { - return this.args.topic.views > 1; - } - get hasLikes() { return ( this.args.topic.like_count > MIN_LIKES_COUNT && @@ -409,7 +398,7 @@ export default class TopicMapSummary extends Component { <:content> @@ -419,7 +408,7 @@ export default class TopicMapSummary extends Component { {{#if this.shouldShowParticipants}} {{/if}}
diff --git a/app/assets/javascripts/discourse/app/controllers/topic.js b/app/assets/javascripts/discourse/app/controllers/topic.js index 63e965acd58..7f16c7b5577 100644 --- a/app/assets/javascripts/discourse/app/controllers/topic.js +++ b/app/assets/javascripts/discourse/app/controllers/topic.js @@ -236,7 +236,11 @@ export default class TopicController extends Controller.extend( @discourseComputed("model.posts_count", "model.postStream.loadingFilter") showBottomTopicMap(postsCount, loading) { - return !loading && postsCount > MIN_POSTS_COUNT; + return ( + this.siteSettings.show_bottom_topic_map && + !loading && + postsCount > MIN_POSTS_COUNT + ); } _removeDeleteOnOwnerReplyBookmarks() { diff --git a/app/assets/javascripts/discourse/app/lib/transform-post.js b/app/assets/javascripts/discourse/app/lib/transform-post.js index 8c96353a63e..1cb2e483f83 100644 --- a/app/assets/javascripts/discourse/app/lib/transform-post.js +++ b/app/assets/javascripts/discourse/app/lib/transform-post.js @@ -169,64 +169,6 @@ export default function transformPost( postAtts.requestedGroupName = topic.requested_group_name; } - const showPMMap = - topic.archetype === "private_message" && post.post_number === 1; - if (showPMMap) { - postAtts.showPMMap = true; - postAtts.allowedGroups = details.allowed_groups; - postAtts.allowedUsers = details.allowed_users; - postAtts.canRemoveAllowedUsers = details.can_remove_allowed_users; - postAtts.canRemoveSelfId = details.can_remove_self_id; - postAtts.canInvite = details.can_invite_to; - } - - const showTopicMap = - (_additionalAttributes.includes("topicMap") && post.post_number === 1) || - showPMMap || - (post.post_number === 1 && - topic.archetype === "regular" && - topic.posts_count > 1); - if (showTopicMap) { - postAtts.showTopicMap = true; - postAtts.topicCreatedAt = topic.created_at; - postAtts.createdByUsername = createdBy.username; - postAtts.createdByAvatarTemplate = createdBy.avatar_template; - postAtts.createdByName = createdBy.name; - - postAtts.lastPostUrl = topic.get("lastPostUrl"); - if (details.last_poster) { - postAtts.lastPostUsername = details.last_poster.username; - postAtts.lastPostAvatarTemplate = details.last_poster.avatar_template; - postAtts.lastPostName = details.last_poster.name; - } - postAtts.lastPostAt = topic.last_posted_at; - - postAtts.topicReplyCount = topic.get("replyCount"); - postAtts.topicViews = topic.views; - postAtts.topicViewsHeat = topic.get("viewsHeat"); - - postAtts.participantCount = topic.participant_count; - postAtts.topicLikeCount = topic.like_count; - postAtts.topicLinks = details.links; - if (postAtts.topicLinks) { - postAtts.topicLinkLength = details.links.length; - } - postAtts.topicPostsCount = topic.posts_count; - - postAtts.participants = details.participants; - - const postStream = topic.get("postStream"); - postAtts.userFilters = postStream.userFilters; - postAtts.topicSummaryEnabled = postStream.summary; - postAtts.topicWordCount = topic.word_count; - postAtts.hasTopRepliesSummary = topic.has_summary; - postAtts.summarizable = topic.summarizable; - - if (post.post_number === 1) { - postAtts.summary = postStream.topicSummary; - } - } - if (postAtts.isDeleted) { postAtts.deletedByAvatarTemplate = post.get( "postDeletedBy.avatar_template" diff --git a/app/assets/javascripts/discourse/app/widgets/post.js b/app/assets/javascripts/discourse/app/widgets/post.js index 443133b72ee..aa8ee9a5834 100644 --- a/app/assets/javascripts/discourse/app/widgets/post.js +++ b/app/assets/javascripts/discourse/app/widgets/post.js @@ -831,7 +831,7 @@ createWidget("post-article", { ]) ); - if (attrs.showTopicMap) { + if (this.shouldShowTopicMap(attrs)) { rows.push(this.buildTopicMap(attrs)); } @@ -900,6 +900,22 @@ createWidget("post-article", { } }, + shouldShowTopicMap(attrs) { + if (attrs.post_number !== 1) { + return false; + } + const isPM = attrs.topic.archetype === "private_message"; + const isRegular = attrs.topic.archetype === "regular"; + const showWithoutReplies = + this.siteSettings.show_topic_map_in_topics_without_replies; + + return ( + attrs.topicMap || + isPM || + (isRegular && (attrs.topic.posts_count > 1 || showWithoutReplies)) + ); + }, + buildTopicMap(attrs) { return new RenderGlimmer( this, @@ -917,7 +933,7 @@ createWidget("post-article", { model: attrs.topic, topicDetails: attrs.topic.get("details"), postStream: attrs.topic.postStream, - showPMMap: attrs.showPMMap, + showPMMap: attrs.topic.archetype === "private_message", showInvite: () => this.sendWidgetAction("showInvite"), removeAllowedGroup: (group) => this.sendWidgetAction("removeAllowedGroup", group), diff --git a/app/assets/javascripts/discourse/tests/integration/components/widgets/post-test.js b/app/assets/javascripts/discourse/tests/integration/components/widgets/post-test.js index 4ac74c9b48f..13344564b13 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/widgets/post-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/widgets/post-test.js @@ -16,7 +16,13 @@ module("Integration | Component | Widget | post", function (hooks) { setupRenderingTest(hooks); test("basic elements", async function (assert) { - this.set("args", { shareUrl: "/example", post_number: 1 }); + const store = getOwner(this).lookup("service:store"); + const topic = store.createRecord("topic", { + id: 123, + archetype: "regular", + }); + + this.set("args", { shareUrl: "/example", post_number: 1, topic }); await render(hbs``); @@ -771,12 +777,29 @@ module("Integration | Component | Widget | post", function (hooks) { assert.strictEqual(count("section.embedded-posts .d-icon-arrow-down"), 1); }); - test("topic map not shown", async function (assert) { - this.set("args", { showTopicMap: false }); + test("shows the topic map when setting the 'topicMap' attribute", async function (assert) { + const store = getOwner(this).lookup("service:store"); + const topic = store.createRecord("topic", { id: 123 }); + this.set("args", { topic, post_number: 1, topicMap: true }); await render(hbs``); - assert.dom(".topic-map").doesNotExist(); + assert.dom(".topic-map").exists(); + }); + + test("shows the topic map when no replies", async function (assert) { + this.siteSettings.show_topic_map_in_topics_without_replies = true; + + const store = getOwner(this).lookup("service:store"); + const topic = store.createRecord("topic", { + id: 123, + archetype: "regular", + }); + this.set("args", { topic, post_number: 1 }); + + await render(hbs``); + + assert.dom(".topic-map").exists(); }); test("topic map - few participants", async function (assert) { @@ -785,6 +808,7 @@ module("Integration | Component | Widget | post", function (hooks) { id: 123, posts_count: 10, participant_count: 2, + archetype: "regular", }); topic.details.set("participants", [ { username: "eviltrout" }, @@ -792,7 +816,7 @@ module("Integration | Component | Widget | post", function (hooks) { ]); this.set("args", { topic, - showTopicMap: true, + post_number: 1, }); await render(hbs``); @@ -806,6 +830,7 @@ module("Integration | Component | Widget | post", function (hooks) { id: 123, posts_count: 10, participant_count: 6, + archetype: "regular", }); topic.postStream.setProperties({ userFilters: ["sam", "codinghorror"] }); topic.details.set("participants", [ @@ -819,7 +844,7 @@ module("Integration | Component | Widget | post", function (hooks) { this.set("args", { topic, - showTopicMap: true, + post_number: 1, }); await render(hbs``); @@ -833,7 +858,11 @@ module("Integration | Component | Widget | post", function (hooks) { test("topic map - links", async function (assert) { const store = getOwner(this).lookup("service:store"); - const topic = store.createRecord("topic", { id: 123 }); + const topic = store.createRecord("topic", { + id: 123, + posts_count: 2, + archetype: "regular", + }); topic.details.set("links", [ { url: "http://link1.example.com", clicks: 0 }, { url: "http://link2.example.com", clicks: 0 }, @@ -842,7 +871,7 @@ module("Integration | Component | Widget | post", function (hooks) { { url: "http://link5.example.com", clicks: 0 }, { url: "http://link6.example.com", clicks: 0 }, ]); - this.set("args", { topic, showTopicMap: true }); + this.set("args", { topic, post_number: 1 }); await render(hbs``); @@ -857,18 +886,28 @@ module("Integration | Component | Widget | post", function (hooks) { test("topic map - no top reply summary", async function (assert) { const store = getOwner(this).lookup("service:store"); - const topic = store.createRecord("topic", { id: 123 }); - this.set("args", { topic, showTopicMap: true }); + const topic = store.createRecord("topic", { + id: 123, + archetype: "regular", + posts_count: 2, + }); + this.set("args", { topic, post_number: 1 }); await render(hbs``); + assert.dom(".topic-map").exists(); assert.dom(".summarization-button .top-replies").doesNotExist(); }); test("topic map - has top replies summary", async function (assert) { const store = getOwner(this).lookup("service:store"); - const topic = store.createRecord("topic", { id: 123, has_summary: true }); - this.set("args", { topic, showTopicMap: true }); + const topic = store.createRecord("topic", { + id: 123, + archetype: "regular", + posts_count: 2, + has_summary: true, + }); + this.set("args", { topic, post_number: 1 }); await render(hbs``); @@ -877,14 +916,16 @@ module("Integration | Component | Widget | post", function (hooks) { test("pm map", async function (assert) { const store = getOwner(this).lookup("service:store"); - const topic = store.createRecord("topic", { id: 123 }); + const topic = store.createRecord("topic", { + id: 123, + archetype: "private_message", + }); topic.details.set("allowed_users", [ EmberObject.create({ username: "eviltrout" }), ]); this.set("args", { topic, - showTopicMap: true, - showPMMap: true, + post_number: 1, }); await render(hbs``); diff --git a/app/assets/stylesheets/common/components/topic-map.scss b/app/assets/stylesheets/common/components/topic-map.scss index 42d5e911f11..a3ee9b1ddf1 100644 --- a/app/assets/stylesheets/common/components/topic-map.scss +++ b/app/assets/stylesheets/common/components/topic-map.scss @@ -2,6 +2,10 @@ // topic map under OP border-top: 1px solid var(--primary-low); border-bottom: none; + + padding-left: calc( + var(--topic-body-width-padding) + var(--topic-avatar-width) + ); } .topic-map.--bottom { @@ -44,14 +48,13 @@ body:not(.archetype-private_message) { font-size: var(--font-down-1); } - @media screen and (max-width: 500px) { - padding-left: 0; + &.--op, + &.--bottom { + @media screen and (max-width: 500px) { + padding-left: 0; + } } - padding-left: calc( - var(--topic-body-width-padding) + var(--topic-avatar-width) - ); - .--users-summary { display: flex; flex-wrap: wrap; @@ -158,6 +161,7 @@ body:not(.archetype-private_message) { .number { color: var(--tertiary); + white-space: nowrap; } .topic-map__stat-label { @@ -310,9 +314,10 @@ body:not(.archetype-private_message) { // DMenu popups -.topic-map__likes-content { +.topic-map__likes-content.fk-d-menu__content { .fk-d-menu__inner-content, .d-modal__body { + padding-bottom: 0.5em; ul { margin: 0; padding: 0; @@ -455,14 +460,18 @@ body:not(.archetype-private_message) { color: var(--primary-medium); } - .link-summary .btn { + .link-summary { width: 100%; - .d-icon { - color: var(--primary-high); - } - .discourse-no-touch & { - &:hover { - background: var(--primary-low); + + .btn { + width: 100%; + .d-icon { + color: var(--primary-high); + } + .discourse-no-touch & { + &:hover { + background: var(--primary-low); + } } } } diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index b7a01da27cb..ed20eb9ce05 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -2664,6 +2664,8 @@ en: use_email_for_username_and_name_suggestions: "Use the first part of email addresses for username and name suggestions. Note that this makes it easier for the public to guess full user email addresses (because a large proportion of people share common services like `gmail.com`)." use_name_for_username_suggestions: "Use a user's full name when suggesting usernames." suggest_weekends_in_date_pickers: "Include weekends (Saturday and Sunday) in date picker suggestions (disable this if you use Discourse only on weekdays, Monday through Friday)." + show_bottom_topic_map: "Shows the topic map at the bottom of the topic when it has 10 replies or more." + show_topic_map_in_topics_without_replies: "Shows the topic map even if the topic has no replies." splash_screen: "Displays a temporary loading screen while site assets load" navigation_menu: "Specify sidebar or header dropdown as the main navigation menu for your site. Sidebar is recommended." diff --git a/config/site_settings.yml b/config/site_settings.yml index 472b3cd2e2d..9d20048180b 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -2976,6 +2976,14 @@ uncategorized: client: true default: true + show_bottom_topic_map: + client: true + default: true + + show_topic_map_in_topics_without_replies: + client: true + default: false + user_preferences: default_email_digest_frequency: enum: "DigestEmailSiteSetting" diff --git a/plugins/styleguide/assets/javascripts/discourse/lib/dummy-data.js b/plugins/styleguide/assets/javascripts/discourse/lib/dummy-data.js index d1fece440cb..980e5a9f31d 100644 --- a/plugins/styleguide/assets/javascripts/discourse/lib/dummy-data.js +++ b/plugins/styleguide/assets/javascripts/discourse/lib/dummy-data.js @@ -168,32 +168,7 @@ export function createData(store) { canBookmark: true, canManage: true, canDelete: true, - createdByUsername: user.username, - createdByAvatarTemplate: user.avatar_template, - lastPostUsername: user.username, - lastPostAvatarTemplate: user.avatar_template, - topicReplyCount: 123, - topicViews: 3456, - participantCount: 10, - topicLikeCount: 14, - topicLinkLength: 5, - topicPostsCount: 4, - participants: [createUser(), createUser(), createUser(), createUser()], post_number: 1, - topicLinks: [ - { - title: "Evil Trout", - url: "https://eviltrout.com", - domain: "eviltrout.com", - clicks: 1024, - }, - { - title: "Cool Site", - url: "http://coolsite.example.com", - domain: "coolsite.example.com", - clicks: 512, - }, - ], }; const postModel = store.createRecord("post", {