diff --git a/ghost/admin/app/components/gh-navigation.js b/ghost/admin/app/components/gh-navigation.js deleted file mode 100644 index 8a7454563c..0000000000 --- a/ghost/admin/app/components/gh-navigation.js +++ /dev/null @@ -1,38 +0,0 @@ -import Component from '@ember/component'; -import {run} from '@ember/runloop'; - -export default Component.extend({ - tagName: 'section', - classNames: 'gh-view', - - didInsertElement() { - let navContainer = this.$('.js-gh-blognav'); - let navElements = '.gh-blognav-item:not(.gh-blognav-item:last-child)'; - // needed because jqueryui sortable doesn't trigger babel's autoscoping - let _this = this; - - this._super(...arguments); - - navContainer.sortable({ - handle: '.gh-blognav-grab', - items: navElements, - - start(event, ui) { - run(() => { - ui.item.data('start-index', ui.item.index()); - }); - }, - - update(event, ui) { - run(() => { - _this.sendAction('moveItem', ui.item.data('start-index'), ui.item.index()); - }); - } - }); - }, - - willDestroyElement() { - this._super(...arguments); - this.$('.ui-sortable').sortable('destroy'); - } -}); diff --git a/ghost/admin/app/components/gh-navitem.js b/ghost/admin/app/components/gh-navitem.js index 0c4dc4e72c..3ce66322c9 100644 --- a/ghost/admin/app/components/gh-navitem.js +++ b/ghost/admin/app/components/gh-navitem.js @@ -1,16 +1,14 @@ import Component from '@ember/component'; -import SortableItem from 'ember-sortable/mixins/sortable-item'; import ValidationState from 'ghost-admin/mixins/validation-state'; import {alias, readOnly} from '@ember/object/computed'; import {computed} from '@ember/object'; import {run} from '@ember/runloop'; -export default Component.extend(ValidationState, SortableItem, { +export default Component.extend(ValidationState, { classNames: 'gh-blognav-item', classNameBindings: ['errorClass', 'navItem.isNew::gh-blognav-item--sortable'], new: false, - handle: '.gh-blognav-grab', model: alias('navItem'), errors: readOnly('navItem.errors'), diff --git a/ghost/admin/app/components/gh-post-settings-menu.js b/ghost/admin/app/components/gh-post-settings-menu.js index 8718889157..78b92ed227 100644 --- a/ghost/admin/app/components/gh-post-settings-menu.js +++ b/ghost/admin/app/components/gh-post-settings-menu.js @@ -5,7 +5,6 @@ import formatMarkdown from 'ghost-admin/utils/format-markdown'; import moment from 'moment'; import {alias, or} from '@ember/object/computed'; import {computed} from '@ember/object'; -import {guidFor} from '@ember/object/internals'; import {htmlSafe} from '@ember/string'; import {run} from '@ember/runloop'; import {inject as service} from '@ember/service'; @@ -138,13 +137,6 @@ export default Component.extend(SettingsMenuMixin, { return seoURL; }), - // live-query of all tags for tag input autocomplete - availableTags: computed(function () { - return this.get('store').filter('tag', {limit: 'all'}, () => { - return true; - }); - }), - showError(error) { // TODO: remove null check once ValidationEngine has been removed if (error) { @@ -530,56 +522,6 @@ export default Component.extend(SettingsMenuMixin, { }); }, - addTag(tagName, index) { - let currentTags = this.get('model.tags'); - let currentTagNames = currentTags.map((tag) => { - return tag.get('name').toLowerCase(); - }); - let availableTagNames, - tagToAdd; - - tagName = tagName.trim(); - - // abort if tag is already selected - if (currentTagNames.includes(tagName.toLowerCase())) { - return; - } - - this.get('availableTags').then((availableTags) => { - availableTagNames = availableTags.map((tag) => { - return tag.get('name').toLowerCase(); - }); - - // find existing tag or create new - if (availableTagNames.includes(tagName.toLowerCase())) { - tagToAdd = availableTags.find((tag) => { - return tag.get('name').toLowerCase() === tagName.toLowerCase(); - }); - } else { - tagToAdd = this.get('store').createRecord('tag', { - name: tagName - }); - - // we need to set a UUID so that selectize has a unique value - // it will be ignored when sent to the server - tagToAdd.set('uuid', guidFor(tagToAdd)); - } - - // push tag onto post relationship - if (tagToAdd) { - this.get('model.tags').insertAt(index, tagToAdd); - } - }); - }, - - removeTag(tag) { - this.get('model.tags').removeObject(tag); - - if (tag.get('isNew')) { - tag.destroyRecord(); - } - }, - deletePost() { if (this.get('deletePost')) { this.get('deletePost')(); diff --git a/ghost/admin/app/components/gh-psm-tags-input.js b/ghost/admin/app/components/gh-psm-tags-input.js new file mode 100644 index 0000000000..714cdc4139 --- /dev/null +++ b/ghost/admin/app/components/gh-psm-tags-input.js @@ -0,0 +1,87 @@ +import Component from '@ember/component'; +import {computed} from '@ember/object'; +import {inject as service} from '@ember/service'; + +export default Component.extend({ + + store: service(), + + // public attrs + post: null, + tagName: '', + + // live-query of all tags for tag input autocomplete + availableTags: computed(function () { + return this.get('store').filter('tag', {limit: 'all'}, () => true); + }), + + availableTagNames: computed('availableTags.@each.name', function () { + return this.get('availableTags').map((tag) => { + return tag.get('name').toLowerCase(); + }); + }), + + actions: { + matchTags(tagName, term) { + return tagName.toLowerCase() === term.trim().toLowerCase(); + }, + + hideCreateOptionOnMatchingTag(term) { + return !this.get('availableTagNames').includes(term.toLowerCase()); + }, + + updateTags(newTags) { + let currentTags = this.get('post.tags'); + + // destroy new+unsaved tags that are no longer selected + currentTags.forEach(function (tag) { + if (!newTags.includes(tag) && tag.get('isNew')) { + tag.destroyRecord(); + } + }); + + // update tags + return this.set('post.tags', newTags); + }, + + createTag(tagName) { + let currentTags = this.get('post.tags'); + let currentTagNames = currentTags.map((tag) => { + return tag.get('name').toLowerCase(); + }); + let tagToAdd; + + tagName = tagName.trim(); + + // abort if tag is already selected + if (currentTagNames.includes(tagName.toLowerCase())) { + return; + } + + // add existing tag or create new one + return this._findTagByName(tagName).then((matchedTag) => { + tagToAdd = matchedTag; + + // create new tag if no match + if (!tagToAdd) { + tagToAdd = this.get('store').createRecord('tag', { + name: tagName + }); + } + + // push tag onto post relationship + return currentTags.pushObject(tagToAdd); + }); + } + }, + + // methods + + _findTagByName(name) { + return this.get('availableTags').then((availableTags) => { + return availableTags.find((tag) => { + return tag.get('name').toLowerCase() === name.toLowerCase(); + }); + }); + } +}); diff --git a/ghost/admin/app/components/gh-selectize.js b/ghost/admin/app/components/gh-selectize.js deleted file mode 100644 index 7f5aba4975..0000000000 --- a/ghost/admin/app/components/gh-selectize.js +++ /dev/null @@ -1,125 +0,0 @@ -/* eslint-disable camelcase */ -import EmberSelectizeComponent from 'ember-cli-selectize/components/ember-selectize'; -import {computed} from '@ember/object'; -import {A as emberA, isArray as isEmberArray} from '@ember/array'; -import {get} from '@ember/object'; -import {isBlank} from '@ember/utils'; -import {run} from '@ember/runloop'; - -export default EmberSelectizeComponent.extend({ - - selectizeOptions: computed(function () { - let options = this._super(...arguments); - - options.onChange = run.bind(this, '_onChange'); - - return options; - }), - - /** - * Event callback that is triggered when user creates a tag - * - modified to pass the caret position to the action - */ - _create(input, callback) { - let caret = this._selectize.caretPos; - - // Delete user entered text - this._selectize.setTextboxValue(''); - // Send create action - - // allow the observers and computed properties to run first - run.schedule('actions', this, function () { - this.sendAction('create-item', input, caret); - }); - // We cancel the creation here, so it's up to you to include the created element - // in the content and selection property - callback(null); - }, - - _addSelection(obj) { - let _valuePath = this.get('_valuePath'); - let val = get(obj, _valuePath); - let caret = this._selectize.caretPos; - - // caret position is always 1 more than the desired index as this method - // is called after selectize has inserted the item and the caret has moved - // to the right - caret = caret - 1; - - this.get('selection').insertAt(caret, obj); - - run.schedule('actions', this, function () { - this.sendAction('add-item', obj); - this.sendAction('add-value', val); - }); - }, - - _onChange(args) { - let selection = get(this, 'selection'); - let valuePath = get(this, '_valuePath'); - let reorderedSelection = emberA([]); - - if (!args || !selection || !isEmberArray(selection) || args.length !== get(selection, 'length')) { - return; - } - - // exit if we're not dealing with the same objects as the selection - let objectsHaveChanged = selection.any(function (obj) { - return args.indexOf(get(obj, valuePath)) === -1; - }); - - if (objectsHaveChanged) { - return; - } - - // exit if the order is still the same - let orderIsSame = selection.every(function (obj, idx) { - return get(obj, valuePath) === args[idx]; - }); - - if (orderIsSame) { - return; - } - - // we have a re-order, update the selection - args.forEach((value) => { - let obj = selection.find(function (item) { - return `${get(item, valuePath)}` === value; - }); - - if (obj) { - reorderedSelection.addObject(obj); - } - }); - - this.set('selection', reorderedSelection); - }, - - _preventOpeningWhenBlank() { - let openOnFocus = this.get('openOnFocus'); - - if (!openOnFocus) { - run.schedule('afterRender', this, function () { - let selectize = this._selectize; - if (selectize) { - selectize.on('dropdown_open', function () { - if (isBlank(selectize.$control_input.val())) { - selectize.close(); - } - }); - selectize.on('type', function (filter) { - if (isBlank(filter)) { - selectize.close(); - } - }); - } - }); - } - }, - - didInsertElement() { - this._super(...arguments); - this._preventOpeningWhenBlank(); - } - -}); diff --git a/ghost/admin/app/components/gh-token-input.js b/ghost/admin/app/components/gh-token-input.js new file mode 100644 index 0000000000..48816daf7c --- /dev/null +++ b/ghost/admin/app/components/gh-token-input.js @@ -0,0 +1,189 @@ +/* global key */ +import Component from '@ember/component'; +import Ember from 'ember'; +import {A} from '@ember/array'; +import { + advanceSelectableOption, + defaultMatcher, + filterOptions +} from 'ember-power-select/utils/group-utils'; +import {computed} from '@ember/object'; +import {get} from '@ember/object'; +import {htmlSafe} from '@ember/string'; +import {isBlank} from '@ember/utils'; +import {task} from 'ember-concurrency'; + +const {Handlebars} = Ember; + +const BACKSPACE = 8; +const TAB = 9; + +export default Component.extend({ + + // public attrs + closeOnSelect: false, + labelField: 'name', + matcher: defaultMatcher, + searchField: 'name', + tagName: '', + triggerComponent: 'gh-token-input/trigger', + + optionsWithoutSelected: computed('options.[]', 'selected.[]', function () { + return this.get('optionsWithoutSelectedTask').perform(); + }), + + actions: { + handleKeydown(select, event) { + // On backspace with empty text, remove the last token but deviate + // from default behaviour by not updating search to match last token + if (event.keyCode === BACKSPACE && isBlank(event.target.value)) { + let lastSelection = select.selected[select.selected.length - 1]; + + if (lastSelection) { + this.get('onchange')(select.selected.slice(0, -1), select); + select.actions.search(''); + select.actions.open(event); + } + + // prevent default + return false; + } + + // Tab should work the same as Enter if there's a highlighted option + if (event.keyCode === TAB && !isBlank(event.target.value) && select.highlighted) { + if (!select.selected || select.selected.indexOf(select.highlighted) === -1) { + select.actions.choose(select.highlighted, event); + return false; + } + } + + // fallback to default + return true; + }, + + onfocus() { + key.setScope('gh-token-input'); + + if (this.get('onfocus')) { + this.get('onfocus')(...arguments); + } + }, + + onblur() { + key.setScope('default'); + + if (this.get('onblur')) { + this.get('onblur')(...arguments); + } + } + }, + + optionsWithoutSelectedTask: task(function* () { + let options = yield this.get('options'); + let selected = yield this.get('selected'); + return options.filter((o) => !selected.includes(o)); + }), + + shouldShowCreateOption(term, options) { + if (this.get('showCreateWhen')) { + return this.get('showCreateWhen')(term, options); + } else { + return this.hideCreateOptionOnSameTerm(term, options); + } + }, + + hideCreateOptionOnSameTerm(term, options) { + let searchField = this.get('searchField'); + let existingOption = options.findBy(searchField, term); + return !existingOption; + }, + + addCreateOption(term, options) { + if (this.shouldShowCreateOption(term, options)) { + options.unshift(this.buildSuggestionForTerm(term)); + } + }, + + searchAndSuggest(term, select) { + return this.get('searchAndSuggestTask').perform(term, select); + }, + + searchAndSuggestTask: task(function* (term, select) { + let newOptions = (yield this.get('optionsWithoutSelected')).toArray(); + + if (term.length === 0) { + return newOptions; + } + + let searchAction = this.get('search'); + if (searchAction) { + let results = yield searchAction(term, select); + + if (results.toArray) { + results = results.toArray(); + } + + this.addCreateOption(term, results); + return results; + } + + newOptions = this.filter(A(newOptions), term); + this.addCreateOption(term, newOptions); + + return newOptions; + }), + + selectOrCreate(selection, select) { + let suggestion = selection.find((option) => { + return option.__isSuggestion__; + }); + + if (suggestion) { + this.get('oncreate')(suggestion.__value__, select); + } else { + this.get('onchange')(selection, select); + } + + // clear select search + select.actions.search(''); + }, + + filter(options, searchText) { + let matcher; + if (this.get('searchField')) { + matcher = (option, text) => this.matcher(get(option, this.get('searchField')), text); + } else { + matcher = (option, text) => this.matcher(option, text); + } + return filterOptions(options || [], searchText, matcher); + }, + + buildSuggestionForTerm(term) { + return { + __isSuggestion__: true, + __value__: term, + text: this.buildSuggestionLabel(term) + }; + }, + + buildSuggestionLabel(term) { + let buildSuggestion = this.get('buildSuggestion'); + if (buildSuggestion) { + return buildSuggestion(term); + } + return htmlSafe(`Add "${Handlebars.Utils.escapeExpression(term)}"...`); + }, + + // always select the first item in the list that isn't the "Add x" option + defaultHighlighted(select) { + let {results} = select; + let option = advanceSelectableOption(results, undefined, 1); + + if (results.length > 1 && option.__isSuggestion__) { + option = advanceSelectableOption(results, option, 1); + } + + return option; + } + +}); diff --git a/ghost/admin/app/components/gh-token-input/select-multiple.js b/ghost/admin/app/components/gh-token-input/select-multiple.js new file mode 100644 index 0000000000..69be0f2952 --- /dev/null +++ b/ghost/admin/app/components/gh-token-input/select-multiple.js @@ -0,0 +1,58 @@ +import $ from 'jquery'; +import PowerSelectMultiple from 'ember-power-select/components/power-select-multiple'; +import {bind} from '@ember/runloop'; + +const endActions = 'click.ghToken mouseup.ghToken touchend.ghToken'; + +// triggering focus on the search input within ESA's onfocus event breaks the +// drag-n-drop functionality in ember-drag-drop so we watch for events that +// could be the start of a drag and disable the default focus behaviour until +// we get another event signalling the end of a drag + +export default PowerSelectMultiple.extend({ + + _canFocus: true, + + willDestroyElement() { + this._super(...arguments); + + if (this._allowFocusListener) { + $(window).off(endActions, this._allowFocusListener); + } + }, + + actions: { + optionMouseDown(event) { + if (event.which === 1 && !event.ctrlKey) { + this._denyFocus(event); + } + }, + + optionTouchStart(event) { + this._denyFocus(event); + }, + + handleFocus() { + if (this._canFocus) { + this._super(...arguments); + } + } + }, + + _denyFocus() { + if (this._canFocus) { + this._canFocus = false; + + this._allowFocusListener = bind(this, this._allowFocus); + + $(window).on(endActions, this._allowFocusListener); + } + }, + + _allowFocus() { + this._canFocus = true; + + $(window).off(endActions, this._allowFocusListener); + this._allowFocusListener = null; + } +}); diff --git a/ghost/admin/app/components/gh-token-input/select.js b/ghost/admin/app/components/gh-token-input/select.js new file mode 100644 index 0000000000..e8eee9335a --- /dev/null +++ b/ghost/admin/app/components/gh-token-input/select.js @@ -0,0 +1,9 @@ +// NOTE: This is only here because we wanted to override the `eventType` attr. +// DO NOT add any functionality here, this will hopefully disappear after an +// upstream PR + +import PowerSelect from 'ember-power-select/components/power-select'; + +export default PowerSelect.extend({ + +}); diff --git a/ghost/admin/app/components/gh-token-input/suggested-option.js b/ghost/admin/app/components/gh-token-input/suggested-option.js new file mode 100644 index 0000000000..041ba0ad19 --- /dev/null +++ b/ghost/admin/app/components/gh-token-input/suggested-option.js @@ -0,0 +1,5 @@ +import Component from '@ember/component'; + +export default Component.extend({ + tagName: '' +}); diff --git a/ghost/admin/app/components/gh-token-input/tag-token.js b/ghost/admin/app/components/gh-token-input/tag-token.js new file mode 100644 index 0000000000..900a97681c --- /dev/null +++ b/ghost/admin/app/components/gh-token-input/tag-token.js @@ -0,0 +1,35 @@ +import DraggableObject from 'ember-drag-drop/components/draggable-object'; +import {computed} from '@ember/object'; +import {readOnly} from '@ember/object/computed'; + +export default DraggableObject.extend({ + + attributeBindings: ['title'], + classNames: ['tag-token'], + classNameBindings: [ + 'primary:tag-token--primary', + 'internal:tag-token--internal' + ], + + content: readOnly('option'), + internal: readOnly('option.isInternal'), + + primary: computed('idx', 'internal', function () { + return !this.get('internal') && this.get('idx') === 0; + }), + + title: computed('option.name', 'primary', 'internal', function () { + let name = this.get('option.name'); + + if (this.get('internal')) { + return `${name} (internal)`; + } + + if (this.get('primary')) { + return `${name} (primary tag)`; + } + + return name; + }) + +}); diff --git a/ghost/admin/app/components/gh-token-input/trigger.js b/ghost/admin/app/components/gh-token-input/trigger.js new file mode 100644 index 0000000000..ff9fbe0c15 --- /dev/null +++ b/ghost/admin/app/components/gh-token-input/trigger.js @@ -0,0 +1,28 @@ +import EmberPowerSelectMultipleTrigger from 'ember-power-select/components/power-select-multiple/trigger'; +import {copy} from '@ember/object/internals'; + +export default EmberPowerSelectMultipleTrigger.extend({ + + actions: { + handleOptionMouseDown(event) { + let action = this.get('extra.optionMouseDown'); + if (action) { + return action(event); + } + }, + + handleOptionTouchStart(event) { + let action = this.get('extra.optionTouchStart'); + if (action) { + return action(event); + } + }, + + reorderItems() { + // ember-drag-drop's sortable-objects has two-way bindings and will + // update EPS' selected value directly. We have to create a copy + // after sorting in order to force the onchange action to be triggered + this.get('select').actions.select(copy(this.get('select.selected'))); + } + } +}); diff --git a/ghost/admin/app/controllers/settings/design.js b/ghost/admin/app/controllers/settings/design.js index 61bbec5210..0c074dcc7c 100644 --- a/ghost/admin/app/controllers/settings/design.js +++ b/ghost/admin/app/controllers/settings/design.js @@ -112,10 +112,6 @@ export default Controller.extend({ navItems.removeObject(item); }, - reorderItems(navItems) { - this.set('model.navigation', navItems); - }, - updateUrl(url, navItem) { if (!navItem) { return; diff --git a/ghost/admin/app/models/tag.js b/ghost/admin/app/models/tag.js index 21c69bacca..530bb00413 100644 --- a/ghost/admin/app/models/tag.js +++ b/ghost/admin/app/models/tag.js @@ -1,10 +1,7 @@ -/* eslint-disable camelcase */ import Model from 'ember-data/model'; import ValidationEngine from 'ghost-admin/mixins/validation-engine'; import attr from 'ember-data/attr'; -import {computed} from '@ember/object'; import {equal} from '@ember/object/computed'; -import {guidFor} from '@ember/object/internals'; import {observer} from '@ember/object'; import {inject as service} from '@ember/service'; @@ -30,13 +27,6 @@ export default Model.extend(ValidationEngine, { feature: service(), - // HACK: ugly hack to main compatibility with selectize as used in the - // PSM tags input - // TODO: remove once we've switched over to EPS for the tags input - uuid: computed(function () { - return guidFor(this); - }), - setVisibility() { let internalRegex = /^#.?/; this.set('visibility', internalRegex.test(this.get('name')) ? 'internal' : 'public'); diff --git a/ghost/admin/app/routes/application.js b/ghost/admin/app/routes/application.js index d0cbed6aa7..d162bf807a 100644 --- a/ghost/admin/app/routes/application.js +++ b/ghost/admin/app/routes/application.js @@ -20,7 +20,7 @@ function K() { let shortcuts = {}; -shortcuts.esc = {action: 'closeMenus', scope: 'all'}; +shortcuts.esc = {action: 'closeMenus', scope: 'default'}; shortcuts[`${ctrlOrCmd}+s`] = {action: 'save', scope: 'all'}; export default Route.extend(ApplicationRouteMixin, ShortcutsRoute, { diff --git a/ghost/admin/app/styles/app-dark.css b/ghost/admin/app/styles/app-dark.css index c1129b8b2f..a6535ec1f8 100644 --- a/ghost/admin/app/styles/app-dark.css +++ b/ghost/admin/app/styles/app-dark.css @@ -28,7 +28,6 @@ @import "components/pagination.css"; @import "components/badges.css"; @import "components/settings-menu.css"; -@import "components/selectize.css"; @import "components/power-select.css"; @import "components/power-calendar.css"; @import "components/publishmenu.css"; @@ -82,7 +81,6 @@ hr { input, .gh-input, .gh-select, -.selectize-input, .gh-select select { color: var(--darkgrey); border-color: color(var(--lightgrey)); @@ -189,21 +187,6 @@ input, background: var(--lightgrey); } -.selectize-dropdown, -.selectize-input, -.selectize-input input { - color: #fff; -} - -.selectize-dropdown .option { - color: var(--lightgrey); -} - -.selectize-input, -.selectize-control.single .selectize-input.input-active { - background: var(--lightgrey); -} - .gh-select select { color: var(--darkgrey); background: var(--lightgrey); diff --git a/ghost/admin/app/styles/app.css b/ghost/admin/app/styles/app.css index fd4d112755..8c3daf823e 100644 --- a/ghost/admin/app/styles/app.css +++ b/ghost/admin/app/styles/app.css @@ -28,7 +28,6 @@ @import "components/pagination.css"; @import "components/badges.css"; @import "components/settings-menu.css"; -@import "components/selectize.css"; @import "components/power-select.css"; @import "components/power-calendar.css"; @import "components/publishmenu.css"; diff --git a/ghost/admin/app/styles/components/dropdowns.css b/ghost/admin/app/styles/components/dropdowns.css index 52351612c7..7fdcc696c8 100644 --- a/ghost/admin/app/styles/components/dropdowns.css +++ b/ghost/admin/app/styles/components/dropdowns.css @@ -151,11 +151,3 @@ .closed > .dropdown-menu { display: none; } - - -/* Selectize -/* ---------------------------------------------------------- */ - -.selectize-dropdown { - z-index: 200; -} diff --git a/ghost/admin/app/styles/components/power-select.css b/ghost/admin/app/styles/components/power-select.css index ac00da6c46..4d72f5138a 100644 --- a/ghost/admin/app/styles/components/power-select.css +++ b/ghost/admin/app/styles/components/power-select.css @@ -152,3 +152,41 @@ .ember-power-select-option[aria-current="true"] { } + + +/* Multiple */ +.ember-power-select-multiple-trigger { + background: #fff; + padding: 5px; + border: rgb(214, 227, 235) 1px solid; + border-radius: 3px; + outline: none; +} + +.ember-power-select-multiple-option { + margin: 2px; + padding: 2px 4px; + border-radius: 3px; + border: 0; + background: #3eb0ef; + color: white; +} + +.ember-power-select-trigger-multiple-input { + height: 24px; + margin: 2px; +} + +.ember-power-select-status-icon { + right: 10px; +} + +/* Token input */ +.gh-token-input .ember-power-select-options { + max-height: 172px; /* 5.5 options */ +} + +/* Tag input */ +.tag-token--primary { + background: color(#3eb0ef lightness(-20%)); +} diff --git a/ghost/admin/app/styles/components/selectize.css b/ghost/admin/app/styles/components/selectize.css deleted file mode 100644 index 553a02a030..0000000000 --- a/ghost/admin/app/styles/components/selectize.css +++ /dev/null @@ -1,405 +0,0 @@ -.selectize-control.plugin-drag_drop.multi > .selectize-input > div.ui-sortable-placeholder { - visibility: visible !important; - border: 0 none !important; - background: #f2f2f2 !important; - background: rgba(0, 0, 0, 0.06) !important; -} - -.selectize-control.plugin-drag_drop .ui-sortable-placeholder:after { - content: "!"; - visibility: hidden; -} - -.selectize-control.plugin-drag_drop .ui-sortable-helper { - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); -} - -.selectize-dropdown-header { - position: relative; - padding: 5px 8px; - border-bottom: 1px solid #d0d0d0; - background: #f8f8f8; - border-radius: var(--border-radius) var(--border-radius) 0 0; -} - -.selectize-dropdown-header-close { - position: absolute; - top: 50%; - right: 8px; - margin-top: -12px; - color: #303030; - font-size: 20px !important; - line-height: 20px; - opacity: 0.4; -} - -.selectize-dropdown-header-close:hover { - color: #000; -} - -.selectize-dropdown.plugin-optgroup_columns .optgroup { - float: left; - box-sizing: border-box; - border-top: 0 none; - border-right: 1px solid #f2f2f2; -} - -.selectize-dropdown.plugin-optgroup_columns .optgroup:last-child { - border-right: 0 none; -} - -.selectize-dropdown.plugin-optgroup_columns .optgroup:before { - display: none; -} - -.selectize-dropdown.plugin-optgroup_columns .optgroup-header { - border-top: 0 none; -} - -.selectize-control.plugin-remove_button [data-value] { - position: relative; - padding-right: 20px !important; -} - -.selectize-control.plugin-remove_button [data-value] .remove { - position: absolute; - top: 0; - right: 0; - bottom: 0; - z-index: 1; - display: flex; - justify-content: center; - align-items: center; - box-sizing: border-box; - width: 17px; - border-radius: 0 2px 2px 0; - color: inherit; - vertical-align: middle; - text-align: center; - text-decoration: none; - font-size: 12px; - font-weight: bold; -} - -.selectize-control.plugin-remove_button [data-value] .remove:hover { - background: rgba(0, 0, 0, 0.05); -} - -.selectize-control.plugin-remove_button [data-value].active .remove { - border-left-color: #00578d; -} - -.selectize-control.plugin-remove_button .disabled [data-value] .remove:hover { - background: none; -} - -.selectize-control.plugin-remove_button .disabled [data-value] .remove { - border-left-color: #aaa; -} - -.selectize-control { - position: relative; -} - -.selectize-dropdown, -.selectize-input, -.selectize-input input { - color: #303030; - font-family: inherit; - font-size: 1.4rem; -} - -.selectize-input, -.selectize-control.single .selectize-input.input-active { - display: inline-block; - background: #fff; - cursor: text; -} - -.selectize-input { - position: relative; - z-index: 1; - display: inline-block; - overflow: hidden; - box-sizing: border-box; - padding: 10px 12px; - width: 100%; - height: 39px; - border: color(var(--lightgrey) l(-5%) s(-10%)) 1px solid; - border-radius: var(--border-radius); - color: color(var(--midgrey) l(-18%)); - transition: border-color 0.15s linear; -} - -.selectize-input.focus { - border-color: color(var(--lightgrey) l(-15%) s(-10%)); -} - -.selectize-control.multi .selectize-input.has-items { - padding: 6px 10px 3px; - height: auto; -} - -.selectize-input.full { - background-color: #fff; -} - -.selectize-input.disabled, -.selectize-input.disabled * { - cursor: default !important; -} - -.selectize-input.dropdown-active { - border-radius: var(--border-radius) var(--border-radius) 0 0; -} - -.selectize-input > * { - display: -moz-inline-stack; - display: inline-block; - vertical-align: baseline; - zoom: 1; - - *display: inline; -} - -.selectize-control.multi .selectize-input > div { - margin: 0 3px 3px 0; - padding: 1px 4px; - background: var(--blue); - color: #fff; - cursor: pointer; -} - - -/* Active tag - selected state when tag is clicked */ -.selectize-control.multi .selectize-input > div.active { - background: color(var(--blue) lightness(-10%)); - color: #fff; -} - -.selectize-control.multi .selectize-input.disabled > div, -.selectize-control.multi .selectize-input.disabled > div.active { - border: 1px solid #aaa; - background: #d2d2d2; - color: #fff; -} - -.selectize-input > input { - display: inline-block !important; - margin: 0 1px !important; - padding: 0 !important; - min-height: 0 !important; - max-width: 100% !important; - max-height: none !important; - border: 0 none !important; - background: none !important; - box-shadow: none !important; - text-indent: 0 !important; - line-height: inherit !important; -} - -.selectize-input > input:-ms-clear { - display: none; -} - -.selectize-input > input:focus { - outline: none !important; -} - -.selectize-input:after { - content: " "; - display: block; - clear: left; -} -.selectize-input.dropdown-active:before { - content: " "; - position: absolute; - right: 0; - bottom: 0; - left: 0; - display: block; - height: 1px; - background: #f0f0f0; -} - -.selectize-dropdown { - position: absolute; - z-index: 1000; - box-sizing: border-box; - margin: -1px 0 0 0; - border: 1px solid #b1b1b1; - border-top: 0 none; - background: #fff; - border-radius: 0 0 var(--border-radius) var(--border-radius); - box-shadow: 0 3px 6px rgba(0, 0, 0, 0.1); -} - -.selectize-dropdown [data-selectable] { - overflow: hidden; - cursor: pointer; -} - -.selectize-dropdown [data-selectable] .highlight { - background: #fff3b8; - border-radius: 1px; -} - -.selectize-dropdown [data-selectable], -.selectize-dropdown .optgroup-header, -.selectize-dropdown .dropdown-empty-message { - padding: 7px 8px; -} - -.selectize-dropdown .optgroup-header { - background: #fff; - color: #303030; - cursor: default; -} - -.selectize-dropdown .active { - background: color(var(--blue) alpha(-85%)); - color: var(--darkgrey); -} - -.selectize-dropdown .active.create { - color: #666; -} - -.selectize-dropdown .create { - color: rgba(48, 48, 48, 0.5); -} - -.selectize-dropdown-content { - overflow-x: hidden; - overflow-y: auto; - max-height: 200px; -} - -.selectize-control.single .selectize-input, -.selectize-control.single .selectize-input input { - cursor: pointer; -} - -.selectize-control.single .selectize-input.input-active, -.selectize-control.single .selectize-input.input-active input { - cursor: text; -} - -.selectize-control.single .selectize-input:after { - content: " "; - position: absolute; - top: 50%; - right: 15px; - display: block; - margin-top: -3px; - width: 0; - height: 0; - border-width: 5px 5px 0 5px; - border-style: solid; - border-color: #808080 transparent transparent transparent; -} - -.selectize-control.single .selectize-input.dropdown-active:after { - margin-top: -4px; - border-width: 0 5px 5px 5px; - border-color: transparent transparent #808080 transparent; -} - -.selectize-control.rtl.single .selectize-input:after { - right: auto; - left: 15px; -} - -.selectize-control.rtl .selectize-input > input { - margin: 0 4px 0 -2px !important; -} - -.selectize-control .selectize-input.disabled { - background-color: #fafafa; - opacity: 0.5; -} - -.selectize-control.multi .selectize-input.has-items { - padding-right: 5px; - padding-left: 5px; -} - -.selectize-control.multi .selectize-input.disabled [data-value] { - background: none; - box-shadow: none; - color: #999; - text-shadow: none; -} - -.selectize-control.multi .selectize-input.disabled [data-value], -.selectize-control.multi .selectize-input.disabled [data-value] .remove { - border-color: #e6e6e6; -} - -.selectize-control.multi .selectize-input.disabled [data-value] .remove { - background: none; -} - -.selectize-control.multi .selectize-input [data-value] { - background: var(--blue); - border-radius: 3px; -} - -.selectize-control.multi .selectize-input [data-value].active { - background: color(var(--blue) lightness(-10%)); -} - -.selectize-control.single .selectize-input { - background: #f9f9f9; -} - -.selectize-control.single .selectize-input, -.selectize-dropdown.single { - border-color: #b8b8b8; -} - -.optgroup:first-of-type .optgroup-header { - margin-bottom: 7px; - padding-top: 0; - padding-bottom: 0; -} - -.selectize-dropdown .optgroup-header { - position: relative; - display: inline-block; - padding-top: 7px; - background: #fff; - color: var(--midgrey); - font-size: 0.85em; -} - -.selectize-dropdown .optgroup-header:after { - content: ""; - position: absolute; - top: 52%; - left: calc(100% + 3px); - display: block; - width: calc(189px - 100%); - height: 1px; - border-bottom: #dfe1e3 1px solid; -} -@media (max-width: 800px) { - .selectize-dropdown .optgroup-header:after { - width: calc(224px - 100%); - } -} -@media (max-width: 500px) { - .selectize-dropdown .optgroup-header:after { - width: calc(80vw - 45px - 100%); - } -} - -.selectize-dropdown .option { - line-height: 1.35em; -} - -.dropdown-empty-message { - position: relative; - color: var(--midgrey); - font-size: 0.9em; -} diff --git a/ghost/admin/app/styles/components/settings-menu.css b/ghost/admin/app/styles/components/settings-menu.css index 3ad88a0c98..5a8cef1081 100644 --- a/ghost/admin/app/styles/components/settings-menu.css +++ b/ghost/admin/app/styles/components/settings-menu.css @@ -188,10 +188,6 @@ color: color(var(--red) lightness(-10%)); } -.settings-menu-content .selectize-input { - padding: 7px 12px; -} - .post-setting-custom-excerpt { font-size: 1.5rem; line-height: 1.35em; diff --git a/ghost/admin/app/styles/layouts/main.css b/ghost/admin/app/styles/layouts/main.css index 5f17b5bf0f..ebf2f3d832 100644 --- a/ghost/admin/app/styles/layouts/main.css +++ b/ghost/admin/app/styles/layouts/main.css @@ -319,12 +319,6 @@ body > .ember-view:not(.default-liquid-destination) { transform: translate3d(80vw, 0, 0); } - .gh-nav-search-input .selectize-input, - .gh-nav-search-input .selectize-input input, - .gh-nav-search-input .selectize-dropdown { - font-size: 1.5rem; - } - .gh-nav-list { font-size: 1.5rem; } diff --git a/ghost/admin/app/templates/components/gh-post-settings-menu.hbs b/ghost/admin/app/templates/components/gh-post-settings-menu.hbs index f354e31e1c..df2fecd680 100644 --- a/ghost/admin/app/templates/components/gh-post-settings-menu.hbs +++ b/ghost/admin/app/templates/components/gh-post-settings-menu.hbs @@ -67,17 +67,7 @@