diff --git a/app/assets/javascripts/discourse/components/dropdown-select-box.js.es6 b/app/assets/javascripts/discourse/components/dropdown-select-box.js.es6 new file mode 100644 index 00000000000..1135bddd019 --- /dev/null +++ b/app/assets/javascripts/discourse/components/dropdown-select-box.js.es6 @@ -0,0 +1,10 @@ +import SelectBoxComponent from "discourse/components/select-box"; + +export default SelectBoxComponent.extend({ + classNames: ["dropdown-select-box"], + wrapper: false, + verticalOffset: 3, + collectionHeight: "auto", + + selectBoxHeaderComponent: "dropdown-select-box/dropdown-header" +}); diff --git a/app/assets/javascripts/discourse/components/dropdown-select-box/dropdown-header.js.es6 b/app/assets/javascripts/discourse/components/dropdown-select-box/dropdown-header.js.es6 new file mode 100644 index 00000000000..b5ec32600f1 --- /dev/null +++ b/app/assets/javascripts/discourse/components/dropdown-select-box/dropdown-header.js.es6 @@ -0,0 +1,7 @@ +import SelectBoxHeaderComponent from "discourse/components/select-box/select-box-header"; + +export default SelectBoxHeaderComponent.extend({ + layoutName: "components/dropdown-select-box/dropdown-header", + + classNames: ["dropdown-header"], +}); diff --git a/app/assets/javascripts/discourse/components/select-box.js.es6 b/app/assets/javascripts/discourse/components/select-box.js.es6 index 8a48b9e4d3a..0fa6c33c107 100644 --- a/app/assets/javascripts/discourse/components/select-box.js.es6 +++ b/app/assets/javascripts/discourse/components/select-box.js.es6 @@ -4,7 +4,6 @@ import { iconHTML } from "discourse-common/lib/icon-library"; export default Ember.Component.extend({ layoutName: "components/select-box", - classNames: "select-box", classNameBindings: ["expanded:is-expanded"], @@ -26,7 +25,6 @@ export default Ember.Component.extend({ value: null, selectedContent: null, noContentLabel: I18n.t("select_box.no_content"), - lastHovered: null, clearSelectionLabel: null, idKey: "id", @@ -44,9 +42,10 @@ export default Ember.Component.extend({ selectBoxCollectionComponent: "select-box/select-box-collection", minWidth: 220, - maxCollectionHeight: 200, + collectionHeight: 200, verticalOffset: 0, horizontalOffset: 0, + fullWidthOnMobile: false, castInteger: false, @@ -67,16 +66,8 @@ export default Ember.Component.extend({ shouldHighlightRow: function() { return (rowComponent) => { - if (Ember.isNone(this.get("value")) && Ember.isNone(this.get("lastHovered"))) { - return false; - } - const id = this._castInteger(rowComponent.get(`content.${this.get("idKey")}`)); - if (Ember.isNone(this.get("lastHovered"))) { - return id === this.get("value"); - } else { - return id === this.get("lastHovered"); - } + return id === this.get("value"); }; }.property(), @@ -96,26 +87,46 @@ export default Ember.Component.extend({ }.property(), applyDirection() { - const offsetTop = this.$()[0].getBoundingClientRect().top; - const windowHeight = $(window).height(); + this.$().removeClass("is-above is-below is-left-aligned is-right-aligned"); + let options = { left: "auto", bottom: "auto", left: "auto", top: "auto" }; const headerHeight = this.$(".select-box-header").outerHeight(false); const filterHeight = this.$(".select-box-filter").outerHeight(false); + const collectionHeight = this.$(".select-box-collection").outerHeight(false); + const windowWidth = $(window).width(); + const windowHeight = $(window).height(); + const boundingRect = this.$()[0].getBoundingClientRect(); + const offsetTop = boundingRect.top; - if (windowHeight - (offsetTop + this.get("maxCollectionHeight") + filterHeight + headerHeight) < 0) { - this.$().addClass("is-reversed"); - this.$(".select-box-body").css({ - left: this.get("horizontalOffset"), - top: "auto", - bottom: headerHeight + this.get("verticalOffset") - }); + if (this.get("fullWidthOnMobile") && this.site.isMobileDevice) { + const margin = 10; + const relativeLeft = this.$().offset().left - $(window).scrollLeft(); + options.left = margin - relativeLeft; + options.width = windowWidth - margin * 2; } else { - this.$().removeClass("is-reversed"); - this.$(".select-box-body").css({ - left: this.get("horizontalOffset"), - top: headerHeight + this.get("verticalOffset"), - bottom: "auto" - }); + const offsetLeft = boundingRect.left; + const bodyWidth = this.$(".select-box-body").outerWidth(false); + const hasRightSpace = (windowWidth - (this.get("horizontalOffset") + offsetLeft + filterHeight + bodyWidth) > 0); + + if (hasRightSpace) { + this.$().addClass("is-left-aligned"); + options.left = this.get("horizontalOffset"); + } else { + this.$().addClass("is-right-aligned"); + options.right = this.get("horizontalOffset"); + } } + + const componentHeight = this.get("verticalOffset") + collectionHeight + filterHeight + headerHeight; + const hasBelowSpace = windowHeight - offsetTop - componentHeight > 0; + if (hasBelowSpace) { + this.$().addClass("is-below"); + options.top = headerHeight + this.get("verticalOffset"); + } else { + this.$().addClass("is-above"); + options.bottom = headerHeight + this.get("verticalOffset"); + } + + this.$(".select-box-body").css(options); }, init() { @@ -161,22 +172,22 @@ export default Ember.Component.extend({ const computedWidth = this.$().outerWidth(false); const computedHeight = this.$().outerHeight(false); - this.$(".select-box-header").css("height", computedHeight); this.$(".select-box-filter").css("height", computedHeight); + this.$(".select-box-header").css("height", computedHeight); if (this.get("expanded")) { if (this.get("scrollableParent").length === 1) { this._applyFixedPosition(computedWidth, computedHeight); } - this.$(".select-box-body").css("width", computedWidth); - this.$(".select-box-collection").css("max-height", this.get("maxCollectionHeight")); + this.$(".select-box-collection").css("max-height", this.get("collectionHeight")); - this.applyDirection(); - - if (this.get("wrapper")) { - this._positionSelectBoxWrapper(); - } + Ember.run.schedule("afterRender", () => { + this.applyDirection(); + if (this.get("wrapper")) { + this._positionSelectBoxWrapper(); + } + }); } else { if (this.get("wrapper")) { this.$(".select-box-wrapper").hide(); @@ -311,10 +322,6 @@ export default Ember.Component.extend({ onClearSelection() { this.setProperties({ value: null, expanded: false }); - }, - - onHoverRow(content) { - this.set("lastHovered", this._castInteger(content[this.get("idKey")])); } }, diff --git a/app/assets/javascripts/discourse/components/select-box/select-box-row.js.es6 b/app/assets/javascripts/discourse/components/select-box/select-box-row.js.es6 index 4c47769e197..a976769ac01 100644 --- a/app/assets/javascripts/discourse/components/select-box/select-box-row.js.es6 +++ b/app/assets/javascripts/discourse/components/select-box/select-box-row.js.es6 @@ -21,7 +21,7 @@ export default Ember.Component.extend({ return templateForRow(this); }, - @computed("shouldHighlightRow", "lastHovered", "value") + @computed("shouldHighlightRow", "value") isHighlighted(shouldHighlightRow) { return shouldHighlightRow(this); }, diff --git a/app/assets/javascripts/discourse/components/topic-footer-mobile-dropdown.js.es6 b/app/assets/javascripts/discourse/components/topic-footer-mobile-dropdown.js.es6 index af7ac645744..2395e43c786 100644 --- a/app/assets/javascripts/discourse/components/topic-footer-mobile-dropdown.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-footer-mobile-dropdown.js.es6 @@ -8,7 +8,7 @@ export default SelectBoxComponent.extend({ dynamicHeaderText: false, - maxCollectionHeight: 300, + collectionHeight: 300, init() { this._super(); diff --git a/app/assets/javascripts/discourse/components/topic-notifications-button.js.es6 b/app/assets/javascripts/discourse/components/topic-notifications-button.js.es6 index b2f5ff05112..3622f7631e5 100644 --- a/app/assets/javascripts/discourse/components/topic-notifications-button.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-notifications-button.js.es6 @@ -1,21 +1,9 @@ -import MountWidget from 'discourse/components/mount-widget'; -import { observes } from 'ember-addons/ember-computed-decorators'; +export default Ember.Component.extend({ + layoutName: "components/topic-notifications-button", -export default MountWidget.extend({ - classNames: ['topic-notifications-container'], - widget: 'topic-notifications-button', + classNames: ['topic-notifications-button'], - buildArgs() { - return { topic: this.get('topic'), appendReason: true, showFullTitle: true }; - }, + appendReason: true, - @observes('topic.details.notification_level') - _queueRerender() { - this.queueRerender(); - }, - - didInsertElement() { - this._super(); - this.dispatch('topic-notifications-button:changed', 'topic-notifications-button'); - } + showFullTitle: true }); diff --git a/app/assets/javascripts/discourse/components/topic-notifications.js.es6 b/app/assets/javascripts/discourse/components/topic-notifications.js.es6 new file mode 100644 index 00000000000..3d19b3e7c76 --- /dev/null +++ b/app/assets/javascripts/discourse/components/topic-notifications.js.es6 @@ -0,0 +1,81 @@ +import DropdownSelectBoxComponent from "discourse/components/dropdown-select-box"; +import { observes, on } from "ember-addons/ember-computed-decorators"; +import computed from "ember-addons/ember-computed-decorators"; +import { topicLevels, buttonDetails } from 'discourse/lib/notification-levels'; +import { iconHTML } from 'discourse-common/lib/icon-library'; + +export default DropdownSelectBoxComponent.extend({ + classNames: ["topic-notifications"], + + content: topicLevels, + + i18nPrefix: 'category.notifications', + i18nPostfix: '', + + textKey: "key", + showFullTitle: true, + fullWidthOnMobile: true, + + minWidth: "auto", + + @on("init") + _setInitialNotificationLevel() { + this.set("value", this.get("topic.details.notification_level")); + }, + + @on("didInsertElement") + _bindGlobalLevelChanged() { + this.appEvents.on("topic-notifications-button:changed", (msg) => { + if (msg.type === "notification") { + this.set("value", msg.id); + } + }); + }, + + @on("willDestroyElement") + _unbindGlobalLevelChanged() { + this.appEvents.off("topic-notifications-button:changed"); + }, + + @observes("value") + _notificationLevelChanged() { + this.get("topic.details").updateNotifications(this.get("value")); + this.appEvents.trigger('topic-notifications-button:changed', {type: 'notification', id: this.get("value")}); + }, + + @computed("topic.details.notification_level") + icon(notificationLevel) { + const details = buttonDetails(notificationLevel); + return iconHTML(details.icon, {class: details.key}).htmlSafe(); + }, + + @computed("topic.details.notification_level", "showFullTitle") + generatedHeadertext(notificationLevel, showFullTitle) { + if (showFullTitle) { + const details = buttonDetails(notificationLevel); + return I18n.t(`topic.notifications.${details.key}.title`); + } else { + return null; + } + }, + + templateForRow: function() { + return (rowComponent) => { + const content = rowComponent.get("content"); + const start = `${this.get('i18nPrefix')}.${content.key}${this.get('i18nPostfix')}`; + const title = I18n.t(`${start}.title`); + const description = I18n.t(`${start}.description`); + + return ` +
+ {{{topic.details.notificationReasonText}}} +
+{{/if}} diff --git a/app/assets/javascripts/discourse/templates/topic/unsubscribe.hbs b/app/assets/javascripts/discourse/templates/topic/unsubscribe.hbs index f330d1046b9..54947fbdaaa 100644 --- a/app/assets/javascripts/discourse/templates/topic/unsubscribe.hbs +++ b/app/assets/javascripts/discourse/templates/topic/unsubscribe.hbs @@ -3,8 +3,11 @@{{{stopNotificiationsText}}}
+- {{i18n "topic.unsubscribe.change_notification_state"}} {{topic-notifications-button topic=model}} + {{i18n "topic.unsubscribe.change_notification_state"}}
+ + {{topic-notifications-button topic=model}} diff --git a/app/assets/javascripts/discourse/widgets/component_connector.js.es6 b/app/assets/javascripts/discourse/widgets/component_connector.js.es6 new file mode 100644 index 00000000000..7484fad179d --- /dev/null +++ b/app/assets/javascripts/discourse/widgets/component_connector.js.es6 @@ -0,0 +1,35 @@ +export default class ComponentConnector { + constructor(widget, componentName, opts) { + this.widget = widget; + this.opts = opts; + this.componentName = componentName; + } + + init() { + const $elem = $(''); + const elem = $elem[0]; + const { opts, widget, componentName } = this; + + Ember.run.next(() => { + const mounted = widget._findView(); + + const view = widget + .register + .lookupFactory(`component:${componentName}`) + .create(opts); + + if (Ember.setOwner) { + Ember.setOwner(view, Ember.getOwner(mounted)); + } + + mounted._connected.push(view); + view.renderer.appendTo(view, $elem[0]); + }); + + return elem; + } + + update() { } +} + +ComponentConnector.prototype.type = 'Widget'; diff --git a/app/assets/javascripts/discourse/widgets/topic-notifications-button.js.es6 b/app/assets/javascripts/discourse/widgets/topic-notifications-button.js.es6 deleted file mode 100644 index 9293c36cc6f..00000000000 --- a/app/assets/javascripts/discourse/widgets/topic-notifications-button.js.es6 +++ /dev/null @@ -1,101 +0,0 @@ -import { createWidget } from 'discourse/widgets/widget'; -import { topicLevels, buttonDetails } from 'discourse/lib/notification-levels'; -import { h } from 'virtual-dom'; -import RawHTML from 'discourse/widgets/raw-html'; -import { iconNode } from 'discourse-common/lib/icon-library'; - -createWidget('notification-option', { - buildKey: attrs => `topic-notifications-button-${attrs.id}`, - tagName: 'li', - - html(attrs) { - return h('a', [ - iconNode(attrs.icon, { class: `icon ${attrs.key}`, tagName: 'span' }), - h('div', [ - h('span.title', I18n.t(`topic.notifications.${attrs.key}.title`)), - h('span.desc', I18n.t(`topic.notifications.${attrs.key}.description`)), - ]) - ]); - }, - - click() { - this.sendWidgetAction('notificationLevelChanged', this.attrs.id); - } -}); - -export default createWidget('topic-notifications-button', { - tagName: 'span.btn-group.notification-options', - buildKey: () => `topic-notifications-button`, - - defaultState() { - return { expanded: false }; - }, - - buildClasses(attrs, state) { - if (state.expanded) { return "open"; } - }, - - buildAttributes() { - return { title: I18n.t('topic.notifications.title') }; - }, - - buttonFor(level) { - const details = buttonDetails(level); - - const button = { - className: `toggle-notification-options`, - label: null, - icon: details.icon, - action: 'toggleDropdown', - iconClass: details.key - }; - - if (this.attrs.showFullTitle) { - button.label = `topic.notifications.${details.key}.title`; - } else { - button.className = 'btn toggle-notifications-options notifications-dropdown'; - } - - return this.attach('button', button); - }, - - html(attrs, state) { - const details = attrs.topic.get('details'); - const result = [ this.buttonFor(details.get('notification_level')) ]; - - if (state.expanded) { - result.push(h('ul.dropdown-menu', topicLevels.map(l => this.attach('notification-option', l)))); - } - - if (attrs.appendReason) { - result.push(new RawHTML({ html: `${details.get('notificationReasonText')}
` })); - } - - return result; - }, - - toggleDropdown() { - this.state.expanded = !this.state.expanded; - }, - - clickOutside() { - if (this.state.expanded) { - this.sendWidgetAction('toggleDropdown'); - } - }, - - notificationLevelChanged(id) { - this.state.expanded = false; - return this.attrs.topic.get('details').updateNotifications(id); - }, - - topicNotificationsButtonChanged(msg) { - switch(msg.type) { - case 'notification': - if (this.attrs.topic.get('details.notification_level') !== msg.id) { - this.notificationLevelChanged(msg.id); - } - break; - } - } -}); diff --git a/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 b/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 index 06ba9421970..2fb698a38c8 100644 --- a/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 +++ b/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 @@ -1,4 +1,5 @@ import { createWidget } from 'discourse/widgets/widget'; +import ComponentConnector from 'discourse/widgets/component_connector'; import { h } from 'virtual-dom'; import { relativeAge } from 'discourse/lib/formatter'; import { iconNode } from 'discourse-common/lib/icon-library'; @@ -313,7 +314,14 @@ createWidget('timeline-footer-controls', { } if (currentUser) { - controls.push(this.attach('topic-notifications-button', { topic })); + controls.push(new ComponentConnector(this, + 'topic-notifications-button', + { + topic, + appendReason: false, + showFullTitle: false + } + )); } return controls; diff --git a/app/assets/stylesheets/common/components/category-select-box.scss b/app/assets/stylesheets/common/components/category-select-box.scss index 48c414d7759..a68634949d2 100644 --- a/app/assets/stylesheets/common/components/category-select-box.scss +++ b/app/assets/stylesheets/common/components/category-select-box.scss @@ -1,4 +1,4 @@ -.select-box.category-select-box { +.category-select-box { .select-box-row { display: -webkit-box; display: -ms-flexbox; diff --git a/app/assets/stylesheets/common/components/dropdown-select-box.scss b/app/assets/stylesheets/common/components/dropdown-select-box.scss new file mode 100644 index 00000000000..053d14f1e9c --- /dev/null +++ b/app/assets/stylesheets/common/components/dropdown-select-box.scss @@ -0,0 +1,39 @@ +.dropdown-select-box.dropdown-select-box { + &.is-expanded { + z-index: 9999; + } + + .select-box-body { + border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + } + + .select-box-row { + margin: 0; + padding: 5px 10px; + + &.is-highlighted { + background: none; + } + + &:hover { + background: $highlight-medium; + } + } + + .dropdown-header { + padding: 0; + border: 0; + outline: 0; + justify-content: flex-start; + width: min-content; + background: none; + + .btn { + align-items: center; + justify-content: space-between; + flex-direction: row; + display: inline-flex; + height: 100%; + } + } +} diff --git a/app/assets/stylesheets/common/components/select-box.scss b/app/assets/stylesheets/common/components/select-box.scss index d56b7d381d3..d043e1623a8 100644 --- a/app/assets/stylesheets/common/components/select-box.scss +++ b/app/assets/stylesheets/common/components/select-box.scss @@ -39,14 +39,14 @@ } .collection, { - border-radius: 0 0 3px 3px; + border-radius: inherit; } .select-box-header { border-radius: 3px 3px 0 0; } - &.is-reversed { + &.is-above { .select-box-header { border-radius: 0 0 3px 3px; } @@ -61,7 +61,7 @@ } } - &.is-reversed { + &.is-above { .select-box-body { bottom: 0; top: auto; @@ -90,6 +90,15 @@ -ms-flex-align: center; align-items: center; justify-content: space-between; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + padding-left: 10px; + padding-right: 10px; &.is-focused { border: 1px solid $tertiary; @@ -97,10 +106,31 @@ -webkit-box-shadow: $tertiary 0px 0px 6px 0px; box-shadow: $tertiary 0px 0px 6px 0px; } + + .current-selection { + text-align: left; + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + color: inherit; + } + + .icon { + margin-right: 5px; + } + + .caret-icon { + margin-left: 5px; + pointer-events: none; + } } .select-box-body { display: none; + width: 100%; background: $secondary; -webkit-box-sizing: border-box; box-sizing: border-box; @@ -115,10 +145,31 @@ display: -webkit-box; display: -ms-flexbox; display: flex; - align-items: center; -webkit-box-pack: start; -ms-flex-pack: start; justify-content: flex-start; + + .text { + margin: 0; + } + + .d-icon { + margin-right: 5px; + } + + &.is-highlighted { + background: $highlight-medium; + } + + &:hover { + background: $highlight-medium; + } + + &.is-selected { + a { + background: $highlight-medium; + } + } } .select-box-collection { @@ -127,9 +178,9 @@ display: -webkit-box; display: -ms-flexbox; display: flex; - -webkit-box-flex: 1; - -ms-flex: 1; - flex: 1; + -webkit-box-flex: 0; + -ms-flex: 0 1 auto; + flex: 0 1 auto; -webkit-box-orient: vertical; -webkit-box-direction: normal; -ms-flex-direction: column; @@ -137,15 +188,68 @@ background: $secondary; overflow-x: hidden; overflow-y: auto; - border-radius: 0 0 3px 3px; + border-radius: inherit; margin: 0; padding: 0; -webkit-overflow-scrolling: touch; + + .collection { + padding: 0; + margin: 0; + + &:hover .select-box-row.is-highlighted { + background: none; + } + + &:hover .select-box-row.is-highlighted:hover { + background: $highlight-medium; + } + } + + &::-webkit-scrollbar { + -webkit-appearance: none; + width: 10px; + } + + &::-webkit-scrollbar-thumb { + cursor: pointer; + border-radius: 5px; + background: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%)); + } + + &::-webkit-scrollbar-track { + background: transparent; + border-radius: 0; + } } .select-box-filter { border-bottom: 1px solid $primary-low; background: $secondary; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + padding: 0 10px; + + .filter-query, .filter-query:focus, .filter-query:active { + background: none; + margin: 0; + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + outline: none; + border: 0; + -webkit-box-shadow: none; + box-shadow: none; + width: 100%; + padding: 5px 0; + } } .select-box-wrapper { @@ -159,132 +263,18 @@ pointer-events: none; border: 1px solid transparent; } -} -.select-box .select-box-header { - height: inherit; - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: horizontal; - -webkit-box-direction: normal; - -ms-flex-direction: row; - flex-direction: row; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - -webkit-box-pack: justify; - -ms-flex-pack: justify; - justify-content: space-between; - padding-left: 10px; - padding-right: 10px; - - .current-selection { - text-align: left; - -webkit-box-flex: 1; - -ms-flex: 1; - flex: 1; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - color: inherit; - } - - .icon { - margin-right: 5px; - } - - .caret-icon { - margin-left: 5px; - pointer-events: none; - } -} - -.select-box .select-box-collection { - -webkit-box-flex: 0; - -ms-flex: 0 1 auto; - flex: 0 1 auto; - - .collection { - padding: 0; - margin: 0; - } - - &::-webkit-scrollbar { - -webkit-appearance: none; - width: 10px; - } - - &::-webkit-scrollbar-thumb { - cursor: pointer; - border-radius: 5px; - background: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%)); - } - - &::-webkit-scrollbar-track { - background: transparent; - border-radius: 0; - } -} - -.select-box .select-box-row { - .text { - margin: 0; - } - - .d-icon { - margin-right: 5px; - } - - &.is-highlighted { - background: $highlight-medium; - } - - &.is-selected { - a { - background: $highlight-medium; - } - } -} - -.select-box .select-box-filter { - background: $secondary; - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - -webkit-box-pack: justify; - -ms-flex-pack: justify; - justify-content: space-between; - padding: 0 10px; - - .filter-query, .filter-query:focus, .filter-query:active { - background: none; - margin: 0; - -webkit-box-flex: 1; - -ms-flex: 1; - flex: 1; - outline: none; + .select-box-offscreen, .select-box .select-box-offscreen:focus { + clip: rect(0 0 0 0); + width: 1px; + height: 1px; border: 0; - -webkit-box-shadow: none; - box-shadow: none; - width: 100%; - padding: 5px 0; + margin: 0; + padding: 0; + overflow: hidden; + position: absolute; + outline: 0; + left: 0px; + top: 0px; } } - -.select-box .select-box-offscreen, .select-box .select-box-offscreen:focus { - clip: rect(0 0 0 0); - width: 1px; - height: 1px; - border: 0; - margin: 0; - padding: 0; - overflow: hidden; - position: absolute; - outline: 0; - left: 0px; - top: 0px; -} diff --git a/app/assets/stylesheets/common/components/topic-notifications.scss b/app/assets/stylesheets/common/components/topic-notifications.scss new file mode 100644 index 00000000000..8d3f5b72552 --- /dev/null +++ b/app/assets/stylesheets/common/components/topic-notifications.scss @@ -0,0 +1,89 @@ +#topic-footer-buttons .topic-notifications .btn { + margin: 0; +} + +#topic-footer-buttons p.reason { + line-height: 16px; + margin: 0 0 0 5px; +} + +.topic-notifications-button { + display: inline-flex; + justify-content: flex-start; + align-items: center; + margin: 5px 0; + + .topic-notifications, .reason { + display: inline-flex; + } +} + +.topic-notifications.topic-notifications { + display: inline-flex; + height: 30px; + + &.is-expanded .collection, &.is-expanded .select-box-collection, &.is-expanded .select-box-body { + border-radius: 0; + } + + .select-box-collection { + padding: 0; + } + + .select-box-body { + background-clip: padding-box; + border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + box-shadow: 0 1px 5px rgba(0,0,0,0.4); + width: 550px; + } + + .select-box-row { + &.is-highlighted .icons .selection-indicator { + visibility: visible; + } + + .icons { + display: flex; + align-items: flex-start; + justify-content: space-between; + align-self: flex-start; + margin-right: 10px; + + .selection-indicator { + width: 6px; + height: 6px; + background: $tertiary; + visibility: hidden; + border-radius: 12px; + align-self: center; + margin-right: 5px; + } + + .d-icon { + font-size: 1.286em; + align-self: flex-start; + margin-right: 0; + opacity: 1; + } + } + + .texts { + line-height: 18px; + flex: 1; + + .title { + font-weight: bold; + display: block; + font-size: 1em; + color: $primary; + } + + .desc { + font-size: 0.857em; + font-weight: normal; + color: #919191; + white-space: normal; + } + } + } +} diff --git a/app/assets/stylesheets/common/topic-timeline.scss b/app/assets/stylesheets/common/topic-timeline.scss index afba6f72cd3..532822ef4e7 100644 --- a/app/assets/stylesheets/common/topic-timeline.scss +++ b/app/assets/stylesheets/common/topic-timeline.scss @@ -212,6 +212,10 @@ margin-right: 0.5em; } + button:last-child { + margin-right: 0; + } + ul.dropdown-menu { right: 0.5em; top: auto; diff --git a/test/javascripts/acceptance/topic-notifications-button-test.js.es6 b/test/javascripts/acceptance/topic-notifications-button-test.js.es6 index bb1c314a1c0..e00f7d50628 100644 --- a/test/javascripts/acceptance/topic-notifications-button-test.js.es6 +++ b/test/javascripts/acceptance/topic-notifications-button-test.js.es6 @@ -19,7 +19,7 @@ acceptance("Topic Notifications button", { QUnit.test("Updating topic notification level", assert => { visit("/t/internationalization-localization/280"); - const notificationOptions = "#topic-footer-buttons .notification-options"; + const notificationOptions = "#topic-footer-buttons .topic-notifications"; andThen(() => { assert.ok( @@ -29,7 +29,7 @@ QUnit.test("Updating topic notification level", assert => { }); click(`${notificationOptions} .tracking`); - click(`${notificationOptions} .dropdown-menu .watching`); + click(`${notificationOptions} .select-box-collection .select-box-row[title=tracking]`); andThen(() => { assert.ok( @@ -44,4 +44,4 @@ QUnit.test("Updating topic notification level", assert => { // 'it should display the right notification level in topic timeline' // ); }); -}); \ No newline at end of file +}); diff --git a/test/javascripts/components/select-box-test.js.es6 b/test/javascripts/components/select-box-test.js.es6 index 94e07f17136..9028cb82e79 100644 --- a/test/javascripts/components/select-box-test.js.es6 +++ b/test/javascripts/components/select-box-test.js.es6 @@ -222,7 +222,7 @@ componentTest('persists filter state when expandind/collapsing', { }); componentTest('supports options to limit size', { - template: '{{select-box maxCollectionHeight=20 content=content}}', + template: '{{select-box collectionHeight=20 content=content}}', beforeEach() { this.set("content", [{ id: 1, text: "robin" }]);