diff --git a/core/admin/assets/js/models/widget.js b/core/admin/assets/js/models/widget.js new file mode 100644 index 0000000000..82be49f241 --- /dev/null +++ b/core/admin/assets/js/models/widget.js @@ -0,0 +1,43 @@ +/*global window, document, Ghost, $, Backbone, _ */ +(function () { + "use strict"; + + Ghost.Models.Widget = Backbone.Model.extend({ + + defaults: { + title: "", + name: "", + author: "", + applicationID: "", + size: "", + content: { + template: '', + data: { + number: { + count: 0, + sub: { + value: 0, + dir: "", // "up" or "down" + item: "", + period: "" + } + } + } + }, + settings: { + settingsPane: false, + enabled: false, + options: [{ + title: "ERROR", + value: "Widget options not set" + }] + } + } + }); + + Ghost.Collections.Widgets = Backbone.Collection.extend({ + // url: Ghost.settings.apiRoot + '/widgets', // What will this be? + model: Ghost.Models.Widget + }); + +}()); \ No newline at end of file diff --git a/core/admin/assets/js/router.js b/core/admin/assets/js/router.js index c2c332d406..dd2f0b958a 100644 --- a/core/admin/assets/js/router.js +++ b/core/admin/assets/js/router.js @@ -6,11 +6,426 @@ Ghost.Router = Backbone.Router.extend({ routes: { + '': 'dashboard', 'content/': 'blog', 'editor': 'editor', 'editor/': 'editor', 'editor/:id': 'editor' }, + dashboard: function () { + var widgets = new Ghost.Collections.Widgets(); + + widgets.add({ + title: "LINZ, AUSTRIA", + name: "time", + author: "Matthew Harrison-Jones", + applicationID: "com.ghost.time", + content: { + template: 'custom/time', + data: { + day: "Today", + weather: "12", + time: "12:42PM", + date: "Monday / March 5 / 2013" + } + }, + settings: { + settingsPane: true, + options: [{ + title: "Timezone", + value: "GMT" + }] + } + }); + + widgets.add({ + title: "Ghost", + name: "image", + author: "Matthew Harrison-Jones", + applicationID: "com.ghost.image", + size: "2x1", + content: { + template: 'default/blank' + }, + settings: { + settingsPane: true + } + }); + + widgets.add({ + title: "Upcoming Posts", + name: "posts", + author: "Matthew Harrison-Jones", + applicationID: "com.ghost.posts", + content: { + template: 'custom/upcoming-posts', + data: { + ready: 9, + pending: 4, + draft: 1 + } + }, + settings: { + settingsPane: true + } + }); + + widgets.add({ + title: "Unique Visitors (7 days)", + name: "stats", + author: "Matthew Harrison-Jones", + applicationID: "com.ghost.stats", + size: "2x2", + content: { + template: 'default/number', + data: { + number: { + count: "293,051", + sub: { + value: "+14%", + dir: "up", + item: "", + period: "in the last 7 days" + } + } + } + }, + settings: { + settingsPane: true + } + }); + + widgets.add({ + title: "Facebook Likes", + name: "facebook", + author: "Matthew Harrison-Jones", + applicationID: "com.ghost.facebook", + content: { + template: 'default/number', + data: { + number: { + count: "12,329", + sub: { + value: "-3", + dir: "down", + item: "likes", + period: "today" + } + } + } + }, + settings: { + settingsPane: true + } + }); + + widgets.add({ + title: "Google Plus", + name: "gplus", + author: "Matthew Harrison-Jones", + applicationID: "com.ghost.gplus", + content: { + template: 'default/number', + data: { + number: { + count: "4,103", + sub: { + item: "have you in circles" + } + } + } + }, + settings: { + settingsPane: true + } + }); + + widgets.add({ + title: "Twitter", + name: "twitter", + author: "Matthew Harrison-Jones", + applicationID: "com.ghost.twitter", + content: { + template: 'default/blank' + }, + settings: { + settingsPane: true, + enabled: true, + options: [ + { + title: "Account", + value: "@JohnONolan" + }, + { + title: "Display", + value: "Last Tweets" + }, + { + title: "Quantity", + value: 6 + } + ] + } + }); + + widgets.add({ + title: "Campaign Monitor", + name: "campaignmonitor", + author: "Matthew Harrison-Jones", + applicationID: "com.ghost.campaignmonitor", + content: { + template: 'default/number', + data: { + number: { + count: "5,693", + sub: { + value: "+63", + dir: "up", + item: "subscribers", + period: "this week" + } + } + } + }, + settings: { + settingsPane: true + } + }); + + widgets.add({ + title: "Most Popular Posts", + name: "popular", + author: "Matthew Harrison-Jones", + applicationID: "com.ghost.popular", + size: "1x2", + content: { + template: 'custom/popular-posts', + data: { + posts: [ + { + title: "The Night of The Headless Horseman Part II", + time: "Yesterday", + count: "3,128" + }, + { + title: "Latin Script & Why it's Particularly Boring to Read", + time: "Wednesday", + count: "1,345" + }, + { + title: "59 Signs Your Cat and/or Dog Might be Planning To Kill You", + time: "Tuesday", + count: "824" + }, + { + title: "A Love Letter to Emma Stone", + time: "Today", + count: "293" + }, + { + title: "Lorem Ipsum Dolor Sit Amet & Other Funny Moments", + time: "Yesterday", + count: "124" + }, + { + title: "Matt Does Git", + time: "Thursday", + count: "100" + } + ] + } + } + }); + + widgets.add({ + title: "Posts This Week (Out Of 20)", + name: "postsWeek", + author: "Matthew Harrison-Jones", + applicationID: "com.ghost.postsWeek", + content: { + template: 'default/blank' + } + }); + + widgets.add({ + title: "Your RSS News Feed", + name: "rss", + author: "Matthew Harrison-Jones", + applicationID: "com.ghost.rss", + size: "2x2", + content: { + template: 'default/blank' + }, + settings: { + settingsPane: true + } + }); + + widgets.add({ + title: "Instagram", + name: "instagram", + author: "Matthew Harrison-Jones", + applicationID: "com.ghost.instagram", + content: { + template: 'custom/instagram', + data: { + image: "http://f.cl.ly/items/303f3y1n3I2L1F10343E/instagram.jpg" + } + }, + settings: { + settingsPane: true, + options: [{ + title: "Account", + value: "@JohnONolan" + }] + } + }); + + widgets.add({ + title: "Klout", + name: "klout", + author: "Matthew Harrison-Jones", + applicationID: "com.ghost.klout", + content: { + template: 'default/number', + data: { + number: { + count: "64.23", + sub: { + value: "-0.42", + dir: "down", + item: "", + period: "in the last 30 days" + } + } + } + }, + settings: { + settingsPane: true + } + }); + + widgets.add({ + title: "Bounce Rate", + name: "bounce", + author: "Matthew Harrison-Jones", + applicationID: "com.ghost.bounce", + content: { + template: 'default/number', + data: { + number: { + count: "40.21%", + sub: { + value: "-2.53%", + dir: "up", + item: "", + period: "in the last month" + } + } + } + }, + settings: { + settingsPane: true + } + }); + + widgets.add({ + title: "Average Time On Site", + name: "avgTime", + author: "Matthew Harrison-Jones", + applicationID: "com.ghost.avgTime", + content: { + template: 'default/number', + data: { + number: { + count: "2m 16s", + sub: { + value: "+31.4%", + dir: "up", + item: "", + period: "in the last month" + } + } + } + }, + settings: { + settingsPane: true + } + }); + + widgets.add({ + title: "Last.fm", + name: "lastfm", + author: "Matthew Harrison-Jones", + applicationID: "com.ghost.lastfm", + content: { + template: 'custom/lastfm', + data: { + cover: "http://f.cl.ly/items/0p0r3T3v3M0R0H1k1p0S/imagine_dragons.png", + artist: "Imagine Dragons", + title: "On Top of The World" + } + }, + settings: { + settingsPane: true + } + }); + + widgets.add({ + title: "Post Ideas", + name: "ideas", + author: "Matthew Harrison-Jones", + applicationID: "com.ghost.ideas", + size: "2x1", + content: { + template: 'custom/post-ideas' + }, + settings: { + settingsPane: true + } + }); + + widgets.add({ + title: "Twitter", + name: "tweets", + author: "Matthew Harrison-Jones", + applicationID: "com.ghost.tweets", + content: { + template: 'custom/tweets', + data: { + avatar: "http://f.cl.ly/items/1A1S0D3T3p1g1B2Z3J0u/ghost_twitter.jpeg", + name: "Ghost", + handle: "@TryGhost", + tweet: "If you're exploring the @twitterapi, be sure and bring the new field guide along. dev.twitter.com/blog/...", + time: "3 May 12" + } + }, + settings: { + settingsPane: true + } + }); + + widgets.add({ + title: "Backups", + name: "backups", + author: "Matthew Harrison-Jones", + applicationID: "com.ghost.backups", + content: { + template: 'default/blank' + }, + settings: { + settingsPane: true + } + }); + + + + + + //widgets.fetch().then(function () { + Ghost.currentView = new Ghost.Views.Dashboard({ el: '#main', collection: widgets }); + //}); + }, blog: function () { var posts = new Ghost.Collections.Posts(); diff --git a/core/admin/assets/js/views/dashboard.js b/core/admin/assets/js/views/dashboard.js index 4e2f58c8ba..568c329546 100644 --- a/core/admin/assets/js/views/dashboard.js +++ b/core/admin/assets/js/views/dashboard.js @@ -1,8 +1,13 @@ -/*global window, document, localStorage, Ghost, Backbone, $, _ */ +/*global window, document, localStorage, Ghost, Backbone, confirm, JST, $, _ */ (function () { "use strict"; - var $widgetContainer = $('.js-widget-container'), $itemElems, widgetPositions; + var Widgets, + Widget, + WidgetContent, + $widgetContainer, + $itemElems, + widgetPositions; widgetPositions = { mobile: {}, @@ -11,62 +16,155 @@ desktop: {} }; - $widgetContainer.packery({ - itemSelector: '.js-widget', - gutter: 10, - columnWidth: 340, - rowHeight: 300 + // Base view + // ---------- + Ghost.Views.Dashboard = Ghost.View.extend({ + initialize: function (options) { + this.addSubview(new Widgets({ el: '.js-widget-container', collection: this.collection })).render(); + } }); - $itemElems = $($widgetContainer.packery('getItemElements')); - // make item elements draggable - $itemElems.draggable(); - // bind Draggable events to Packery - $widgetContainer.packery('bindUIDraggableEvents', $itemElems); + // Widgets + // ---------- + Widgets = Ghost.View.extend({ + initialize: function () { + $widgetContainer = this.$el; + }, - // show item order after layout - function orderItems() { - // items are in order within the layout - var $itemElems = $($widgetContainer.packery('getItemElements')), order = {}; + packeryInit: function () { + var self = this; + $widgetContainer.packery({ + itemSelector: '.js-widget', + gutter: 10, + columnWidth: 340, + rowHeight: 300 + }); - $.each($itemElems, function (index, key) { - order[key.getAttribute("data-widget-id")] = index; - }); - return order; - } + $itemElems = $($widgetContainer.packery('getItemElements')); - // On resize button click - $(".js-widget-resizer").on("click", function () { - var $parent = $(this).closest('.js-widget'), data = $(this).data('size'); + // make item elements draggable + $itemElems.draggable(); + // bind Draggable events to Packery + $widgetContainer.packery('bindUIDraggableEvents', $itemElems); - $parent.removeClass("widget-1x2 widget-2x1 widget-2x2"); + $widgetContainer.packery('on', 'dragItemPositioned', function () { + var viewportSize = $(window).width(); + if (viewportSize <= 400) { // Mobile + widgetPositions.mobile = self.getWidgetOrder($itemElems); + } else if (viewportSize > 400 && viewportSize <= 800) { // Tablet + widgetPositions.tablet = self.getWidgetOrder($itemElems); + } else if (viewportSize > 800 && viewportSize <= 1000) { // Netbook + widgetPositions.netbook = self.getWidgetOrder($itemElems); + } else if (viewportSize > 1000) { + widgetPositions.desktop = self.getWidgetOrder($itemElems); + } + localStorage.setItem('widgetPositions', JSON.stringify(widgetPositions)); - if (data !== "1x1") { - $parent.addClass('widget-' + data); - $widgetContainer.packery('fit', $parent.get(0)); - } else { - $widgetContainer.packery(); + // Retrieve the object from storage with `JSON.parse(localStorage.getItem('widgetPositions'));` + }); + }, + + getWidgetOrder: function (itemElems) { + // items are in order within the layout + var order = {}; + + _.each(itemElems, function (widget, index) { + order[widget.getAttribute("data-widget-id")] = index; + }); + return order; + }, + + render: function () { + this.collection.each(function (model) { + this.$el.append(this.addSubview(new Widget({model: model})).render().el); + }, this); + this.packeryInit(); } - $(this).siblings('.active').removeClass('active'); - $(this).addClass('active'); - }); - $widgetContainer.packery('on', 'dragItemPositioned', function () { - var viewportSize = $(window).width(); - if (viewportSize <= 400) { // Mobile - widgetPositions.mobile = orderItems(); - } else if (viewportSize > 400 && viewportSize <= 800) { // Tablet - widgetPositions.tablet = orderItems(); - } else if (viewportSize > 800 && viewportSize <= 1000) { // Netbook - widgetPositions.netbook = orderItems(); - } else if (viewportSize > 1000) { - widgetPositions.desktop = orderItems(); - } - localStorage.setItem('widgetPositions', JSON.stringify(widgetPositions)); + // Widget + // ---------- + Widget = Ghost.View.extend({ + + tagName: 'article', + attributes: function () { + var size = (this.model.get('size')) + ? " widget-" + this.model.get('size') + : "", + settings = (this.model.attributes.settings.enabled) + ? " widget-settings" + : ""; + + return { + class: 'widget-' + this.model.get('name') + size + settings + ' js-widget', + 'data-widget-id': this.model.get('applicationID') + }; + }, + + events: { + 'click .js-widget-resizer': 'resizeWidget', + 'click .js-view-settings': 'showSettings', + 'click .js-view-widget': 'showWidget' + }, + + resizeWidget: function (e) { + e.preventDefault(); + var data = $(e.currentTarget).data('size'); + + this.$el.removeClass("widget-1x2 widget-2x1 widget-2x2"); + + if (data !== "1x1") { + this.$el.addClass('widget-' + data); + $widgetContainer.packery('fit', this.el); + } else { + $widgetContainer.packery(); + } + + $(e.currentTarget).siblings('.active').removeClass('active'); + $(e.currentTarget).addClass('active'); + }, + + showSettings: function (e) { + e.preventDefault(); + this.model.attributes.settings.enabled = true; + this.$el.addClass("widget-settings"); + this.render(); + }, + + showWidget: function (e) { + e.preventDefault(); + this.model.attributes.settings.enabled = false; + this.$el.removeClass("widget-settings"); + this.render(); + }, + + template: JST['content/widget'], + + render: function () { + this.$el.html(this.template(this.model.toJSON())); + if (!this.model.attributes.settings.enabled) { + this.$(".widget-content").html(this.addSubview(new WidgetContent({model: this.model})).render().el); + } + return this; + } + + }); + + // Widget Content + // ---------- + WidgetContent = Ghost.View.extend({ + + getTemplate: function () { + return JST['content/widgets/' + this.model.attributes.content.template]; + }, + + render: function () { + this.template = this.getTemplate(); + this.$el.html(this.template(this.model.toJSON())); + return this; + } - // Retrieve the object from storage with `JSON.parse(localStorage.getItem('widgetPositions'));` }); }()); \ No newline at end of file diff --git a/core/admin/assets/sass/layouts/dashboard.scss b/core/admin/assets/sass/layouts/dashboard.scss index 6dc58a260a..28fc2ba362 100644 --- a/core/admin/assets/sass/layouts/dashboard.scss +++ b/core/admin/assets/sass/layouts/dashboard.scss @@ -81,6 +81,10 @@ } } +.ui-draggable-dragging { + z-index: 9999; // Keep dragged Widget ontop +} + /* ========================================================================== Widget Sizes ========================================================================== */ diff --git a/core/admin/assets/tmpl/content/widget.hbs b/core/admin/assets/tmpl/content/widget.hbs new file mode 100644 index 0000000000..8d83aa06ed --- /dev/null +++ b/core/admin/assets/tmpl/content/widget.hbs @@ -0,0 +1,44 @@ +{{#if settings.enabled}} +
+ {{Title}} Settings +
+
+
+ {{#each settings.options}} + + {{/each}} +
+ +{{else}} +
+
+ +{{/if}} \ No newline at end of file diff --git a/core/admin/assets/tmpl/content/widgets/custom/instagram.hbs b/core/admin/assets/tmpl/content/widgets/custom/instagram.hbs new file mode 100644 index 0000000000..3b774f9a18 --- /dev/null +++ b/core/admin/assets/tmpl/content/widgets/custom/instagram.hbs @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/core/admin/assets/tmpl/content/widgets/custom/lastfm.hbs b/core/admin/assets/tmpl/content/widgets/custom/lastfm.hbs new file mode 100644 index 0000000000..e6a7dce689 --- /dev/null +++ b/core/admin/assets/tmpl/content/widgets/custom/lastfm.hbs @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/core/admin/assets/tmpl/content/widgets/custom/popular-posts.hbs b/core/admin/assets/tmpl/content/widgets/custom/popular-posts.hbs new file mode 100644 index 0000000000..2c9e89b073 --- /dev/null +++ b/core/admin/assets/tmpl/content/widgets/custom/popular-posts.hbs @@ -0,0 +1,15 @@ + + \ No newline at end of file diff --git a/core/admin/assets/tmpl/content/widgets/custom/post-ideas.hbs b/core/admin/assets/tmpl/content/widgets/custom/post-ideas.hbs new file mode 100644 index 0000000000..cd7b032396 --- /dev/null +++ b/core/admin/assets/tmpl/content/widgets/custom/post-ideas.hbs @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/core/admin/assets/tmpl/content/widgets/custom/time.hbs b/core/admin/assets/tmpl/content/widgets/custom/time.hbs new file mode 100644 index 0000000000..32a6898b14 --- /dev/null +++ b/core/admin/assets/tmpl/content/widgets/custom/time.hbs @@ -0,0 +1,8 @@ +
+ {{content.data.day}} + {{content.data.weather}}° +
+ \ No newline at end of file diff --git a/core/admin/assets/tmpl/content/widgets/custom/tweets.hbs b/core/admin/assets/tmpl/content/widgets/custom/tweets.hbs new file mode 100644 index 0000000000..4c6757efb2 --- /dev/null +++ b/core/admin/assets/tmpl/content/widgets/custom/tweets.hbs @@ -0,0 +1,18 @@ +
+
+ +
+ {{content.data.name}} + {{contnet.data.handle}} +
+
+{{{content.data.tweet}}} +
+ \ No newline at end of file diff --git a/core/admin/assets/tmpl/content/widgets/custom/upcoming-posts.hbs b/core/admin/assets/tmpl/content/widgets/custom/upcoming-posts.hbs new file mode 100644 index 0000000000..9023da4b95 --- /dev/null +++ b/core/admin/assets/tmpl/content/widgets/custom/upcoming-posts.hbs @@ -0,0 +1,9 @@ +
+ +
+ +
\ No newline at end of file diff --git a/core/admin/assets/tmpl/content/widgets/default/blank.hbs b/core/admin/assets/tmpl/content/widgets/default/blank.hbs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/admin/assets/tmpl/content/widgets/default/number.hbs b/core/admin/assets/tmpl/content/widgets/default/number.hbs new file mode 100644 index 0000000000..4920e48c6b --- /dev/null +++ b/core/admin/assets/tmpl/content/widgets/default/number.hbs @@ -0,0 +1,4 @@ +
+ {{content.data.number.count}} + {{content.data.number.sub.value}} {{content.data.number.sub.item}} {{content.data.number.sub.period}} +
\ No newline at end of file diff --git a/core/admin/views/dashboard.hbs b/core/admin/views/dashboard.hbs index 8bd89ba5dc..361b1ac208 100644 --- a/core/admin/views/dashboard.hbs +++ b/core/admin/views/dashboard.hbs @@ -1,12 +1,7 @@ {{#contentFor 'bodyScripts'}} - - - {{/contentFor}} {{!< default}}
-
-
-
- Today - 12° -
- -
-
- Linz, Austria -
-
-
- -
-
- -
-
- Ghost -
-
-
- -
-
-
- -
-
    -
  • 9 Ready
  • -
  • 4 Pending
  • -
  • 1 Draft
  • -
-
-
-
- Upcoming Posts -
-
-
- -
-
-
- 293,051 - +14% in the last 7 days -
-
-
- Unique Visitors (7 days) -
-
-
- -
-
-
- 12,329 - -3 likes today - -
-
-
- Facebook Likes -
-
-
- -
-
-
- 4,103 - have you in circles -
-
-
- Google Plus -
-
-
- -
-
- Twitter Settings -
-
-
- - - -
-
-
-
- - - - -
-
- - - -
-
- - - -
-
- -
-
-
-
-
- -
-
-
- 5,693 - +63 subscribers this week -
-
-
- Campaign Monitor -
-
-
- - - -
-
- -
-
- Posts This Week (Out Of 20) -
-
-
- - -
-
- -
-
- Your RSS News Feed -
-
-
- -
-
- -
-
- Instagram -
-
-
- -
-
-
- 64.23 - -0.42 in the last 30 days -
-
-
- Klout -
-
-
- -
-
-
- 40.21% - -2.53% in the last month -
-
-
- Bounce Rate -
-
-
- -
-
-
- 2m 16s - +31.4% in the last month -
-
-
- Average Time On Site -
-
-
- -
-
- - -
-
- Last.fm -
-
-
- -
-
- - -
-
- Post Ideas -
-
-
- -
-
-
- - - -
- -
- - -
-
-
- Twitter -
-
-
- -
-
- -
- -
\ No newline at end of file diff --git a/core/admin/views/default.hbs b/core/admin/views/default.hbs index dce72828b2..b12205f94d 100644 --- a/core/admin/views/default.hbs +++ b/core/admin/views/default.hbs @@ -45,6 +45,8 @@ + + @@ -55,7 +57,9 @@ + +