Implement popovers

This commit is contained in:
Paul Adam Davis 2014-09-29 12:17:27 +01:00
parent 133aff0626
commit 3a13563f0b
12 changed files with 415 additions and 35 deletions

View File

@ -258,52 +258,52 @@
%dropdown-triangle-top {
&:before {
@include triangle(($dropdown_triangle * 2), #fff, up);
@include triangle($dropdown_triangle, #fff, up);
top: -$dropdown_triangle;
}
&:after {
@include triangle(($dropdown_triangle * 2) + 2, darken($lightgrey, 15%), up);
top: -($dropdown_triangle + 1);
@include triangle($dropdown_triangle + 2, darken($lightgrey, 15%), up);
top: -($dropdown_triangle + 2);
}
}
%dropdown-triangle-bottom {
&:before {
@include triangle(($dropdown_triangle * 2), #fff, down);
@include triangle($dropdown_triangle, #fff, down);
bottom: -$dropdown_triangle;
}
&:after {
@include triangle(($dropdown_triangle * 2) + 2, darken($lightgrey, 15%), down);
bottom: -($dropdown_triangle + 1);
@include triangle($dropdown_triangle + 2, darken($lightgrey, 15%), down);
bottom: -($dropdown_triangle + 2);
}
}
%dropdown-triangle-center {
&:before {
left: 50%;
margin-left: (-$dropdown_triangle);
margin-left: -($dropdown_triangle / 2);
}
&:after {
left: 50%;
margin-left: -($dropdown_triangle + 1);
margin-left: -($dropdown_triangle / 2 + 2);
}
}
// TODO: Make the values here use the $dropdown_triangle var
%dropdown-triangle-left {
&:before {
left: ($dropdown_triangle + 2);
left: ($dropdown_triangle / 2 + 2);
}
&:after {
left: ($dropdown_triangle + 1);
left: ($dropdown_triangle / 2);
}
}
%dropdown-triangle-right {
&:before {
left: auto;
right: ($dropdown_triangle + 2);
right: ($dropdown_triangle / 2 + 2);
}
&:after {
left: auto;
right: ($dropdown_triangle + 1);
right: ($dropdown_triangle / 2);
}
}

View File

@ -0,0 +1,265 @@
//
// Popovers
// --------------------------------------------------
.popover-item {
position: relative;
display: inline-block;
padding: 11px 26px 13px 16px;
background: $darkgrey;
min-width: 300px;
max-width: 400px;
border-radius: 6px;
font-size: 1.2rem;
color: $midgrey;
}
.popover-title {
font-size: 1.4rem;
font-weight: 300;
color: #fff;
}
.popover-desc {
margin-top: -4px;
}
.popover-body {
margin-top: 11px;
line-height: 1.7;
b {
color: #fff;
}
> *:last-child {
margin: 0;
}
}
//
// Popover triangles
// --------------------------------------------------
// Placeholders
%popover-triangle {
&:before {
content: '';
position: absolute;
display: block;
} // :before
}
// The triangle itself
%popover-triangle-vertical-top {
&:before {
@include triangle($popover_triangle, $darkgrey, up, shallow);
top: -(floor($popover_triangle * $popover_triangle_shallow_multiplier));
}
}
%popover-triangle-vertical-bottom {
&:before {
@include triangle($popover_triangle, $darkgrey, down, shallow);
bottom: -(floor($popover_triangle * $popover_triangle_shallow_multiplier));
}
}
%popover-triangle-horizontal-left {
&:before {
@include triangle($popover_triangle, $darkgrey, left, shallow);
left: -(floor($popover_triangle * $popover_triangle_shallow_multiplier));
}
}
%popover-triangle-horizontal-right {
&:before {
@include triangle($popover_triangle, $darkgrey, right, shallow);
right: -(floor($popover_triangle * $popover_triangle_shallow_multiplier));
}
}
// Triangle positions
%popover-triangle-vertical-center {
&:before {
left: 50%;
margin-left: -($popover_triangle / 2);
}
}
%popover-triangle-vertical-left {
&:before {
left: $popover_triangle;
}
}
%popover-triangle-vertical-right {
&:before {
left: auto;
right: $popover_triangle;
}
}
%popover-triangle-horizontal-center {
&:before {
top: 50%;
margin-top: -$popover_triangle;
}
}
%popover-triangle-horizontal-top {
&:before {
top: $popover_triangle;
}
}
%popover-triangle-horizontal-bottom {
&:before {
top: auto;
bottom: $popover_triangle;
}
}
// Usable classes
.popover-triangle-top {
transform-origin: top center;
@extend %popover-triangle;
@extend %popover-triangle-vertical-top;
@extend %popover-triangle-vertical-center;
}
.popover-triangle-top-left {
transform-origin: top left;
@extend %popover-triangle;
@extend %popover-triangle-vertical-top;
@extend %popover-triangle-vertical-left;
}
.popover-triangle-top-right {
transform-origin: top right;
@extend %popover-triangle;
@extend %popover-triangle-vertical-top;
@extend %popover-triangle-vertical-right;
}
.popover-triangle-bottom {
transform-origin: bottom center;
@extend %popover-triangle;
@extend %popover-triangle-vertical-bottom;
@extend %popover-triangle-vertical-center;
}
.popover-triangle-bottom-left {
transform-origin: bottom left;
@extend %popover-triangle;
@extend %popover-triangle-vertical-bottom;
@extend %popover-triangle-vertical-left;
}
.popover-triangle-bottom-right {
transform-origin: bottom right;
@extend %popover-triangle;
@extend %popover-triangle-vertical-bottom;
@extend %popover-triangle-vertical-right;
}
.popover-triangle-left {
transform-origin: left center;
@extend %popover-triangle;
@extend %popover-triangle-horizontal-left;
@extend %popover-triangle-horizontal-center;
}
.popover-triangle-left-top {
transform-origin: left top;
@extend %popover-triangle;
@extend %popover-triangle-horizontal-left;
@extend %popover-triangle-horizontal-top;
}
.popover-triangle-left-bottom {
transform-origin: left bottom;
@extend %popover-triangle;
@extend %popover-triangle-horizontal-left;
@extend %popover-triangle-horizontal-bottom;
}
.popover-triangle-right {
transform-origin: right center;
@extend %popover-triangle;
@extend %popover-triangle-horizontal-right;
@extend %popover-triangle-horizontal-center;
}
.popover-triangle-right-top {
transform-origin: right top;
@extend %popover-triangle;
@extend %popover-triangle-horizontal-right;
@extend %popover-triangle-horizontal-top;
}
.popover-triangle-right-bottom {
transform-origin: right bottom;
@extend %popover-triangle;
@extend %popover-triangle-horizontal-right;
@extend %popover-triangle-horizontal-bottom;
}
// Show/hide popover
// Position relative to the position of the triangle
// So... `popover-triangle-left-top` opens on the right of the button
// because the triangle is on the top left, poitning to the top right of the button
//
// |------| |-----------------|
// |Button| < Popover content |
// |------| | Lorem ipsum dol |
// |-----------------|
.popover {
position: relative;
display: inline-block;
.popover-item {
position: absolute;
z-index: 20;
&.open {
display: block;
}
&.closed {
display: none;
}
}
.popover-item.popover-triangle-bottom {
bottom: calc(100% + 16px);
left: 50%;
transform: translateX(-50%);
}
.popover-item.popover-triangle-bottom-left {
bottom: calc(100% + 16px);
left: 0;
}
.popover-item.popover-triangle-bottom-right {
bottom: calc(100% + 16px);
right: 0;
}
.popover-item.popover-triangle-top {
top: calc(100% + 16px);
left: 50%;
transform: translateX(-50%);
}
.popover-item.popover-triangle-top-left {
top: calc(100% + 16px);
left: 0;
}
.popover-item.popover-triangle-top-right {
top: calc(100% + 16px);
right: 0;
}
.popover-item.popover-triangle-left {
left: calc(100% + 16px);
top: 50%;
transform: translateY(-50%);
}
.popover-item.popover-triangle-left-top {
left: calc(100% + 16px);
top: 50%;
transform: translateY(-($popover_triangle * 2));
}
.popover-item.popover-triangle-left-bottom {
left: calc(100% + 16px);
top: 50%;
transform: translateY(calc(-100% + #{($popover_triangle * 2)}));
}
.popover-item.popover-triangle-right {
right: calc(100% + 16px);
top: 50%;
transform: translateY(-50%);
}
.popover-item.popover-triangle-right-top {
right: calc(100% + 16px);
top: 50%;
transform: translateY(-($popover_triangle * 2));
}
.popover-item.popover-triangle-right-bottom {
right: calc(100% + 16px);
top: 50%;
transform: translateY(calc(-100% + #{($popover_triangle * 2)}));
}
}//.popover

View File

@ -103,31 +103,35 @@
//==== Simple SCSS mixin to create CSS triangles
//==== Example: @include css-triangle (10px, #fff, "up");
@mixin triangle ($size: 20px, $color: #000, $direction: "down") {
$size: $size / 2;
@mixin triangle ($size: 20px, $color: #000, $direction: "down", $type: "normal") {
$verticalSize: $size;
width: 0;
height: 0;
@if $type == "shallow" {
$verticalSize: floor($size * $popover_triangle_shallow_multiplier);
}
@if $direction == "down" {
border-left: $size solid #{setTriangleColor($direction, "left", $color)};
border-right: $size solid #{setTriangleColor($direction, "right", $color)};
border-top: $size solid #{setTriangleColor($direction, "top", $color)};
border-top: $verticalSize solid #{setTriangleColor($direction, "top", $color)};
}
@if $direction == "up" {
border-left: $size solid #{setTriangleColor($direction, "left", $color)};
border-right: $size solid #{setTriangleColor($direction, "right", $color)};
border-bottom: $size solid #{setTriangleColor($direction, "bottom", $color)};
border-bottom: $verticalSize solid #{setTriangleColor($direction, "bottom", $color)};
}
@if $direction == "left" {
border-right: $size solid #{setTriangleColor($direction, "right", $color)};
border-right: $verticalSize solid #{setTriangleColor($direction, "right", $color)};
border-top: $size solid #{setTriangleColor($direction, "top", $color)};
border-bottom: $size solid #{setTriangleColor($direction, "bottom", $color)};
}
@if $direction == "right" {
border-left: $size solid #{setTriangleColor($direction, "left", $color)};
border-left: $verticalSize solid #{setTriangleColor($direction, "left", $color)};
border-bottom: $size solid #{setTriangleColor($direction, "bottom", $color)};
border-top: $size solid #{setTriangleColor($direction, "top", $color)};
}

View File

@ -45,6 +45,8 @@ $at2x: 2 device-pixel-ratio;
$dropdown_triangle: 8px;
$popover_triangle: 14px;
$popover_triangle_shallow_multiplier: 0.8;

View File

@ -43,6 +43,7 @@
@import "components/dropdowns";
@import "components/pagination";
@import "components/badges";
@import "components/popovers";
//

View File

@ -42,7 +42,7 @@ var GhostDropdown = Ember.Component.extend(DropdownMixin, {
name = this.get('name'),
button = this.get('button'),
targetDropdownName = options.target;
if (name === targetDropdownName && (!isOpen || isClosing)) {
if (!button) {
button = options.button;

View File

@ -0,0 +1,15 @@
import DropdownButton from 'ghost/components/gh-dropdown-button';
var PopoverButton = DropdownButton.extend({
click: Ember.K, // We don't want clicks on popovers, but dropdowns have them. So `K`ill them here.
mouseEnter: function (event) {
this._super(event);
this.get('dropdown').toggleDropdown(this.get('popoverName'), this);
},
mouseLeave: function (event) {
this._super(event);
this.get('dropdown').toggleDropdown(this.get('popoverName'), this);
}
});
export default PopoverButton;

View File

@ -0,0 +1,7 @@
import GhostDropdown from 'ghost/components/gh-dropdown';
var GhostPopover = GhostDropdown.extend({
classNames: 'ghost-popover'
});
export default GhostPopover;

View File

@ -0,0 +1,75 @@
---
layout: default
title: Popovers &middot; Ghost UI
---
<header class="page-header">
<a class="menu-button" href="#"><span class="sr-only">Menu</span></a>
<h2>Popovers</h2>
</header>
<section class="page-content" style="padding: 5%; text-align: center;">
<h1>Popovers</h1>
<hr>
<div class="popover-item popover-triangle-bottom">
<div class="popover-title">URL Structure Formatting</div>
<div class="popover-desc">You can use dynamic variables in this field.</div>
<div class="popover-body">
<p>
<b>%t</b> - The title of your post (or page)<br>
<b>%c</b> - The tag which your post is categorised in<br>
<b>%y</b> - The year your post was published<br>
<b>%m</b> - The month your post was published<br>
<b>%d</b> - The day your post was published
</p>
</div>
</div>
<hr>
{% assign popover_classes = "popover-triangle-top|popover-triangle-top-left|popover-triangle-top-right|popover-triangle-bottom|popover-triangle-bottom-left|popover-triangle-bottom-right|popover-triangle-right|popover-triangle-right-top|popover-triangle-right-bottom|popover-triangle-left|popover-triangle-left-top|popover-triangle-left-bottom" | split: "|" %}
{% for item in popover_classes %}
<div class="popover">
<span class="label label-default hover-me">{{item}}</span>
<div class="popover-item closed {{item}}">
<div class="popover-title">URL Structure Formatting</div>
<div class="popover-desc">You can use dynamic variables in this field.</div>
<div class="popover-body">
<p>
<b>%t</b> - The title of your post (or page)<br>
<b>%c</b> - The tag which your post is categorised in<br>
<b>%y</b> - The year your post was published<br>
<b>%m</b> - The month your post was published<br>
<b>%d</b> - The day your post was published
</p>
</div>
</div>
</div>
<br><br>
{% endfor %}
<br>
<br>
<br>
<br>
<br>
</section>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(function(){
$(".hover-me").hover(function(){
$(this).next(".popover-item").addClass("open fade-in").removeClass("closed fade-out");
}, function(){
$(this).next(".popover-item").removeClass("fade-in").addClass("fade-out");
$(this).next(".popover-item").on('animationend webkitAnimationEnd oanimationend MSAnimationEnd', function (event) {
if (event.originalEvent.animationName === 'fade-out') {
$(this).removeClass("open fade-out").addClass("closed");
}
});
});
});
</script>

View File

@ -1,17 +1,4 @@
import BodyEventListener from 'ghost/mixins/body-event-listener';
var DropdownService = Ember.Object.extend(Ember.Evented, BodyEventListener, {
bodyClick: function (event) {
/*jshint unused:false */
this.closeDropdowns();
},
closeDropdowns: function () {
this.trigger('close');
},
toggleDropdown: function (dropdownName, dropdownButton) {
this.trigger('toggle', {target: dropdownName, button: dropdownButton});
}
});
import DropdownService from 'ghost/utils/dropdown-service';
var dropdownInitializer = {
name: 'dropdown',
@ -19,12 +6,18 @@ var dropdownInitializer = {
initialize: function (container, application) {
application.register('dropdown:service', DropdownService);
// Inject dropdowns
application.inject('component:gh-dropdown', 'dropdown', 'dropdown:service');
application.inject('component:gh-dropdown-button', 'dropdown', 'dropdown:service');
application.inject('controller:modals.delete-post', 'dropdown', 'dropdown:service');
application.inject('controller:modals.transfer-owner', 'dropdown', 'dropdown:service');
application.inject('route:application', 'dropdown', 'dropdown:service');
// Inject popovers
application.inject('component:gh-popover', 'dropdown', 'dropdown:service');
application.inject('component:gh-popover-button', 'dropdown', 'dropdown:service');
application.inject('route:application', 'dropdown', 'dropdown:service');
}
};
export default dropdownInitializer;
export default dropdownInitializer;

View File

@ -6,7 +6,7 @@
<div class="page-content">
<div class="settings-content">
<header class="settings-view-header">
<h2 class="page-title">Ugly Debug Tools</h2>
<div class="js-settings-header-inner settings-header-inner">
@ -15,6 +15,7 @@
</header>
<section class="content settings-debug">
<form id="settings-export">
<fieldset>
<div class="form-group">

View File

@ -0,0 +1,17 @@
// This is used by the dropdown initializer (and subsequently popovers) to manage closing & toggeling
import BodyEventListener from 'ghost/mixins/body-event-listener';
var DropdownService = Ember.Object.extend(Ember.Evented, BodyEventListener, {
bodyClick: function (event) {
/*jshint unused:false */
this.closeDropdowns();
},
closeDropdowns: function () {
this.trigger('close');
},
toggleDropdown: function (dropdownName, dropdownButton) {
this.trigger('toggle', {target: dropdownName, button: dropdownButton});
}
});
export default DropdownService;