mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-24 23:48:13 -05:00
Added delete button with confirmation to snippets in card menus
no issue - show a delete icon when a snippet is hovered in plus/slash menus - show a confirmation dialog when the delete icon is clicked - keep menus open whilst displaying the delete confirmation dialog
This commit is contained in:
parent
cddd977536
commit
1bd4b5cda7
14 changed files with 140 additions and 10 deletions
|
@ -32,5 +32,6 @@
|
|||
@wordCountDidChange={{action this.onWordCountChange}}
|
||||
@snippets={{@snippets}}
|
||||
@saveSnippet={{@saveSnippet}}
|
||||
@deleteSnippet={{@deleteSnippet}}
|
||||
/>
|
||||
</div>
|
|
@ -8,8 +8,11 @@
|
|||
{{svg-jar "arrow-down-small"}}
|
||||
</span>
|
||||
</GhDropdownButton>
|
||||
<GhDropdown @name="members-label-menu" @tagName="div"
|
||||
@classNames="dropdown-menu dropdown-triangle-top-right dropdown-action">
|
||||
<GhDropdown
|
||||
@name="members-label-menu"
|
||||
@tagName="div"
|
||||
@classNames="dropdown-menu dropdown-triangle-top-right dropdown-action"
|
||||
>
|
||||
<ul class="dropdown-content">
|
||||
{{#each @availableLabels as |label|}}
|
||||
<li class="{{if (eq @selectedLabel.name label.name) "selected"}}">
|
||||
|
|
20
ghost/admin/app/components/modal-delete-snippet.hbs
Normal file
20
ghost/admin/app/components/modal-delete-snippet.hbs
Normal file
|
@ -0,0 +1,20 @@
|
|||
<header class="modal-header">
|
||||
<h1>Are you sure?</h1>
|
||||
</header>
|
||||
<a class="close" href="" role="button" title="Close" {{action "closeModal"}}>{{svg-jar "close"}}<span class="hidden">Close</span></a>
|
||||
|
||||
<div class="modal-body">
|
||||
<p>
|
||||
Deleting snippet "{{this.snippet.name}}" will make it unavailable to all staff users.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button {{action "closeModal"}} class="gh-btn"><span>Cancel</span></button>
|
||||
<GhTaskButton
|
||||
@buttonText="Delete Snippet"
|
||||
@successText="Deleted"
|
||||
@task={{this.deleteSnippet}}
|
||||
@taskArgs={{this.snippet}}
|
||||
@class="gh-btn gh-btn-red gh-btn-icon" />
|
||||
</div>
|
27
ghost/admin/app/components/modal-delete-snippet.js
Normal file
27
ghost/admin/app/components/modal-delete-snippet.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
import ModalComponent from 'ghost-admin/components/modal-base';
|
||||
import {alias} from '@ember/object/computed';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency';
|
||||
|
||||
export default ModalComponent.extend({
|
||||
router: service(),
|
||||
notifications: service(),
|
||||
|
||||
snippet: alias('model'),
|
||||
|
||||
actions: {
|
||||
confirm() {
|
||||
this.deleteSnippet.perform();
|
||||
}
|
||||
},
|
||||
|
||||
deleteSnippet: task(function* (snippet) {
|
||||
try {
|
||||
yield this.confirm(snippet);
|
||||
} catch (error) {
|
||||
this.notifications.showAPIError(error, {key: 'snippet.delete.failed'});
|
||||
} finally {
|
||||
this.send('closeModal');
|
||||
}
|
||||
}).drop()
|
||||
});
|
|
@ -102,6 +102,7 @@ export default Controller.extend({
|
|||
showReAuthenticateModal: false,
|
||||
showEmailPreviewModal: false,
|
||||
showUpgradeModal: false,
|
||||
showDeleteSnippetModal: false,
|
||||
hostLimitError: null,
|
||||
// koenig related properties
|
||||
wordcount: null,
|
||||
|
@ -310,6 +311,14 @@ export default Controller.extend({
|
|||
snippetRecord.rollbackAttributes();
|
||||
throw error;
|
||||
});
|
||||
},
|
||||
|
||||
toggleDeleteSnippetModal(snippet) {
|
||||
this.set('snippetToDelete', snippet);
|
||||
},
|
||||
|
||||
deleteSnippet(snippet) {
|
||||
return snippet.destroyRecord();
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -272,4 +272,4 @@
|
|||
.dropdown-action.fade-out {
|
||||
animation-duration: .001s;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -804,6 +804,40 @@
|
|||
color: var(--darkgrey);
|
||||
}
|
||||
|
||||
.kg-cardmenu-card-hover .kg-cardmenu-action-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0;
|
||||
transition: opacity ease-in-out 0.15s;
|
||||
padding: 4px;
|
||||
margin-top: -2px;
|
||||
margin-bottom: -2px;
|
||||
margin-right: 4px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.kg-cardmenu-card-hover:hover .kg-cardmenu-action-icon {
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
.kg-cardmenu-card-hover .kg-cardmenu-action-icon:hover {
|
||||
background: var(--whitegrey-d1);
|
||||
}
|
||||
|
||||
.kg-cardmenu-card-hover .kg-cardmenu-action-icon svg {
|
||||
margin: 0;
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
.kg-cardmenu-card-hover .kg-cardmenu-action-icon svg path {
|
||||
fill: var(--midgrey);
|
||||
}
|
||||
|
||||
.kg-cardmenu-card-hover .kg-cardmenu-action-icon:hover svg path {
|
||||
fill: var(--darkgrey);
|
||||
}
|
||||
|
||||
/* Padded container housing title + editor canvas, scrollable content */
|
||||
.gh-koenig-editor-pane {
|
||||
padding: 11vw 92px;
|
||||
|
|
|
@ -83,6 +83,7 @@
|
|||
@onWordCountChange={{action "updateWordCount"}}
|
||||
@snippets={{this.snippets}}
|
||||
@saveSnippet={{action "saveSnippet"}}
|
||||
@deleteSnippet={{action "toggleDeleteSnippetModal"}}
|
||||
/>
|
||||
|
||||
<div class="absolute flex items-center br3 bg-white {{if editor.headerClass "right-4 bottom-4" "right-6 bottom-6"}}">
|
||||
|
@ -134,6 +135,16 @@
|
|||
/>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.snippetToDelete}}
|
||||
<GhFullscreenModal
|
||||
@modal="delete-snippet"
|
||||
@model={{this.snippetToDelete}}
|
||||
@confirm={{action "deleteSnippet"}}
|
||||
@close={{action "toggleDeleteSnippetModal"}}
|
||||
@modifier="action wide"
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
<LiquidWormhole>
|
||||
<GhPostSettingsMenu
|
||||
@post={{this.post}}
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
@editor={{this.editor}}
|
||||
@editorRange={{this.selectedRange}}
|
||||
@snippets={{this.snippets}}
|
||||
@deleteSnippet={{this.deleteSnippet}}
|
||||
@replaceWithCardSection={{action "replaceWithCardSection"}}
|
||||
@replaceWithPost={{action "replaceWithPost"}}
|
||||
/>
|
||||
|
@ -60,6 +61,7 @@
|
|||
@editor={{this.editor}}
|
||||
@editorRange={{this.selectedRange}}
|
||||
@snippets={{this.snippets}}
|
||||
@deleteSnippet={{this.deleteSnippet}}
|
||||
@replaceWithCardSection={{action "replaceWithCardSection"}}
|
||||
@replaceWithPost={{action "replaceWithPost"}}
|
||||
/>
|
||||
|
|
|
@ -6,9 +6,17 @@
|
|||
</div>
|
||||
{{#each section.items as |item|}}
|
||||
{{#if (or (not item.developerExperiment) (enable-developer-experiments))}}
|
||||
<div class="{{if (eq item @selectedItem) "kg-cardmenu-card-selected"}} {{kg-style "cardmenu-card"}}" {{on "click" (fn @itemClicked item)}} data-kg="cardmenu-card" role="menuitem">
|
||||
<div
|
||||
class="{{if (eq item @selectedItem) "kg-cardmenu-card-selected"}} {{kg-style "cardmenu-card"}}"
|
||||
data-kg="cardmenu-card"
|
||||
role="menuitem"
|
||||
{{on "click" (fn @itemClicked item)}}
|
||||
>
|
||||
<div class="{{kg-style "cardmenu-icon"}} {{item.iconClass}}" aria-hidden="true">{{svg-jar item.icon class="w7 h7"}}</div>
|
||||
<div class="{{kg-style "cardmenu-label"}}">{{item.label}}</div>
|
||||
{{#if item.deleteClicked}}
|
||||
<span class="kg-cardmenu-action-icon" {{on "click" item.deleteClicked}}>{{svg-jar "trash"}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
{{svg-jar "koenig/search"}}
|
||||
<input type="text" placeholder="Search for a card..." class="gh-input koenig-cardmenu-search-input">
|
||||
</div> --}}
|
||||
<KoenigMenuContent @itemSections={{this.itemSections}} @itemClicked={{action "itemClicked"}} />
|
||||
<KoenigMenuContent
|
||||
@itemSections={{this.itemSections}}
|
||||
@itemClicked={{action "itemClicked"}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
|
@ -53,7 +53,12 @@ export default Component.extend({
|
|||
label: snippet.name,
|
||||
icon: snippetIcon(snippet),
|
||||
type: 'snippet',
|
||||
matches: [snippet.name.toLowerCase()]
|
||||
matches: [snippet.name.toLowerCase()],
|
||||
deleteClicked: (event) => {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
this.deleteSnippet(snippet);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -236,7 +241,9 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
_handleWindowMousedown(event) {
|
||||
if (!event.target.closest(`#${this.elementId}`)) {
|
||||
if (
|
||||
!event.target.closest(`#${this.elementId}, .fullscreen-modal`)
|
||||
) {
|
||||
this._hideMenu();
|
||||
}
|
||||
},
|
||||
|
|
|
@ -72,7 +72,12 @@ export default class KoenigSlashMenuComponent extends Component {
|
|||
label: snippet.name,
|
||||
icon: snippetIcon(snippet),
|
||||
type: 'snippet',
|
||||
matches: [snippet.name.toLowerCase()]
|
||||
matches: [snippet.name.toLowerCase()],
|
||||
deleteClicked: (event) => {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
this.args.deleteSnippet(snippet);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -303,7 +308,7 @@ export default class KoenigSlashMenuComponent extends Component {
|
|||
|
||||
_handleWindowMousedown(event) {
|
||||
// clicks outside the menu should always close
|
||||
if (!event.target.closest(`#${this.containerElement.id}`)) {
|
||||
if (!event.target.closest(`#${this.containerElement.id}, .fullscreen-modal`)) {
|
||||
this._hideMenu();
|
||||
|
||||
// clicks on the menu but not on a button should be ignored so that the
|
||||
|
|
|
@ -21,7 +21,7 @@ export function kgStyle([style], options) {
|
|||
break;
|
||||
|
||||
case 'cardmenu-label':
|
||||
cssClass = 'f-7 tracked-1 fw4 ma0 ml4';
|
||||
cssClass = 'f-7 tracked-1 fw4 ma0 ml4 flex-grow-1';
|
||||
break;
|
||||
|
||||
// Container cards
|
||||
|
|
Loading…
Add table
Reference in a new issue