From 0bb07d395a9167aefe5d625f14178a4c19d3723a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Wed, 8 Nov 2017 10:39:26 +0100 Subject: [PATCH] REFACTOR: composer to use flexbox --- .../discourse/components/composer-body.js.es6 | 14 +- .../components/composer-editor.js.es6 | 82 +--- .../discourse/controllers/composer.js.es6 | 28 +- .../templates/components/composer-editor.hbs | 26 +- .../templates/components/d-editor.hbs | 26 +- .../discourse/templates/composer.hbs | 257 ++++++----- .../stylesheets/common/base/compose.scss | 267 ++++++++--- app/assets/stylesheets/common/d-editor.scss | 119 +++-- app/assets/stylesheets/desktop/compose.scss | 382 +--------------- app/assets/stylesheets/mobile/compose.scss | 427 +++++------------- 10 files changed, 604 insertions(+), 1024 deletions(-) diff --git a/app/assets/javascripts/discourse/components/composer-body.js.es6 b/app/assets/javascripts/discourse/components/composer-body.js.es6 index 1d193b52575..8df136d3724 100644 --- a/app/assets/javascripts/discourse/components/composer-body.js.es6 +++ b/app/assets/javascripts/discourse/components/composer-body.js.es6 @@ -15,6 +15,7 @@ export default Ember.Component.extend(KeyEnterEscape, { 'composer.createdPost:created-post', 'composer.creatingTopic:topic', 'composer.whisper:composing-whisper', + 'showPreview:show-preview:hide-preview', 'currentUserPrimaryGroupClass'], @computed("currentUser.primary_group_name") @@ -41,19 +42,6 @@ export default Ember.Component.extend(KeyEnterEscape, { const h = $('#reply-control').height() || 0; this.movePanels(h + "px"); - - // Figure out the size of the fields - const $fields = this.$('.composer-fields'); - const fieldPos = $fields.position(); - if (fieldPos) { - this.$('.wmd-controls').css('top', $fields.height() + fieldPos.top + 5); - } - - // get the submit panel height - const submitPos = this.$('.submit-panel').position(); - if (submitPos) { - this.$('.wmd-controls').css('bottom', h - submitPos.top + 7); - } }); }, diff --git a/app/assets/javascripts/discourse/components/composer-editor.js.es6 b/app/assets/javascripts/discourse/components/composer-editor.js.es6 index 424a7bcd25f..8c5dc774758 100644 --- a/app/assets/javascripts/discourse/components/composer-editor.js.es6 +++ b/app/assets/javascripts/discourse/components/composer-editor.js.es6 @@ -1,5 +1,5 @@ import userSearch from 'discourse/lib/user-search'; -import { default as computed, on, observes } from 'ember-addons/ember-computed-decorators'; +import { default as computed, on } from 'ember-addons/ember-computed-decorators'; import { linkSeenMentions, fetchUnseenMentions } from 'discourse/lib/link-mentions'; import { linkSeenCategoryHashtags, fetchUnseenCategoryHashtags } from 'discourse/lib/link-category-hashtags'; import { linkSeenTagHashtags, fetchUnseenTagHashtags } from 'discourse/lib/link-tag-hashtag'; @@ -18,11 +18,9 @@ import { lookupCachedUploadUrl, cacheShortUploadUrl } from 'pretty-text/image-short-url'; export default Ember.Component.extend({ - classNames: ['wmd-controls'], - classNameBindings: ['showToolbar:toolbar-visible', ':wmd-controls', 'showPreview', 'showPreview::hide-preview'], + classNameBindings: ['showToolbar:toolbar-visible', ':wmd-controls'], uploadProgress: 0, - showPreview: true, _xhr: null, @computed @@ -30,35 +28,6 @@ export default Ember.Component.extend({ return `[${I18n.t('uploading')}]() `; }, - @on('init') - _setupPreview() { - const val = (this.site.mobileView ? false : (this.keyValueStore.get('composer.showPreview') || 'true')); - this.set('showPreview', val === 'true'); - - this.appEvents.on('composer:show-preview', () => { - this.set('showPreview', true); - }); - - this.appEvents.on('composer:hide-preview', () => { - this.set('showPreview', false); - }); - }, - - @computed('site.mobileView', 'showPreview') - forcePreview(mobileView, showPreview) { - return mobileView && showPreview; - }, - - @computed('showPreview') - toggleText: function(showPreview) { - return showPreview ? I18n.t('composer.hide_preview') : I18n.t('composer.show_preview'); - }, - - @observes('showPreview') - showPreviewChanged() { - this.keyValueStore.set({ key: 'composer.showPreview', value: this.get('showPreview') }); - }, - @computed markdownOptions() { return { @@ -363,7 +332,7 @@ export default Ember.Component.extend({ }); if (this.site.mobileView) { - this.$(".mobile-file-upload").on("click.uploader", function () { + $("#reply-control .mobile-file-upload").on("click.uploader", function () { // redirect the click on the hidden file input $("#mobile-uploader").click(); }); @@ -373,29 +342,28 @@ export default Ember.Component.extend({ }, _optionsLocation() { - // long term we want some smart positioning algorithm in popup-menu - // the problem is that positioning in a fixed panel is a nightmare - // cause offsetParent can end up returning a fixed element and then - // using offset() is not going to work, so you end up needing special logic - // especially since we allow for negative .top, provided there is room on screen - const myPos = this.$().position(); - const buttonPos = this.$('.options').position(); + const composer = $("#reply-control"); + const composerOffset = composer.offset(); + const composerPosition = composer.position(); - const popupHeight = $('#reply-control .popup-menu').height(); - const popupWidth = $('#reply-control .popup-menu').width(); + const buttonBarOffset = $('#reply-control .d-editor-button-bar').offset(); + const optionsButton = $('#reply-control .d-editor-button-bar .options'); - var top = myPos.top + buttonPos.top - 15; - var left = myPos.left + buttonPos.left - (popupWidth/2); + const popupMenu = $("#reply-control .popup-menu"); + const popupWidth = popupMenu.outerWidth(); + const popupHeight = popupMenu.outerHeight(); - const composerPos = $('#reply-control').position(); + const headerHeight = $(".d-header").outerHeight(); - if (composerPos.top + top - popupHeight < 0) { - top = top + popupHeight + this.$('.options').height() + 50; + let left = optionsButton.offset().left - composerOffset.left; + let top = buttonBarOffset.top - composerOffset.top - popupHeight + popupMenu.innerHeight(); + + if (top + composerPosition.top - headerHeight - popupHeight < 0) { + top += popupHeight + optionsButton.outerHeight(); } - var replyWidth = $('#reply-control').width(); - if (left + popupWidth > replyWidth) { - left = replyWidth - popupWidth - 40; + if (left + popupWidth > composer.width()) { + left -= popupWidth - optionsButton.outerWidth(); } return { position: "absolute", left, top }; @@ -493,7 +461,7 @@ export default Ember.Component.extend({ @on('willDestroyElement') _unbindUploadTarget() { this._validUploads = 0; - this.$(".mobile-file-upload").off("click.uploader"); + $("#reply-control .mobile-file-upload").off("click.uploader"); this.messageBus.unsubscribe("/uploads/composer"); const $uploadTarget = this.$(); try { $uploadTarget.fileupload("destroy"); } @@ -504,8 +472,6 @@ export default Ember.Component.extend({ @on('willDestroyElement') _composerClosed() { this.appEvents.trigger('composer:will-close'); - this.appEvents.off('composer:show-preview'); - this.appEvents.off('composer:hide-preview'); Ember.run.next(() => { $('#main-outlet').css('padding-bottom', 0); // need to wait a bit for the "slide down" transition of the composer @@ -541,12 +507,12 @@ export default Ember.Component.extend({ } }, - showUploadModal(toolbarEvent) { - this.sendAction('showUploadSelector', toolbarEvent); + togglePreview() { + this.sendAction('togglePreview'); }, - togglePreview() { - this.toggleProperty('showPreview'); + showUploadModal(toolbarEvent) { + this.sendAction('showUploadSelector', toolbarEvent); }, extraButtons(toolbar) { diff --git a/app/assets/javascripts/discourse/controllers/composer.js.es6 b/app/assets/javascripts/discourse/controllers/composer.js.es6 index 506bee7e02d..e33fe3a2561 100644 --- a/app/assets/javascripts/discourse/controllers/composer.js.es6 +++ b/app/assets/javascripts/discourse/controllers/composer.js.es6 @@ -2,7 +2,7 @@ import DiscourseURL from 'discourse/lib/url'; import Quote from 'discourse/lib/quote'; import Draft from 'discourse/models/draft'; import Composer from 'discourse/models/composer'; -import { default as computed, observes } from 'ember-addons/ember-computed-decorators'; +import { default as computed, observes, on } from 'ember-addons/ember-computed-decorators'; import InputValidation from 'discourse/models/input-validation'; import { getOwner } from 'discourse-common/lib/get-owner'; import { escapeExpression } from 'discourse/lib/utilities'; @@ -68,9 +68,27 @@ export default Ember.Controller.extend({ isUploading: false, topic: null, linkLookup: null, + showPreview: true, + forcePreview: Ember.computed.and('site.mobileView', 'showPreview'), whisperOrUnlistTopic: Ember.computed.or('model.whisper', 'model.unlistTopic'), categories: Ember.computed.alias('site.categoriesList'), + @on('init') + _setupPreview() { + const val = (this.site.mobileView ? false : (this.keyValueStore.get('composer.showPreview') || 'true')); + this.set('showPreview', val === 'true'); + }, + + @computed('showPreview') + toggleText: function(showPreview) { + return showPreview ? I18n.t('composer.hide_preview') : I18n.t('composer.show_preview'); + }, + + @observes('showPreview') + showPreviewChanged() { + this.keyValueStore.set({ key: 'composer.showPreview', value: this.get('showPreview') }); + }, + @computed('model.replyingToTopic', 'model.creatingPrivateMessage', 'model.targetUsernames') focusTarget(replyingToTopic, creatingPM, usernames) { if (this.capabilities.isIOS) { return "none"; } @@ -206,6 +224,10 @@ export default Ember.Controller.extend({ actions: { + togglePreview() { + this.toggleProperty('showPreview'); + }, + typed() { this.checkReplyLength(); this.get('model').typing(); @@ -291,10 +313,6 @@ export default Ember.Controller.extend({ return false; }, - togglePreview() { - this.get('model').togglePreview(); - }, - // Import a quote from the post importQuote(toolbarEvent) { const postStream = this.get('topic.postStream'); diff --git a/app/assets/javascripts/discourse/templates/components/composer-editor.hbs b/app/assets/javascripts/discourse/templates/components/composer-editor.hbs index 3d3f6fc8eb9..bf6dcecd21f 100644 --- a/app/assets/javascripts/discourse/templates/components/composer-editor.hbs +++ b/app/assets/javascripts/discourse/templates/components/composer-editor.hbs @@ -13,28 +13,6 @@ forcePreview=forcePreview composerEvents=true}} -
- {{#if site.mobileView}} +{{#if site.mobileView}} - {{i18n 'upload'}} - - {{#if showPreview}} - {{d-button action='togglePreview' class='hide-preview' label='composer.hide_preview'}} - {{/if}} - {{else}} - {{{toggleText}}} - {{/if}} - - {{#if isUploading}} -
- {{loading-spinner size="small"}} {{i18n 'upload_selector.uploading'}} - {{uploadProgress}}% - {{#if isCancellable}} - {{d-icon "times"}} - {{/if}} -
- {{/if}} -
- {{draftStatus}} -
-
+{{/if}} diff --git a/app/assets/javascripts/discourse/templates/components/d-editor.hbs b/app/assets/javascripts/discourse/templates/components/d-editor.hbs index 961b63c6efd..c928412ebc4 100644 --- a/app/assets/javascripts/discourse/templates/components/d-editor.hbs +++ b/app/assets/javascripts/discourse/templates/components/d-editor.hbs @@ -1,4 +1,5 @@ +
{{#d-editor-modal class="insert-link" hidden=insertLinkHidden okAction="insertLink"}}

{{i18n "composer.link_dialog_title"}}

@@ -8,19 +9,18 @@
-
- {{#each toolbar.groups as |group|}} - {{#each group.buttons as |b|}} - {{d-button action=b.action actionParam=b translatedTitle=b.title label=b.label icon=b.icon class=b.className}} - {{/each}} - {{#unless group.lastGroup}} -
- {{/unless}} - {{/each}} -
-
-
+
+ {{#each toolbar.groups as |group|}} + {{#each group.buttons as |b|}} + {{d-button action=b.action actionParam=b translatedTitle=b.title label=b.label icon=b.icon class=b.className}} + {{/each}} + {{#unless group.lastGroup}} +
+ {{/unless}} + {{/each}} +
+ {{conditional-loading-spinner condition=loading}} {{textarea tabindex=tabindex value=value class="d-editor-input" placeholder=placeholderTranslated}} {{popup-input-tip validation=validation}} @@ -30,7 +30,7 @@
{{{preview}}}
- {{plugin-outlet name="editor-preview"}} + {{plugin-outlet name="editor-preview" classNames="d-editor-plugin"}}
diff --git a/app/assets/javascripts/discourse/templates/composer.hbs b/app/assets/javascripts/discourse/templates/composer.hbs index 98ad6257f1e..4cf90be63b9 100644 --- a/app/assets/javascripts/discourse/templates/composer.hbs +++ b/app/assets/javascripts/discourse/templates/composer.hbs @@ -1,11 +1,11 @@ -{{#composer-body - composer=model - openIfDraft="openIfDraft" - typed="typed" - cancelled="cancelled" - save="save"}} +{{#composer-body composer=model + showPreview=showPreview + openIfDraft="openIfDraft" + typed="typed" + cancelled="cancelled" + save="save"}} + {{#if visible}} -
{{#if showPopupMenu}} {{#popup-menu visible=optionsVisible hide="hideOptions" title="composer.options"}} @@ -19,134 +19,169 @@ {{/popup-menu}} {{/if}} - {{composer-messages composer=model messageCount=messageCount addLinkLookup="addLinkLookup"}} + {{composer-messages composer=model + messageCount=messageCount + addLinkLookup="addLinkLookup"}} -
- {{composer-toggles - composeState=model.composeState - toggleComposer=(action "toggle") - toggleToolbar=(action "toggleToolbar")}} + {{composer-toggles composeState=model.composeState + toggleComposer=(action "toggle") + toggleToolbar=(action "toggleToolbar")}} - {{#if model.viewOpen}} -
-
- {{plugin-outlet name="composer-open" args=(hash model=model)}} + {{#if model.viewOpen}} -
- {{{model.actionTitle}}} - {{#unless site.mobileView}} +
+ +
+ + {{plugin-outlet name="composer-open" args=(hash model=model)}} + +
+ {{{model.actionTitle}}} + + {{#unless site.mobileView}} {{#if whisperOrUnlistTopicText}} ({{whisperOrUnlistTopicText}}) {{/if}} - {{/unless}} + {{/unless}} - {{#if canEdit}} - {{#if showEditReason}} -
- {{text-field autofocus="true" value=editReason tabindex="7" id="edit-reason" maxlength="255" placeholderKey="composer.edit_reason_placeholder"}} -
- {{else}} - {{i18n 'composer.show_edit_reason'}} - {{/if}} + {{#if canEdit}} + {{#if showEditReason}} + {{text-field autofocus="true" value=editReason tabindex="7" id="edit-reason" maxlength="255" placeholderKey="composer.edit_reason_placeholder"}} + {{else}} + {{i18n 'composer.show_edit_reason'}} {{/if}} -
+ {{/if}} +
- {{#if model.canEditTitle}} -
- {{#if model.creatingPrivateMessage}} - {{composer-user-selector topicId=topicModel.id - usernames=model.targetUsernames - hasGroups=model.hasTargetGroups - focusTarget=focusTarget}} - {{#if showWarning}} -
- -
- {{/if}} - {{/if}} - - {{composer-title composer=model lastValidatedAt=lastValidatedAt focusTarget=focusTarget}} - - {{#if model.showCategoryChooser}} -
- {{category-chooser value=model.categoryId scopedCategoryId=scopedCategoryId tabindex="3"}} - {{popup-input-tip validation=categoryValidation}} -
- {{#if model.archetype.hasOptions}} - {{d-button action="showOptions" label="topic.options"}} - {{/if}} + {{#if model.canEditTitle}} + {{#if model.creatingPrivateMessage}} +
+ {{composer-user-selector topicId=topicModel.id + usernames=model.targetUsernames + hasGroups=model.hasTargetGroups + focusTarget=focusTarget + class="users-input"}} + {{#if showWarning}} + {{/if}}
{{/if}} - {{plugin-outlet name="composer-fields" args=(hash model=model)}} -
- {{composer-editor topic=topic - composer=model - lastValidatedAt=lastValidatedAt - canWhisper=canWhisper - showPopupMenu=showPopupMenu - draftStatus=model.draftStatus - isUploading=isUploading - groupsMentioned="groupsMentioned" - cannotSeeMention="cannotSeeMention" - importQuote="importQuote" - showOptions="showOptions" - hideOptions="hideOptions" - optionsVisible=optionsVisible - showToolbar=showToolbar - showUploadSelector="showUploadSelector" - afterRefresh="afterRefresh"}} +
- {{#if currentUser}} -
- {{plugin-outlet name="composer-fields-below" args=(hash model=model)}} - {{#if canEditTags}} - {{tag-chooser tags=model.tags tabIndex="4" categoryId=model.categoryId}} + {{composer-title composer=model lastValidatedAt=lastValidatedAt focusTarget=focusTarget}} + + {{#if model.showCategoryChooser}} +
+ {{category-chooser value=model.categoryId scopedCategoryId=scopedCategoryId tabindex="3"}} + {{popup-input-tip validation=categoryValidation}} +
+ {{#if model.archetype.hasOptions}} + {{d-button action="showOptions" label="topic.options"}} + {{/if}} {{/if}} - {{composer-save-button - action=(action "save") - icon=model.saveIcon - label=model.saveLabel - disableSubmit=disableSubmit}} - {{i18n 'cancel'}} +
+ {{/if}} - {{#if site.mobileView}} + {{plugin-outlet name="composer-fields" args=(hash model=model)}} + +
+ + {{composer-editor topic=topic + composer=model + lastValidatedAt=lastValidatedAt + canWhisper=canWhisper + showPopupMenu=showPopupMenu + draftStatus=model.draftStatus + isUploading=isUploading + isCancellable=isCancellable + uploadProgress=uploadProgress + groupsMentioned="groupsMentioned" + cannotSeeMention="cannotSeeMention" + importQuote="importQuote" + showOptions="showOptions" + hideOptions="hideOptions" + optionsVisible=optionsVisible + togglePreview="togglePreview" + showToolbar=showToolbar + showUploadSelector="showUploadSelector" + afterRefresh="afterRefresh"}} + +
+ {{plugin-outlet name="composer-fields-below" args=(hash model=model)}} + + {{#if canEditTags}} + {{tag-chooser tags=model.tags tabIndex="4" categoryId=model.categoryId}} + {{/if}} + +
+ {{composer-save-button action=(action "save") + icon=model.saveIcon + label=model.saveLabel + disableSubmit=disableSubmit}} + + {{i18n 'cancel'}} + + {{#if site.mobileView}} {{#if whisperOrUnlistTopic}} {{d-icon "eye-slash"}} {{/if}} - {{/if}} -
- {{/if}} -
- {{else}} -
-
-
- {{#if model.createdPost}} - {{i18n 'composer.saved'}} - {{else}} - {{i18n 'composer.saving'}} {{loading-spinner size="small"}} - {{/if}} -
-
- {{#if model.topic}} - {{d-icon "mail-forward"}} {{{draftTitle}}} - {{else}} - {{i18n "composer.saved_draft"}} - {{/if}} + {{/if}} + + + {{#if isUploading}} +
+ {{loading-spinner size="small"}} {{i18n 'upload_selector.uploading'}} + {{uploadProgress}}% + {{#if isCancellable}} + {{d-icon "times"}} + {{/if}} +
+ {{/if}} +
+ {{model.draftStatus}}
-
- {{/if}} -
-
+
+ {{#if site.mobileView}} + {{i18n 'upload'}} + + {{#if showPreview}} + {{d-button action='togglePreview' class='hide-preview' label='composer.hide_preview'}} + {{/if}} + {{else}} + {{{toggleText}}} + {{/if}} + +
+
+
+ + {{else}} +
+ {{#if model.createdPost}} + {{i18n 'composer.saved'}} + {{else}} + {{i18n 'composer.saving'}} {{loading-spinner size="small"}} + {{/if}} +
+ +
+ {{#if model.topic}} + {{d-icon "mail-forward"}} {{{draftTitle}}} + {{else}} + {{i18n "composer.saved_draft"}} + {{/if}} +
+ {{/if}} + {{/if}} + {{/composer-body}} diff --git a/app/assets/stylesheets/common/base/compose.scss b/app/assets/stylesheets/common/base/compose.scss index 35bac3fdcaf..4d14bff26d3 100644 --- a/app/assets/stylesheets/common/base/compose.scss +++ b/app/assets/stylesheets/common/base/compose.scss @@ -1,9 +1,196 @@ +#reply-control { + background-color: $primary-low; + border-top: 1px solid $primary-low; + bottom: 0; + height: 0; + position: fixed; + display: flex; + flex-direction: column; + transition: height 250ms ease; + width: 100%; + z-index: 999; + + .toggler, + .toggle-toolbar { + position: absolute; + color: $primary-medium; + } + + .toggler { + right: 1px; + } + + .toggle-toolbar { + right: 30px; + } + + .saving-text, + .draft-text { + display: none; + padding-left: 10px; + .spinner { + margin-left: 5px; + } + i { + color: $primary-medium; + } + } + + &.open { + height: 300px; + &.edit-title { + height: 400px; // more room when editing the title + } + } + + &.closed { + height: 0 !important; + } + + &.draft, + &.saving { + height: 40px !important; + justify-content: center; + } + + &.draft { + cursor: pointer; + display: flex; + .draft-text { + display: block; + } + .grippie, .saving-text { + display: none; + } + .toggler { + right: 10px; + } + } + + &.saving .saving-text { + display: flex; + } + + input[type="text"] { + border: 0; + } + + .reply-to { + color: $tertiary; + margin-bottom: 10px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + i { + color: $primary-medium; + } + } + + .whisper, + .display-edit-reason { + font-style: italic; + color: $primary-medium !important; + } + + #edit-reason { + margin: 4px; + } + + .user-selector, + .title-and-category { + display: flex; + align-items: center; + margin-bottom: 10px; + position: relative; + } + + .title-input { + position: relative; + .popup-tip {margin-top: -30px;} + } + + .add-warning { + margin-left: 1em; + } + + #reply-title { + width: 400px; + padding: 6px 10px; + margin: 0 10px 0 0; + } + + .tag-chooser { + margin: 5px 0 0 0; + flex-basis: 30%; + } + + .wmd-controls { + position: relative; + display: flex; + flex-direction: column; + flex-grow: 1; + min-height: 0; + } + + .d-editor-button-bar .btn { + padding: 0 6px; + } + + .save-or-cancel { + margin-top: 5px; + flex-basis: 50%; + display: flex; + align-items: center; + #draft-status, + #file-uploading { + margin-left: 25px; + } + #file-uploading { + display: flex; + .spinner { + margin-right: 5px; + } + } + } + + .composer-bottom-right { + flex-basis: 50%; + display: flex; + flex-direction: row-reverse; + .toggle-preview { + order: 2; + } + } + + .with-tags { + .composer-bottom-right { + flex-basis: 60%; + margin-left: auto; + } + .save-or-cancel { + order: 3; + } + } + + .create { + margin-right: 5px; + } + + #draft-status, #file-uploading { + color: dark-light-choose($primary-medium, $secondary-medium); + } +} + +.cooked > *:first-child { + margin-top: 0; +} + .autocomplete { z-index: 999999; position: absolute; width: 240px; background-color: $secondary; - border: 1px solid $primary-low; + border: 1px solid $primary-low; ul { list-style: none; padding: 0; @@ -15,7 +202,7 @@ padding: 0 2px; } - border-bottom: 1px solid $primary-low; + border-bottom: 1px solid $primary-low; a { padding: 5px; @@ -35,7 +222,7 @@ background-color: $tertiary-low; } @include hover { - background-color: dark-light-choose($highlight-low, $highlight-medium); + background-color: $highlight-low; text-decoration: none; } } @@ -43,36 +230,6 @@ } } -#reply-control { - .d-editor-textarea-wrapper .spinner { - z-index: 1000; - margin-top: 5em; - } - - .d-editor-button-bar { - -moz-box-sizing: border-box; - box-sizing: border-box; - margin: 0px; - padding: 5px; - border-bottom: 2px solid $primary-low; - height: 33px; - .btn:hover { - color: $primary-low; - } - } - - textarea { - box-shadow: none; - } -} - - -.saving-text .spinner { - display: inline-block; - left: 5px; - top: 4px; -} - div.ac-wrap.disabled { input { display:none; @@ -90,7 +247,7 @@ div.ac-wrap div.item a.remove, .remove-link { border-radius: 12px; width: 10px; display: inline-block; - border: 1px solid $primary-low; + border: 1px solid $primary-low; &:hover { background-color: $danger-low; border: 1px solid $danger-medium; @@ -103,7 +260,7 @@ div.ac-wrap { overflow: auto; max-height: 150px; background-color: $secondary; - border: 1px solid $primary-low; + border: 1px solid $primary-low; padding: 5px 4px 1px 4px; div.item { float: left; @@ -140,43 +297,3 @@ div.ac-wrap { color: lighten($primary, 40%); } } - -#reply-control { - .composer-loading { - position: absolute; - left: 48%; - top: 20%; - } - .whisper { - margin-left: 1em; - font-style: italic; - } -} - -#reply-control.topic-featured-link-only.open { - .wmd-controls { display: none; } -} - -#cancel-file-upload { - font-size: 1.6em; -} - -#draft-status, #file-uploading { - color: dark-light-choose($primary-medium, $secondary-medium); -} - -.composer-bottom-right { - .spinner.small { - width: 6px; - height: 6px; - } -} - -// this removes the topmost margin from the first element in the topic post -// if we don't do this, all posts would have extra space at the top -.d-editor-preview > *:first-child { - margin-top: 0; -} -.cooked > *:first-child { - margin-top: 0; -} diff --git a/app/assets/stylesheets/common/d-editor.scss b/app/assets/stylesheets/common/d-editor.scss index b1a97021b0d..9d016e9a80d 100644 --- a/app/assets/stylesheets/common/d-editor.scss +++ b/app/assets/stylesheets/common/d-editor.scss @@ -1,9 +1,6 @@ -.d-editor { - border: 1px solid $primary-low; -} - .d-editor-container { - padding: 0 10px 13px 10px; + display: flex; + flex-grow: 1; } .d-editor-overlay { @@ -18,6 +15,12 @@ z-index: 1001; } +.d-editor { + display: flex; + flex-grow: 1; + min-height: 0; +} + .d-editor .d-editor-modal { min-width: 400px; position: absolute; @@ -34,18 +37,35 @@ } } +.d-editor-textarea-wrapper, +.d-editor-preview-wrapper { + flex: 1; +} + +.d-editor-textarea-wrapper { + display: flex; + flex-direction: column; + background-color: $secondary; + position: relative; +} + +.d-editor-preview-wrapper { + margin-left: 5px; + max-width: 50%; + display: flex; + flex-direction: column; + background: $secondary; +} + .d-editor-button-bar { - margin: 5px; - padding: 0; - height: 20px; - overflow: hidden; + display: flex; + align-items: center; + border-bottom: 2px solid $primary-low; + min-height: 30px; button { background-color: transparent; - padding: 2px 4px; - float: left; - margin-right: 6px; - min-width: 20px; + color: $primary-medium; } .btn:not(.no-text) { @@ -59,61 +79,62 @@ .btn.italic { font-style: italic; } - - .btn.heading { - font-family: Palatino, Cambria, Georgia, "Times New Roman", serif; - font-weight: bold; - } } .d-editor-spacer { width: 1px; height: 20px; - margin-right: 8px; - margin-left: 5px; + margin: 0 5px; background-color: $primary-low; display: inline-block; - float: left; +} + +.d-editor-input, +.d-editor-preview { + box-shadow: none; + box-sizing: border-box; + height: 100%; + margin: 0; + min-height: auto; + width: 100%; + word-wrap: break-word; + flex-grow: 1; + &:focus { + box-shadow: none; + border: 0; + outline: 0; + } +} + +.d-editor-plugin { + display: flex; + overflow: auto; } .d-editor-input { - color: $primary; - width: 98%; - height: 200px; - - &:disabled { - background-color: $primary-low; - } + border: 0; + padding: 7px; + overflow-x: hidden; } .d-editor-preview { - color: $primary; border: 1px dashed $primary-low; overflow: auto; cursor: default; - margin-top: 8px; - padding: 8px 8px 0 8px; - video { - max-width: 100%; - max-height: 500px; - height: auto; - } - audio { - max-width: 100%; - } - &.hidden { - width: 0; - visibility: hidden; - } - + background-color: $secondary; + padding: 7px; } -.composing-whisper { - .d-editor-preview { - font-style: italic; - color: $primary-medium !important; - } + +.composing-whisper .d-editor-preview { + font-style: italic; + color: $primary-medium !important; } .d-editor-preview > *:first-child { margin-top: 0; } + +.hide-preview .d-editor-preview-wrapper { + display: none; + flex: 0; +} diff --git a/app/assets/stylesheets/desktop/compose.scss b/app/assets/stylesheets/desktop/compose.scss index ea905523cd0..33f5b47e9a1 100644 --- a/app/assets/stylesheets/desktop/compose.scss +++ b/app/assets/stylesheets/desktop/compose.scss @@ -1,19 +1,3 @@ -// styles that apply to the reply pane that slides up to compose replies - -// hack, this needs to be done cleaner -#private-message-users { - width: 400px; - float: left; -} - -.add-warning { - width: 300px; - display: inline-block; - position: relative; - top: -30px; - margin-left: 20px; -} - .composer-popup-container { max-width: 1500px; margin-left: auto; @@ -29,12 +13,11 @@ left: 50%; // The composer goes off-center at 1550px @media (min-width: 1550px) { - left: calc(50% - 15px); + left: calc(50%); } overflow-y: auto; z-index: 110; padding: 10px 10px 35px 10px; - box-shadow: 3px 3px 3px rgba(0,0,0, 0.34); background: $highlight-medium; @@ -59,7 +42,7 @@ right: 10px; bottom: 10px; color: $primary; - padding: 6px 4px 2px 4px; + opacity: 0.5; font-size: 1.071em; &:before { content: 'esc'; @@ -85,6 +68,10 @@ } } +.d-editor-container { + max-width: 100%; +} + .custom-body { background-color: $tertiary-low; p { @@ -123,354 +110,27 @@ width: calc(50% - 65px); } -// only disabled when the device is touch-only -.touch.mobile-device #reply-control.open .grippie { - display: none; -} - #reply-control { - .toggle-preview, #draft-status, #file-uploading { - position: absolute; - bottom: -31px; - margin-top: 0; - } - .toggle-preview { - right: 5px; - } - #draft-status, #file-uploading { - right: 51%; - } - #file-uploading { - font-size: 0.857em; - } - transition: height 0.4s ease; - width: 100%; - z-index: 999; - height: 0; - background-color: $primary-low; - bottom: 0; - font-size: 1em; - position: fixed; - .toggler { - right: 1px; - position: absolute; - i { font-size: 1.1em; } - color: dark-light-choose($primary-medium, $secondary-medium); - padding: 0 10px 5px 10px; - } - a.cancel { - padding-left: 7px; - } - .control-row { - margin: 0 5px 0 5px; - } - .saving-text { - display: none; - } - .draft-text { - display: none; - } - .grippie { - display: none; - } - // The various states - &.open { - height: 300px; - .grippie { - display: block; - } - } - &.closed { - height: 0 !important; - } - &.draft { - height: 40px !important; - cursor: pointer; - border-top: 1px solid $primary-low; - .draft-text { - display: block; - - i { - color: dark-light-choose($primary-medium, $secondary-medium); - } - } - } - &.saving { - height: 40px !important; - border-top: 1px solid $primary-low; - .saving-text { - display: block; - } - } .reply-area { max-width: 1500px; - margin-left: auto; - margin-right: auto; - float: none; - .ac-wrap { - padding-left: 10px; - } - } - - // When the post is new (new topic) the sizings are different - &.edit-title { - - &.open { - height: 400px; - } - .contents { - input#reply-title { - padding: 7px 10px; - margin-bottom: 0; - color: $primary; - width: 400px; - } - .wmd-controls { - transition: top 0.3s ease; - top: 100px; - } - } - } - .contents { - padding-left: 10px; - padding-top: 5px; - min-width: 1280px; - .form-element { - position: relative; - display: inline-block; - - .category-input .category-chooser { - width: 430px; - @include medium-width { width: 285px; } - @include small-width { width: 220px; } - - .select-box-kit-header { - padding: 7px 10px; - } - } - } - .edit-reason-input { - display: inline-block; - position: absolute; - margin-left: 10px; - top: 18px; - #edit-reason { - margin: -7px 0 0; - padding: 5px; - float: left; - width: 300px; - } - } - #reply-title { - color: $primary; - margin-right: 5px; - float: left; - &:disabled { - background-color: $primary-low; - } - } - #topic-featured-link { - padding: 7px 10px; - margin: 6px 10px 3px 0; - width: 400px; - } - .d-editor-input:disabled { - background-color: $primary-low; - } - .d-editor-input, .d-editor-preview { - color: $primary; - } - - .d-editor-preview { - border: 1px dashed $primary-low; - overflow: auto; - visibility: visible; - cursor: default; - video { - max-width: 100%; - max-height: 500px; - height: auto; - } - audio { - max-width: 100%; - } - &.hidden { - width: 0; - visibility: hidden; - } - } - .d-editor-input { - bottom: 35px; - } - - .submit-panel { - width: 28%; - position: absolute; - display: block; - bottom: 8px; - } - .future-date-input .examples { - margin-top: 0; - padding-bottom: 8px; - } - } - .title-input, .category-input, .show-admin-options { - display: inline; - float: left; - } - .show-admin-options { - vertical-align: top; - margin-top: 8px; - background: $primary-low; - &:hover { - color: $secondary; - background: $primary; - } - } - .title-input .popup-tip { - width: 300px; - margin-top: 8px; - left: 150px; - } - .category-input .popup-tip { - width: 240px; - left: 432px; - top: -19px; - } -} - -.reply-to { - margin-bottom: 10px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - color: $tertiary; - - @media (min-width: 1101px) { - max-width: 80%; - } - @media (max-width: 1100px) { - max-width: 500px; - } - @media (max-width: 600px) { - max-width: 300px; - } - - i { - color: dark-light-choose($primary-medium, $secondary-medium); - } -} - -#reply-control { - .wmd-controls.hide-preview { - .d-editor-input { - width: 100%; - } - .d-editor-button-bar { - width: 100%; - } - .d-editor-preview-wrapper { - display: none; - } - .d-editor-textarea-wrapper { - width: 100%; - } - } - - .wmd-controls { - left: 30px; - right: 30px; - position: absolute; - bottom: 48px; - top: 50px; - - - .d-editor-input, .d-editor-preview { - -moz-box-sizing: border-box; - box-sizing: border-box; - width: 100%; - height: 100%; - min-height: auto; - padding: 7px; - margin: 0; - background-color: $secondary; - word-wrap: break-word; - } - .d-editor-input, .d-editor-preview-header { - position: absolute; - left: 0; - top: 0; - border: 0px; - border-top: 30px solid transparent; - @include border-radius-all(0); - } - .d-editor-preview-header { - font-size: 0.929em; - line-height: 18px; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - overflow: scroll; - .marker, .caret { - display: inline-block; - vertical-align: top; - } - } - .d-editor, .d-editor-container, .d-editor-textarea-wrapper, .d-editor-preview-wrapper { - position: relative; - -moz-box-sizing: border-box; - box-sizing: border-box; - height: 100%; - min-height: 100%; - margin: 0; - padding: 0; - } - .d-editor-textarea-wrapper { - width: 50%; - padding-right: 5px; - float: left; - .popup-tip { - margin-top: 3px; - right: 4px; - } - } - .d-editor-preview-wrapper { - width: 50%; - padding-left: 5px; - float: right; - } - } - .d-editor-button-bar { - top: 0; - position: absolute; - color: dark-light-choose($primary-medium, $secondary-medium); - background-color: $secondary; - z-index: 100; - overflow: hidden; - width: 50%; - - -moz-box-sizing: border-box; + margin: 0 auto; + padding: 0 10px 10px 10px; box-sizing: border-box; - - button { - color: dark-light-choose($primary-high, $secondary-high); + height: calc(100% - 11px); + width: 100%; + display: flex; + flex-direction: column; + .submit-panel { + display: flex; + flex-wrap: wrap; + align-items: center; + flex-shrink: 0; } } } -#reply-control.topic-featured-link-only.open { - height: 200px; -} - -.control-row.reply-area { - padding-left: 20px; - padding-right: 20px; -} - -@media all and (min-width: 1550px) { - #reply-control { - .wmd-controls { - width: 1450px; - left: auto; - right: auto; - } - } +#draft-status, +#file-uploading { + flex-grow: 1; + text-align: right; } diff --git a/app/assets/stylesheets/mobile/compose.scss b/app/assets/stylesheets/mobile/compose.scss index 00ff9c9c736..ff85b35ccde 100644 --- a/app/assets/stylesheets/mobile/compose.scss +++ b/app/assets/stylesheets/mobile/compose.scss @@ -1,10 +1,3 @@ -// styles that apply to the reply pane that slides up to compose replies - -// hack, this needs to be done cleaner -.private-message input.span8 { - width: 47%; -} - .composer-popup-container { display: none !important; // can be removed if inline JS CSS is removed from composer-popup } @@ -13,338 +6,142 @@ display: none !important; // can be removed if inline JS CSS is removed from composer-popup } -input { - background: $secondary; - color: $primary; - padding: 4px; - border-radius: 3px; - box-shadow: inset 0 1px 1px rgba(0,0,0, .3); - border: 1px solid $primary-low; -} - #reply-control { - input[type="text"] { - box-shadow: none; - -webkit-appearance: none; - } -} - -textarea { - box-shadow: none; - -webkit-appearance: none; -} - -input[type=radio], input[type=checkbox] { - box-shadow: none; -} - -#reply-control { - &.no-transition { - transition: none; - } -} - - -#reply-control { - // used for upload link - .composer-bottom-right { - float: right; - line-height: 3em; - } - #mobile-uploader { display: none; } - .mobile-file-upload.hidden { display: none; } - #draft-status, #file-uploading, .mobile-file-upload { display: inline-block; } - transition: height .4s ease-in-out; - width: 100%; - z-index: 1039; - height: 0; - background-color: $primary-low; - bottom: 0; - font-size: 1em; - position: fixed; - .toggle-toolbar, .toggler { - right: 1px; - position: absolute; - font-size: 1.071em; - color: dark-light-choose($primary-medium, $secondary-medium); - } - - .toggle-toolbar { - right: 30px; - } - - a.cancel { - padding-left: 7px; - line-height: 30px; - } - .control-row { - margin: 0 5px 0 5px; - .reply-to { - overflow: hidden; - max-width: 80%; - white-space: nowrap; - i { - color: dark-light-choose($primary-medium, $secondary-medium); - } + z-index: 1002; //d-header is 1001 + .reply-area { + padding: 0 5px; + display: flex; + flex-direction: column; + flex-grow: 1; } - } - .saving-text { - display: none; - } - .draft-text { - display: none; - } - .grippie { - display: none; - } - // The various states - &.open { - max-height: 100%; // ensure no overflow e.g. on small Android - height: 270px; - } - &.closed { - height: 0 !important; - } - &.draft { - height: 35px !important; - cursor: pointer; - border-top: 1px solid $primary-low; - .draft-text { - display: block; - position: absolute; - margin-right: 40px; - max-width: 80%; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - i { - color: dark-light-choose($primary-medium, $secondary-medium); - } - } - } - &.saving { - height: 40px !important; - border-top: 1px solid $primary-low; - .saving-text { - display: block; - } - } - - // if this is a new topic, make room for the category field in the editor on - // a small screen mobile device - &.edit-title { &.open { - max-height: 100%; // ensure no overflow e.g. on small Android height: 250px; - } - .contents { - input#reply-title { - padding: 5px; - margin-top: 6px; - width: 100%; - box-sizing: border-box; - border: 1px solid $secondary; + &.edit-title { + height: 100%; } - .category-input { - margin-top: 3px; + } - .category-chooser { - width: 100%; + .reply-to { + margin: 5px; + max-width: calc(100% - 60px); + } + + .toggle-toolbar, + .toggler { + top: 2px; + } + + &.draft { + .toggle-toolbar, + .toggler { + top: 8px; + } + } + + .title-input { + margin-bottom: 5px; + } + + #reply-title { + width: calc(100% - 20px); + } + + .category-input { + margin-bottom: 5px; + .category-chooser { + width: 100% !important; + } + } + + .submit-panel { + margin-bottom: 5px; + display: flex; + align-items: baseline; + flex-shrink: 0; + .save-or-cancel { + flex-basis: 69%; + } + .composer-bottom-right { + flex-basis: 30%; + } + } + + .d-editor-textarea-wrapper { + width: 100%; + } + + &.show-preview { + .d-editor-preview-wrapper { + position: fixed; + z-index: 1000000; + top: 0; + bottom: 0; + left: 0; + right: 0; + background-color: $secondary; + max-width: 100%; + margin: 0; + .d-editor-preview { + margin-bottom: 40px; + overflow: auto; } } - .wmd-controls { - transition: top 0.3s ease; - top: 110px; + .btn.hide-preview { + position: fixed; + right: 5px; + bottom: 5px; + z-index: 1000001; } } - } - .contents { - padding: 8px 5px 0 5px; - .edit-reason-input, .display-edit-reason { + &.hide-preview { + .d-editor-preview-wrapper { + display: none; + } + } + + .d-editor-button-bar { display: none; } - .edit-reason-input { - display: inline-block; - margin-left: 2px; - #edit-reason { + + .toolbar-visible .d-editor-button-bar { + display: flex; + } + + .d-editor-button-bar .btn { + @media all and ( max-width: 350px) { + padding: 2px 4px; + } + &.preview { margin: 0; - padding: 2px; } } - #reply-title { - margin-right: 10px; - &:disabled { - background-color: dark-light-choose($primary-low-mid, $secondary-high); - } + + #mobile-uploader { + display: none; } - .d-editor-input:disabled { - background-color: dark-light-choose($primary-low-mid, $secondary-high); + + .title-and-category, + .user-selector { + flex-direction: column; + margin: 0; } - .d-editor-input { - color: dark-light-choose(darken($primary, 40%), blend-primary-secondary(90%)); - bottom: 35px; + + .title-input, + .category-input, + .users-input, + .add-warning { width: 100%; - height: 100%; - padding: 7px; - margin: 0; - background-color: $secondary; - word-wrap: break-word; - box-sizing: border-box; - border: 1px solid $secondary; - } - .submit-panel { - // need minimum width that fits, or this'll wrap cancel under submit/create which is super bad - width: 180px; - position: absolute; - display: block; - bottom: 0; - white-space: nowrap; - .btn { - max-width: 120px; - overflow: hidden; - white-space: nowrap; - } - } - } - .popup-tip .close { - padding: 0 2px 2px 8px; // so my fingers can touch the little x - } - .title-input .popup-tip { - width: 240px; - right: 5px; - } - .category-input .popup-tip { - width: 240px; - right: 5px; - } - .d-editor-textarea-wrapper .popup-tip { - top: 28px; - } - button.btn.no-text { - margin: 7px 0 0 5px; - position: absolute; - } - .create.btn-primary { - margin-bottom: 8px; - } -} - -#reply-control.edit-title.private-message { - .wmd-controls { - transition: top 0.3s ease; - top: 120px; - } -} - -#reply-control { - - .d-editor { - height: 100%; - } - - .d-editor-container { - height: 100%; - } - - .wmd-controls { - left: 10px; - right: 10px; - position: absolute; - top: 40px; - bottom: 50px; - display: block; - .d-editor-container { - padding: 0; - } - .d-editor-preview-wrapper { - display: none; } - .btn.hide-preview { - position: fixed; - right: 5px; - bottom: 5px; - z-index: 1000001; + .add-warning { + margin: 5px 0 5px 5px; } - .d-editor-preview-wrapper.force-preview { - display: block; - position: fixed; - z-index: 1000000; - top: 0; - bottom: 0; - left: 0; - right: 0; - background-color: $secondary; + #draft-status { + color: $primary-medium; + } - .d-editor-preview { - height: 90%; - height: calc(100% - 60px); - border: 0; - overflow: auto; - } - } - .d-editor-textarea-wrapper { - position: relative; - box-sizing: border-box; - height: 100%; - min-height: 100%; - margin: 0; - padding: 0; - .popup-tip { - margin-top: 3px; - right: 4px; - } - } - } - .d-editor-button-bar { - display: none; } - - .wmd-controls.toolbar-visible .d-editor-input { - padding-top: 40px; - } - - .wmd-controls.toolbar-visible .d-editor-button-bar { - - .btn.link, .btn.upload, .btn.rule, .btn.bullet, .btn.list, .btn.heading { - display: none; - } - - display: block; - margin: 1px 4px; - position: absolute; - color: dark-light-choose($primary-medium, $secondary-medium); - background-color: $secondary; - z-index: 100; - overflow: hidden; - width: 100%; - width: calc(100% - 10px); - - -moz-box-sizing: border-box; - box-sizing: border-box; - - button { - color: dark-light-choose($primary-medium, $secondary-medium); - } - button.btn.no-text { - margin: 0 2px; - padding: 2px 5px; - position: static; - } - } -} - -// make sure the category selector *NEVER* gets focus by default on mobile anywhere -.select2-hidden, -.select2-search, -.select2-focusser { - display:none !important; -} - -#reply-control.edit-title.open { - height: 100%; -}