0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-03 23:00:14 -05:00

Complete Modal Refactor

* Smoother animations
* Removed blurring in Chrome temporarily
* Centering is now done in CSS (the height is calculated in JS to work in FF and Opera)
* Modals now need close: true to be set to enable the close icon and shortcuts for closing (ESC key, background clicking)
This commit is contained in:
Matthew Harrison-Jones 2013-09-17 17:24:53 +01:00 committed by Hannah Wolfe
parent adae9f4180
commit 2305329041
8 changed files with 237 additions and 204 deletions

View file

@ -667,7 +667,9 @@ body.zen {
/* ============================================================================= /* =============================================================================
Markdown Help Modal Markdown Help Modal
============================================================================= */ ============================================================================= */
.markdown-help-container{
padding-bottom: 20px;
}
.modal-markdown-help-table { .modal-markdown-help-table {
margin-top: 0; margin-top: 0;
} }

View file

@ -984,32 +984,42 @@ nav {
Modals Modals
========================================================================== */ ========================================================================== */
#modal-container { #modal-container {
&.active { @include box-sizing(border-box);
position: absolute; display: none;
top: 0; position: fixed;
bottom: 0; top: 0;
left: 0; bottom: 0;
right: 0; left: 0;
z-index: 999; right: 0;
@include transition(all 0.15s linear 0s); overflow-x: auto;
@include transform(translateZ(0)); overflow-y: scroll;
z-index: 1040;
pointer-events: none;
@include transition(all 0.15s linear 0s);
@include transform(translateZ(0));
}
&.dark { .fade {
background: rgba(0,0,0,0.4); opacity: 0;
} @include transition(opacity 0.2s linear 0s);
@include transform(translateZ(0));
.modal-background {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 999;
}
&.in {
opacity: 1;
} }
} }
.modal-background {
display: none;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: rgba(0,0,0,0.4);
z-index: 1030;
}
body.blur > *:not(#modal-container) { body.blur > *:not(#modal-container) {
@include transition(all 0.15s linear 0s); @include transition(all 0.15s linear 0s);
-webkit-filter: blur(2px); -webkit-filter: blur(2px);
@ -1022,30 +1032,29 @@ body.blur > *:not(#modal-container) {
%modal, .modal { %modal, .modal {
@include box-sizing(border-box); @include box-sizing(border-box);
max-height: 90%; left: 50%;
right: auto;
width: 450px; width: 450px;
padding: 0; margin-left: auto;
background: #fff; margin-right: auto;
border-radius: $rounded; padding-top: 30px;
overflow:auto; padding-bottom: 30px;
z-index: 1001; z-index: 1050;
box-shadow: rgba(0,0,0,0.2) 0 0 0 6px; pointer-events: auto;
&.fade {
opacity: 0;
@include transition(opacity 0.2s linear 0s);
&.in { @include breakpoint($tablet) {
opacity: 1; width: auto;
} padding: 10px;
} };
button { button {
min-width: 100px; min-width: 100px;
} }
@include breakpoint($mobile) { @include breakpoint($tablet) {
width: 100%; width: 100%;
margin-left: 0;
} }
} }
@ -1055,16 +1064,49 @@ body.blur > *:not(#modal-container) {
.modal-action { .modal-action {
@extend %modal; @extend %modal;
padding: 60px 0 30px;
@include breakpoint($tablet) {
padding: 30px 0;
}
.modal-footer { .modal-footer {
margin-top: 20px; margin-top: 20px;
} }
} }
.modal-content {
@include box-sizing(padding-box);
position: relative;
background-clip: padding-box;
background-color: #FFFFFF;
border-radius: $rounded;
box-shadow: rgba(0,0,0,0.2) 0 0 0 6px;
.close {
@include box-sizing(border-box);
position: absolute;
top: 15px;
right: 15px;
width: 16px;
min-height: 16px;
padding: 0;
margin: 0;
border: none;
z-index: 9999;
@include icon($i-x, 1em, $midgrey);
@include transition(opacity 0.3s linear);
&:hover {
color: $darkgrey;
}
}
}
.modal-header { .modal-header {
position: relative; position: relative;
padding: 20px; padding: 20px;
border-bottom: 1px solid $lightgrey; border-bottom: 1px solid $lightbrown;
h1 { h1 {
display: inline-block; display: inline-block;
@ -1072,31 +1114,13 @@ body.blur > *:not(#modal-container) {
font-size: 1.5em; font-size: 1.5em;
font-weight: bold; font-weight: bold;
} }
.close {
@include box-sizing(border-box);
position: absolute;
top: 10px;
right: 20px;
width: 16px;
min-height: 16px;
padding: 0;
margin: 0;
border: none;
opacity: 0.4;
@include icon($i-close, 1em, $midgrey);
@include transition(opacity 0.3s linear);
&:hover{
opacity: 1;
}
}
} }
.modal-content { .modal-body {
padding: 0 20px; position: relative;
min-height: 100px; min-height: 100px;
padding: 0 20px;
overflow-y: auto;
} }
.modal-footer { .modal-footer {
@ -1107,7 +1131,7 @@ body.blur > *:not(#modal-container) {
.modal-style-wide { .modal-style-wide {
width: 550px; width: 550px;
@include breakpoint($mobile) { @include breakpoint($tablet) {
width: 100%; width: 100%;
} }
} }
@ -1363,6 +1387,7 @@ main {
} }
} }
} }
.pre-image-uploader { .pre-image-uploader {
@include box-sizing(border-box); @include box-sizing(border-box);
@include baseline; @include baseline;

View file

@ -104,7 +104,6 @@
} }
$(".modal-copyToHTML-content").text(md).selectText(); $(".modal-copyToHTML-content").text(md).selectText();
$(".js-modal").center();
pass = false; pass = false;
break; break;
case "list": case "list":

View file

@ -4,10 +4,10 @@
Ghost.Models.uploadModal = Backbone.Model.extend({ Ghost.Models.uploadModal = Backbone.Model.extend({
options: { options: {
close: false, close: true,
type: "action", type: "action",
style: "wide", style: ["wide"],
animation: 'fadeIn', animation: 'fade',
afterRender: function () { afterRender: function () {
this.$('.js-drop-zone').upload(); this.$('.js-drop-zone').upload();
}, },

View file

@ -1,12 +1,14 @@
<aside class="modal-background"></aside>
<article class="modal{{#if options.type}}-{{options.type}}{{/if}} {{#if options.style}}{{#each options.style}}modal-style-{{this}} {{/each}}{{/if}}{{options.animation}} js-modal"> <article class="modal{{#if options.type}}-{{options.type}}{{/if}} {{#if options.style}}{{#each options.style}}modal-style-{{this}} {{/each}}{{/if}}{{options.animation}} js-modal">
{{#if content.title}}<header class="modal-header"><h1>{{content.title}}</h1>{{#if options.close}}<a class="close" href="#"><span class="hidden">Close</span></a>{{/if}}</header>{{/if}}
<section class="modal-content"> <section class="modal-content">
{{#if content.title}}<header class="modal-header"><h1>{{content.title}}</h1></header>{{/if}}
{{#if options.close}}<a class="close" href="#"><span class="hidden">Close</span></a>{{/if}}
<section class="modal-body">
</section>
{{#if options.confirm}}
<footer class="modal-footer">
<button class="js-button-accept {{#if options.confirm.accept.buttonClass}}{{options.confirm.accept.buttonClass}}{{else}}button-add{{/if}}">{{options.confirm.accept.text}}</button>
<button class="js-button-reject {{#if options.confirm.reject.buttonClass}}{{options.confirm.reject.buttonClass}}{{else}}button-delete{{/if}}">{{options.confirm.reject.text}}</button>
</footer>
{{/if}}
</section> </section>
{{#if options.confirm}}
<footer class="modal-footer">
<button class="js-button-accept {{#if options.confirm.accept.buttonClass}}{{options.confirm.accept.buttonClass}}{{else}}button-add{{/if}}">{{options.confirm.accept.text}}</button>
<button class="js-button-reject {{#if options.confirm.reject.buttonClass}}{{options.confirm.reject.buttonClass}}{{else}}button-delete{{/if}}">{{options.confirm.reject.text}}</button>
</footer>
{{/if}}
</article> </article>

View file

@ -1,107 +1,109 @@
<table class="modal-markdown-help-table"> <section class="markdown-help-container">
<thead> <table class="modal-markdown-help-table">
<tr> <thead>
<th>Result</th> <tr>
<th>Markdown</th> <th>Result</th>
<th>Shortcut</th> <th>Markdown</th>
</tr> <th>Shortcut</th>
</thead> </tr>
<tbody> </thead>
<tr> <tbody>
<td><strong>Bold</strong></td> <tr>
<td>**text**</td> <td><strong>Bold</strong></td>
<td>Ctrl / Cmd + B</td> <td>**text**</td>
</tr> <td>Ctrl / Cmd + B</td>
<tr> </tr>
<td><em>Emphasize</em></td> <tr>
<td>__text__</td> <td><em>Emphasize</em></td>
<td>Ctrl / Cmd + I</td> <td>__text__</td>
</tr> <td>Ctrl / Cmd + I</td>
<tr> </tr>
<td><code>Inline Code</code></td> <tr>
<td>`code`</td> <td><code>Inline Code</code></td>
<td>Cmd + K / Ctrl + Shift + K</td> <td>`code`</td>
</tr> <td>Cmd + K / Ctrl + Shift + K</td>
<tr> </tr>
<td>Strike-through</td> <tr>
<td>~~text~~</td> <td>Strike-through</td>
<td>Ctrl + Alt + U</td> <td>~~text~~</td>
</tr> <td>Ctrl + Alt + U</td>
<tr> </tr>
<td><a href="#">Link</a></td> <tr>
<td>[title](http://)</td> <td><a href="#">Link</a></td>
<td>Ctrl + Shift + L</td> <td>[title](http://)</td>
</tr> <td>Ctrl + Shift + L</td>
<tr> </tr>
<td>Image</td> <tr>
<td>![alt](http://)</td> <td>Image</td>
<td>Ctrl + Shift + I</td> <td>![alt](http://)</td>
</tr> <td>Ctrl + Shift + I</td>
<tr> </tr>
<td>List</td> <tr>
<td>* item</td> <td>List</td>
<td>Ctrl + L</td> <td>* item</td>
</tr> <td>Ctrl + L</td>
<tr> </tr>
<td>Blockquote</td> <tr>
<td>> quote</td> <td>Blockquote</td>
<td>Ctrl + Q</td> <td>> quote</td>
</tr> <td>Ctrl + Q</td>
<tr> </tr>
<td>H1</td> <tr>
<td># Heading</td> <td>H1</td>
<td>Ctrl + Alt + 1</td> <td># Heading</td>
</tr> <td>Ctrl + Alt + 1</td>
<tr> </tr>
<td>H2</td> <tr>
<td>## Heading</td> <td>H2</td>
<td>Ctrl + Alt + 2</td> <td>## Heading</td>
</tr> <td>Ctrl + Alt + 2</td>
<tr> </tr>
<td>H3</td> <tr>
<td>### Heading</td> <td>H3</td>
<td>Ctrl + Alt + 3</td> <td>### Heading</td>
</tr> <td>Ctrl + Alt + 3</td>
<tr> </tr>
<td>H4</td> <tr>
<td>#### Heading</td> <td>H4</td>
<td>Ctrl + Alt + 4</td> <td>#### Heading</td>
</tr> <td>Ctrl + Alt + 4</td>
<tr> </tr>
<td>H5</td> <tr>
<td>##### Heading</td> <td>H5</td>
<td>Ctrl + Alt + 5</td> <td>##### Heading</td>
</tr> <td>Ctrl + Alt + 5</td>
<tr> </tr>
<td>H6</td> <tr>
<td>###### Heading</td> <td>H6</td>
<td>Ctrl + Alt + 6</td> <td>###### Heading</td>
</tr> <td>Ctrl + Alt + 6</td>
<tr> </tr>
<td>Select Word</td> <tr>
<td></td> <td>Select Word</td>
<td>Ctrl + Alt + W</td> <td></td>
</tr> <td>Ctrl + Alt + W</td>
<tr> </tr>
<td>Uppercase</td> <tr>
<td></td> <td>Uppercase</td>
<td>Ctrl + U</td> <td></td>
</tr> <td>Ctrl + U</td>
<tr> </tr>
<td>Lowercase</td> <tr>
<td></td> <td>Lowercase</td>
<td>Ctrl + Shift + U</td> <td></td>
</tr> <td>Ctrl + Shift + U</td>
<tr> </tr>
<td>Titlecase</td> <tr>
<td></td> <td>Titlecase</td>
<td>Ctrl + Alt + Shift + U</td> <td></td>
</tr> <td>Ctrl + Alt + Shift + U</td>
<tr> </tr>
<td>Insert Current Date</td> <tr>
<td></td> <td>Insert Current Date</td>
<td>Ctrl + Shift + 1</td> <td></td>
</tr> <td>Ctrl + Shift + 1</td>
</tbody> </tr>
</table> </tbody>
For further Markdown syntax reference: <a href="http://daringfireball.net/projects/markdown/syntax" target="_blank">Markdown Documentation</a> </table>
For further Markdown syntax reference: <a href="http://daringfireball.net/projects/markdown/syntax" target="_blank">Markdown Documentation</a>
</section>

View file

@ -273,14 +273,19 @@
initialize: function () { initialize: function () {
this.render(); this.render();
var self = this; var self = this;
if (!this.model.options.confirm) { if (this.model.options.close) {
shortcut.add("ESC", function () { shortcut.add("ESC", function () {
self.removeElement(); self.removeElement();
}); });
$(document).on('click', '.modal-background', function (e) { $(document).on('click', '.modal-background', function () {
self.removeElement(e); self.removeElement();
}); });
} else { } else {
shortcut.remove("ESC");
$(document).off('click', '.modal-background');
}
if (this.model.options.confirm) {
// Initiate functions for buttons here so models don't get tied up. // Initiate functions for buttons here so models don't get tied up.
this.acceptModal = function () { this.acceptModal = function () {
this.model.options.confirm.accept.func.call(this); this.model.options.confirm.accept.func.call(this);
@ -290,8 +295,6 @@
this.model.options.confirm.reject.func.call(this); this.model.options.confirm.reject.func.call(this);
self.removeElement(); self.removeElement();
}; };
shortcut.remove("ESC");
$(document).off('click', '.modal-background');
} }
}, },
templateData: function () { templateData: function () {
@ -303,28 +306,26 @@
'click .js-button-reject': 'rejectModal' 'click .js-button-reject': 'rejectModal'
}, },
afterRender: function () { afterRender: function () {
this.$(".modal-content").html(this.addSubview(new Ghost.Views.Modal.ContentView({model: this.model})).render().el); this.$el.fadeIn(50);
this.$el.children(".js-modal").center({animate: false}).css("max-height", $(window).height() - 120); // same as resize(), but the debounce causes init lag $(".modal-background").fadeIn(10, function () {
this.$el.addClass("active dark"); $(this).addClass("in");
});
if (document.body.style.webkitFilter !== undefined) { // Detect webkit filters if (this.model.options.confirm) {
$("body").addClass("blur"); this.$('.close').remove();
} }
this.$(".modal-body").html(this.addSubview(new Ghost.Views.Modal.ContentView({model: this.model})).render().el);
// if (document.body.style.webkitFilter !== undefined) { // Detect webkit filters
// $("body").addClass("blur"); // Removed due to poor performance in Chrome
// }
if (_.isFunction(this.model.options.afterRender)) { if (_.isFunction(this.model.options.afterRender)) {
this.model.options.afterRender.call(this); this.model.options.afterRender.call(this);
} }
if (this.model.options.animation) { if (this.model.options.animation) {
this.animate(this.$el.children(".js-modal")); this.animate(this.$el.children(".js-modal"));
} }
var self = this;
$(window).on('resize', self.resize);
}, },
// #### resize
// Center and resize modal based on window height
resize: _.debounce(function () {
$(".js-modal").center().css("max-height", $(window).height() - 120);
}, 50),
// #### remove // #### remove
// Removes Backbone attachments from modals // Removes Backbone attachments from modals
remove: function () { remove: function () {
@ -357,11 +358,12 @@
if (document.body.style.filter !== undefined) { if (document.body.style.filter !== undefined) {
$("body").removeClass("blur"); $("body").removeClass("blur");
} }
self.$el.removeClass('dark'); $(".modal-background").removeClass('in');
setTimeout(function () { setTimeout(function () {
self.remove(); self.remove();
self.$el.removeClass('active'); self.$el.hide();
$(".modal-background").hide();
}, removeBackgroundDelay); }, removeBackgroundDelay);
}, removeModalDelay); }, removeModalDelay);

View file

@ -33,8 +33,9 @@
{{{body}}} {{{body}}}
</main> </main>
<aside id="modal-container"> <div id="modal-container">
</aside> </div>
<div class="modal-background fade"></div>
{{{ghostScriptTags}}} {{{ghostScriptTags}}}