mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-12-18 03:25:31 -05:00
UX: Move links from gutter to below posts
This commit is contained in:
parent
e9ba6e4e99
commit
4a7567b485
9 changed files with 137 additions and 182 deletions
|
@ -1,72 +0,0 @@
|
||||||
import { iconNode } from 'discourse/helpers/fa-icon';
|
|
||||||
import { createWidget } from 'discourse/widgets/widget';
|
|
||||||
import { h } from 'virtual-dom';
|
|
||||||
import RawHtml from 'discourse/widgets/raw-html';
|
|
||||||
|
|
||||||
const MAX_GUTTER_LINKS = 5;
|
|
||||||
|
|
||||||
export default createWidget('post-gutter', {
|
|
||||||
tagName: 'div.gutter',
|
|
||||||
buildKey: (attrs) => `post-gutter-${attrs.id}`,
|
|
||||||
|
|
||||||
defaultState() {
|
|
||||||
return { collapsed: true };
|
|
||||||
},
|
|
||||||
|
|
||||||
html(attrs, state) {
|
|
||||||
const links = this.attrs.links || [];
|
|
||||||
|
|
||||||
const result = [];
|
|
||||||
let toShow = links.length;
|
|
||||||
if (state.collapsed && toShow > MAX_GUTTER_LINKS) { toShow = MAX_GUTTER_LINKS; }
|
|
||||||
|
|
||||||
const seenTitles = {};
|
|
||||||
|
|
||||||
let titleCount = 0;
|
|
||||||
links.forEach(function(l) {
|
|
||||||
let title = l.title;
|
|
||||||
if (title && !seenTitles[title]) {
|
|
||||||
seenTitles[title] = true;
|
|
||||||
titleCount++;
|
|
||||||
if (result.length < toShow) {
|
|
||||||
const linkBody = [new RawHtml({html: `<span>${Discourse.Emoji.unescape(Handlebars.Utils.escapeExpression(title))}</span>`})];
|
|
||||||
if (l.clicks) {
|
|
||||||
linkBody.push(h('span.badge.badge-notification.clicks', l.clicks.toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
const className = l.reflection ? 'inbound' : 'outbound';
|
|
||||||
const link = h('a.track-link', {className, attributes: {href: l.url}}, linkBody);
|
|
||||||
result.push(h('li', link));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (state.collapsed) {
|
|
||||||
const remaining = titleCount - MAX_GUTTER_LINKS;
|
|
||||||
|
|
||||||
if (remaining > 0) {
|
|
||||||
result.push(h('li', h('a.toggle-more', I18n.t('post.more_links', {count: remaining}))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attrs.canReplyAsNewTopic) {
|
|
||||||
result.push(h('a.reply-new', [iconNode('plus'), I18n.t('post.reply_as_new_topic')]));
|
|
||||||
}
|
|
||||||
|
|
||||||
return h('ul.post-links', result);
|
|
||||||
},
|
|
||||||
|
|
||||||
click(e) {
|
|
||||||
const $target = $(e.target);
|
|
||||||
if ($target.hasClass('toggle-more')) {
|
|
||||||
this.sendWidgetAction('showAll');
|
|
||||||
} else if ($target.closest('.reply-new').length) {
|
|
||||||
this.sendWidgetAction('newTopicAction');
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
showAll() {
|
|
||||||
this.state.collapsed = false;
|
|
||||||
}
|
|
||||||
});
|
|
65
app/assets/javascripts/discourse/widgets/post-links.js.es6
Normal file
65
app/assets/javascripts/discourse/widgets/post-links.js.es6
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import { iconNode } from 'discourse/helpers/fa-icon';
|
||||||
|
import { createWidget } from 'discourse/widgets/widget';
|
||||||
|
import { h } from 'virtual-dom';
|
||||||
|
import RawHtml from 'discourse/widgets/raw-html';
|
||||||
|
|
||||||
|
export default createWidget('post-links', {
|
||||||
|
tagName: 'div.post-links-container',
|
||||||
|
buildKey: (attrs) => `post-links-${attrs.id}`,
|
||||||
|
|
||||||
|
defaultState() {
|
||||||
|
return { collapsed: true };
|
||||||
|
},
|
||||||
|
|
||||||
|
html(attrs, state) {
|
||||||
|
const links = this.attrs.links || [];
|
||||||
|
|
||||||
|
const result = [];
|
||||||
|
if (links.length) {
|
||||||
|
if (state.collapsed) {
|
||||||
|
return this.attach('link', {
|
||||||
|
labelCount: `post_links.title`,
|
||||||
|
count: links.length,
|
||||||
|
action: 'expandLinks',
|
||||||
|
className: 'expand-links'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const seenTitles = {};
|
||||||
|
|
||||||
|
let titleCount = 0;
|
||||||
|
links.forEach(function(l) {
|
||||||
|
let title = l.title;
|
||||||
|
if (title && !seenTitles[title]) {
|
||||||
|
seenTitles[title] = true;
|
||||||
|
titleCount++;
|
||||||
|
const linkBody = [new RawHtml({html: `<span>${Discourse.Emoji.unescape(Handlebars.Utils.escapeExpression(title))}</span>`})];
|
||||||
|
if (l.clicks) {
|
||||||
|
linkBody.push(h('span.badge.badge-notification.clicks', l.clicks.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push(h('li',
|
||||||
|
h('a.track-link', {
|
||||||
|
className: l.reflection ? 'inbound' : 'outbound',
|
||||||
|
attributes: {href: l.url}
|
||||||
|
}, [linkBody, iconNode(l.reflection ? 'arrow-left' : 'arrow-right')])
|
||||||
|
));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attrs.canReplyAsNewTopic) {
|
||||||
|
result.push(h('li', this.attach('link', {
|
||||||
|
className: 'reply-new',
|
||||||
|
contents: () => [I18n.t('post.reply_as_new_topic'), iconNode('plus')],
|
||||||
|
action: 'newTopicAction'
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
|
return h('ul.post-links', result);
|
||||||
|
},
|
||||||
|
|
||||||
|
expandLinks() {
|
||||||
|
this.state.collapsed = false;
|
||||||
|
}
|
||||||
|
});
|
|
@ -306,6 +306,7 @@ createWidget('post-body', {
|
||||||
if (attrs.showTopicMap) {
|
if (attrs.showTopicMap) {
|
||||||
result.push(this.attach('topic-map', attrs));
|
result.push(this.attach('topic-map', attrs));
|
||||||
}
|
}
|
||||||
|
result.push(this.attach('post-links', attrs));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -341,9 +342,7 @@ createWidget('post-article', {
|
||||||
rows.push(h('div.row', h('section.embedded-posts.top.topic-body.offset2', replies)));
|
rows.push(h('div.row', h('section.embedded-posts.top.topic-body.offset2', replies)));
|
||||||
}
|
}
|
||||||
|
|
||||||
rows.push(h('div.row', [this.attach('post-avatar', attrs),
|
rows.push(h('div.row', [this.attach('post-avatar', attrs), this.attach('post-body', attrs)]));
|
||||||
this.attach('post-body', attrs),
|
|
||||||
this.attach('post-gutter', attrs)]));
|
|
||||||
return rows;
|
return rows;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#topic-title {
|
#topic-title {
|
||||||
|
|
||||||
.title-wrapper {
|
.title-wrapper {
|
||||||
float: left;
|
float: left;
|
||||||
width: 90%;
|
width: 90%;
|
||||||
|
@ -79,3 +78,49 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.post-links-container {
|
||||||
|
@include unselectable;
|
||||||
|
clear: both;
|
||||||
|
text-align: right;
|
||||||
|
margin-top: 1em;
|
||||||
|
|
||||||
|
.expand-links {
|
||||||
|
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
|
||||||
|
}
|
||||||
|
|
||||||
|
.track-link {
|
||||||
|
padding-left: 10px;
|
||||||
|
display: inline-block;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
a[href] {
|
||||||
|
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
|
||||||
|
}
|
||||||
|
i {
|
||||||
|
font-size: 0.857em;
|
||||||
|
margin-left: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a.reply-new {
|
||||||
|
i {
|
||||||
|
background: $secondary;
|
||||||
|
border-radius: 20px;
|
||||||
|
transition: all linear .15s;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
color: $tertiary;
|
||||||
|
i {
|
||||||
|
background: dark-light-diff($tertiary, $secondary, 85%, -65%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -47,25 +47,6 @@ h1 .topic-statuses .topic-status i {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.topic-post {
|
|
||||||
.gutter {
|
|
||||||
.reply-new {
|
|
||||||
.discourse-no-touch & {
|
|
||||||
opacity:0;
|
|
||||||
transition: opacity 0.7s ease-in-out;
|
|
||||||
}
|
|
||||||
.discourse-touch & {opacity: 1;}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover .gutter, .selected .gutter {
|
|
||||||
.reply-new,
|
|
||||||
.track-link {
|
|
||||||
opacity:1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
section.post-menu-area {
|
section.post-menu-area {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
@ -637,51 +618,6 @@ blockquote {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.gutter {
|
|
||||||
margin-top: 13px;
|
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
z-index: 1;
|
|
||||||
padding-left: 757px;
|
|
||||||
|
|
||||||
ul {margin: 0;}
|
|
||||||
li {margin-bottom: 10px;}
|
|
||||||
i {font-size: 0.857em;}
|
|
||||||
|
|
||||||
.reply-new {
|
|
||||||
padding-left: 27px;
|
|
||||||
display: inline-block;
|
|
||||||
overflow:hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.track-link {
|
|
||||||
padding-left: 10px;
|
|
||||||
display: inline-block;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post-links {
|
|
||||||
list-style-type: none;
|
|
||||||
position: relative;
|
|
||||||
line-height: 18px;
|
|
||||||
word-wrap: break-word;
|
|
||||||
a i {
|
|
||||||
position: relative;
|
|
||||||
margin-right: 7px;
|
|
||||||
margin-top: -2px;
|
|
||||||
margin-left: -17px;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.toggle-more {
|
|
||||||
display: block;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// variables are used to calculate the width of .gap
|
// variables are used to calculate the width of .gap
|
||||||
$topic-body-width: 690px;
|
$topic-body-width: 690px;
|
||||||
$topic-body-width-padding: 11px;
|
$topic-body-width-padding: 11px;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-menu-area {
|
.post-menu-area {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
|
@ -53,8 +54,6 @@
|
||||||
margin-bottom: 2px;
|
margin-bottom: 2px;
|
||||||
}
|
}
|
||||||
.private-message-glyph { display: none; }
|
.private-message-glyph { display: none; }
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.private-message-glyph {
|
.private-message-glyph {
|
||||||
|
@ -64,26 +63,6 @@
|
||||||
}
|
}
|
||||||
.private_message #topic-title .private-message-glyph { display: inline; }
|
.private_message #topic-title .private-message-glyph { display: inline; }
|
||||||
|
|
||||||
a.reply-new {
|
|
||||||
margin-top: 3px;
|
|
||||||
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
|
|
||||||
i {
|
|
||||||
margin-right: 3px;
|
|
||||||
background: $secondary;
|
|
||||||
padding: 1.5px 3px;
|
|
||||||
border-radius: 20px;
|
|
||||||
transition: all linear .15s;
|
|
||||||
margin-left: -20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover.reply-new {
|
|
||||||
color: $tertiary;
|
|
||||||
i {
|
|
||||||
background: dark-light-diff($tertiary, $secondary, 85%, -65%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.topic-error {
|
.topic-error {
|
||||||
padding: 18px;
|
padding: 18px;
|
||||||
width: 60%;
|
width: 60%;
|
||||||
|
|
|
@ -143,10 +143,6 @@ button {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.reply-new {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post-actions {
|
.post-actions {
|
||||||
/* overriding display: here was causing hidden element to take up space */
|
/* overriding display: here was causing hidden element to take up space */
|
||||||
}
|
}
|
||||||
|
|
|
@ -1815,6 +1815,10 @@ en:
|
||||||
clicks:
|
clicks:
|
||||||
one: "1 click"
|
one: "1 click"
|
||||||
other: "%{count} clicks"
|
other: "%{count} clicks"
|
||||||
|
post_links:
|
||||||
|
title:
|
||||||
|
one: "1 post link"
|
||||||
|
other: "%{count} post links"
|
||||||
|
|
||||||
topic_statuses:
|
topic_statuses:
|
||||||
warning:
|
warning:
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { moduleForWidget, widgetTest } from 'helpers/widget-test';
|
import { moduleForWidget, widgetTest } from 'helpers/widget-test';
|
||||||
|
|
||||||
moduleForWidget('post-gutter');
|
moduleForWidget('post-links');
|
||||||
|
|
||||||
widgetTest("duplicate links", {
|
widgetTest("duplicate links", {
|
||||||
template: '{{mount-widget widget="post-gutter" args=args}}',
|
template: '{{mount-widget widget="post-links" args=args}}',
|
||||||
setup() {
|
setup() {
|
||||||
this.set('args', {
|
this.set('args', {
|
||||||
id: 2,
|
id: 2,
|
||||||
|
@ -14,12 +14,15 @@ widgetTest("duplicate links", {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
test(assert) {
|
test(assert) {
|
||||||
|
click('.expand-links');
|
||||||
|
andThen(() => {
|
||||||
assert.equal(this.$('.post-links a.track-link').length, 1, 'it hides the dupe link');
|
assert.equal(this.$('.post-links a.track-link').length, 1, 'it hides the dupe link');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
widgetTest("collapsed links", {
|
widgetTest("collapsed links", {
|
||||||
template: '{{mount-widget widget="post-gutter" args=args}}',
|
template: '{{mount-widget widget="post-links" args=args}}',
|
||||||
setup() {
|
setup() {
|
||||||
this.set('args', {
|
this.set('args', {
|
||||||
id: 1,
|
id: 1,
|
||||||
|
@ -35,8 +38,8 @@ widgetTest("collapsed links", {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
test(assert) {
|
test(assert) {
|
||||||
assert.equal(this.$('.post-links a.track-link').length, 5, 'collapses by default');
|
assert.ok(this.$('.expand-links').length, 'collapsed by default');
|
||||||
click('a.toggle-more');
|
click('a.expand-links');
|
||||||
andThen(() => {
|
andThen(() => {
|
||||||
assert.equal(this.$('.post-links a.track-link').length, 7);
|
assert.equal(this.$('.post-links a.track-link').length, 7);
|
||||||
});
|
});
|
||||||
|
@ -44,7 +47,7 @@ widgetTest("collapsed links", {
|
||||||
});
|
});
|
||||||
|
|
||||||
widgetTest("reply as new topic", {
|
widgetTest("reply as new topic", {
|
||||||
template: '{{mount-widget widget="post-gutter" args=args newTopicAction="newTopicAction"}}',
|
template: '{{mount-widget widget="post-links" args=args newTopicAction="newTopicAction"}}',
|
||||||
setup() {
|
setup() {
|
||||||
this.set('args', { canReplyAsNewTopic: true });
|
this.set('args', { canReplyAsNewTopic: true });
|
||||||
this.on('newTopicAction', () => this.newTopicTriggered = true);
|
this.on('newTopicAction', () => this.newTopicTriggered = true);
|
Loading…
Reference in a new issue