UX: Show group card with animated loading state (#15253)

* Remove _calculateTopOffset entirely

* Show group card with animated loading state

Showing the animated loading state before rending the actual content prevents an
awkward scroll position jump when displaying this card.

This mimics the behaviour of the user card (which uses the same `CardContentsBase` mixin).

* Fix two user card issues

1. A JS console error (with no consequences) when clicking a group mention
2. User cards weren't being loaded from the header (for example, for PMs)

Co-authored-by: Penar Musaraj <pmusaraj@gmail.com>
This commit is contained in:
jbrw 2021-12-15 13:47:31 -05:00 committed by GitHub
parent 9fd92f329e
commit a2fcc360dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 82 additions and 78 deletions

View File

@ -41,11 +41,13 @@ export default Component.extend(CardContentsBase, CleansUp, {
},
_showCallback(username, $target) {
this.store
this._positionCard($target);
this.setProperties({ visible: true, loading: true });
return this.store
.find("group", username)
.then((group) => {
this.setProperties({ group, visible: true });
this._positionCard($target);
this.setProperties({ group });
if (!group.flair_url && !group.flair_bg_color) {
group.set("flair_url", "fa-users");
}

View File

@ -4,7 +4,6 @@ import DiscourseURL from "discourse/lib/url";
import Mixin from "@ember/object/mixin";
import afterTransition from "discourse/lib/after-transition";
import { escapeExpression } from "discourse/lib/utilities";
import headerOutletHeights from "discourse/lib/header-outlet-height";
import { inject as service } from "@ember/service";
import { wantsNewWindow } from "discourse/lib/intercept-click";
import { bind } from "discourse-common/utils/decorators";
@ -63,7 +62,7 @@ export default Mixin.create({
}
const closestArticle = target.closest("article");
const postId = closestArticle ? closestArticle.dataset.postId : null;
const postId = closestArticle?.dataset?.postId || null;
const wasVisible = this.visible;
const previousTarget = this.cardTarget;
@ -164,9 +163,9 @@ export default Mixin.create({
return false;
},
_topicHeaderTrigger(username, $target) {
_topicHeaderTrigger(username, target) {
this.setProperties({ isFixed: true, isDocked: true });
return this._show(username, $target);
return this._show(username, target);
},
_bindMobileScroll() {
@ -234,10 +233,9 @@ export default Mixin.create({
}
}
position.top -= this._calculateTopOffset(
$("#main-outlet").offset(),
headerOutletHeights()
);
// It looks better to have the card aligned slightly higher
position.top -= 24;
if (isFixed) {
position.top -= $("html").scrollTop();
//if content is fixed and will be cut off on the bottom, display it above...
@ -286,13 +284,6 @@ export default Mixin.create({
});
},
// some plugins/themes modify the page layout and may
// need to override this calculation for the card to
// position correctly
_calculateTopOffset(mainOutletOffset, outletHeights) {
return mainOutletOffset.top - outletHeights;
},
@bind
_hide() {
if (!this.visible) {

View File

@ -1,69 +1,81 @@
{{#if visible}}
<div class="card-content">
<div class="card-row first-row">
<div class="group-card-avatar">
<a href={{groupPath}} {{action "showGroup" group}} class="card-huge-avatar">
{{avatar-flair
flairName=group.name
flairUrl=group.flair_url
flairBgColor=group.flair_bg_color
flairColor=group.flair_color
}}
</a>
{{#if this.loading}}
<div class="card-row first-row">
<div class="group-card-avatar">
<div class="card-avatar-placeholder animated-placeholder placeholder-animation"></div>
</div>
</div>
<div class="names">
<span>
<h1 class={{group.name}}>
<a href={{groupPath}} {{action "showGroup" group}} class="group-page-link">{{group.name}}</a>
</h1>
{{#if group.full_name}}
<h2 class="full-name">{{group.full_name}}</h2>
{{else}}
<h2 class="username">{{group.name}}</h2>
{{/if}}
</span>
</div>
<ul class="usercard-controls group-details-button">
<li>
{{group-membership-button
model=group
showLogin=(route-action "showLogin")
}}
</li>
{{#if group.messageable}}
<li>
{{d-button
action=(action "messageGroup")
class="btn-primary group-message-button inline"
icon="envelope"
label="groups.message"
}}
</li>
{{/if}}
</ul>
</div>
{{#if this.group.bio_excerpt}}
<div class="card-row second-row">
<div class="bio">
{{html-safe this.group.bio_excerpt}}
</div>
<div class="animated-placeholder placeholder-animation"></div>
</div>
{{/if}}
{{#if group.members}}
<div class="card-row third-row">
<div class="members metadata">
{{#each group.members as |user|}}
<a {{action "close"}} href={{user.path}} class="card-tiny-avatar">{{bound-avatar user "tiny"}}</a>
{{/each}}
{{#if showMoreMembers}}
<a href={{groupPath}} {{action "showGroup" group}} class="more-members-link">
<span class="more-members-count">+{{moreMembersCount}} {{i18n "more"}}</span>
</a>
{{else}}
<div class="card-row first-row">
<div class="group-card-avatar">
<a href={{groupPath}} {{action "showGroup" group}} class="card-huge-avatar">
{{avatar-flair
flairName=group.name
flairUrl=group.flair_url
flairBgColor=group.flair_bg_color
flairColor=group.flair_color
}}
</a>
</div>
<div class="names">
<span>
<h1 class={{group.name}}>
<a href={{groupPath}} {{action "showGroup" group}} class="group-page-link">{{group.name}}</a>
</h1>
{{#if group.full_name}}
<h2 class="full-name">{{group.full_name}}</h2>
{{else}}
<h2 class="username">{{group.name}}</h2>
{{/if}}
</span>
</div>
<ul class="usercard-controls group-details-button">
<li>
{{group-membership-button
model=group
showLogin=(route-action "showLogin")
}}
</li>
{{#if group.messageable}}
<li>
{{d-button
action=(action "messageGroup")
class="btn-primary group-message-button inline"
icon="envelope"
label="groups.message"
}}
</li>
{{/if}}
</div>
</ul>
</div>
{{#if this.group.bio_excerpt}}
<div class="card-row second-row">
<div class="bio">
{{html-safe this.group.bio_excerpt}}
</div>
</div>
{{/if}}
{{#if group.members}}
<div class="card-row third-row">
<div class="members metadata">
{{#each group.members as |user|}}
<a {{action "close"}} href={{user.path}} class="card-tiny-avatar">{{bound-avatar user "tiny"}}</a>
{{/each}}
{{#if showMoreMembers}}
<a href={{groupPath}} {{action "showGroup" group}} class="more-members-link">
<span class="more-members-count">+{{moreMembersCount}} {{i18n "more"}}</span>
</a>
{{/if}}
</div>
</div>
{{/if}}
{{/if}}
</div>
{{/if}}

View File

@ -46,11 +46,10 @@ createWidget("topic-header-participant", {
},
click(e) {
const $target = $(e.target);
this.appEvents.trigger(
`topic-header:trigger-${this.attrs.type}-card`,
this.attrs.username,
$target
e.target
);
e.preventDefault();
},