mirror of
https://github.com/discourse/discourse.git
synced 2025-01-18 16:42:46 +08:00
FEATURE: user and group cards on mobile (#7246)
This commit is contained in:
parent
f072da1bfe
commit
ec2123809f
|
@ -2,6 +2,7 @@ import { setting } from "discourse/lib/computed";
|
|||
import { default as computed } from "ember-addons/ember-computed-decorators";
|
||||
import CardContentsBase from "discourse/mixins/card-contents-base";
|
||||
import CleansUp from "discourse/mixins/cleans-up";
|
||||
import { groupPath } from "discourse/lib/url";
|
||||
|
||||
const maxMembersToDisplay = 10;
|
||||
|
||||
|
@ -40,7 +41,7 @@ export default Ember.Component.extend(CardContentsBase, CleansUp, {
|
|||
|
||||
@computed("group")
|
||||
groupPath(group) {
|
||||
return `${Discourse.BaseUri}/g/${group.name}`;
|
||||
return groupPath(group.name);
|
||||
},
|
||||
|
||||
_showCallback(username, $target) {
|
||||
|
@ -88,6 +89,11 @@ export default Ember.Component.extend(CardContentsBase, CleansUp, {
|
|||
showGroup(group) {
|
||||
this.showGroup(group);
|
||||
this._close();
|
||||
},
|
||||
|
||||
showUser(user) {
|
||||
this.showUser(user);
|
||||
this._close();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -205,8 +205,8 @@ export default Ember.Component.extend(
|
|||
this._close();
|
||||
},
|
||||
|
||||
showUser() {
|
||||
this.showUser(this.get("user"));
|
||||
showUser(username) {
|
||||
this.showUser(username);
|
||||
this._close();
|
||||
},
|
||||
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
import {
|
||||
default as DiscourseURL,
|
||||
userPath,
|
||||
groupPath
|
||||
} from "discourse/lib/url";
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
topic: Ember.inject.controller(),
|
||||
application: Ember.inject.controller(),
|
||||
|
@ -9,7 +15,11 @@ export default Ember.Controller.extend({
|
|||
},
|
||||
|
||||
showUser(user) {
|
||||
this.transitionToRoute("user", user);
|
||||
DiscourseURL.routeTo(userPath(user.username_lower));
|
||||
},
|
||||
|
||||
showGroup(group) {
|
||||
DiscourseURL.routeTo(groupPath(group.name));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -52,6 +52,10 @@ export function userPath(subPath) {
|
|||
return Discourse.getURL(subPath ? `/u/${subPath}` : "/u");
|
||||
}
|
||||
|
||||
export function groupPath(subPath) {
|
||||
return Discourse.getURL(subPath ? `/g/${subPath}` : "/g");
|
||||
}
|
||||
|
||||
let _jumpScheduled = false;
|
||||
export function jumpToElement(elementId) {
|
||||
if (_jumpScheduled || Ember.isEmpty(elementId)) {
|
||||
|
|
|
@ -26,8 +26,8 @@ export default Ember.Mixin.create({
|
|||
|
||||
username = Ember.Handlebars.Utils.escapeExpression(username.toString());
|
||||
|
||||
// Don't show on mobile or nested
|
||||
if (this.site.mobileView || $target.parents(".card-content").length) {
|
||||
// Don't show if nested
|
||||
if ($target.parents(".card-content").length) {
|
||||
this._close();
|
||||
DiscourseURL.routeTo($target.attr("href"));
|
||||
return false;
|
||||
|
@ -97,10 +97,6 @@ export default Ember.Mixin.create({
|
|||
}
|
||||
|
||||
this._close();
|
||||
|
||||
if (this.site.mobileView) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -149,58 +145,67 @@ export default Ember.Mixin.create({
|
|||
|
||||
Ember.run.schedule("afterRender", () => {
|
||||
if (target) {
|
||||
let position = target.offset();
|
||||
if (position) {
|
||||
position.bottom = "unset";
|
||||
if (!this.site.mobileView) {
|
||||
let position = target.offset();
|
||||
if (position) {
|
||||
position.bottom = "unset";
|
||||
|
||||
if (rtl) {
|
||||
// The site direction is rtl
|
||||
position.right = $(window).width() - position.left + 10;
|
||||
position.left = "auto";
|
||||
let overage = $(window).width() - 50 - (position.right + width);
|
||||
if (overage < 0) {
|
||||
position.right += overage;
|
||||
position.top += target.height() + 48;
|
||||
verticalAdjustments += target.height() + 48;
|
||||
}
|
||||
} else {
|
||||
// The site direction is ltr
|
||||
position.left += target.width() + 10;
|
||||
|
||||
let overage = $(window).width() - 50 - (position.left + width);
|
||||
if (overage < 0) {
|
||||
position.left += overage;
|
||||
position.top += target.height() + 48;
|
||||
verticalAdjustments += target.height() + 48;
|
||||
}
|
||||
}
|
||||
|
||||
position.top -= $("#main-outlet").offset().top;
|
||||
if (isFixed) {
|
||||
position.top -= $("html").scrollTop();
|
||||
//if content is fixed and will be cut off on the bottom, display it above...
|
||||
if (
|
||||
position.top + height + verticalAdjustments >
|
||||
$(window).height() - 50
|
||||
) {
|
||||
position.bottom =
|
||||
$(window).height() -
|
||||
(target.offset().top - $("html").scrollTop());
|
||||
if (verticalAdjustments > 0) {
|
||||
position.bottom += 48;
|
||||
if (rtl) {
|
||||
// The site direction is rtl
|
||||
position.right = $(window).width() - position.left + 10;
|
||||
position.left = "auto";
|
||||
let overage = $(window).width() - 50 - (position.right + width);
|
||||
if (overage < 0) {
|
||||
position.right += overage;
|
||||
position.top += target.height() + 48;
|
||||
verticalAdjustments += target.height() + 48;
|
||||
}
|
||||
} else {
|
||||
// The site direction is ltr
|
||||
position.left += target.width() + 10;
|
||||
|
||||
let overage = $(window).width() - 50 - (position.left + width);
|
||||
if (overage < 0) {
|
||||
position.left += overage;
|
||||
position.top += target.height() + 48;
|
||||
verticalAdjustments += target.height() + 48;
|
||||
}
|
||||
position.top = "unset";
|
||||
}
|
||||
}
|
||||
|
||||
const avatarOverflowSize = 44;
|
||||
if (isDocked && position.top < avatarOverflowSize) {
|
||||
position.top = avatarOverflowSize;
|
||||
}
|
||||
position.top -= $("#main-outlet").offset().top;
|
||||
if (isFixed) {
|
||||
position.top -= $("html").scrollTop();
|
||||
//if content is fixed and will be cut off on the bottom, display it above...
|
||||
if (
|
||||
position.top + height + verticalAdjustments >
|
||||
$(window).height() - 50
|
||||
) {
|
||||
position.bottom =
|
||||
$(window).height() -
|
||||
(target.offset().top - $("html").scrollTop());
|
||||
if (verticalAdjustments > 0) {
|
||||
position.bottom += 48;
|
||||
}
|
||||
position.top = "unset";
|
||||
}
|
||||
}
|
||||
|
||||
this.$().css(position);
|
||||
const avatarOverflowSize = 44;
|
||||
if (isDocked && position.top < avatarOverflowSize) {
|
||||
position.top = avatarOverflowSize;
|
||||
}
|
||||
|
||||
this.$().css(position);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.site.mobileView) {
|
||||
$(".card-cloak").removeClass("hidden");
|
||||
let position = target.offset();
|
||||
position.top = "10%"; // match modal behaviour
|
||||
position.left = 0;
|
||||
this.$().css(position);
|
||||
}
|
||||
this.$().toggleClass("docked-card", isDocked);
|
||||
|
||||
// After the card is shown, focus on the first link
|
||||
|
@ -216,6 +221,9 @@ export default Ember.Mixin.create({
|
|||
_hide() {
|
||||
if (!this.get("visible")) {
|
||||
this.$().css({ left: -9999, top: -9999 });
|
||||
if (this.site.mobileView) {
|
||||
$(".card-cloak").addClass("hidden");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
<div class="card-row first-row">
|
||||
<div class="group-card-avatar">
|
||||
<a href="{{groupPath}}" {{action "showGroup" group}} class="card-huge-avatar">
|
||||
<a href {{action "showGroup" group}} class="card-huge-avatar">
|
||||
{{avatar-flair
|
||||
flairURL=group.flair_url
|
||||
flairBgColor=group.flair_bg_color
|
||||
|
@ -14,7 +14,7 @@
|
|||
<div class="names">
|
||||
<span>
|
||||
<h1 class="{{group.name}}">
|
||||
<a href="{{groupPath}}" {{action "showGroup"}}>{{group.name}}</a>
|
||||
<a href {{action "showGroup" group}} class='group-page-link'>{{group.name}}</a>
|
||||
</h1>
|
||||
{{#if group.full_name}}
|
||||
<h2 class='full-name'>{{group.full_name}}</h2>
|
||||
|
@ -23,18 +23,22 @@
|
|||
{{/if}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="usercard-controls group-details-button">
|
||||
{{group-membership-button
|
||||
<ul class="usercard-controls group-details-button">
|
||||
<li>
|
||||
{{group-membership-button
|
||||
model=group
|
||||
showLogin=(route-action "showLogin")}}
|
||||
</li>
|
||||
{{#if group.messageable}}
|
||||
{{d-button
|
||||
<li>
|
||||
{{d-button
|
||||
action=(action "messageGroup")
|
||||
class="btn-primary group-message-button inline"
|
||||
icon="envelope"
|
||||
label="groups.message"}}
|
||||
</li>
|
||||
{{/if}}
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{{#if group.bio_cooked}}
|
||||
|
@ -67,10 +71,10 @@
|
|||
<div class="card-row fourth-row">
|
||||
<div class="members metadata">
|
||||
{{#each group.members as |user|}}
|
||||
<a href="{{user.path}}" {{action "showUser" user}} class="card-tiny-avatar">{{bound-avatar user "tiny"}}</a>
|
||||
<a href {{action 'showUser' user}} class="card-tiny-avatar">{{bound-avatar user "tiny"}}</a>
|
||||
{{/each}}
|
||||
{{#if showMoreMembers}}
|
||||
<a href="{{groupPath}}" {{action "showGroup" group}} class="more-members-link"><span
|
||||
<a href {{action "showGroup" group}} class="more-members-link"><span
|
||||
class="more-members-count">+{{moreMembersCount}}
|
||||
{{i18n "more"}}</span></a>
|
||||
{{/if}}
|
||||
|
@ -79,4 +83,4 @@
|
|||
{{/if}}
|
||||
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
<div class="card-row first-row">
|
||||
<div class="user-card-avatar">
|
||||
<a href="{{user.path}}" {{action "showUser"}} class="card-huge-avatar">{{bound-avatar user "huge"}}</a>
|
||||
<a href {{action "showUser" user}} class="card-huge-avatar">{{bound-avatar user "huge"}}</a>
|
||||
{{#if user.primary_group_name}}
|
||||
{{avatar-flair
|
||||
flairURL=user.primary_group_flair_url
|
||||
|
@ -16,10 +16,12 @@
|
|||
<div class="names">
|
||||
<span>
|
||||
<h1 class="{{staff}} {{newUser}} {{if nameFirst "full-name" "username"}}">
|
||||
<a href="{{user.path}}" {{action "showUser"}}>{{if nameFirst user.name (format-username username)}}
|
||||
{{user-status user currentUser=currentUser}}</a>
|
||||
<a href {{action "showUser" user}} class='user-profile-link'>
|
||||
{{if nameFirst user.name (format-username username)}}
|
||||
{{user-status user currentUser=currentUser}}
|
||||
</a>
|
||||
</h1>
|
||||
{{plugin-outlet name="user-card-after-username" args=(hash user=user showUser=(action "showUser")) tagName=''}}
|
||||
{{plugin-outlet name="user-card-after-username" args=(hash user=user showUser=(action "showUser" user)) tagName=''}}
|
||||
{{#unless nameFirst}}
|
||||
{{#if user.name}}
|
||||
<h2 class='full-name'>{{user.name}}</h2>
|
||||
|
@ -188,9 +190,11 @@
|
|||
{{user-badge badge=ub.badge user=user}}
|
||||
{{/each}}
|
||||
{{#if showMoreBadges}}
|
||||
{{#link-to 'user.badges' user class="user-badge more-user-badges"}}
|
||||
{{i18n 'badges.more_badges' count=moreBadgesCount}}
|
||||
{{/link-to}}
|
||||
<span class='more-user-badges'>
|
||||
{{#link-to 'user.badges' user}}
|
||||
{{i18n 'badges.more_badges' count=moreBadgesCount}}
|
||||
{{/link-to}}
|
||||
</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
@ -198,4 +202,4 @@
|
|||
{{/if}}
|
||||
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
|
|
@ -1,47 +1,44 @@
|
|||
<td>
|
||||
{{~#unless expandPinned}}
|
||||
<div class='pull-left'>
|
||||
<a href="{{topic.lastPostUrl}}">{{avatar topic.lastPoster imageSize="large"}}</a>
|
||||
<a href="{{topic.lastPostUrl}}" data-user-card="{{topic.last_poster_username}}">{{avatar topic.lastPoster imageSize="large"}}</a>
|
||||
</div>
|
||||
<div class='right'>
|
||||
{{else}}
|
||||
<div>
|
||||
{{/unless~}}
|
||||
<div class='main-link'>
|
||||
{{~raw-plugin-outlet name="topic-list-before-status"}}
|
||||
{{~raw "topic-status" topic=topic~}}
|
||||
{{~topic-link topic~}}
|
||||
{{~#if topic.featured_link~}}
|
||||
{{~topic-featured-link topic~}}
|
||||
{{~/if~}}
|
||||
{{~#if topic.unseen~}}
|
||||
<span class="badge-notification new-topic"></span>
|
||||
{{~/if~}}
|
||||
{{~#if expandPinned~}}
|
||||
{{~raw "list/topic-excerpt" topic=topic~}}
|
||||
{{~/if~}}
|
||||
</div>
|
||||
|
||||
<div class='pull-right'>
|
||||
{{raw "list/post-count-or-badges" topic=topic postBadgesEnabled=showTopicPostBadges}}
|
||||
</div>
|
||||
|
||||
<div class="topic-item-stats clearfix">
|
||||
{{#unless hideCategory}}
|
||||
<div class='category'>
|
||||
{{category-link topic.category}}
|
||||
{{else}}
|
||||
<div>
|
||||
{{/unless~}}
|
||||
<div class='main-link'>
|
||||
{{~raw-plugin-outlet name="topic-list-before-status"}}
|
||||
{{~raw "topic-status" topic=topic~}}
|
||||
{{~topic-link topic~}}
|
||||
{{~#if topic.featured_link~}}
|
||||
{{~topic-featured-link topic~}}
|
||||
{{~/if~}}
|
||||
{{~#if topic.unseen~}}
|
||||
<span class="badge-notification new-topic"></span>
|
||||
{{~/if~}}
|
||||
{{~#if expandPinned~}}
|
||||
{{~raw "list/topic-excerpt" topic=topic~}}
|
||||
{{~/if~}}
|
||||
</div>
|
||||
{{/unless}}
|
||||
|
||||
{{discourse-tags topic mode="list"}}
|
||||
|
||||
<div class="pull-right">
|
||||
<div class='num activity last'>
|
||||
<span class="age activity" title="{{topic.bumpedAtTitle}}"><a href="{{topic.lastPostUrl}}">{{format-date topic.bumpedAt format="tiny" noTitle="true"}}</a></span>
|
||||
<div class='pull-right'>
|
||||
{{raw "list/post-count-or-badges" topic=topic postBadgesEnabled=showTopicPostBadges}}
|
||||
</div>
|
||||
<div class="topic-item-stats clearfix">
|
||||
{{#unless hideCategory}}
|
||||
<div class='category'>
|
||||
{{category-link topic.category}}
|
||||
</div>
|
||||
{{/unless}}
|
||||
{{discourse-tags topic mode="list"}}
|
||||
<div class="pull-right">
|
||||
<div class='num activity last'>
|
||||
<span class="age activity" title="{{topic.bumpedAtTitle}}"><a
|
||||
href="{{topic.lastPostUrl}}">{{format-date topic.bumpedAt format="tiny" noTitle="true"}}</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</td>
|
|
@ -1,3 +1,7 @@
|
|||
{{#if site.mobileView}}
|
||||
<div class="card-cloak hidden"></div>
|
||||
{{/if}}
|
||||
|
||||
{{user-card-contents
|
||||
currentPath=application.currentPath
|
||||
topic=topic.model
|
||||
|
@ -9,4 +13,5 @@
|
|||
currentPath=application.currentPath
|
||||
topic=topic.model
|
||||
showUser=(action "showUser")
|
||||
showGroup=(action "showGroup")
|
||||
createNewMessageViaParams=(route-action "createNewMessageViaParams")}}
|
||||
|
|
|
@ -5,14 +5,11 @@ $avatar_margin: -50px; // negative margin makes avatars extend above cards
|
|||
// shared styles for user and group cards
|
||||
#user-card,
|
||||
#group-card {
|
||||
position: absolute;
|
||||
width: $card_width;
|
||||
z-index: z("usercard");
|
||||
box-shadow: shadow("card");
|
||||
color: $primary;
|
||||
background: $secondary center center;
|
||||
background-size: cover;
|
||||
min-height: 175px;
|
||||
transition: opacity 0.2s, transform 0.2s;
|
||||
-webkit-transition: opacity 0.2s, -webkit-transform 0.2s;
|
||||
opacity: 0;
|
||||
|
@ -21,17 +18,8 @@ $avatar_margin: -50px; // negative margin makes avatars extend above cards
|
|||
opacity: 1;
|
||||
@include transform(scale(1));
|
||||
}
|
||||
&.fixed {
|
||||
position: fixed;
|
||||
z-index: z("composer", "content") + 1;
|
||||
}
|
||||
|
||||
&.docked-card {
|
||||
z-index: z("header") + 1;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
padding: 12px;
|
||||
padding: 10px;
|
||||
background: rgba($secondary, 0.85);
|
||||
margin-top: 80px;
|
||||
&:after {
|
||||
|
@ -44,74 +32,71 @@ $avatar_margin: -50px; // negative margin makes avatars extend above cards
|
|||
}
|
||||
}
|
||||
&.no-bg {
|
||||
min-height: 50px;
|
||||
.card-content {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
.names {
|
||||
flex: 1 1 auto;
|
||||
margin-left: 0.75em;
|
||||
span {
|
||||
display: block;
|
||||
.card-row:not(.first-row) {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
// avatar - names - controls
|
||||
.first-row {
|
||||
.names {
|
||||
padding-left: 1.25em;
|
||||
span {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.usercard-controls {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
button {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.btn {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
h1 {
|
||||
margin: 0;
|
||||
line-height: $line-height-medium;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
a {
|
||||
color: $primary;
|
||||
}
|
||||
.d-icon {
|
||||
font-size: $font-down-1;
|
||||
color: $primary;
|
||||
}
|
||||
}
|
||||
h2 {
|
||||
font-size: $font-up-1;
|
||||
margin: 0;
|
||||
font-weight: normal;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
a {
|
||||
color: $primary;
|
||||
}
|
||||
}
|
||||
h3 {
|
||||
display: inline;
|
||||
margin-right: 0.5em;
|
||||
font-size: $font-0;
|
||||
font-weight: normal;
|
||||
color: $primary;
|
||||
.desc,
|
||||
a {
|
||||
color: $primary-high;
|
||||
}
|
||||
}
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
h1,
|
||||
h2 {
|
||||
a {
|
||||
color: $primary;
|
||||
}
|
||||
}
|
||||
h2,
|
||||
h3 {
|
||||
font-weight: normal;
|
||||
}
|
||||
p {
|
||||
margin: 0 0 5px 0;
|
||||
}
|
||||
.btn {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.usercard-controls {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
button {
|
||||
width: 100%;
|
||||
min-width: 150px;
|
||||
}
|
||||
}
|
||||
.card-row:not(.first-row) {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
// styles for user cards
|
||||
// styles for user cards only
|
||||
#user-card {
|
||||
// avatar - names - controls
|
||||
.first-row {
|
||||
|
@ -121,7 +106,6 @@ $avatar_margin: -50px; // negative margin makes avatars extend above cards
|
|||
height: $avatar_width;
|
||||
}
|
||||
.user-card-avatar {
|
||||
margin-right: 10px;
|
||||
margin-top: $avatar_margin;
|
||||
}
|
||||
.new-user a {
|
||||
|
@ -196,9 +180,9 @@ $avatar_margin: -50px; // negative margin makes avatars extend above cards
|
|||
display: flex;
|
||||
align-items: flex-start;
|
||||
.user-badge {
|
||||
display: flex;
|
||||
white-space: nowrap;
|
||||
margin: 0 0.5em 0 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
background: $primary-very-low;
|
||||
border: 1px solid $primary-low;
|
||||
color: $primary;
|
||||
|
@ -206,16 +190,17 @@ $avatar_margin: -50px; // negative margin makes avatars extend above cards
|
|||
.badge-display-name {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 185px;
|
||||
}
|
||||
.more-user-badges {
|
||||
overflow: hidden;
|
||||
a {
|
||||
@extend .user-badge;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// styles for group cards
|
||||
// styles for group cards only
|
||||
#group-card {
|
||||
// avatar - names and controls
|
||||
.first-row {
|
||||
|
@ -223,19 +208,18 @@ $avatar_margin: -50px; // negative margin makes avatars extend above cards
|
|||
.group-card-avatar {
|
||||
margin-top: $avatar_margin;
|
||||
}
|
||||
.group-card-avatar {
|
||||
.avatar-flair {
|
||||
width: $avatar_width;
|
||||
height: $avatar_width;
|
||||
display: flex;
|
||||
color: $primary;
|
||||
.d-icon {
|
||||
margin: auto;
|
||||
font-size: $avatar_width / 1.5;
|
||||
}
|
||||
&.rounded {
|
||||
border-radius: 50%;
|
||||
}
|
||||
.avatar-flair {
|
||||
display: flex;
|
||||
background-size: contain;
|
||||
width: $avatar_width;
|
||||
height: $avatar_width;
|
||||
color: $primary;
|
||||
.d-icon {
|
||||
margin: auto;
|
||||
font-size: $avatar_width / 1.5;
|
||||
}
|
||||
&.rounded {
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,7 +9,6 @@
|
|||
@import "desktop/header";
|
||||
@import "desktop/login";
|
||||
@import "desktop/modal";
|
||||
@import "desktop/user-card";
|
||||
@import "desktop/category-list";
|
||||
@import "desktop/latest-topic-list";
|
||||
@import "desktop/topic-list";
|
||||
|
|
52
app/assets/stylesheets/desktop/components/user-card.scss
Normal file
52
app/assets/stylesheets/desktop/components/user-card.scss
Normal file
|
@ -0,0 +1,52 @@
|
|||
// shared styles for user and group cards
|
||||
#user-card,
|
||||
#group-card {
|
||||
position: absolute;
|
||||
z-index: z("usercard");
|
||||
&.fixed {
|
||||
position: fixed;
|
||||
z-index: z("composer", "content") + 1;
|
||||
}
|
||||
&.docked-card {
|
||||
z-index: z("header") + 1;
|
||||
}
|
||||
// avatar - names - controls
|
||||
.first-row {
|
||||
.names {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.usercard-controls {
|
||||
button {
|
||||
min-width: 150px;
|
||||
}
|
||||
}
|
||||
}
|
||||
h1 {
|
||||
.d-icon {
|
||||
font-size: $font-down-1;
|
||||
}
|
||||
}
|
||||
h2 {
|
||||
font-size: $font-up-1;
|
||||
}
|
||||
h3 {
|
||||
font-size: $font-0;
|
||||
}
|
||||
}
|
||||
|
||||
// styles for user cards only
|
||||
#user-card {
|
||||
// badges
|
||||
.sixth-row {
|
||||
.badge-section {
|
||||
.user-badge {
|
||||
display: block;
|
||||
max-width: 185px;
|
||||
margin: 0 0.5em 0 0;
|
||||
}
|
||||
.more-user-badges {
|
||||
max-width: 125px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
88
app/assets/stylesheets/mobile/components/user-card.scss
Normal file
88
app/assets/stylesheets/mobile/components/user-card.scss
Normal file
|
@ -0,0 +1,88 @@
|
|||
$avatar_width: 120px;
|
||||
|
||||
// shared styles for user and group cards
|
||||
#user-card,
|
||||
#group-card {
|
||||
position: fixed;
|
||||
// mobile cards should always be on top of everything - 1102
|
||||
z-index: z("mobile-composer") + 2;
|
||||
max-width: 95vw;
|
||||
margin: 0 2.5vw;
|
||||
max-height: 90vh;
|
||||
// avatar - names - controls
|
||||
.first-row {
|
||||
flex-wrap: wrap;
|
||||
.names {
|
||||
flex: 1 1 calc(100% - #{$avatar_width});
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.usercard-controls {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
margin-top: 1em;
|
||||
button {
|
||||
white-space: nowrap;
|
||||
}
|
||||
li {
|
||||
flex: 1;
|
||||
& + li {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
h1 {
|
||||
font-size: $font-up-3;
|
||||
.d-icon {
|
||||
font-size: $font-down-2;
|
||||
}
|
||||
}
|
||||
h2 {
|
||||
font-size: $font-0;
|
||||
}
|
||||
h3 {
|
||||
font-size: $font-down-1;
|
||||
}
|
||||
}
|
||||
|
||||
// styles for user cards only
|
||||
#user-card {
|
||||
// badges
|
||||
.sixth-row {
|
||||
.badge-section {
|
||||
flex-wrap: wrap;
|
||||
> span {
|
||||
display: flex;
|
||||
flex: 0 1 50%;
|
||||
max-width: 50%; // for text ellipsis
|
||||
padding: 2px 0;
|
||||
box-sizing: border-box;
|
||||
&:nth-of-type(1),
|
||||
&:nth-of-type(3) {
|
||||
padding-right: 4px;
|
||||
}
|
||||
a {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
.user-badge {
|
||||
display: flex;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mobile card cloak
|
||||
.card-cloak {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: z("mobile-composer") + 1; // 1101
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
background-color: rgba(black, 0.5);
|
||||
animation: fadein 0.2s;
|
||||
}
|
|
@ -132,3 +132,17 @@ blockquote {
|
|||
#simple-container {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
// this is used to provide visual feedback that indicates that the user / group
|
||||
// cards are loading after the user clicks on an avatar. It's mostly for very slow
|
||||
// connections. Users on good connections won't notice it.
|
||||
[data-user-card]:focus {
|
||||
.avatar,
|
||||
+ .avatar-flair {
|
||||
animation: wave 0.75s infinite;
|
||||
animation-delay: 0.5s;
|
||||
}
|
||||
.avatar {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -137,7 +137,6 @@
|
|||
app/assets/stylesheets/desktop/topic-post.scss | 8 +-
|
||||
app/assets/stylesheets/desktop/topic.scss | 5 +-
|
||||
app/assets/stylesheets/desktop/upload.scss | 2 +-
|
||||
app/assets/stylesheets/desktop/user-card.scss | 2 +-
|
||||
app/assets/stylesheets/desktop/user.scss | 8 -
|
||||
app/assets/stylesheets/mobile.scss | 1 +
|
||||
app/assets/stylesheets/mobile/alert.scss | 2 +
|
||||
|
|
|
@ -1,11 +1,22 @@
|
|||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import DiscourseURL from "discourse/lib/url";
|
||||
|
||||
acceptance("Group Card - Mobile", { mobileView: true });
|
||||
|
||||
QUnit.test("group card", async assert => {
|
||||
await visit("/t/301/1");
|
||||
assert.ok(invisible("#group-card"), "user card is invisible by default");
|
||||
assert.ok(
|
||||
invisible("#group-card"),
|
||||
"mobile group card is invisible by default"
|
||||
);
|
||||
|
||||
await click("a.mention-group:first");
|
||||
assert.ok(visible(".group-details-container"), "group page should be shown");
|
||||
assert.ok(visible("#group-card"), "mobile group card should appear");
|
||||
|
||||
sandbox.stub(DiscourseURL, "routeTo");
|
||||
await click(".card-content a.group-page-link");
|
||||
assert.ok(
|
||||
DiscourseURL.routeTo.calledWith("/g/discourse"),
|
||||
"it should navigate to the group page"
|
||||
);
|
||||
});
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import DiscourseURL from "discourse/lib/url";
|
||||
|
||||
acceptance("Group Card");
|
||||
|
||||
|
@ -8,4 +9,11 @@ QUnit.test("group card", async assert => {
|
|||
|
||||
await click("a.mention-group:first");
|
||||
assert.ok(visible("#group-card"), "card should appear");
|
||||
|
||||
sandbox.stub(DiscourseURL, "routeTo");
|
||||
await click(".card-content a.group-page-link");
|
||||
assert.ok(
|
||||
DiscourseURL.routeTo.calledWith("/g/discourse"),
|
||||
"it should navigate to the group page"
|
||||
);
|
||||
});
|
||||
|
|
22
test/javascripts/acceptance/user-card-mobile-test.js.es6
Normal file
22
test/javascripts/acceptance/user-card-mobile-test.js.es6
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import DiscourseURL from "discourse/lib/url";
|
||||
|
||||
acceptance("User Card - Mobile", { mobileView: true });
|
||||
|
||||
QUnit.test("user card", async assert => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
assert.ok(
|
||||
invisible("#user-card"),
|
||||
"mobile user card is invisible by default"
|
||||
);
|
||||
|
||||
await click("a[data-user-card=eviltrout]:first");
|
||||
assert.ok(visible("#user-card"), "mobile user card should appear");
|
||||
|
||||
sandbox.stub(DiscourseURL, "routeTo");
|
||||
await click(".card-content a.user-profile-link");
|
||||
assert.ok(
|
||||
DiscourseURL.routeTo.calledWith("/u/eviltrout"),
|
||||
"it should navigate to the user profile"
|
||||
);
|
||||
});
|
|
@ -4,13 +4,16 @@ import DiscourseURL from "discourse/lib/url";
|
|||
acceptance("User Card");
|
||||
|
||||
QUnit.test("user card", async assert => {
|
||||
await visit("/");
|
||||
await visit("/t/internationalization-localization/280");
|
||||
assert.ok(invisible("#user-card"), "user card is invisible by default");
|
||||
|
||||
await click("a[data-user-card=eviltrout]:first");
|
||||
assert.ok(visible("#user-card"), "card should appear");
|
||||
|
||||
sandbox.stub(DiscourseURL, "routeTo");
|
||||
await click(".card-content a.mention");
|
||||
assert.ok(DiscourseURL.routeTo.calledWith("/u/eviltrout"));
|
||||
await click(".card-content a.user-profile-link");
|
||||
assert.ok(
|
||||
DiscourseURL.routeTo.calledWith("/u/eviltrout"),
|
||||
"it should navigate to the user profile"
|
||||
);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user