Merge pull request #1 from TryGhost/master

Initial commit
This commit is contained in:
Matthew Harrison-Jones 2013-05-11 12:47:19 -07:00
commit 150f542543
119 changed files with 19679 additions and 2 deletions

24
.afignore Normal file
View File

@ -0,0 +1,24 @@
#ignore database
b-cov
*.seed
*.log
*.csv
*.dat
*.out
*.pid
*.gz
pids
logs
results
npm-debug.log
.idea/*
*.iml
projectFilesBackup
.DS_Store
# Ghost DB file
ghost/data/*.db

31
.gitignore vendored Normal file
View File

@ -0,0 +1,31 @@
b-cov
*.seed
*.log
*.csv
*.dat
*.out
*.pid
*.gz
pids
logs
results
npm-debug.log
node_modules
.idea/*
*.iml
projectFilesBackup
.DS_Store
# Ghost DB file
*.db
/core/admin/assets/css
.sass-cache/
/core/admin/assets/sass/config.rb
/core/admin/assets/sass/layouts/config.rb
/core/admin/assets/sass/modules/config.rb
/ghost/.idea/

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "content/themes/casper"]
path = content/themes/casper
url = git@github.com:TryGhost/Casper.git

5
.groc.json Normal file
View File

@ -0,0 +1,5 @@
{
"glob": ["README.md", "config.js", "app.js", "core/ghost.js", "core/admin/assets/js/*.js", "core/frontend/helpers/index.js", "core/lang/i18n.js"],
"except": ["core/admin/assets/lib/chart.min.js"],
"out": "./docs"
}

22
LICENSE Normal file
View File

@ -0,0 +1,22 @@
Copyright (c) 2013 Ghost
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,2 +1,85 @@
Ghost
=====
# Ghost
Welcome to the Ghost core repo. The code here is the result of a few stolen hours of free time hacking a proof of concept for the Kickstarter video. Pretty much everything is subject to and expected to change.
The top priorities right now are:
* Having a core RESTful API and consuming it internally
* Data model design & implementation - including a potential switch from JugglingDB to bookshelf.js
* Authentication and ACL
* Improving core architecture & design - modular structure, better dependency injection, testable code with tests
###To Install:
**Note:** It is highly recommended that you use the [Ghost-Vagrant](https://github.com/TryGhost/Ghost-Vagrant) setup for developing Ghost.
1. Clone the git repo
1. cd into the project folder and run ```npm install```.
* If the install fails with errors to do with "node-gyp rebuild", follow the Sqlite3 install instructions
1. cd into /core/admin/assets and run ```compass compile --css-dir=css```
Frontend can be located at [localhost:3333](localhost:3333), Admin is at [localhost:3333/ghost](localhost:3333/ghost)
#### Sqlite3 Install Instructions
Ghost depends upon sqlite3, which has to be built for each OS. NPM is as smart as it can be about this, and as long as your machine has all the pre-requisites for compiling/building a C++ program, the npm install still works.
However, if you don't have the required pre-requisites, you will need to either get them, or as a shortcut, obtain a precompiled sqlite3 package for your OS.
I have created some of these, and they can be obtained from [this GitHub issue](https://github.com/developmentseed/node-sqlite3/issues/106).
The pre-compiled package should be downloaded, extracted and placed in the node\_modules folder, such that it lives in node\_modules/sqlite3, if you have a partial install of the sqlite3 package, replace it with the files you downloaded from github. Be sure that all the sqlite3 files and folders live directly in node\_modules/sqlite3 - there should note be a node\_modules/sqlite3/sqlite3 folder.
###Dependencies:
* express.js framework
* handlebars for templating
* standard css for frontend
* sass for admin (pre-compiled)
* moment.js for time / date manipulation
* underscore for object & array utils
* showdown for converting markdown to HTML
* nodeunit for unit testing
* sqlite3 for data storage
* jugglingdb ORM for interacting with the database
* Polyglot.js for i18n
#### Frontend libraries:
* jQuery 1.9.1
* showdown for converting markdown to HTML
* codemirror editor
### Working features:
* Dashboard
* new post link
* Admin menu
* G, dashboard, content, new post & settings menu items go to correct pages
* Content screen
* Lists all posts with correct titles (incorrect time etc)
* Select post in list highlights that post and opens it in the preview pane
* Write screen
* Live preview works for all standard markdown
* Save draft button saves entered title & content. Everything is published by default.
* Editing/opening existing post puts correct info in title and content panels & save updates content.
* Database
* The database is created and populated with basic data on first run of the server
* New posts and edits save and last forever
* The data can be reset by opening data/datastore.db and emptying the file. The next restart of the server will cause the database to be recreated and repopulated.
* Frontend
* Homepage lists a number of posts as configured in config.js
* Clicking on an individual post loads an individual post page
* Date formatting helper uses moment
### Front End Work
A SASS compiler is required to work with the CSS in this project.
Run ```compass compile --css-dir=css``` from /core/admin/assets.
We also recommend [CodeKit](http://incident57.com/codekit/) (Paid/Mac) and [Scout](http://mhs.github.io/scout-app/) (Free/Mac/PC).

80
app.js Normal file
View File

@ -0,0 +1,80 @@
// # Ghost main app file
/*global require */
(function () {
"use strict";
// Module dependencies.
var express = require('express'),
fs = require('fs'),
admin = require('./core/admin/controllers'),
frontend = require('./core/frontend/controllers'),
flash = require('connect-flash'),
Ghost = require('./core/ghost'),
I18n = require('./core/lang/i18n'),
helpers = require('./core/frontend/helpers'),
auth,
// ## Variables
/**
* Create new Ghost object
* @type {Ghost}
*/
ghost = new Ghost();
ghost.app().configure('development', function () {
ghost.app().use(express.favicon(__dirname + '/content/images/favicon.ico'));
ghost.app().use(express.errorHandler());
ghost.app().use(I18n.load(ghost));
ghost.app().use(express.bodyParser());
ghost.app().use(express.cookieParser('try-ghost'));
ghost.app().use(express.session({ cookie: { maxAge: 60000 }}));
ghost.app().use(flash());
ghost.app().use(ghost.initTheme(ghost.app()));
});
/**
* Setup login details
* p.s. love it.
*
* @type {*}
*/
auth = express.basicAuth('ghostadmin', 'Wh0YouGonnaCall?');
helpers.loadCoreHelpers(ghost);
/**
* API routes..
* @todo convert these into a RESTful, public, authenticated API!
*/
ghost.app().post('/api/v0.1/posts/create', auth, admin.posts.create);
ghost.app().post('/api/v0.1/posts/edit', auth, admin.posts.edit);
ghost.app().get('/api/v0.1/posts', auth, admin.posts.index);
/**
* Admin routes..
* @todo put these somewhere in admin
*/
ghost.app().get('/ghost/editor/:id', auth, admin.editor);
ghost.app().get('/ghost/editor', auth, admin.editor);
ghost.app().get('/ghost/blog', auth, admin.blog);
ghost.app().get('/ghost/settings', auth, admin.settings);
ghost.app().get('/ghost/debug', auth, admin.debug.index);
ghost.app().get('/ghost/debug/db/delete/', auth, admin.debug.dbdelete);
ghost.app().get('/ghost/debug/db/populate/', auth, admin.debug.dbpopulate);
ghost.app().get('/ghost', auth, admin.index);
/**
* Frontend routes..
* @todo dynamic routing, homepage generator, filters ETC ETC
*/
ghost.app().get('/:slug', frontend.single);
ghost.app().get('/', frontend.homepage);
ghost.app().listen(3333, function () {
console.log("Express server listening on port " + 3333);
console.log('process: ', process.env);
});
}());

62
config.js Normal file
View File

@ -0,0 +1,62 @@
// # Ghost Configuration
/**
* global module
**/
(function () {
"use strict";
/**
* @module config
* @type {Object}
*/
var config = {};
// ## Admin settings
/**
* @property {string} defaultLang
*/
config.defaultLang = 'en';
/**
* @property {boolean} forceI18n
*/
config.forceI18n = true;
// ## Themes
/**
* @property {string} themeDir
*/
// Themes
config.themeDir = 'themes';
/**
* @property {string} activeTheme
*/
config.activeTheme = 'casper';
// ## Homepage settings
/**
* @module homepage
* @type {Object}
*/
config.homepage = {};
/**
* @property {number} features
*/
config.homepage.features = 1;
/**
* @property {number} posts
*/
config.homepage.posts = 4;
/**
* @property {Object} exports
*/
module.exports = config;
}());

26
config.rb Normal file
View File

@ -0,0 +1,26 @@
# Require any additional compass plugins here.
# Set this to the root of your project when deployed:
http_path = "/"
css_dir = "core/admin/assets/css"
sass_dir = "core/admin/assets/sass"
images_dir = "core/admin/assets/img"
javascripts_dir = "core/admin/assets/js"
fonts_dir = "core/admin/assets/fonts"
output_style = :nested
# To enable relative paths to assets via compass helper functions. Uncomment:
# relative_assets = true
# To disable debugging comments that display the original location of your selectors. Uncomment:
# line_comments = false
color_output = false
# If you prefer the indented syntax, you might want to regenerate this
# project again passing --syntax sass, or you can uncomment this:
# preferred_syntax = :sass
# and then run:
# sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass

13
content/README.md Normal file
View File

@ -0,0 +1,13 @@
#Content
This section of the repo is the area that a normal user is allowed to add and change stuff. This is where their themes, plugins and images will live.
By default for an install:
* the themes directory will contain Casper
* the plugins directory will be empty
* the images directory will be empty
Currently the plugins and images directory contain some stuff for testing.
By default, Ghost will support very basic image uploads. It will be expected and encouraged for users to connect to a 3rd party service for improved media support and a CDN. Much like comments, we don't see supporting advanced file uploads, having a media library or being a CDN as core competencies - there are already plenty of people out there doing this much better than we can.

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
content/images/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
content/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -0,0 +1,45 @@
/*globals exports */
(function () {
"use strict";
var FancyFirstChar;
FancyFirstChar = function (ghost) {
this.ghost = function () {
return ghost;
};
};
FancyFirstChar.prototype.init = function () {
this.ghost().registerFilter('prePostsRender', function (posts) {
var post,
originalContent,
newContent,
firstCharIndex = 0;
console.log('got content to filter', posts);
for (post in posts) {
if (posts.hasOwnProperty(post)) {
originalContent = posts[post].content;
if (originalContent.substr(0, 1) === '<') {
firstCharIndex = originalContent.indexOf('>') + 1;
}
newContent = originalContent.substr(0, firstCharIndex);
newContent += '<span class="fancyChar">';
newContent += originalContent.substr(firstCharIndex, 1);
newContent += '</span>';
newContent += originalContent.substr(firstCharIndex + 1, originalContent.length - firstCharIndex - 1);
posts[post].content = newContent;
}
}
return posts;
});
};
FancyFirstChar.prototype.activate = function () {};
FancyFirstChar.prototype.deactivate = function () {};
module.exports = FancyFirstChar;
}());

1
content/themes/casper Submodule

@ -0,0 +1 @@
Subproject commit 151f5d3f4c3b613a283a0733ffd1f97f403f477c

12
core/README.md Normal file
View File

@ -0,0 +1,12 @@
# Core
Core contains the bread and butter of ghost. It is currently divided up into:
* **admin** - the views, controllers, assets and helpers for rendering & working the admin panel
* **frontend** - the controllers & helpers for creating the frontend of the blog. Views & assets live in themes
* **lang** - the current home of everything i18n, this was done as a proof of concept on a very early version of the prototype and needs love
* **shared** - basically everything to do with data & models. The sqlite db file lives in the data folder here. This is the part that needs the most work so it doesn't make much sense yet, and is also the highest priority
* **test** - currently contains two sad unit tests and a set of html prototypes of the admin UI. Really, this folder should reflect all of core. It is my personal mission to make that happen ASAP & get us linked up with Travis.
* **ghost.js** - currently both the glue that binds everything together and what gives us the API for registering themes and plugins. The initTheme function is a bit of a hack which lets us serve different views & static content up for the admin & frontend.
This structure is by no means final and recommendations are more than welcome.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

@ -0,0 +1,75 @@
// # Temporary Admin UI
/*global document, jQuery */
(function ($) {
"use strict";
// UTILS
/**
* Allows to check contents of each element exactly
* @param obj
* @param index
* @param meta
* @param stack
* @returns {boolean}
*/
$.expr[":"].containsExact = function (obj, index, meta, stack) {
return (obj.textContent || obj.innerText || $(obj).text() || "") === meta[3];
};
$(document).ready(function () {
// ## Set interactions for all menus
// This finds all visible '.overlay' elements and hides them upon clicking away from the element itself.
$("body").on('click', function (event) {
var $target = $(event.target);
if (!$target.parents().is(".overlay:visible") && !$target.is(".overlay:visible")) {
$("body").find(".overlay:visible").fadeOut();
}
});
// EDITOR / NOTIFICATIONS
$('.entry-content header, .entry-preview header').on('click', function () {
$('.entry-content, .entry-preview').removeClass('active');
$(this).closest('section').addClass('active');
});
$('.entry-title .icon-fullscreen').on('click', function (e) {
e.preventDefault();
$('body').toggleClass('fullscreen');
});
$('.content-list-content li').on('click', function (e) {
var $target = $(e.target).closest('li'),
$preview = $('.content-preview');
$('.content-list-content li').removeClass('active');
$target.addClass('active');
// *****
// this means a *lot* of extra gumpf is in the DOM and should really be done with AJAX when we have proper
// data API endpoints
// ideally, we need a way to bind data to views properly... backbone marionette, angular, etc
// *****
//
/**
* @todo Remove gumpf
*/
$preview.find('.content-preview-content .wrapper').html($target.data('content'));
$preview.find('.post-controls .post-edit').attr('href', '/ghost/editor/' + $target.data('id'));
});
$('.options.up').on('click', function (e) {
e.stopPropagation();
$(this).next("ul").fadeToggle(200);
});
$('.editor-options').on('click', 'li', function (e) {
$('.button-save').data("state", $(this).data("title")).attr('data-state', $(this).data("title")).text($(this).text());
$('.editor-options .active').removeClass('active');
$(this).addClass('active');
});
});
}(jQuery));

View File

@ -0,0 +1,27 @@
/*global window, history, jQuery, Showdown, CodeMirror */
(function ($) {
"use strict";
$(document).ready(function () {
// Shadow on Markdown if scrolled
$('.content-list-content').on('scroll', function (e) {
if ($('.content-list-content').scrollTop() > 10) {
$('.content-list').addClass('scrolling');
} else {
$('.content-list').removeClass('scrolling');
}
});
// Shadow on Preview if scrolled
$('.content-preview-content').on('scroll', function (e) {
if ($('.content-preview-content').scrollTop() > 10) {
$('.content-preview').addClass('scrolling');
} else {
$('.content-preview').removeClass('scrolling');
}
});
});
}(jQuery));

View File

@ -0,0 +1,157 @@
// # Article Editor
/*global window, document, history, jQuery, Showdown, CodeMirror, shortcut */
(function ($, ShowDown, CodeMirror, shortcut) {
"use strict";
// ## Converter Initialisation
/**
* @property converter
* @type {ShowDown.converter}
*/
// Initialise the Showdown converter for Markdown.
// var delay;
var converter = new ShowDown.converter({extensions: ['ghostdown']}),
editor = CodeMirror.fromTextArea(document.getElementById('entry-markdown'), {
mode: 'markdown',
tabMode: 'indent',
lineWrapping: true
});
// ## Functions
/**
* @method Update word count
* @todo Really not the best way to do things as it includes Markdown formatting along with words
* @constructor
*/
// This updates the word count on the editor preview panel.
function updateWordCount() {
var wordCount = document.getElementsByClassName('entry-word-count')[0],
editorValue = editor.getValue();
if (editorValue.length) {
wordCount.innerHTML = editorValue.match(/\S+/g).length + ' words';
}
}
/**
* @method updatePreview
* @constructor
*/
// This updates the editor preview panel.
// Currently gets called on every key press.
// Also trigger word count update
function updatePreview() {
var preview = document.getElementsByClassName('rendered-markdown')[0];
preview.innerHTML = converter.makeHtml(editor.getValue());
updateWordCount();
}
/**
* @method Save
* @constructor
*/
// This method saves a post
function save() {
var entry = {
title: document.getElementById('entry-title').value,
markdown: editor.getValue()
},
urlSegments = window.location.pathname.split('/');
if (urlSegments[2] === 'editor' && urlSegments[3] && /^[a-zA-Z0-9]+$/.test(urlSegments[2])) {
entry.id = urlSegments[3];
$.ajax({
url: '/api/v0.1/posts/edit',
method: 'POST',
data: entry,
success: function (data) {
console.log('response', data);
},
error: function (error) {
console.log('error', error);
}
});
} else {
$.ajax({
url: '/api/v0.1/posts/create',
method: 'POST',
data: entry,
success: function (data) {
console.log('response', data);
history.pushState(data, '', '/ghost/editor/' + data.id);
},
error: function (jqXHR, status, error) {
var errors = JSON.parse(jqXHR.responseText);
console.log('FAILED', errors);
}
});
}
}
// ## Main Initialisation
$(document).ready(function () {
$('.entry-markdown header, .entry-preview header').click(function (e) {
$('.entry-markdown, .entry-preview').removeClass('active');
$(e.target).closest('section').addClass('active');
});
editor.on("change", function () {
//clearTimeout(delay);
//delay = setTimeout(updatePreview, 50);
updatePreview();
});
updatePreview();
$('.button-save').on('click', function () {
save();
});
// Sync scrolling
function syncScroll(e) {
// vars
var $codeViewport = $(e.target),
$previewViewport = $('.entry-preview-content'),
$codeContent = $('.CodeMirror-sizer'),
$previewContent = $('.rendered-markdown'),
// calc position
codeHeight = $codeContent.height() - $codeViewport.height(),
previewHeight = $previewContent.height() - $previewViewport.height(),
ratio = previewHeight / codeHeight,
previewPostition = $codeViewport.scrollTop() * ratio;
// apply new scroll
$previewViewport.scrollTop(previewPostition);
}
// TODO: Debounce
$('.CodeMirror-scroll').on('scroll', syncScroll);
// Shadow on Markdown if scrolled
$('.CodeMirror-scroll').on('scroll', function (e) {
if ($('.CodeMirror-scroll').scrollTop() > 10) {
$('.entry-markdown').addClass('scrolling');
} else {
$('.entry-markdown').removeClass('scrolling');
}
});
// Shadow on Preview if scrolled
$('.entry-preview-content').on('scroll', function (e) {
if ($('.entry-preview-content').scrollTop() > 10) {
$('.entry-preview').addClass('scrolling');
} else {
$('.entry-preview').removeClass('scrolling');
}
});
// Zen writing mode
shortcut.add("Alt+Shift+Z", function () {
$('body').toggleClass('zen');
});
});
}(jQuery, Showdown, CodeMirror, shortcut));

View File

@ -0,0 +1,21 @@
/*globals document, jQuery */
(function ($) {
"use strict";
var changePage = function (e) {
var newPage = $(this).children('a').attr('href');
e.preventDefault();
$('.settings-menu .active').removeClass('active');
$(this).addClass('active');
$('.settings-content').fadeOut().delay(250);
$(newPage).fadeIn();
};
$(document).ready(function() {
$('.settings-menu li').on('click', changePage);
});
}(jQuery));

View File

@ -0,0 +1,196 @@
// ## Tag Selector UI
/*jslint regexp: true */ // - would like to remove this
/*global jQuery, document, window */
(function ($) {
"use strict";
var suggestions,
categoryOffset,
existingTags = [ // This will be replaced by an API return.
'quim',
'quimtastic',
'quimmy',
'quimlord',
'quickly',
'joaquim pheonix',
'quimcy jones'
],
keys = {
UP: 38,
DOWN: 40,
ESC: 27,
ENTER: 13,
COMMA: 188,
BACKSPACE: 8
};
function findTerms(searchTerm, array) {
searchTerm = searchTerm.toUpperCase();
return $.map(array, function (item) {
var match = item.toUpperCase().indexOf(searchTerm) !== -1;
return match ? item : null;
});
}
function showSuggestions($target, searchTerm) {
suggestions.show();
var results = findTerms(searchTerm, existingTags),
pos = $target.position(),
styles = {
left: pos.left
},
maxSuggestions = 5, // Limit the suggestions number
results_length = results.length,
i,
suggest;
suggestions.css(styles);
suggestions.html("");
if (results_length < maxSuggestions) {
maxSuggestions = results_length;
}
for (i = 0; i < maxSuggestions; i += 1) {
suggestions.append("<li><a href='#'>" + results[i] + "</a></li>");
}
suggest = $('ul.suggestions li a:contains("' + searchTerm + '")');
suggest.each(function () {
var src_str = $(this).html(),
term = searchTerm,
pattern;
term = term.replace(/(\s+)/, "(<[^>]+>)*$1(<[^>]+>)*");
pattern = new RegExp("(" + term + ")", "i");
src_str = src_str.replace(pattern, "<mark>$1</mark>");
src_str = src_str.replace(/(<mark>[^<>]*)((<[^>]+>)+)([^<>]*<\/mark>)/, "$1</mark>$2<mark>$4");
$(this).html(src_str);
});
}
function handleTagKeyup(e) {
var $target = $(e.currentTarget),
searchTerm = $.trim($target.val()).toLowerCase(),
category,
populator;
if (e.keyCode === keys.UP) {
e.preventDefault();
if (suggestions.is(":visible")) {
if (suggestions.children(".selected").length === 0) {
suggestions.find("li:last-child").addClass('selected');
} else {
suggestions.children(".selected").removeClass('selected').prev().addClass('selected');
}
}
} else if (e.keyCode === keys.DOWN) {
e.preventDefault();
if (suggestions.is(":visible")) {
if (suggestions.children(".selected").length === 0) {
suggestions.find("li:first-child").addClass('selected');
} else {
suggestions.children(".selected").removeClass('selected').next().addClass('selected');
}
}
} else if (e.keyCode === keys.ESC) {
suggestions.hide();
} else if ((e.keyCode === keys.ENTER || e.keyCode === keys.COMMA)
&& searchTerm) { // Submit tag using enter or comma key
e.preventDefault();
if (suggestions.is(":visible") && suggestions.children(".selected").length !== 0) {
if ($('.category:containsExact("' + suggestions.children(".selected").text() + '")').length === 0) {
category = $('<span class="category">' + suggestions.children(".selected").text() + '</span>');
if ($target.data('populate')) {
populator = $($target.data('populate'));
populator.append(category);
}
}
suggestions.hide();
} else {
if (e.keyCode === keys.COMMA) {
searchTerm = searchTerm.replace(",", "");
} // Remove comma from string if comma is uses to submit.
if ($('.category:containsExact("' + searchTerm + '")').length === 0) {
category = $('<span class="category">' + searchTerm + '</span>');
if ($target.data('populate')) {
populator = $($target.data('populate'));
populator.append(category);
}
}
}
$target.val('').focus();
searchTerm = ""; // Used to reset search term
suggestions.hide();
}
if (e.keyCode === keys.UP || e.keyCode === keys.DOWN) {
return false;
}
if (searchTerm) {
showSuggestions($target, searchTerm);
} else {
suggestions.hide();
}
}
function handleTagKeyDown(e) {
var $target = $(e.currentTarget),
populator,
lastBlock;
// Delete character tiggers on Keydown, so needed to check on that event rather than Keyup.
if (e.keyCode === keys.BACKSPACE && !$target.val()) {
populator = $($target.data('populate'));
lastBlock = populator.find('.category').last();
lastBlock.remove();
}
}
function handleSuggestionClick(e) {
var $target = $(e.currentTarget),
category = $('<span class="category">' + $(e.currentTarget).text() + '</span>'),
populator;
if ($target.parent().data('populate')) {
populator = $($target.parent().data('populate'));
populator.append(category);
suggestions.hide();
$('[data-input-behaviour="tag"]').val('').focus();
}
}
function handleCategoryClick(e) {
$(e.currentTarget).remove();
}
function handleClickOff(e) {
if (window.matchMedia('max-width: 650px')) {
e.preventDefault();
$('body').toggleClass('off-canvas');
}
}
$(document).ready(function () {
suggestions = $("ul.suggestions").hide(); // Initnialise suggestions overlay
if ($('.category-input').length) {
categoryOffset = $('.category-input').offset().left;
$('.category-blocks').css({'left': categoryOffset + 'px'});
}
$('[data-input-behaviour="tag"]')
.on('keyup', handleTagKeyup)
.on('keydown', handleTagKeyDown);
$('ul.suggestions').on('click', "li", handleSuggestionClick);
$('.categories').on('click', ".category", handleCategoryClick);
$('[data-off-canvas]').on('click', handleClickOff);
});
}(jQuery));

View File

@ -0,0 +1,30 @@
// # Toggle Support
/*global document, jQuery */
(function ($) {
"use strict";
$(document).ready(function () {
// ## Toggle Up In Your Grill
// Allows for toggling via data-attributes.
// ### Usage
// <nav>
// <a href="#" data-toggle=".toggle-me">Toggle</a>
// <ul class="toggle-me">
// <li>Toggled yo</li>
// </ul>
// </nav>
$('[data-toggle]').each(function () {
var toggle = $(this).data('toggle');
$(this).parent().children(toggle).hide();
});
$('[data-toggle]').on('click', function (e) {
e.preventDefault();
$(this).toggleClass('active');
var toggle = $(this).data('toggle');
$(this).parent().children(toggle).fadeToggle(100).toggleClass('open');
});
});
}(jQuery));

39
core/admin/assets/lib/chart.min.js vendored Normal file
View File

@ -0,0 +1,39 @@
var Chart=function(s){function v(a,c,b){a=A((a-c.graphMin)/(c.steps*c.stepValue),1,0);return b*c.steps*a}function x(a,c,b,e){function h(){g+=f;var k=a.animation?A(d(g),null,0):1;e.clearRect(0,0,q,u);a.scaleOverlay?(b(k),c()):(c(),b(k));if(1>=g)D(h);else if("function"==typeof a.onAnimationComplete)a.onAnimationComplete()}var f=a.animation?1/A(a.animationSteps,Number.MAX_VALUE,1):1,d=B[a.animationEasing],g=a.animation?0:1;"function"!==typeof c&&(c=function(){});D(h)}function C(a,c,b,e,h,f){var d;a=
Math.floor(Math.log(e-h)/Math.LN10);h=Math.floor(h/(1*Math.pow(10,a)))*Math.pow(10,a);e=Math.ceil(e/(1*Math.pow(10,a)))*Math.pow(10,a)-h;a=Math.pow(10,a);for(d=Math.round(e/a);d<b||d>c;)a=d<b?a/2:2*a,d=Math.round(e/a);c=[];z(f,c,d,h,a);return{steps:d,stepValue:a,graphMin:h,labels:c}}function z(a,c,b,e,h){if(a)for(var f=1;f<b+1;f++)c.push(E(a,{value:(e+h*f).toFixed(0!=h%1?h.toString().split(".")[1].length:0)}))}function A(a,c,b){return!isNaN(parseFloat(c))&&isFinite(c)&&a>c?c:!isNaN(parseFloat(b))&&
isFinite(b)&&a<b?b:a}function y(a,c){var b={},e;for(e in a)b[e]=a[e];for(e in c)b[e]=c[e];return b}function E(a,c){var b=!/\W/.test(a)?F[a]=F[a]||E(document.getElementById(a).innerHTML):new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g," ").split("<%").join("\t").replace(/((^|%>)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split("\t").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');");return c?
b(c):b}var r=this,B={linear:function(a){return a},easeInQuad:function(a){return a*a},easeOutQuad:function(a){return-1*a*(a-2)},easeInOutQuad:function(a){return 1>(a/=0.5)?0.5*a*a:-0.5*(--a*(a-2)-1)},easeInCubic:function(a){return a*a*a},easeOutCubic:function(a){return 1*((a=a/1-1)*a*a+1)},easeInOutCubic:function(a){return 1>(a/=0.5)?0.5*a*a*a:0.5*((a-=2)*a*a+2)},easeInQuart:function(a){return a*a*a*a},easeOutQuart:function(a){return-1*((a=a/1-1)*a*a*a-1)},easeInOutQuart:function(a){return 1>(a/=0.5)?
0.5*a*a*a*a:-0.5*((a-=2)*a*a*a-2)},easeInQuint:function(a){return 1*(a/=1)*a*a*a*a},easeOutQuint:function(a){return 1*((a=a/1-1)*a*a*a*a+1)},easeInOutQuint:function(a){return 1>(a/=0.5)?0.5*a*a*a*a*a:0.5*((a-=2)*a*a*a*a+2)},easeInSine:function(a){return-1*Math.cos(a/1*(Math.PI/2))+1},easeOutSine:function(a){return 1*Math.sin(a/1*(Math.PI/2))},easeInOutSine:function(a){return-0.5*(Math.cos(Math.PI*a/1)-1)},easeInExpo:function(a){return 0==a?1:1*Math.pow(2,10*(a/1-1))},easeOutExpo:function(a){return 1==
a?1:1*(-Math.pow(2,-10*a/1)+1)},easeInOutExpo:function(a){return 0==a?0:1==a?1:1>(a/=0.5)?0.5*Math.pow(2,10*(a-1)):0.5*(-Math.pow(2,-10*--a)+2)},easeInCirc:function(a){return 1<=a?a:-1*(Math.sqrt(1-(a/=1)*a)-1)},easeOutCirc:function(a){return 1*Math.sqrt(1-(a=a/1-1)*a)},easeInOutCirc:function(a){return 1>(a/=0.5)?-0.5*(Math.sqrt(1-a*a)-1):0.5*(Math.sqrt(1-(a-=2)*a)+1)},easeInElastic:function(a){var c=1.70158,b=0,e=1;if(0==a)return 0;if(1==(a/=1))return 1;b||(b=0.3);e<Math.abs(1)?(e=1,c=b/4):c=b/(2*
Math.PI)*Math.asin(1/e);return-(e*Math.pow(2,10*(a-=1))*Math.sin((1*a-c)*2*Math.PI/b))},easeOutElastic:function(a){var c=1.70158,b=0,e=1;if(0==a)return 0;if(1==(a/=1))return 1;b||(b=0.3);e<Math.abs(1)?(e=1,c=b/4):c=b/(2*Math.PI)*Math.asin(1/e);return e*Math.pow(2,-10*a)*Math.sin((1*a-c)*2*Math.PI/b)+1},easeInOutElastic:function(a){var c=1.70158,b=0,e=1;if(0==a)return 0;if(2==(a/=0.5))return 1;b||(b=1*0.3*1.5);e<Math.abs(1)?(e=1,c=b/4):c=b/(2*Math.PI)*Math.asin(1/e);return 1>a?-0.5*e*Math.pow(2,10*
(a-=1))*Math.sin((1*a-c)*2*Math.PI/b):0.5*e*Math.pow(2,-10*(a-=1))*Math.sin((1*a-c)*2*Math.PI/b)+1},easeInBack:function(a){return 1*(a/=1)*a*(2.70158*a-1.70158)},easeOutBack:function(a){return 1*((a=a/1-1)*a*(2.70158*a+1.70158)+1)},easeInOutBack:function(a){var c=1.70158;return 1>(a/=0.5)?0.5*a*a*(((c*=1.525)+1)*a-c):0.5*((a-=2)*a*(((c*=1.525)+1)*a+c)+2)},easeInBounce:function(a){return 1-B.easeOutBounce(1-a)},easeOutBounce:function(a){return(a/=1)<1/2.75?1*7.5625*a*a:a<2/2.75?1*(7.5625*(a-=1.5/2.75)*
a+0.75):a<2.5/2.75?1*(7.5625*(a-=2.25/2.75)*a+0.9375):1*(7.5625*(a-=2.625/2.75)*a+0.984375)},easeInOutBounce:function(a){return 0.5>a?0.5*B.easeInBounce(2*a):0.5*B.easeOutBounce(2*a-1)+0.5}},q=s.canvas.width,u=s.canvas.height;window.devicePixelRatio&&(s.canvas.style.width=q+"px",s.canvas.style.height=u+"px",s.canvas.height=u*window.devicePixelRatio,s.canvas.width=q*window.devicePixelRatio,s.scale(window.devicePixelRatio,window.devicePixelRatio));this.PolarArea=function(a,c){r.PolarArea.defaults={scaleOverlay:!0,
scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleShowLine:!0,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)",scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animation:!0,animationSteps:100,animationEasing:"easeOutBounce",
animateRotate:!0,animateScale:!1,onAnimationComplete:null};var b=c?y(r.PolarArea.defaults,c):r.PolarArea.defaults;return new G(a,b,s)};this.Radar=function(a,c){r.Radar.defaults={scaleOverlay:!1,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleShowLine:!0,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!1,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)",
scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,angleShowLineOut:!0,angleLineColor:"rgba(0,0,0,.1)",angleLineWidth:1,pointLabelFontFamily:"'Arial'",pointLabelFontStyle:"normal",pointLabelFontSize:12,pointLabelFontColor:"#666",pointDot:!0,pointDotRadius:3,pointDotStrokeWidth:1,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,animation:!0,animationSteps:60,animationEasing:"easeOutQuart",onAnimationComplete:null};var b=c?y(r.Radar.defaults,c):r.Radar.defaults;return new H(a,b,s)};this.Pie=function(a,
c){r.Pie.defaults={segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animation:!0,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,onAnimationComplete:null};var b=c?y(r.Pie.defaults,c):r.Pie.defaults;return new I(a,b,s)};this.Doughnut=function(a,c){r.Doughnut.defaults={segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,percentageInnerCutout:50,animation:!0,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,
onAnimationComplete:null};var b=c?y(r.Doughnut.defaults,c):r.Doughnut.defaults;return new J(a,b,s)};this.Line=function(a,c){r.Line.defaults={scaleOverlay:!1,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,bezierCurve:!0,
pointDot:!0,pointDotRadius:4,pointDotStrokeWidth:2,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,animation:!0,animationSteps:60,animationEasing:"easeOutQuart",onAnimationComplete:null};var b=c?y(r.Line.defaults,c):r.Line.defaults;return new K(a,b,s)};this.Bar=function(a,c){r.Bar.defaults={scaleOverlay:!1,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",
scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,barShowStroke:!0,barStrokeWidth:2,barValueSpacing:5,barDatasetSpacing:1,animation:!0,animationSteps:60,animationEasing:"easeOutQuart",onAnimationComplete:null};var b=c?y(r.Bar.defaults,c):r.Bar.defaults;return new L(a,b,s)};var G=function(a,c,b){var e,h,f,d,g,k,j,l,m;g=Math.min.apply(Math,[q,u])/2;g-=Math.max.apply(Math,[0.5*c.scaleFontSize,0.5*c.scaleLineWidth]);
d=2*c.scaleFontSize;c.scaleShowLabelBackdrop&&(d+=2*c.scaleBackdropPaddingY,g-=1.5*c.scaleBackdropPaddingY);l=g;d=d?d:5;e=Number.MIN_VALUE;h=Number.MAX_VALUE;for(f=0;f<a.length;f++)a[f].value>e&&(e=a[f].value),a[f].value<h&&(h=a[f].value);f=Math.floor(l/(0.66*d));d=Math.floor(0.5*(l/d));m=c.scaleShowLabels?c.scaleLabel:null;c.scaleOverride?(j={steps:c.scaleSteps,stepValue:c.scaleStepWidth,graphMin:c.scaleStartValue,labels:[]},z(m,j.labels,j.steps,c.scaleStartValue,c.scaleStepWidth)):j=C(l,f,d,e,h,
m);k=g/j.steps;x(c,function(){for(var a=0;a<j.steps;a++)if(c.scaleShowLine&&(b.beginPath(),b.arc(q/2,u/2,k*(a+1),0,2*Math.PI,!0),b.strokeStyle=c.scaleLineColor,b.lineWidth=c.scaleLineWidth,b.stroke()),c.scaleShowLabels){b.textAlign="center";b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;var e=j.labels[a];if(c.scaleShowLabelBackdrop){var d=b.measureText(e).width;b.fillStyle=c.scaleBackdropColor;b.beginPath();b.rect(Math.round(q/2-d/2-c.scaleBackdropPaddingX),Math.round(u/2-k*(a+
1)-0.5*c.scaleFontSize-c.scaleBackdropPaddingY),Math.round(d+2*c.scaleBackdropPaddingX),Math.round(c.scaleFontSize+2*c.scaleBackdropPaddingY));b.fill()}b.textBaseline="middle";b.fillStyle=c.scaleFontColor;b.fillText(e,q/2,u/2-k*(a+1))}},function(e){var d=-Math.PI/2,g=2*Math.PI/a.length,f=1,h=1;c.animation&&(c.animateScale&&(f=e),c.animateRotate&&(h=e));for(e=0;e<a.length;e++)b.beginPath(),b.arc(q/2,u/2,f*v(a[e].value,j,k),d,d+h*g,!1),b.lineTo(q/2,u/2),b.closePath(),b.fillStyle=a[e].color,b.fill(),
c.segmentShowStroke&&(b.strokeStyle=c.segmentStrokeColor,b.lineWidth=c.segmentStrokeWidth,b.stroke()),d+=h*g},b)},H=function(a,c,b){var e,h,f,d,g,k,j,l,m;a.labels||(a.labels=[]);g=Math.min.apply(Math,[q,u])/2;d=2*c.scaleFontSize;for(e=l=0;e<a.labels.length;e++)b.font=c.pointLabelFontStyle+" "+c.pointLabelFontSize+"px "+c.pointLabelFontFamily,h=b.measureText(a.labels[e]).width,h>l&&(l=h);g-=Math.max.apply(Math,[l,1.5*(c.pointLabelFontSize/2)]);g-=c.pointLabelFontSize;l=g=A(g,null,0);d=d?d:5;e=Number.MIN_VALUE;
h=Number.MAX_VALUE;for(f=0;f<a.datasets.length;f++)for(m=0;m<a.datasets[f].data.length;m++)a.datasets[f].data[m]>e&&(e=a.datasets[f].data[m]),a.datasets[f].data[m]<h&&(h=a.datasets[f].data[m]);f=Math.floor(l/(0.66*d));d=Math.floor(0.5*(l/d));m=c.scaleShowLabels?c.scaleLabel:null;c.scaleOverride?(j={steps:c.scaleSteps,stepValue:c.scaleStepWidth,graphMin:c.scaleStartValue,labels:[]},z(m,j.labels,j.steps,c.scaleStartValue,c.scaleStepWidth)):j=C(l,f,d,e,h,m);k=g/j.steps;x(c,function(){var e=2*Math.PI/
a.datasets[0].data.length;b.save();b.translate(q/2,u/2);if(c.angleShowLineOut){b.strokeStyle=c.angleLineColor;b.lineWidth=c.angleLineWidth;for(var d=0;d<a.datasets[0].data.length;d++)b.rotate(e),b.beginPath(),b.moveTo(0,0),b.lineTo(0,-g),b.stroke()}for(d=0;d<j.steps;d++){b.beginPath();if(c.scaleShowLine){b.strokeStyle=c.scaleLineColor;b.lineWidth=c.scaleLineWidth;b.moveTo(0,-k*(d+1));for(var f=0;f<a.datasets[0].data.length;f++)b.rotate(e),b.lineTo(0,-k*(d+1));b.closePath();b.stroke()}c.scaleShowLabels&&
(b.textAlign="center",b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily,b.textBaseline="middle",c.scaleShowLabelBackdrop&&(f=b.measureText(j.labels[d]).width,b.fillStyle=c.scaleBackdropColor,b.beginPath(),b.rect(Math.round(-f/2-c.scaleBackdropPaddingX),Math.round(-k*(d+1)-0.5*c.scaleFontSize-c.scaleBackdropPaddingY),Math.round(f+2*c.scaleBackdropPaddingX),Math.round(c.scaleFontSize+2*c.scaleBackdropPaddingY)),b.fill()),b.fillStyle=c.scaleFontColor,b.fillText(j.labels[d],0,-k*(d+
1)))}for(d=0;d<a.labels.length;d++){b.font=c.pointLabelFontStyle+" "+c.pointLabelFontSize+"px "+c.pointLabelFontFamily;b.fillStyle=c.pointLabelFontColor;var f=Math.sin(e*d)*(g+c.pointLabelFontSize),h=Math.cos(e*d)*(g+c.pointLabelFontSize);b.textAlign=e*d==Math.PI||0==e*d?"center":e*d>Math.PI?"right":"left";b.textBaseline="middle";b.fillText(a.labels[d],f,-h)}b.restore()},function(d){var e=2*Math.PI/a.datasets[0].data.length;b.save();b.translate(q/2,u/2);for(var g=0;g<a.datasets.length;g++){b.beginPath();
b.moveTo(0,d*-1*v(a.datasets[g].data[0],j,k));for(var f=1;f<a.datasets[g].data.length;f++)b.rotate(e),b.lineTo(0,d*-1*v(a.datasets[g].data[f],j,k));b.closePath();b.fillStyle=a.datasets[g].fillColor;b.strokeStyle=a.datasets[g].strokeColor;b.lineWidth=c.datasetStrokeWidth;b.fill();b.stroke();if(c.pointDot){b.fillStyle=a.datasets[g].pointColor;b.strokeStyle=a.datasets[g].pointStrokeColor;b.lineWidth=c.pointDotStrokeWidth;for(f=0;f<a.datasets[g].data.length;f++)b.rotate(e),b.beginPath(),b.arc(0,d*-1*
v(a.datasets[g].data[f],j,k),c.pointDotRadius,2*Math.PI,!1),b.fill(),b.stroke()}b.rotate(e)}b.restore()},b)},I=function(a,c,b){for(var e=0,h=Math.min.apply(Math,[u/2,q/2])-5,f=0;f<a.length;f++)e+=a[f].value;x(c,null,function(d){var g=-Math.PI/2,f=1,j=1;c.animation&&(c.animateScale&&(f=d),c.animateRotate&&(j=d));for(d=0;d<a.length;d++){var l=j*a[d].value/e*2*Math.PI;b.beginPath();b.arc(q/2,u/2,f*h,g,g+l);b.lineTo(q/2,u/2);b.closePath();b.fillStyle=a[d].color;b.fill();c.segmentShowStroke&&(b.lineWidth=
c.segmentStrokeWidth,b.strokeStyle=c.segmentStrokeColor,b.stroke());g+=l}},b)},J=function(a,c,b){for(var e=0,h=Math.min.apply(Math,[u/2,q/2])-5,f=h*(c.percentageInnerCutout/100),d=0;d<a.length;d++)e+=a[d].value;x(c,null,function(d){var k=-Math.PI/2,j=1,l=1;c.animation&&(c.animateScale&&(j=d),c.animateRotate&&(l=d));for(d=0;d<a.length;d++){var m=l*a[d].value/e*2*Math.PI;b.beginPath();b.arc(q/2,u/2,j*h,k,k+m,!1);b.arc(q/2,u/2,j*f,k+m,k,!0);b.closePath();b.fillStyle=a[d].color;b.fill();c.segmentShowStroke&&
(b.lineWidth=c.segmentStrokeWidth,b.strokeStyle=c.segmentStrokeColor,b.stroke());k+=m}},b)},K=function(a,c,b){var e,h,f,d,g,k,j,l,m,t,r,n,p,s=0;g=u;b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;t=1;for(d=0;d<a.labels.length;d++)e=b.measureText(a.labels[d]).width,t=e>t?e:t;q/a.labels.length<t?(s=45,q/a.labels.length<Math.cos(s)*t?(s=90,g-=t):g-=Math.sin(s)*t):g-=c.scaleFontSize;d=c.scaleFontSize;g=g-5-d;e=Number.MIN_VALUE;h=Number.MAX_VALUE;for(f=0;f<a.datasets.length;f++)for(l=
0;l<a.datasets[f].data.length;l++)a.datasets[f].data[l]>e&&(e=a.datasets[f].data[l]),a.datasets[f].data[l]<h&&(h=a.datasets[f].data[l]);f=Math.floor(g/(0.66*d));d=Math.floor(0.5*(g/d));l=c.scaleShowLabels?c.scaleLabel:"";c.scaleOverride?(j={steps:c.scaleSteps,stepValue:c.scaleStepWidth,graphMin:c.scaleStartValue,labels:[]},z(l,j.labels,j.steps,c.scaleStartValue,c.scaleStepWidth)):j=C(g,f,d,e,h,l);k=Math.floor(g/j.steps);d=1;if(c.scaleShowLabels){b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;
for(e=0;e<j.labels.length;e++)h=b.measureText(j.labels[e]).width,d=h>d?h:d;d+=10}r=q-d-t;m=Math.floor(r/(a.labels.length-1));n=q-t/2-r;p=g+c.scaleFontSize/2;x(c,function(){b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor;b.beginPath();b.moveTo(q-t/2+5,p);b.lineTo(q-t/2-r-5,p);b.stroke();0<s?(b.save(),b.textAlign="right"):b.textAlign="center";b.fillStyle=c.scaleFontColor;for(var d=0;d<a.labels.length;d++)b.save(),0<s?(b.translate(n+d*m,p+c.scaleFontSize),b.rotate(-(s*(Math.PI/180))),b.fillText(a.labels[d],
0,0),b.restore()):b.fillText(a.labels[d],n+d*m,p+c.scaleFontSize+3),b.beginPath(),b.moveTo(n+d*m,p+3),c.scaleShowGridLines&&0<d?(b.lineWidth=c.scaleGridLineWidth,b.strokeStyle=c.scaleGridLineColor,b.lineTo(n+d*m,5)):b.lineTo(n+d*m,p+3),b.stroke();b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor;b.beginPath();b.moveTo(n,p+5);b.lineTo(n,5);b.stroke();b.textAlign="right";b.textBaseline="middle";for(d=0;d<j.steps;d++)b.beginPath(),b.moveTo(n-3,p-(d+1)*k),c.scaleShowGridLines?(b.lineWidth=c.scaleGridLineWidth,
b.strokeStyle=c.scaleGridLineColor,b.lineTo(n+r+5,p-(d+1)*k)):b.lineTo(n-0.5,p-(d+1)*k),b.stroke(),c.scaleShowLabels&&b.fillText(j.labels[d],n-8,p-(d+1)*k)},function(d){function e(b,c){return p-d*v(a.datasets[b].data[c],j,k)}for(var f=0;f<a.datasets.length;f++){b.strokeStyle=a.datasets[f].strokeColor;b.lineWidth=c.datasetStrokeWidth;b.beginPath();b.moveTo(n,p-d*v(a.datasets[f].data[0],j,k));for(var g=1;g<a.datasets[f].data.length;g++)c.bezierCurve?b.bezierCurveTo(n+m*(g-0.5),e(f,g-1),n+m*(g-0.5),
e(f,g),n+m*g,e(f,g)):b.lineTo(n+m*g,e(f,g));b.stroke();c.datasetFill?(b.lineTo(n+m*(a.datasets[f].data.length-1),p),b.lineTo(n,p),b.closePath(),b.fillStyle=a.datasets[f].fillColor,b.fill()):b.closePath();if(c.pointDot){b.fillStyle=a.datasets[f].pointColor;b.strokeStyle=a.datasets[f].pointStrokeColor;b.lineWidth=c.pointDotStrokeWidth;for(g=0;g<a.datasets[f].data.length;g++)b.beginPath(),b.arc(n+m*g,p-d*v(a.datasets[f].data[g],j,k),c.pointDotRadius,0,2*Math.PI,!0),b.fill(),b.stroke()}}},b)},L=function(a,
c,b){var e,h,f,d,g,k,j,l,m,t,r,n,p,s,w=0;g=u;b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;t=1;for(d=0;d<a.labels.length;d++)e=b.measureText(a.labels[d]).width,t=e>t?e:t;q/a.labels.length<t?(w=45,q/a.labels.length<Math.cos(w)*t?(w=90,g-=t):g-=Math.sin(w)*t):g-=c.scaleFontSize;d=c.scaleFontSize;g=g-5-d;e=Number.MIN_VALUE;h=Number.MAX_VALUE;for(f=0;f<a.datasets.length;f++)for(l=0;l<a.datasets[f].data.length;l++)a.datasets[f].data[l]>e&&(e=a.datasets[f].data[l]),a.datasets[f].data[l]<
h&&(h=a.datasets[f].data[l]);f=Math.floor(g/(0.66*d));d=Math.floor(0.5*(g/d));l=c.scaleShowLabels?c.scaleLabel:"";c.scaleOverride?(j={steps:c.scaleSteps,stepValue:c.scaleStepWidth,graphMin:c.scaleStartValue,labels:[]},z(l,j.labels,j.steps,c.scaleStartValue,c.scaleStepWidth)):j=C(g,f,d,e,h,l);k=Math.floor(g/j.steps);d=1;if(c.scaleShowLabels){b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;for(e=0;e<j.labels.length;e++)h=b.measureText(j.labels[e]).width,d=h>d?h:d;d+=10}r=q-d-t;m=
Math.floor(r/a.labels.length);s=(m-2*c.scaleGridLineWidth-2*c.barValueSpacing-(c.barDatasetSpacing*a.datasets.length-1)-(c.barStrokeWidth/2*a.datasets.length-1))/a.datasets.length;n=q-t/2-r;p=g+c.scaleFontSize/2;x(c,function(){b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor;b.beginPath();b.moveTo(q-t/2+5,p);b.lineTo(q-t/2-r-5,p);b.stroke();0<w?(b.save(),b.textAlign="right"):b.textAlign="center";b.fillStyle=c.scaleFontColor;for(var d=0;d<a.labels.length;d++)b.save(),0<w?(b.translate(n+
d*m,p+c.scaleFontSize),b.rotate(-(w*(Math.PI/180))),b.fillText(a.labels[d],0,0),b.restore()):b.fillText(a.labels[d],n+d*m+m/2,p+c.scaleFontSize+3),b.beginPath(),b.moveTo(n+(d+1)*m,p+3),b.lineWidth=c.scaleGridLineWidth,b.strokeStyle=c.scaleGridLineColor,b.lineTo(n+(d+1)*m,5),b.stroke();b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor;b.beginPath();b.moveTo(n,p+5);b.lineTo(n,5);b.stroke();b.textAlign="right";b.textBaseline="middle";for(d=0;d<j.steps;d++)b.beginPath(),b.moveTo(n-3,p-(d+1)*
k),c.scaleShowGridLines?(b.lineWidth=c.scaleGridLineWidth,b.strokeStyle=c.scaleGridLineColor,b.lineTo(n+r+5,p-(d+1)*k)):b.lineTo(n-0.5,p-(d+1)*k),b.stroke(),c.scaleShowLabels&&b.fillText(j.labels[d],n-8,p-(d+1)*k)},function(d){b.lineWidth=c.barStrokeWidth;for(var e=0;e<a.datasets.length;e++){b.fillStyle=a.datasets[e].fillColor;b.strokeStyle=a.datasets[e].strokeColor;for(var f=0;f<a.datasets[e].data.length;f++){var g=n+c.barValueSpacing+m*f+s*e+c.barDatasetSpacing*e+c.barStrokeWidth*e;b.beginPath();
b.moveTo(g,p);b.lineTo(g,p-d*v(a.datasets[e].data[f],j,k)+c.barStrokeWidth/2);b.lineTo(g+s,p-d*v(a.datasets[e].data[f],j,k)+c.barStrokeWidth/2);b.lineTo(g+s,p);c.barShowStroke&&b.stroke();b.closePath();b.fill()}}},b)},D=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){window.setTimeout(a,1E3/60)},F={}};

View File

@ -0,0 +1,246 @@
/* BASICS */
.CodeMirror {
/* Set height, width, borders, and global font properties here */
font-family: monospace;
height: 300px;
}
.CodeMirror-scroll {
/* Set scrolling behaviour here */
overflow: auto;
}
/* PADDING */
.CodeMirror-lines {
padding: 4px 0; /* Vertical padding around content */
}
.CodeMirror pre {
padding: 0 4px; /* Horizontal padding of content */
}
.CodeMirror-scrollbar-filler {
background-color: white; /* The little square between H and V scrollbars */
}
/* GUTTER */
.CodeMirror-gutters {
border-right: 1px solid #ddd;
background-color: #f7f7f7;
}
.CodeMirror-linenumbers {}
.CodeMirror-linenumber {
padding: 0 3px 0 5px;
min-width: 20px;
text-align: right;
color: #999;
}
/* CURSOR */
.CodeMirror div.CodeMirror-cursor {
border-left: 1px solid black;
z-index: 3;
}
/* Shown when moving in bi-directional text */
.CodeMirror div.CodeMirror-secondarycursor {
border-left: 1px solid silver;
}
.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
width: auto;
border: 0;
background: #7e7;
z-index: 1;
}
/* Can style cursor different in overwrite (non-insert) mode */
.CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite {}
.cm-tab { display: inline-block; }
/* DEFAULT THEME */
.cm-s-default .cm-keyword {color: #708;}
.cm-s-default .cm-atom {color: #219;}
.cm-s-default .cm-number {color: #164;}
.cm-s-default .cm-def {color: #00f;}
.cm-s-default .cm-variable {color: black;}
.cm-s-default .cm-variable-2 {color: #05a;}
.cm-s-default .cm-variable-3 {color: #085;}
.cm-s-default .cm-property {color: black;}
.cm-s-default .cm-operator {color: black;}
.cm-s-default .cm-comment {color: #a50;}
.cm-s-default .cm-string {color: #a11;}
.cm-s-default .cm-string-2 {color: #f50;}
.cm-s-default .cm-meta {color: #555;}
.cm-s-default .cm-error {color: #f00;}
.cm-s-default .cm-qualifier {color: #555;}
.cm-s-default .cm-builtin {color: #30a;}
.cm-s-default .cm-bracket {color: #997;}
.cm-s-default .cm-tag {color: #170;}
.cm-s-default .cm-attribute {color: #00c;}
.cm-s-default .cm-header {color: blue;}
.cm-s-default .cm-quote {color: #090;}
.cm-s-default .cm-hr {color: #999;}
.cm-s-default .cm-link {color: #00c;}
.cm-negative {color: #d44;}
.cm-positive {color: #292;}
.cm-header, .cm-strong {font-weight: bold;}
.cm-em {font-style: italic;}
.cm-link {text-decoration: underline;}
.cm-invalidchar {color: #f00;}
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
/* STOP */
/* The rest of this file contains styles related to the mechanics of
the editor. You probably shouldn't touch them. */
.CodeMirror {
line-height: 1;
position: relative;
overflow: hidden;
background: white;
color: black;
}
.CodeMirror-scroll {
/* 30px is the magic margin used to hide the element's real scrollbars */
/* See overflow: hidden in .CodeMirror */
margin-bottom: -30px; margin-right: -30px;
padding-bottom: 30px; padding-right: 30px;
height: 100%;
outline: none; /* Prevent dragging from highlighting the element */
position: relative;
}
.CodeMirror-sizer {
position: relative;
}
/* The fake, visible scrollbars. Used to force redraw during scrolling
before actuall scrolling happens, thus preventing shaking and
flickering artifacts. */
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler {
position: absolute;
z-index: 6;
display: none;
}
.CodeMirror-vscrollbar {
right: 0; top: 0;
overflow-x: hidden;
overflow-y: scroll;
}
.CodeMirror-hscrollbar {
bottom: 0; left: 0;
overflow-y: hidden;
overflow-x: scroll;
}
.CodeMirror-scrollbar-filler {
right: 0; bottom: 0;
z-index: 6;
}
.CodeMirror-gutters {
position: absolute; left: 0; top: 0;
height: 100%;
padding-bottom: 30px;
z-index: 3;
}
.CodeMirror-gutter {
height: 100%;
padding-bottom: 30px;
margin-bottom: -32px;
display: inline-block;
/* Hack to make IE7 behave */
*zoom:1;
*display:inline;
}
.CodeMirror-gutter-elt {
position: absolute;
cursor: default;
z-index: 4;
}
.CodeMirror-lines {
cursor: text;
}
.CodeMirror pre {
/* Reset some styles that the rest of the page might have set */
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
border-width: 0;
background: transparent;
font-family: inherit;
font-size: inherit;
margin: 0;
white-space: pre;
word-wrap: normal;
line-height: inherit;
color: inherit;
z-index: 2;
position: relative;
overflow: visible;
}
.CodeMirror-wrap pre {
word-wrap: break-word;
white-space: pre-wrap;
word-break: normal;
}
.CodeMirror-linebackground {
position: absolute;
left: 0; right: 0; top: 0; bottom: 0;
z-index: 0;
}
.CodeMirror-linewidget {
position: relative;
z-index: 2;
overflow: auto;
}
.CodeMirror-widget {
display: inline-block;
}
.CodeMirror-wrap .CodeMirror-scroll {
overflow-x: hidden;
}
.CodeMirror-measure {
position: absolute;
width: 100%; height: 0px;
overflow: hidden;
visibility: hidden;
}
.CodeMirror-measure pre { position: static; }
.CodeMirror div.CodeMirror-cursor {
position: absolute;
visibility: hidden;
border-right: none;
width: 0;
}
.CodeMirror-focused div.CodeMirror-cursor {
visibility: visible;
}
.CodeMirror-selected { background: #d9d9d9; }
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
.cm-searching {
background: #ffa;
background: rgba(255, 255, 0, .4);
}
/* IE7 hack to prevent it from returning funny offsetTops on the spans */
.CodeMirror span { *vertical-align: text-bottom; }
@media print {
/* Hide the cursor when printing */
.CodeMirror div.CodeMirror-cursor {
visibility: hidden;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,344 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>CodeMirror: Markdown mode</title>
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="../../addon/edit/continuelist.js"></script>
<script src="../xml/xml.js"></script>
<script src="markdown.js"></script>
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
<link rel="stylesheet" href="../../doc/docs.css">
</head>
<body>
<h1>CodeMirror: Markdown mode</h1>
<!-- source: http://daringfireball.net/projects/markdown/basics.text -->
<form><textarea id="code" name="code">
Markdown: Basics
================
&lt;ul id="ProjectSubmenu"&gt;
&lt;li&gt;&lt;a href="/projects/markdown/" title="Markdown Project Page"&gt;Main&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="selected" title="Markdown Basics"&gt;Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/projects/markdown/syntax" title="Markdown Syntax Documentation"&gt;Syntax&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/projects/markdown/license" title="Pricing and License Information"&gt;License&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/projects/markdown/dingus" title="Online Markdown Web Form"&gt;Dingus&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
Getting the Gist of Markdown's Formatting Syntax
------------------------------------------------
This page offers a brief overview of what it's like to use Markdown.
The [syntax page] [s] provides complete, detailed documentation for
every feature, but Markdown should be very easy to pick up simply by
looking at a few examples of it in action. The examples on this page
are written in a before/after style, showing example syntax and the
HTML output produced by Markdown.
It's also helpful to simply try Markdown out; the [Dingus] [d] is a
web application that allows you type your own Markdown-formatted text
and translate it to XHTML.
**Note:** This document is itself written using Markdown; you
can [see the source for it by adding '.text' to the URL] [src].
[s]: /projects/markdown/syntax "Markdown Syntax"
[d]: /projects/markdown/dingus "Markdown Dingus"
[src]: /projects/markdown/basics.text
## Paragraphs, Headers, Blockquotes ##
A paragraph is simply one or more consecutive lines of text, separated
by one or more blank lines. (A blank line is any line that looks like
a blank line -- a line containing nothing but spaces or tabs is
considered blank.) Normal paragraphs should not be indented with
spaces or tabs.
Markdown offers two styles of headers: *Setext* and *atx*.
Setext-style headers for `&lt;h1&gt;` and `&lt;h2&gt;` are created by
"underlining" with equal signs (`=`) and hyphens (`-`), respectively.
To create an atx-style header, you put 1-6 hash marks (`#`) at the
beginning of the line -- the number of hashes equals the resulting
HTML header level.
Blockquotes are indicated using email-style '`&gt;`' angle brackets.
Markdown:
A First Level Header
====================
A Second Level Header
---------------------
Now is the time for all good men to come to
the aid of their country. This is just a
regular paragraph.
The quick brown fox jumped over the lazy
dog's back.
### Header 3
&gt; This is a blockquote.
&gt;
&gt; This is the second paragraph in the blockquote.
&gt;
&gt; ## This is an H2 in a blockquote
Output:
&lt;h1&gt;A First Level Header&lt;/h1&gt;
&lt;h2&gt;A Second Level Header&lt;/h2&gt;
&lt;p&gt;Now is the time for all good men to come to
the aid of their country. This is just a
regular paragraph.&lt;/p&gt;
&lt;p&gt;The quick brown fox jumped over the lazy
dog's back.&lt;/p&gt;
&lt;h3&gt;Header 3&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a blockquote.&lt;/p&gt;
&lt;p&gt;This is the second paragraph in the blockquote.&lt;/p&gt;
&lt;h2&gt;This is an H2 in a blockquote&lt;/h2&gt;
&lt;/blockquote&gt;
### Phrase Emphasis ###
Markdown uses asterisks and underscores to indicate spans of emphasis.
Markdown:
Some of these words *are emphasized*.
Some of these words _are emphasized also_.
Use two asterisks for **strong emphasis**.
Or, if you prefer, __use two underscores instead__.
Output:
&lt;p&gt;Some of these words &lt;em&gt;are emphasized&lt;/em&gt;.
Some of these words &lt;em&gt;are emphasized also&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Use two asterisks for &lt;strong&gt;strong emphasis&lt;/strong&gt;.
Or, if you prefer, &lt;strong&gt;use two underscores instead&lt;/strong&gt;.&lt;/p&gt;
## Lists ##
Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`,
`+`, and `-`) as list markers. These three markers are
interchangable; this:
* Candy.
* Gum.
* Booze.
this:
+ Candy.
+ Gum.
+ Booze.
and this:
- Candy.
- Gum.
- Booze.
all produce the same output:
&lt;ul&gt;
&lt;li&gt;Candy.&lt;/li&gt;
&lt;li&gt;Gum.&lt;/li&gt;
&lt;li&gt;Booze.&lt;/li&gt;
&lt;/ul&gt;
Ordered (numbered) lists use regular numbers, followed by periods, as
list markers:
1. Red
2. Green
3. Blue
Output:
&lt;ol&gt;
&lt;li&gt;Red&lt;/li&gt;
&lt;li&gt;Green&lt;/li&gt;
&lt;li&gt;Blue&lt;/li&gt;
&lt;/ol&gt;
If you put blank lines between items, you'll get `&lt;p&gt;` tags for the
list item text. You can create multi-paragraph list items by indenting
the paragraphs by 4 spaces or 1 tab:
* A list item.
With multiple paragraphs.
* Another item in the list.
Output:
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A list item.&lt;/p&gt;
&lt;p&gt;With multiple paragraphs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Another item in the list.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
### Links ###
Markdown supports two styles for creating links: *inline* and
*reference*. With both styles, you use square brackets to delimit the
text you want to turn into a link.
Inline-style links use parentheses immediately after the link text.
For example:
This is an [example link](http://example.com/).
Output:
&lt;p&gt;This is an &lt;a href="http://example.com/"&gt;
example link&lt;/a&gt;.&lt;/p&gt;
Optionally, you may include a title attribute in the parentheses:
This is an [example link](http://example.com/ "With a Title").
Output:
&lt;p&gt;This is an &lt;a href="http://example.com/" title="With a Title"&gt;
example link&lt;/a&gt;.&lt;/p&gt;
Reference-style links allow you to refer to your links by names, which
you define elsewhere in your document:
I get 10 times more traffic from [Google][1] than from
[Yahoo][2] or [MSN][3].
[1]: http://google.com/ "Google"
[2]: http://search.yahoo.com/ "Yahoo Search"
[3]: http://search.msn.com/ "MSN Search"
Output:
&lt;p&gt;I get 10 times more traffic from &lt;a href="http://google.com/"
title="Google"&gt;Google&lt;/a&gt; than from &lt;a href="http://search.yahoo.com/"
title="Yahoo Search"&gt;Yahoo&lt;/a&gt; or &lt;a href="http://search.msn.com/"
title="MSN Search"&gt;MSN&lt;/a&gt;.&lt;/p&gt;
The title attribute is optional. Link names may contain letters,
numbers and spaces, but are *not* case sensitive:
I start my morning with a cup of coffee and
[The New York Times][NY Times].
[ny times]: http://www.nytimes.com/
Output:
&lt;p&gt;I start my morning with a cup of coffee and
&lt;a href="http://www.nytimes.com/"&gt;The New York Times&lt;/a&gt;.&lt;/p&gt;
### Images ###
Image syntax is very much like link syntax.
Inline (titles are optional):
![alt text](/path/to/img.jpg "Title")
Reference-style:
![alt text][id]
[id]: /path/to/img.jpg "Title"
Both of the above examples produce the same output:
&lt;img src="/path/to/img.jpg" alt="alt text" title="Title" /&gt;
### Code ###
In a regular paragraph, you can create code span by wrapping text in
backtick quotes. Any ampersands (`&amp;`) and angle brackets (`&lt;` or
`&gt;`) will automatically be translated into HTML entities. This makes
it easy to use Markdown to write about HTML example code:
I strongly recommend against using any `&lt;blink&gt;` tags.
I wish SmartyPants used named entities like `&amp;mdash;`
instead of decimal-encoded entites like `&amp;#8212;`.
Output:
&lt;p&gt;I strongly recommend against using any
&lt;code&gt;&amp;lt;blink&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;
&lt;p&gt;I wish SmartyPants used named entities like
&lt;code&gt;&amp;amp;mdash;&lt;/code&gt; instead of decimal-encoded
entites like &lt;code&gt;&amp;amp;#8212;&lt;/code&gt;.&lt;/p&gt;
To specify an entire block of pre-formatted code, indent every line of
the block by 4 spaces or 1 tab. Just like with code spans, `&amp;`, `&lt;`,
and `&gt;` characters will be escaped automatically.
Markdown:
If you want your page to validate under XHTML 1.0 Strict,
you've got to put paragraph tags in your blockquotes:
&lt;blockquote&gt;
&lt;p&gt;For example.&lt;/p&gt;
&lt;/blockquote&gt;
Output:
&lt;p&gt;If you want your page to validate under XHTML 1.0 Strict,
you've got to put paragraph tags in your blockquotes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;blockquote&amp;gt;
&amp;lt;p&amp;gt;For example.&amp;lt;/p&amp;gt;
&amp;lt;/blockquote&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
mode: 'markdown',
lineNumbers: true,
theme: "default",
extraKeys: {"Enter": "newlineAndIndentContinueMarkdownList"}
});
</script>
<p>Optionally depends on the XML mode for properly highlighted inline XML blocks.</p>
<p><strong>MIME types defined:</strong> <code>text/x-markdown</code>.</p>
<p><strong>Parsing/Highlighting Tests:</strong> <a href="../../test/index.html#markdown_*">normal</a>, <a href="../../test/index.html#verbose,markdown_*">verbose</a>.</p>
</body>
</html>

View File

@ -0,0 +1,526 @@
CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
var htmlFound = CodeMirror.mimeModes.hasOwnProperty("text/html");
var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? "text/html" : "text/plain");
var aliases = {
html: "htmlmixed",
js: "javascript",
json: "application/json",
c: "text/x-csrc",
"c++": "text/x-c++src",
java: "text/x-java",
csharp: "text/x-csharp",
"c#": "text/x-csharp",
scala: "text/x-scala"
};
var getMode = (function () {
var i, modes = {}, mimes = {}, mime;
var list = [];
for (var m in CodeMirror.modes)
if (CodeMirror.modes.propertyIsEnumerable(m)) list.push(m);
for (i = 0; i < list.length; i++) {
modes[list[i]] = list[i];
}
var mimesList = [];
for (var m in CodeMirror.mimeModes)
if (CodeMirror.mimeModes.propertyIsEnumerable(m))
mimesList.push({mime: m, mode: CodeMirror.mimeModes[m]});
for (i = 0; i < mimesList.length; i++) {
mime = mimesList[i].mime;
mimes[mime] = mimesList[i].mime;
}
for (var a in aliases) {
if (aliases[a] in modes || aliases[a] in mimes)
modes[a] = aliases[a];
}
return function (lang) {
return modes[lang] ? CodeMirror.getMode(cmCfg, modes[lang]) : null;
};
}());
// Should underscores in words open/close em/strong?
if (modeCfg.underscoresBreakWords === undefined)
modeCfg.underscoresBreakWords = true;
// Turn on fenced code blocks? ("```" to start/end)
if (modeCfg.fencedCodeBlocks === undefined) modeCfg.fencedCodeBlocks = false;
// Turn on task lists? ("- [ ] " and "- [x] ")
if (modeCfg.taskLists === undefined) modeCfg.taskLists = false;
var codeDepth = 0;
var header = 'header'
, code = 'comment'
, quote1 = 'atom'
, quote2 = 'number'
, list1 = 'variable-2'
, list2 = 'variable-3'
, list3 = 'keyword'
, hr = 'hr'
, image = 'tag'
, linkinline = 'link'
, linkemail = 'link'
, linktext = 'link'
, linkhref = 'string'
, em = 'em'
, strong = 'strong';
var hrRE = /^([*\-=_])(?:\s*\1){2,}\s*$/
, ulRE = /^[*\-+]\s+/
, olRE = /^[0-9]+\.\s+/
, taskListRE = /^\[(x| )\](?=\s)/ // Must follow ulRE or olRE
, headerRE = /^(?:\={1,}|-{1,})$/
, textRE = /^[^!\[\]*_\\<>` "'(]+/;
function switchInline(stream, state, f) {
state.f = state.inline = f;
return f(stream, state);
}
function switchBlock(stream, state, f) {
state.f = state.block = f;
return f(stream, state);
}
// Blocks
function blankLine(state) {
// Reset linkTitle state
state.linkTitle = false;
// Reset EM state
state.em = false;
// Reset STRONG state
state.strong = false;
// Reset state.quote
state.quote = 0;
if (!htmlFound && state.f == htmlBlock) {
state.f = inlineNormal;
state.block = blockNormal;
}
// Mark this line as blank
state.thisLineHasContent = false;
return null;
}
function blockNormal(stream, state) {
var prevLineIsList = (state.list !== false);
if (state.list !== false && state.indentationDiff >= 0) { // Continued list
if (state.indentationDiff < 4) { // Only adjust indentation if *not* a code block
state.indentation -= state.indentationDiff;
}
state.list = null;
} else if (state.list !== false && state.indentation > 0) {
state.list = null;
state.listDepth = Math.floor(state.indentation / 4);
} else if (state.list !== false) { // No longer a list
state.list = false;
state.listDepth = 0;
}
if (state.indentationDiff >= 4) {
state.indentation -= 4;
stream.skipToEnd();
return code;
} else if (stream.eatSpace()) {
return null;
} else if (stream.peek() === '#' || (state.prevLineHasContent && stream.match(headerRE)) ) {
state.header = true;
} else if (stream.eat('>')) {
state.indentation++;
state.quote = 1;
stream.eatSpace();
while (stream.eat('>')) {
stream.eatSpace();
state.quote++;
}
} else if (stream.peek() === '[') {
return switchInline(stream, state, footnoteLink);
} else if (stream.match(hrRE, true)) {
return hr;
} else if ((!state.prevLineHasContent || prevLineIsList) && (stream.match(ulRE, true) || stream.match(olRE, true))) {
state.indentation += 4;
state.list = true;
state.listDepth++;
if (modeCfg.taskLists && stream.match(taskListRE, false)) {
state.taskList = true;
}
} else if (modeCfg.fencedCodeBlocks && stream.match(/^```([\w+#]*)/, true)) {
// try switching mode
state.localMode = getMode(RegExp.$1);
if (state.localMode) state.localState = state.localMode.startState();
switchBlock(stream, state, local);
return code;
}
return switchInline(stream, state, state.inline);
}
function htmlBlock(stream, state) {
var style = htmlMode.token(stream, state.htmlState);
if (htmlFound && style === 'tag' && state.htmlState.type !== 'openTag' && !state.htmlState.context) {
state.f = inlineNormal;
state.block = blockNormal;
}
if (state.md_inside && stream.current().indexOf(">")!=-1) {
state.f = inlineNormal;
state.block = blockNormal;
state.htmlState.context = undefined;
}
return style;
}
function local(stream, state) {
if (stream.sol() && stream.match(/^```/, true)) {
state.localMode = state.localState = null;
state.f = inlineNormal;
state.block = blockNormal;
return code;
} else if (state.localMode) {
return state.localMode.token(stream, state.localState);
} else {
stream.skipToEnd();
return code;
}
}
// Inline
function getType(state) {
var styles = [];
if (state.taskOpen) { return "meta"; }
if (state.taskClosed) { return "property"; }
if (state.strong) { styles.push(strong); }
if (state.em) { styles.push(em); }
if (state.linkText) { styles.push(linktext); }
if (state.code) { styles.push(code); }
if (state.header) { styles.push(header); }
if (state.quote) { styles.push(state.quote % 2 ? quote1 : quote2); }
if (state.list !== false) {
var listMod = (state.listDepth - 1) % 3;
if (!listMod) {
styles.push(list1);
} else if (listMod === 1) {
styles.push(list2);
} else {
styles.push(list3);
}
}
return styles.length ? styles.join(' ') : null;
}
function handleText(stream, state) {
if (stream.match(textRE, true)) {
return getType(state);
}
return undefined;
}
function inlineNormal(stream, state) {
var style = state.text(stream, state);
if (typeof style !== 'undefined')
return style;
if (state.list) { // List marker (*, +, -, 1., etc)
state.list = null;
return getType(state);
}
if (state.taskList) {
var taskOpen = stream.match(taskListRE, true)[1] !== "x";
if (taskOpen) state.taskOpen = true;
else state.taskClosed = true;
state.taskList = false;
return getType(state);
}
state.taskOpen = false;
state.taskClosed = false;
var ch = stream.next();
if (ch === '\\') {
stream.next();
return getType(state);
}
// Matches link titles present on next line
if (state.linkTitle) {
state.linkTitle = false;
var matchCh = ch;
if (ch === '(') {
matchCh = ')';
}
matchCh = (matchCh+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
var regex = '^\\s*(?:[^' + matchCh + '\\\\]+|\\\\\\\\|\\\\.)' + matchCh;
if (stream.match(new RegExp(regex), true)) {
return linkhref;
}
}
// If this block is changed, it may need to be updated in GFM mode
if (ch === '`') {
var t = getType(state);
var before = stream.pos;
stream.eatWhile('`');
var difference = 1 + stream.pos - before;
if (!state.code) {
codeDepth = difference;
state.code = true;
return getType(state);
} else {
if (difference === codeDepth) { // Must be exact
state.code = false;
return t;
}
return getType(state);
}
} else if (state.code) {
return getType(state);
}
if (ch === '!' && stream.match(/\[[^\]]*\] ?(?:\(|\[)/, false)) {
stream.match(/\[[^\]]*\]/);
state.inline = state.f = linkHref;
return image;
}
if (ch === '[' && stream.match(/.*\](\(| ?\[)/, false)) {
state.linkText = true;
return getType(state);
}
if (ch === ']' && state.linkText) {
var type = getType(state);
state.linkText = false;
state.inline = state.f = linkHref;
return type;
}
if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, true)) {
return switchInline(stream, state, inlineElement(linkinline, '>'));
}
if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, true)) {
return switchInline(stream, state, inlineElement(linkemail, '>'));
}
if (ch === '<' && stream.match(/^\w/, false)) {
if (stream.string.indexOf(">")!=-1) {
var atts = stream.string.substring(1,stream.string.indexOf(">"));
if (/markdown\s*=\s*('|"){0,1}1('|"){0,1}/.test(atts)) {
state.md_inside = true;
}
}
stream.backUp(1);
return switchBlock(stream, state, htmlBlock);
}
if (ch === '<' && stream.match(/^\/\w*?>/)) {
state.md_inside = false;
return "tag";
}
var ignoreUnderscore = false;
if (!modeCfg.underscoresBreakWords) {
if (ch === '_' && stream.peek() !== '_' && stream.match(/(\w)/, false)) {
var prevPos = stream.pos - 2;
if (prevPos >= 0) {
var prevCh = stream.string.charAt(prevPos);
if (prevCh !== '_' && prevCh.match(/(\w)/, false)) {
ignoreUnderscore = true;
}
}
}
}
var t = getType(state);
if (ch === '*' || (ch === '_' && !ignoreUnderscore)) {
if (state.strong === ch && stream.eat(ch)) { // Remove STRONG
state.strong = false;
return t;
} else if (!state.strong && stream.eat(ch)) { // Add STRONG
state.strong = ch;
return getType(state);
} else if (state.em === ch) { // Remove EM
state.em = false;
return t;
} else if (!state.em) { // Add EM
state.em = ch;
return getType(state);
}
} else if (ch === ' ') {
if (stream.eat('*') || stream.eat('_')) { // Probably surrounded by spaces
if (stream.peek() === ' ') { // Surrounded by spaces, ignore
return getType(state);
} else { // Not surrounded by spaces, back up pointer
stream.backUp(1);
}
}
}
return getType(state);
}
function linkHref(stream, state) {
// Check if space, and return NULL if so (to avoid marking the space)
if(stream.eatSpace()){
return null;
}
var ch = stream.next();
if (ch === '(' || ch === '[') {
return switchInline(stream, state, inlineElement(linkhref, ch === '(' ? ')' : ']'));
}
return 'error';
}
function footnoteLink(stream, state) {
if (stream.match(/^[^\]]*\]:/, true)) {
state.f = footnoteUrl;
return linktext;
}
return switchInline(stream, state, inlineNormal);
}
function footnoteUrl(stream, state) {
// Check if space, and return NULL if so (to avoid marking the space)
if(stream.eatSpace()){
return null;
}
// Match URL
stream.match(/^[^\s]+/, true);
// Check for link title
if (stream.peek() === undefined) { // End of line, set flag to check next line
state.linkTitle = true;
} else { // More content on line, check if link title
stream.match(/^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/, true);
}
state.f = state.inline = inlineNormal;
return linkhref;
}
var savedInlineRE = [];
function inlineRE(endChar) {
if (!savedInlineRE[endChar]) {
// Escape endChar for RegExp (taken from http://stackoverflow.com/a/494122/526741)
endChar = (endChar+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
// Match any non-endChar, escaped character, as well as the closing
// endChar.
savedInlineRE[endChar] = new RegExp('^(?:[^\\\\]|\\\\.)*?(' + endChar + ')');
}
return savedInlineRE[endChar];
}
function inlineElement(type, endChar, next) {
next = next || inlineNormal;
return function(stream, state) {
stream.match(inlineRE(endChar));
state.inline = state.f = next;
return type;
};
}
return {
startState: function() {
return {
f: blockNormal,
prevLineHasContent: false,
thisLineHasContent: false,
block: blockNormal,
htmlState: CodeMirror.startState(htmlMode),
indentation: 0,
inline: inlineNormal,
text: handleText,
linkText: false,
linkTitle: false,
em: false,
strong: false,
header: false,
taskList: false,
list: false,
listDepth: 0,
quote: 0
};
},
copyState: function(s) {
return {
f: s.f,
prevLineHasContent: s.prevLineHasContent,
thisLineHasContent: s.thisLineHasContent,
block: s.block,
htmlState: CodeMirror.copyState(htmlMode, s.htmlState),
indentation: s.indentation,
localMode: s.localMode,
localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null,
inline: s.inline,
text: s.text,
linkTitle: s.linkTitle,
em: s.em,
strong: s.strong,
header: s.header,
taskList: s.taskList,
list: s.list,
listDepth: s.listDepth,
quote: s.quote,
md_inside: s.md_inside
};
},
token: function(stream, state) {
if (stream.sol()) {
if (stream.match(/^\s*$/, true)) {
state.prevLineHasContent = false;
return blankLine(state);
} else {
state.prevLineHasContent = state.thisLineHasContent;
state.thisLineHasContent = true;
}
// Reset state.header
state.header = false;
// Reset state.taskList
state.taskList = false;
// Reset state.code
state.code = false;
state.f = state.block;
var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length;
var difference = Math.floor((indentation - state.indentation) / 4) * 4;
if (difference > 4) difference = 4;
var adjustedIndentation = state.indentation + difference;
state.indentationDiff = adjustedIndentation - state.indentation;
state.indentation = adjustedIndentation;
if (indentation > 0) return null;
}
return state.f(stream, state);
},
blankLine: blankLine,
getType: getType
};
}, "xml");
CodeMirror.defineMIME("text/x-markdown", "markdown");

View File

@ -0,0 +1,636 @@
(function() {
var mode = CodeMirror.getMode({tabSize: 4}, "markdown");
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
MT("plainText",
"foo");
// Code blocks using 4 spaces (regardless of CodeMirror.tabSize value)
MT("codeBlocksUsing4Spaces",
" [comment foo]");
// Code blocks using 4 spaces with internal indentation
MT("codeBlocksUsing4SpacesIndentation",
" [comment bar]",
" [comment hello]",
" [comment world]",
" [comment foo]",
"bar");
// Code blocks using 4 spaces with internal indentation
MT("codeBlocksUsing4SpacesIndentation",
" foo",
" [comment bar]",
" [comment hello]",
" [comment world]");
// Code blocks using 1 tab (regardless of CodeMirror.indentWithTabs value)
MT("codeBlocksUsing1Tab",
"\t[comment foo]");
// Inline code using backticks
MT("inlineCodeUsingBackticks",
"foo [comment `bar`]");
// Block code using single backtick (shouldn't work)
MT("blockCodeSingleBacktick",
"[comment `]",
"foo",
"[comment `]");
// Unclosed backticks
// Instead of simply marking as CODE, it would be nice to have an
// incomplete flag for CODE, that is styled slightly different.
MT("unclosedBackticks",
"foo [comment `bar]");
// Per documentation: "To include a literal backtick character within a
// code span, you can use multiple backticks as the opening and closing
// delimiters"
MT("doubleBackticks",
"[comment ``foo ` bar``]");
// Tests based on Dingus
// http://daringfireball.net/projects/markdown/dingus
//
// Multiple backticks within an inline code block
MT("consecutiveBackticks",
"[comment `foo```bar`]");
// Multiple backticks within an inline code block with a second code block
MT("consecutiveBackticks",
"[comment `foo```bar`] hello [comment `world`]");
// Unclosed with several different groups of backticks
MT("unclosedBackticks",
"[comment ``foo ``` bar` hello]");
// Closed with several different groups of backticks
MT("closedBackticks",
"[comment ``foo ``` bar` hello``] world");
// atx headers
// http://daringfireball.net/projects/markdown/syntax#header
MT("atxH1",
"[header # foo]");
MT("atxH2",
"[header ## foo]");
MT("atxH3",
"[header ### foo]");
MT("atxH4",
"[header #### foo]");
MT("atxH5",
"[header ##### foo]");
MT("atxH6",
"[header ###### foo]");
// H6 - 7x '#' should still be H6, per Dingus
// http://daringfireball.net/projects/markdown/dingus
MT("atxH6NotH7",
"[header ####### foo]");
// Setext headers - H1, H2
// Per documentation, "Any number of underlining =s or -s will work."
// http://daringfireball.net/projects/markdown/syntax#header
// Ideally, the text would be marked as `header` as well, but this is
// not really feasible at the moment. So, instead, we're testing against
// what works today, to avoid any regressions.
//
// Check if single underlining = works
MT("setextH1",
"foo",
"[header =]");
// Check if 3+ ='s work
MT("setextH1",
"foo",
"[header ===]");
// Check if single underlining - works
MT("setextH2",
"foo",
"[header -]");
// Check if 3+ -'s work
MT("setextH2",
"foo",
"[header ---]");
// Single-line blockquote with trailing space
MT("blockquoteSpace",
"[atom > foo]");
// Single-line blockquote
MT("blockquoteNoSpace",
"[atom >foo]");
// No blank line before blockquote
MT("blockquoteNoBlankLine",
"foo",
"[atom > bar]");
// Nested blockquote
MT("blockquoteSpace",
"[atom > foo]",
"[number > > foo]",
"[atom > > > foo]");
// Single-line blockquote followed by normal paragraph
MT("blockquoteThenParagraph",
"[atom >foo]",
"",
"bar");
// Multi-line blockquote (lazy mode)
MT("multiBlockquoteLazy",
"[atom >foo]",
"[atom bar]");
// Multi-line blockquote followed by normal paragraph (lazy mode)
MT("multiBlockquoteLazyThenParagraph",
"[atom >foo]",
"[atom bar]",
"",
"hello");
// Multi-line blockquote (non-lazy mode)
MT("multiBlockquote",
"[atom >foo]",
"[atom >bar]");
// Multi-line blockquote followed by normal paragraph (non-lazy mode)
MT("multiBlockquoteThenParagraph",
"[atom >foo]",
"[atom >bar]",
"",
"hello");
// Check list types
MT("listAsterisk",
"foo",
"bar",
"",
"[variable-2 * foo]",
"[variable-2 * bar]");
MT("listPlus",
"foo",
"bar",
"",
"[variable-2 + foo]",
"[variable-2 + bar]");
MT("listDash",
"foo",
"bar",
"",
"[variable-2 - foo]",
"[variable-2 - bar]");
MT("listNumber",
"foo",
"bar",
"",
"[variable-2 1. foo]",
"[variable-2 2. bar]");
// Lists require a preceding blank line (per Dingus)
MT("listBogus",
"foo",
"1. bar",
"2. hello");
// Formatting in lists (*)
MT("listAsteriskFormatting",
"[variable-2 * ][variable-2&em *foo*][variable-2 bar]",
"[variable-2 * ][variable-2&strong **foo**][variable-2 bar]",
"[variable-2 * ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
"[variable-2 * ][variable-2&comment `foo`][variable-2 bar]");
// Formatting in lists (+)
MT("listPlusFormatting",
"[variable-2 + ][variable-2&em *foo*][variable-2 bar]",
"[variable-2 + ][variable-2&strong **foo**][variable-2 bar]",
"[variable-2 + ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
"[variable-2 + ][variable-2&comment `foo`][variable-2 bar]");
// Formatting in lists (-)
MT("listDashFormatting",
"[variable-2 - ][variable-2&em *foo*][variable-2 bar]",
"[variable-2 - ][variable-2&strong **foo**][variable-2 bar]",
"[variable-2 - ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
"[variable-2 - ][variable-2&comment `foo`][variable-2 bar]");
// Formatting in lists (1.)
MT("listNumberFormatting",
"[variable-2 1. ][variable-2&em *foo*][variable-2 bar]",
"[variable-2 2. ][variable-2&strong **foo**][variable-2 bar]",
"[variable-2 3. ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
"[variable-2 4. ][variable-2&comment `foo`][variable-2 bar]");
// Paragraph lists
MT("listParagraph",
"[variable-2 * foo]",
"",
"[variable-2 * bar]");
// Multi-paragraph lists
//
// 4 spaces
MT("listMultiParagraph",
"[variable-2 * foo]",
"",
"[variable-2 * bar]",
"",
" [variable-2 hello]");
// 4 spaces, extra blank lines (should still be list, per Dingus)
MT("listMultiParagraphExtra",
"[variable-2 * foo]",
"",
"[variable-2 * bar]",
"",
"",
" [variable-2 hello]");
// 4 spaces, plus 1 space (should still be list, per Dingus)
MT("listMultiParagraphExtraSpace",
"[variable-2 * foo]",
"",
"[variable-2 * bar]",
"",
" [variable-2 hello]",
"",
" [variable-2 world]");
// 1 tab
MT("listTab",
"[variable-2 * foo]",
"",
"[variable-2 * bar]",
"",
"\t[variable-2 hello]");
// No indent
MT("listNoIndent",
"[variable-2 * foo]",
"",
"[variable-2 * bar]",
"",
"hello");
// Blockquote
MT("blockquote",
"[variable-2 * foo]",
"",
"[variable-2 * bar]",
"",
" [variable-2&atom > hello]");
// Code block
MT("blockquoteCode",
"[variable-2 * foo]",
"",
"[variable-2 * bar]",
"",
" [comment > hello]",
"",
" [variable-2 world]");
// Code block followed by text
MT("blockquoteCodeText",
"[variable-2 * foo]",
"",
" [variable-2 bar]",
"",
" [comment hello]",
"",
" [variable-2 world]");
// Nested list
MT("listAsteriskNested",
"[variable-2 * foo]",
"",
" [variable-3 * bar]");
MT("listPlusNested",
"[variable-2 + foo]",
"",
" [variable-3 + bar]");
MT("listDashNested",
"[variable-2 - foo]",
"",
" [variable-3 - bar]");
MT("listNumberNested",
"[variable-2 1. foo]",
"",
" [variable-3 2. bar]");
MT("listMixed",
"[variable-2 * foo]",
"",
" [variable-3 + bar]",
"",
" [keyword - hello]",
"",
" [variable-2 1. world]");
MT("listBlockquote",
"[variable-2 * foo]",
"",
" [variable-3 + bar]",
"",
" [atom&variable-3 > hello]");
MT("listCode",
"[variable-2 * foo]",
"",
" [variable-3 + bar]",
"",
" [comment hello]");
// Code with internal indentation
MT("listCodeIndentation",
"[variable-2 * foo]",
"",
" [comment bar]",
" [comment hello]",
" [comment world]",
" [comment foo]",
" [variable-2 bar]");
// List nesting edge cases
MT("listNested",
"[variable-2 * foo]",
"",
" [variable-3 * bar]",
"",
" [variable-2 hello]"
);
MT("listNested",
"[variable-2 * foo]",
"",
" [variable-3 * bar]",
"",
" [variable-3 * foo]"
);
// Code followed by text
MT("listCodeText",
"[variable-2 * foo]",
"",
" [comment bar]",
"",
"hello");
// Following tests directly from official Markdown documentation
// http://daringfireball.net/projects/markdown/syntax#hr
MT("hrSpace",
"[hr * * *]");
MT("hr",
"[hr ***]");
MT("hrLong",
"[hr *****]");
MT("hrSpaceDash",
"[hr - - -]");
MT("hrDashLong",
"[hr ---------------------------------------]");
// Inline link with title
MT("linkTitle",
"[link [[foo]]][string (http://example.com/ \"bar\")] hello");
// Inline link without title
MT("linkNoTitle",
"[link [[foo]]][string (http://example.com/)] bar");
// Inline link with image
MT("linkImage",
"[link [[][tag ![[foo]]][string (http://example.com/)][link ]]][string (http://example.com/)] bar");
// Inline link with Em
MT("linkEm",
"[link [[][link&em *foo*][link ]]][string (http://example.com/)] bar");
// Inline link with Strong
MT("linkStrong",
"[link [[][link&strong **foo**][link ]]][string (http://example.com/)] bar");
// Inline link with EmStrong
MT("linkEmStrong",
"[link [[][link&strong **][link&em&strong *foo**][link&em *][link ]]][string (http://example.com/)] bar");
// Image with title
MT("imageTitle",
"[tag ![[foo]]][string (http://example.com/ \"bar\")] hello");
// Image without title
MT("imageNoTitle",
"[tag ![[foo]]][string (http://example.com/)] bar");
// Image with asterisks
MT("imageAsterisks",
"[tag ![[*foo*]]][string (http://example.com/)] bar");
// Not a link. Should be normal text due to square brackets being used
// regularly in text, especially in quoted material, and no space is allowed
// between square brackets and parentheses (per Dingus).
MT("notALink",
"[[foo]] (bar)");
// Reference-style links
MT("linkReference",
"[link [[foo]]][string [[bar]]] hello");
// Reference-style links with Em
MT("linkReferenceEm",
"[link [[][link&em *foo*][link ]]][string [[bar]]] hello");
// Reference-style links with Strong
MT("linkReferenceStrong",
"[link [[][link&strong **foo**][link ]]][string [[bar]]] hello");
// Reference-style links with EmStrong
MT("linkReferenceEmStrong",
"[link [[][link&strong **][link&em&strong *foo**][link&em *][link ]]][string [[bar]]] hello");
// Reference-style links with optional space separator (per docuentation)
// "You can optionally use a space to separate the sets of brackets"
MT("linkReferenceSpace",
"[link [[foo]]] [string [[bar]]] hello");
// Should only allow a single space ("...use *a* space...")
MT("linkReferenceDoubleSpace",
"[[foo]] [[bar]] hello");
// Reference-style links with implicit link name
MT("linkImplicit",
"[link [[foo]]][string [[]]] hello");
// @todo It would be nice if, at some point, the document was actually
// checked to see if the referenced link exists
// Link label, for reference-style links (taken from documentation)
MT("labelNoTitle",
"[link [[foo]]:] [string http://example.com/]");
MT("labelIndented",
" [link [[foo]]:] [string http://example.com/]");
MT("labelSpaceTitle",
"[link [[foo bar]]:] [string http://example.com/ \"hello\"]");
MT("labelDoubleTitle",
"[link [[foo bar]]:] [string http://example.com/ \"hello\"] \"world\"");
MT("labelTitleDoubleQuotes",
"[link [[foo]]:] [string http://example.com/ \"bar\"]");
MT("labelTitleSingleQuotes",
"[link [[foo]]:] [string http://example.com/ 'bar']");
MT("labelTitleParenthese",
"[link [[foo]]:] [string http://example.com/ (bar)]");
MT("labelTitleInvalid",
"[link [[foo]]:] [string http://example.com/] bar");
MT("labelLinkAngleBrackets",
"[link [[foo]]:] [string <http://example.com/> \"bar\"]");
MT("labelTitleNextDoubleQuotes",
"[link [[foo]]:] [string http://example.com/]",
"[string \"bar\"] hello");
MT("labelTitleNextSingleQuotes",
"[link [[foo]]:] [string http://example.com/]",
"[string 'bar'] hello");
MT("labelTitleNextParenthese",
"[link [[foo]]:] [string http://example.com/]",
"[string (bar)] hello");
MT("labelTitleNextMixed",
"[link [[foo]]:] [string http://example.com/]",
"(bar\" hello");
MT("linkWeb",
"[link <http://example.com/>] foo");
MT("linkEmail",
"[link <user@example.com>] foo");
MT("emAsterisk",
"[em *foo*] bar");
MT("emUnderscore",
"[em _foo_] bar");
MT("emInWordAsterisk",
"foo[em *bar*]hello");
MT("emInWordUnderscore",
"foo[em _bar_]hello");
// Per documentation: "...surround an * or _ with spaces, itll be
// treated as a literal asterisk or underscore."
MT("emEscapedBySpaceIn",
"foo [em _bar _ hello_] world");
MT("emEscapedBySpaceOut",
"foo _ bar[em _hello_]world");
// Unclosed emphasis characters
// Instead of simply marking as EM / STRONG, it would be nice to have an
// incomplete flag for EM and STRONG, that is styled slightly different.
MT("emIncompleteAsterisk",
"foo [em *bar]");
MT("emIncompleteUnderscore",
"foo [em _bar]");
MT("strongAsterisk",
"[strong **foo**] bar");
MT("strongUnderscore",
"[strong __foo__] bar");
MT("emStrongAsterisk",
"[em *foo][em&strong **bar*][strong hello**] world");
MT("emStrongUnderscore",
"[em _foo][em&strong __bar_][strong hello__] world");
// "...same character must be used to open and close an emphasis span.""
MT("emStrongMixed",
"[em _foo][em&strong **bar*hello__ world]");
MT("emStrongMixed",
"[em *foo][em&strong __bar_hello** world]");
// These characters should be escaped:
// \ backslash
// ` backtick
// * asterisk
// _ underscore
// {} curly braces
// [] square brackets
// () parentheses
// # hash mark
// + plus sign
// - minus sign (hyphen)
// . dot
// ! exclamation mark
MT("escapeBacktick",
"foo \\`bar\\`");
MT("doubleEscapeBacktick",
"foo \\\\[comment `bar\\\\`]");
MT("escapeAsterisk",
"foo \\*bar\\*");
MT("doubleEscapeAsterisk",
"foo \\\\[em *bar\\\\*]");
MT("escapeUnderscore",
"foo \\_bar\\_");
MT("doubleEscapeUnderscore",
"foo \\\\[em _bar\\\\_]");
MT("escapeHash",
"\\# foo");
MT("doubleEscapeHash",
"\\\\# foo");
// Tests to make sure GFM-specific things aren't getting through
MT("taskList",
"[variable-2 * [ ]] bar]");
MT("fencedCodeBlocks",
"[comment ```]",
"foo",
"[comment ```]");
})();

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,223 @@
/**
* http://www.openjs.com/scripts/events/keyboard_shortcuts/
* Version : 2.01.B
* By Binny V A
* License : BSD
*/
shortcut = {
'all_shortcuts':{},//All the shortcuts are stored in this array
'add': function(shortcut_combination,callback,opt) {
//Provide a set of default options
var default_options = {
'type':'keydown',
'propagate':false,
'disable_in_input':false,
'target':document,
'keycode':false
}
if(!opt) opt = default_options;
else {
for(var dfo in default_options) {
if(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];
}
}
var ele = opt.target;
if(typeof opt.target == 'string') ele = document.getElementById(opt.target);
var ths = this;
shortcut_combination = shortcut_combination.toLowerCase();
//The function to be called at keypress
var func = function(e) {
e = e || window.event;
if(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields
var element;
if(e.target) element=e.target;
else if(e.srcElement) element=e.srcElement;
if(element.nodeType==3) element=element.parentNode;
if(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;
}
//Find Which key is pressed
if (e.keyCode) code = e.keyCode;
else if (e.which) code = e.which;
var character = String.fromCharCode(code).toLowerCase();
if(code == 188) character=","; //If the user presses , when the type is onkeydown
if(code == 190) character="."; //If the user presses , when the type is onkeydown
var keys = shortcut_combination.split("+");
//Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
var kp = 0;
//Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
var shift_nums = {
"`":"~",
"1":"!",
"2":"@",
"3":"#",
"4":"$",
"5":"%",
"6":"^",
"7":"&",
"8":"*",
"9":"(",
"0":")",
"-":"_",
"=":"+",
";":":",
"'":"\"",
",":"<",
".":">",
"/":"?",
"\\":"|"
}
//Special Keys - and their codes
var special_keys = {
'esc':27,
'escape':27,
'tab':9,
'space':32,
'return':13,
'enter':13,
'backspace':8,
'scrolllock':145,
'scroll_lock':145,
'scroll':145,
'capslock':20,
'caps_lock':20,
'caps':20,
'numlock':144,
'num_lock':144,
'num':144,
'pause':19,
'break':19,
'insert':45,
'home':36,
'delete':46,
'end':35,
'pageup':33,
'page_up':33,
'pu':33,
'pagedown':34,
'page_down':34,
'pd':34,
'left':37,
'up':38,
'right':39,
'down':40,
'f1':112,
'f2':113,
'f3':114,
'f4':115,
'f5':116,
'f6':117,
'f7':118,
'f8':119,
'f9':120,
'f10':121,
'f11':122,
'f12':123
}
var modifiers = {
shift: { wanted:false, pressed:false},
ctrl : { wanted:false, pressed:false},
alt : { wanted:false, pressed:false},
meta : { wanted:false, pressed:false} //Meta is Mac specific
};
if(e.ctrlKey) modifiers.ctrl.pressed = true;
if(e.shiftKey) modifiers.shift.pressed = true;
if(e.altKey) modifiers.alt.pressed = true;
if(e.metaKey) modifiers.meta.pressed = true;
for(var i=0; k=keys[i],i<keys.length; i++) {
//Modifiers
if(k == 'ctrl' || k == 'control') {
kp++;
modifiers.ctrl.wanted = true;
} else if(k == 'shift') {
kp++;
modifiers.shift.wanted = true;
} else if(k == 'alt') {
kp++;
modifiers.alt.wanted = true;
} else if(k == 'meta') {
kp++;
modifiers.meta.wanted = true;
} else if(k.length > 1) { //If it is a special key
if(special_keys[k] == code) kp++;
} else if(opt['keycode']) {
if(opt['keycode'] == code) kp++;
} else { //The special keys did not match
if(character == k) kp++;
else {
if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase
character = shift_nums[character];
if(character == k) kp++;
}
}
}
}
if(kp == keys.length &&
modifiers.ctrl.pressed == modifiers.ctrl.wanted &&
modifiers.shift.pressed == modifiers.shift.wanted &&
modifiers.alt.pressed == modifiers.alt.wanted &&
modifiers.meta.pressed == modifiers.meta.wanted) {
callback(e);
if(!opt['propagate']) { //Stop the event
//e.cancelBubble is supported by IE - this will kill the bubbling process.
e.cancelBubble = true;
e.returnValue = false;
//e.stopPropagation works in Firefox.
if (e.stopPropagation) {
e.stopPropagation();
e.preventDefault();
}
return false;
}
}
}
this.all_shortcuts[shortcut_combination] = {
'callback':func,
'target':ele,
'event': opt['type']
};
//Attach the function with the event
if(ele.addEventListener) ele.addEventListener(opt['type'], func, false);
else if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);
else ele['on'+opt['type']] = func;
},
//Remove the shortcut - just specify the shortcut and I will remove the binding
'remove':function(shortcut_combination) {
shortcut_combination = shortcut_combination.toLowerCase();
var binding = this.all_shortcuts[shortcut_combination];
delete(this.all_shortcuts[shortcut_combination])
if(!binding) return;
var type = binding['event'];
var ele = binding['target'];
var callback = binding['callback'];
if(ele.detachEvent) ele.detachEvent('on'+type, callback);
else if(ele.removeEventListener) ele.removeEventListener(type, callback, false);
else ele['on'+type] = false;
}
}

View File

@ -0,0 +1,22 @@
(function () {
var ghostdown = function (converter) {
return [
// [image] syntax
{
type: 'lang',
filter: function (source) {
return source.replace(/\n+!image\[([\d\w\s]*)\]/gi, function (match, alt, a) {
return '<section class="image-uploader"><span class="media"><span class="hidden">Image Upload</span></span><div class="description">Add image of <strong>' + alt + '</strong></div><a class="image-url" title="Add image from URL"><span class="hidden">URL</a><a class="image-webcam" title="Add image from webcam"><span class="hidden">Webcam</a></section>';
});
}
}
];
};
// Client-side export
if (typeof window !== 'undefined' && window.Showdown && window.Showdown.extensions) {
window.Showdown.extensions.ghostdown = ghostdown;
}
// Server-side export
if (typeof module !== 'undefined') module.exports = ghostdown;
}());

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
/* Welcome to Compass. Use this file to write IE specific override styles. */

View File

@ -0,0 +1,366 @@
/*
* These are the styles used to control the look and feel of the widgetised
* dashboard of the Ghost admin system. The first screen you see on login.
*
*/
.widget {
width:341px;
height:300px;
background:#fff;
@include box-shadow;
float:left;
margin:0 15px 15px 0;
display:none;
}
.none {
margin-right:0;
}
.time {
background-image: url(../img/dash/Time@2x.png);
background-size: 341px 300px;
}
.image {
max-width: 100%;
width: 682px + 15px;
background-image: url(../img/dash/Image@2x.png);
background-size: 697px 300px;
}
.stats {
max-width: 100%;
width: 682px + 15px;
height: 615px;
background-image: url(../img/dash/Stats@2x.png);
background-size: 697px 615px;
}
.facebook {
background-image: url(../img/dash/Facebook@2x.png);
background-size: 341px 300px;
}
.gplus {
background-image: url(../img/dash/GooglePlus@2x.png);
background-size: 341px 300px;
}
.twitter {
background-image: url(../img/dash/Twitter@2x.png);
background-size: 341px 300px;
}
.campaignmonitor {
background-image: url(../img/dash/CampaignMonitor@2x.png);
background-size: 341px 300px;
}
.posts {
background-image: url(../img/dash/PostsStats@2x.png);
background-size: 341px 300px;
position: relative;
}
.chart {
box-sizing: border-box;
width: 250px;
height: 250px;
margin: 25px auto 0 auto;
background: #242628;
border: #efefef 54px solid;
border-radius: 500px;
}
#poststats {
position: relative;
top:-54px;
left: -54px;
}
.data {
position: absolute;
top: 87px;
color: $midgrey;
font-size: 13px;
list-style: none;
}
.ready {
font-size: 18px;
vertical-align: -5%;
margin-right: 5px;
color: $green;
}
.pending {
font-size: 18px;
vertical-align: -5%;
margin-right: 5px;
color: #f9e15d;
}
.draft {
font-size: 18px;
vertical-align: -5%;
margin-right: 5px;
color: $red;
}
/*
.dashboard-controls {
@extend %box;
padding:0 15px;
.text {
padding:12px 0;
}
}
.controls-nav {
float:left;
margin-left:20px;
ul {
border-left: $lightgrey 1px solid;
li {
margin: 0;
border-right: 1px solid $lightgrey;
a {
padding: 12px 15px;
color: $grey;
span {
color: $darkgrey;
}
&:hover {
color: $darkgrey;
text-decoration: none;
}
}
}
}
}
.widget-stats {
span {
display: block;
font-size: 1.6em;
line-height: 1.2em;
color: $grey;
margin-bottom: 15px;
strong {
font-size: 1.2em;
}
}
span:first-child {
font-size: 5.4em;
line-height: 1.4em;
color: #000;
margin-bottom: 0;
}
}
@media only screen and (min-width: 1200px) {
.span4 .vert2 {
.widget-stats {
span {
font-size: 2.6em;
strong {
font-size: 1.2em;
}
}
span:first-child {
font-size: 12.4em;
}
}
}
}
// Time & Date Box
.time-date {
.time {
font-size: 7.4em;
line-height: 0.7em;
border-bottom: 1px solid $lightgrey;
span {
font-size: 0.2em;
color: $grey;
text-transform: uppercase;
font-style: normal;
}
@media only screen and (min-width: 1400px) {
span {
font-size: 0.3em;
}
}
}
.date {
font-size: 2.2em;
line-height: 1em;
font-weight: bold;
color: #000;
padding: 15px 0;
span {
font-size: 0.7em;
font-weight: normal;
display: block;
line-height: 1em;
color: $grey;
}
}
}
// Post Statuses Box
.post-statuses {
.status-levels {
width: 30%;
div {
text-indent: -9999px;
}
}
.status-text {
width: 70%;
text-transform: uppercase;
font-size: 1.2em;
color: $grey;
div {
background: none;
padding: 15px 0;
}
strong {
font-size: 1.6em;
width: 60px;
padding-right: 5px;
text-align: right;
display: inline-block;
}
}
.scheduled {
background: $green;
strong {
color: $green;
}
}
.pending {
background: #fcd039;
strong {
color: #fcd039;
}
}
.draft {
background: $red;
strong {
color: $red;
}
}
}
.todays-traffic {
ul {
li {
position: relative;
padding: 10px;
margin-bottom: 1px;
div {
position: relative;
z-index: 99;
}
}
li:before {
content: '';
position: absolute;
height: 34px;
top: 0;
left: 0;
z-index: 20;
}
li:nth-child(1):before {
background: $blue;
width: 80%;
}
li:nth-child(2):before {
background: lighten($blue, 3%);
width: 60%;
}
li:nth-child(3):before {
background: lighten($blue, 6%);
width: 40%;
}
li:nth-child(4):before {
background: lighten($blue, 10%);
width: 20%;
}
}
}
.table {
width: 100%;
display: block;
margin-bottom: 10px;
thead, tbody, tr {
display: block;
}
@media only screen and (min-width: 400px) {
thead {
display: none;
}
}
tbody {
tr {
background: $lightbrown;
margin-top: 5px;
display: block;
position: relative;
&:first-child {
margin-top: 0;
}
}
@media only screen and (min-width: 1200px) {
tr {
padding: 0 10px 0 40px;
margin-top: 15px;
}
}
td {
padding: 10px;
text-align: right;
color: $grey;
strong {
color: #000;
}
span {
display: none;
}
@media only screen and (min-width: 500px) {
span {
display: inline;
}
}
.callout {
color: $green;
}
&:first-child {
text-align: left;
}
}
}
.user-img {
position: absolute;
top: 0;
left: 0;
display: none;
}
@media only screen and (min-width: 1200px) {
.user-img {
display: block;
}
}
}
*/

View File

@ -0,0 +1,523 @@
/*
* These styles control elements specific to the post editor screen
* used for publishing content with Ghost.
*
* Table of Contents:
*
* Editor / Preview
* Post Preview Content
* Full Screen Mode
* Publish Bar
*/
/* =============================================================================
Editor / Preview
============================================================================= */
.editor {
// The main post title
.entry-title {
@extend %box;
height: 35px;
padding: 10px 15px;
margin-bottom: 15px;
position:relative;
@include breakpoint($mobile) {
@include box-shadow(none);
}
input {
border: 0;
margin: 0;
padding:0;
font-size: 2em;
font-weight: 300;
width: 100%;
&:focus {
outline: 0;
}
}
}
// The two content panel wrappers, positioned left/right
.entry-markdown { left:0; border-right:$lightbrown 2px solid; }
.entry-preview { right:0; border-left:$lightbrown 2px solid; }
// The visual styles for both panels
.entry-markdown, .entry-preview {
@include box-sizing(border-box);
width: 50%;
padding: 15px;
position: absolute;
bottom:40px; // height of the publish bar
top:69px; // height of the post title + margin
background: #fff;
@include box-shadow;
@include breakpoint($mobile) {
@include box-shadow(none);
}
// Convert all content areas to small boxes
@include breakpoint($netbook) {
top:109px;
left:0;
right:0;
width:100%;
border:none;
z-index:100;
min-height:380px;
.markdown, .entry-preview-content {
height:50px;
overflow: hidden;
}
}
.floatingheader {
// Turn headers into tabs which act as links
// both headers set to grey/inactive colour
@include breakpoint($netbook) {
cursor:pointer;
width:50%;
border-right:$lightbrown 2px solid;
color:#fff;
font-weight: normal;
background:$brown;
position:absolute;
top:-40px;
left:0;
@include box-shadow(rgba(0,0,0,0.1) 0 -2px 3px inset);
a {
color:#fff;
}
}
a {
color: $brown;
}
.markdown-help {
@include icon($i-question, '', lighten($brown, 15%));
float:right;
&:hover {
@include icon($i-question, '', $brown)
}
}
.entry-word-count {
float:right;
}
}
// Give the tab with the .active class the highest z-index
&.active {
z-index: 200;
}
// Restore the normal height of the .active tab (inactive tab stays small, hidden behind)
&.active .markdown,
&.active .entry-preview-content {
height:auto;
overflow: auto;
}
// Restore the white bg of the currently .active tab, remove hand cursor from currently active tab
&.active header {
@include breakpoint($netbook) {
cursor:auto;
color: $brown;
background:#fff;
@include box-shadow(none);
a {
color: $brown;
}
}
}
// Hide markdown icon + wordcount when we hit mobile
@include breakpoint($mobile) {
.markdown-help,
.entry-word-count {
display: none;
}
}
}
.entry-markdown-content {
textarea {
border: 0;
width: 100%;
height: 100%;
max-width: 100%;
margin: 0;
padding: 0;
position:absolute;
top: 0;
right:0;
bottom:0;
left:0;
&:focus {
outline: 0;
}
}
.CodeMirror {
height: auto;
position:absolute;
top:0;
left:0;
right:0;
bottom:0;
font-family: $font-family-mono;
font-size:1.1em;
line-height:1.2em;
color: lighten($darkgrey, 30%);
.CodeMirror-focused,
.CodeMirror-selected {
color: $darkgrey;
background: lighten($blue, 20%);
text-shadow: none;
}
::selection {
color: $darkgrey;
background: lighten($blue, 20%);
text-shadow: none;
}
}
.CodeMirror-lines {
padding: 65px 0 40px 0; /* Vertical padding around content */
@include breakpoint($netbook) {padding-top: 25px;}
@include breakpoint($mobile) {padding: 15px 0;}
}
.CodeMirror pre {
padding: 0 40px; /* Horizontal padding of content */
@include breakpoint($mobile) {padding: 0 15px;}
}
.cm-header {
color:#000;
font-size: 1.4em;
line-height: 1.4em;
}
.cm-string,
.cm-link,
.cm-comment,
.cm-quote {color:#000;}
}
.entry-preview {
// Align the tab of entry-preview on the right
.floatingheader {
@include breakpoint($netbook) {
right:0;
left:auto;
border-right:none;
border-left:$lightbrown 2px solid;
}
}
.entry-preview-content {
position:absolute;
top:0;
right:0;
bottom:0;
left:0;
padding: 60px 40px 40px 40px;
overflow: auto;
// Tweak padding for smaller screens
@include breakpoint($netbook) {padding-top: 20px;}
@include breakpoint($mobile) {padding: 15px;}
}
}
// Special case, when scrolling, add shadows to content headers.
.scrolling {
.floatingheader {
@include breakpoint($netbook) {
@include box-shadow(none);
}
&::before,
&::after {
@include breakpoint($netbook) {display:none;}
}
}
.CodeMirror-scroll,
.entry-preview-content {
@include breakpoint($netbook) {
@include box-shadow(0 5px 5px rgba(0,0,0,0.05) inset);
}
}
}
}//.editor
/* =============================================================================
Post Preview Content
============================================================================= */
// The styles for the actual content inside the preview
// TODO: These should just be defaults, overridden by editor.hbs in theme dir
.entry-preview-content,
.content-preview-content {
font-size:1.15em;
line-height: 1.5em;
a {
color: $blue;
text-decoration: underline;
}
p {
text-indent: 0;
margin: 1.2em 0 1.6em;
&:first-child {
margin-top:0;
}
}
h1 {
font-size: 3em;
}
h2 {
font-size: 2.2em;
}
h3 {
font-size: 1.8em;
}
.btn {
text-decoration: none;
color: $grey;
}
.img-placeholder {
border: 5px dashed $grey;
height: 100px;
position: relative;
span {
display: block;
height: 30px;
position: absolute;
margin-top: -15px;
top: 50%;
width: 100%;
text-align: center;
}
}
img {
width: 100%;
height: auto;
}
}
/* =============================================================================
Full Screen Mode
============================================================================= */
body.zen {
background: lighten($lightbrown, 3%);
#usermenu {display:none;}
#global-header, #publish-bar {
@include opacity(0);
height:0;
overflow: hidden;
@include transition(all 0.5s ease-out);
}
main {top: 15px;@include transition(all 0.5s ease-out);}
.entry-markdown, .entry-preview {bottom:0;@include transition(all 0.5s ease-out);}
}
/* =============================================================================
Publish Bar
============================================================================= */
#publish-bar {
@include box-sizing(border-box);
height:40px;
padding: 0;
color: $midgrey;
background: darken($darkgrey, 4%);
position: fixed;
bottom: 0;
left:0;
right:0;
z-index:900;
@include box-shadow(0 -2px 8px rgba(0,0,0,0.2));
@include breakpoint($netbook) {font-weight:normal;}
button {
min-height: 30px;
height: 30px;
line-height: 12px;
padding: 0 10px;
margin-top: 5px;
border-top:rgba(255,255,255,0.4) 1px solid;
}
.button-link { border-top: none; }
.options {
width:30px;
min-height: 30px;
height: 30px;
margin-top:5px;
@include box-shadow(rgba(255,255,255,0.4) 0 1px 0 inset);
&.up:hover {
@include icon($i-chevron-down) {
margin-top:-5px;
@include transform(rotate(540deg));
@include transition(transform 0.6s ease);
};
}
}
.splitbutton-save{
.button-save{
@include transition(width 0.25s ease);
}
.editor-options{
@extend %menu;
@extend %menu-right;
bottom: 140%;
right: -3%;
a{
font-size: 14px;
}
}
}
}
#entry-categories {
position: absolute;
top:0;
left:0;
right: 165px;
bottom:0;
text-transform: none;
padding: 10px 0 0 0;
}
.category-label {
display: block;
float:left;
@include icon($i-tag);
padding:1px 8px 0 8px;
@include transition;
&:hover {
cursor:pointer;
color: $lightgrey;
}
}
.category-input {
display: inline-block;
color: $lightgrey;
font-weight: 300;
background: transparent;
border: none;
&:focus {outline:none;}
}
.category {
@include icon-after($i-x, 8px, $darkgrey) {
margin-left:4px;
vertical-align:5%;
text-shadow: rgba(255,255,255,0.15) 0 1px 0;
@include transition;
}
display: block;
float: left;
margin-right: 5px;
padding: 0 5px;
color: $lightgrey;
background: lighten($grey, 15%);
@include border-radius;
@include box-shadow(
rgba(255,255,255,0.2) 0 1px 0 inset,
#000 0 1px 3px
);
&:hover {
cursor: pointer;
@include icon-after($i-x, 8px, $lightgrey) {text-shadow: none;}
}
}
.suggestions {
@extend %menu;
bottom: 100%;
li.selected{
background: $blue;
@include box-shadow(
rgba(255,255,255,0.2) 0 1px 0 inset,
rgba(0,0,0,0.5) 0 1px 5px
);
}
mark{
background: none;
color: white;
font-weight: bold;
}
}
#entry-settings {
@include icon($i-settings, 1.1em){vertical-align:0;};
@include box-sizing(border-box);
display:inline-block;
padding: 0 10px;
line-height: 1.8em;
color: $midgrey;
@include transition;
&:hover {
color: $lightgrey;
}
}
#entry-settings-menu {
position: absolute;
bottom:50px;
right:-5px;
}
#entry-actions {
margin-right:6px;
position: relative;
}
#entry-actions-menu {
position: absolute;
bottom:50px;
right:-5px;
}

View File

@ -0,0 +1,138 @@
/*
* These styles control elements specific to the Ghost admin login screen.
*
* Table of Contents:
*
*
*/
/* =============================================================================
Login
============================================================================= */
.ghost-login {
color: $midgrey;
@include breakpoint($mobile) {
background: $lightbrown;
}
main {
max-width: 530px;
margin: 240px auto;
padding: 0;
text-align: center;
background: #fff;
@include border-radius(4px);
border-top: $darkgrey 15px solid;
@include box-shadow;
@include breakpoint(630px) {
max-width: 264px;
}
}
.login-logo {
width: 100%;
max-width: 400px;
margin: 80px 0 70px 0;
@include breakpoint(630px) {
max-width: 235px;
margin: 40px 0;
}
}
#login {
@include box-sizing(border-box);
max-width: 530px;
padding: 15px;
background: $darkgrey;
@include border-radius(0 0 4px 4px);
@include breakpoint(630px) {
max-width: 264px;
padding: 15px;
}
div {
position:relative;
margin:0 0 5px 0;
background: lighten($darkgrey, 15%);
float: left;
}
input {
display:inline-block;
clear:both;
margin:0;
padding-left: 8px;
width: 168px;
position: relative;
border: none;
color: #fff;
font-size: 1.1em;
background: transparent;
@include transition(none);
&:focus {
background: lighten($darkgrey, 22%);
border-color: #000;
}
@include breakpoint(630px) {
width:201px;
@include transition(none);
}
}
.email-wrap {
position:relative;
@include icon($i-mail, 12px) {position:absolute;bottom:8px;left:8px;z-index:100;};
margin-right: 2px;
@include border-radius(2px 0 0 2px);
@include breakpoint(630px) {
margin-right:0;
@include border-radius(2px);
}
.email {
padding-left: 28px;
}
}
.password-wrap {
position:relative;
@include icon($i-lock, 10px) {position:absolute;bottom:9px;left:11px;z-index:100;};
@include border-radius(0 2px 2px 0);
@include breakpoint(630px) {
@include border-radius(2px);
}
.password {
padding-left: 28px;
}
}
button {
width: 80px;
height: 30px;
margin:0 0 0 15px;
padding: 9px;
min-height: 30px;
min-width: 80px;
@include box-shadow(rgba(255,255,255,0.15) 0 1px 0 inset);
@include breakpoint(630px) {
margin:0;
width: 100%;
}
}
}
}//.ghost-login

View File

@ -0,0 +1,245 @@
/*
* These styles control elements specific to the mage posts screen
* used for previewing and reading existing content in Ghost.
*
* Table of Contents:
*
* Manage
* Preview
*
*/
/* =============================================================================
Manage
============================================================================= */
.manage {
.content-list {
@include box-sizing(border-box);
width: 35%;
padding: 15px;
position: absolute;
bottom:0;
top:0;
left:0;
border-right:$lightbrown 2px solid;
background: #fff;
@include box-shadow;
@include breakpoint(900px) {
width:300px;
}
@include breakpoint($tablet) {
width:auto;
right:0;
z-index: 500;
border:none;
}
.content-filter {
position:relative;
z-index: 300;
> a {
padding: 5px;
margin-left:-5px;
}
}
.button-add {
@include icon($i-add);
position:absolute;
top:10px;
right:15px;
z-index: 700;
color: #fff;
padding-left:5px;
}
.content-list-content {
position:absolute;
top:0;
right:0;
bottom:0;
left:0;
overflow: auto;
padding-top: 40px;
}
.entry-title {
font-size: 1.4em;
line-height:1.1em;
margin-bottom:0.5em;
font-weight: normal;
}
.views {
@include icon($i-stats, 10px, $brown);
float:right;
text-align: right;
margin-left:15px;
@include breakpoint($tablet) {
float:none;
}
}
.featured .date {
@include icon($i-featured, 11px) {
margin-right:12px;
vertical-align: 0;
};
}
ol {
list-style: none;
padding:0;
margin:0;
border-top: $lightbrown 1px solid;
li {
margin:0;
padding: 0;
border-bottom: $lightbrown 1px solid;
position:relative;
a {
display:block;
padding:20px 15px;
color: $brown;
@include breakpoint($mobile) { padding:15px; }
@include breakpoint($tablet) { padding-right: 40px; }
@include icon-after($i-chevron) {
position:absolute;
top:50%;
margin-top:-6px;
right:15px;
}
@include breakpoint($biggerthan-tablet) { &::after {display: none} }
&:hover { text-decoration: none; }
}
}//li
li.active {
@include breakpoint($biggerthan-tablet) {
// only apply active styles on larger devices
border-bottom: lighten($midgrey, 40%) 1px solid;
background: lighten($midgrey, 45%);
@include box-shadow(
lighten($midgrey, 40%) 0 -1px 0, // top border
rgba(0,0,0,0.06) 7px 0 0 inset, // big left border
lighten($midgrey, 40%) 1px 0 0 inset // small left border
);
a:hover {
@include box-shadow(rgba(0,0,0,0.1) 7px 0 0 inset);
@include transition(all 0.4s ease);
}
.entry-title { font-weight: bold; }
.entry-meta { color: $darkgrey; }
.views {
@include icon($i-stats, 10px, $darkgrey);
color: $darkgrey;
font-weight: normal;
}
}
}//li.active
}
}//.content-list
/* =============================================================================
Preview
============================================================================= */
.content-preview {
@include box-sizing(border-box);
width: 65%;
padding: 15px;
position: absolute;
bottom:0;
top:0;
right:0;
border-left:$lightbrown 2px solid;
background: #fff;
@include box-shadow;
@include breakpoint(900px) {
width: auto;
left: 300px;
}
.unfeatured {
@include icon($i-unfeatured, 14px);
vertical-align: -6%;
margin: 0 7px 0 -5px;
padding: 5px;
}
.featured {
@include icon($i-featured, 14px);
vertical-align: -6%;
margin: 0 7px 0 -5px;
padding: 5px;
}
.normal {
text-transform: none;
margin:0 3px;
}
.content-preview-content {
position: absolute;
top:0;
right:0;
bottom:0;
left:0;
overflow: auto;
padding: 80px 40px;
.wrapper {
max-width: 700px;
margin:0 auto;
}
}
.post-controls {
float:right;
position: relative;
ul {
position: absolute;
top:15px;
right:-15px;
}
}
.post-edit {
@include icon($i-edit, 14px);
margin-right:7px;
padding: 5px;
}
.post-settings {
@include icon($i-settings, 14px);
padding: 5px;
margin-right: -5px;
}
img {
width:100%;
height:auto;
}
}//.preview-post
}//.manage

View File

@ -0,0 +1,226 @@
/*
* These styles control elements specific to the settings screen
* used for configuring your Ghost install.
*
* Table of Contents:
*
* Settings
*
*/
/* =============================================================================
Settings
============================================================================= */
.settings {
// The main white bg for the page
.wrapper {
background: #fff;
@include box-shadow;
position:absolute;
top:0;
bottom:0;
left:0;
right:0;
margin:0;
padding:0;
}
.title {
text-transform: uppercase;
font-weight: normal;
font-size: 1.6em;
line-height: 0.8em;
margin:0 0 18px 0;
padding:0;
border: none;
}
/* =============================================================================
Sidebar
============================================================================= */
//The whole left column sidebar, duh.
.settings-sidebar {
width:20%;
position:absolute;
top:0;
left:0;
bottom:0;
z-index: 700;
@include box-shadow($lightbrown 1px 0 0);
@include breakpoint($tablet) {
width:100%;
@include box-shadow(none);
}
> header {
height: 17px;
padding: 30px 15px 30px 40px;
margin-bottom: 0;
border-bottom: none;
@include box-shadow(#edece4 0 -1px 0 inset);
@include breakpoint($netbook) {
padding-left: 15px;
};
}
}//.settings-sidebar
//Main settings-menu styles, apply to every item
.settings-menu {
position:absolute;
top: 77px; //30px + 17px title + 30px
left:0;
bottom:0;
right:-1px;
overflow: auto;
@include breakpoint($tablet) { right:0; };
ul {
border-top:none;
@include breakpoint($tablet) { border-bottom: #edece4 1px solid; }
}
li {
margin-right:1px;
border-top: #fff 1px solid;
@include breakpoint($tablet) {
margin-right:0;
border-top: #edece4 1px solid;
}
a {
padding:15px 15px 15px 40px;
border-bottom:none;
@include breakpoint($netbook) { padding-left: 15px; }
@include breakpoint($tablet) {
@include icon-after($i-chevron) {float:right;margin-top:5px;};
}
}
&:first-child { border-top: none; }
&:first-child.active { border-top:none; }
&.active {
@include breakpoint($biggerthan-tablet) {
// only apply active styles on larger devices
margin-right:0;
position:relative;
z-index: 300;
border-top: #edece4 1px solid;
@include box-shadow(#fff 1px 0 0, #edece4 0 1px 0);
@include transition;
a {
color: $darkgrey;
font-weight: bold;
background: #fff;
}
}
}//.active
}//li
// Give all icons some space
li a:before {
margin-right: 20px;
@include breakpoint($netbook) {
margin-right: 15px;
}
}
// Add the icons for specific menu items
.general a { @include icon($i-settings) }
.publishing a { @include icon($i-content) }
.services a { @include icon($i-services) }
.users a { @include icon($i-users) }
.appearance a { @include icon($i-appearance) }
.plugins a { @include icon($i-plugins) }
}//.settings-menu
/* =============================================================================
Content
============================================================================= */
// The main content panel on the right
.settings-content {
padding:0;
position:absolute;
top:0;
right:0;
left:20%;
bottom:0;
@include breakpoint($tablet) { display: none; }
display: none;
&.active {display:block;}
> header {
height: 17px;
padding: 30px 220px 29px 40px;
border-bottom:$lightbrown 1px solid;
margin-bottom:40px;
text-transform: none;
font-weight: normal;
line-height: inherit;
color: inherit;
@include breakpoint($netbook) { padding-left:15px; }
@include breakpoint($letterbox) {
height: auto;
padding: 5px;
position: absolute;
top:0;
right:0;
border:none;
.title { display:none; }
}
}//header
.page-actions {
position:absolute;
top:20px;
right:40px;
z-index: 700;
font-size: 1em;
@include breakpoint($netbook) { right:15px; }
.button-add {
position:relative;
padding-left:50px;
@include icon($i-add, 1.4em, rgba(255,255,255,0.6)) {
position: absolute;
top:0;
padding:9px 8px 0 0;
left:9px;
bottom:0;
width: 20px;
border-right: darken($green, 8%) 1px solid;
};
}
}
.content {
position: absolute;
top:77px; //30px + 17px title + 30px
right:0;
left:0;
bottom:0;
overflow:auto;
padding:40px;
@include breakpoint($netbook) { padding-left:15px; }
@include breakpoint($letterbox) { top: 0; }
}
}//.settings-content
}//.settings

View File

@ -0,0 +1,16 @@
@-webkit-keyframes off-canvas {
0% { left:0; }
100% { left:300px; }
}
@-moz-keyframes off-canvas {
0% { opacity: 0; }
100% { opacity: 1; }
}
@-o-keyframes off-canvas {
0% { opacity: 0; }
100% { opacity: 1; }
}
@keyframes off-canvas {
0% { opacity: 0; }
100% { opacity: 1; }
}

View File

@ -0,0 +1,546 @@
/*
* Breakpoint Sass 1.3.0
* Last updated: 2012-08-28
* Copyright: Mason Wendell 2012 - MIT Licensed
* Source: https://github.com/canarymason/breakpoint
*/
//////////////////////////////
// Default Variables
//////////////////////////////
$breakpoint-default-feature: 'min-width' !default;
$breakpoint-default-media: 'all' !default;
$breakpoint-force-media-all: false !default;
$breakpoint-default-pair: 'width' !default;
$breakpoint-to-ems: false !default;
$breakpoint-prefixes: 'webkit' 'moz' !default;
$breakpoint-prefixed-queries: 'device-pixel-ratio' 'min-device-pixel-ratio' 'max-device-pixel-ratio' !default;
$breakpoint-no-queries: false !default;
$breakpoint-no-query-wrappers: false !default;
$breakpoint-base-font-size: false;
//////////////////////////////
// Converts the input value to Base EMs
//////////////////////////////
@function breakpoint-to-base-em($value, $base-font-size: false) {
$value-unit: unit($value);
// Will convert relative EMs into root EMs.
@if $base-font-size and type-of($base-font-size) == 'number' and $value-unit == 'em' {
$base-unit: unit($base-font-size);
@if $base-unit == 'px' or $base-unit == '%' or $base-unit == 'em' or $base-unit == 'pt' {
@return base-conversion($value) / base-conversion($base-font-size) * 1em;
}
@else {
@warn '#{$base-font-size} is not set in valid units for font size!';
@return false;
}
}
@else {
@return base-conversion($value);
}
}
@function base-conversion($value) {
$unit: unit($value);
@if $unit == 'px' {
@return $value / 16px * 1em;
}
@else if $unit == '%' {
@return $value / 100% * 1em;
}
@else if $unit == 'em' {
@return $value;
}
@else if $unit == 'pt' {
@return $value / 12pt * 1em;
}
@else {
@return $value;
// @warn 'Everything is terrible! What have you done?!';
}
}
//////////////////////////////
// Returns whether the feature can have a min/max pair
//////////////////////////////
@function breakpoint-min-max($feature) {
@if $feature == 'color' or $feature == 'color-index' or $feature == 'aspect-ratio' or $feature == 'device-height' or $feature == 'device-width' or $feature == 'height' or $feature == 'monochrome' or $feature == 'resolution' or $feature == 'width' or $feature == 'device-pixel-ratio' {
@return true;
}
@else {
@return false;
}
}
//////////////////////////////
// Returns whether the feature can have a string value
//////////////////////////////
@function breakpoint-string-value($feature) {
@if $feature == 'orientation' or $feature == 'scan' or $feature == 'color' or $feature == 'resolution' or $feature == 'min-resolution' or $feature == 'max-resolution' {
@return true;
}
@else {
@return false;
}
}
//////////////////////////////
// Experimental Media Queries
//////////////////////////////
@function breakpoint-experimental($property, $prefix) {
@if $property == 'min-device-pixel-ratio' {
@if $prefix == 'webkit' {
@return '-#{$prefix}-#{$property}';
}
@else if $prefix == 'moz' {
@return 'min--#{$prefix}-device-pixel-ratio';
}
@else {
@warn '#{$property} is not fully supported in -#{prefix}';
@return 'ERROR';
}
}
@else if $property == 'max-device-pixel-ratio' {
@if $prefix == 'webkit' {
@return '-#{$prefix}-#{$property}';
}
@else if $prefix == 'moz' {
@return 'max--#{$prefix}-device-pixel-ratio';
}
@else {
@warn '#{$property} is not fully supported in -#{prefix}';
@return 'ERROR';
}
}
@else {
@return '-#{$prefix}-#{$property}';
}
}
//////////////////////////////
// Private Breakpoint Variables
//////////////////////////////
$TXkgdmFyaWFibGUhIEdvIGF3YXkh: () !default;
//////////////////////////////
// Breakpoint Get Context
// $feature: Input feature to get it's current MQ context. Returns false if no context
//////////////////////////////
@function breakpoint-get-context($feature) {
@each $context in $TXkgdmFyaWFibGUhIEdvIGF3YXkh {
@if $feature == nth($context, 1) {
@return nth($context, 2);
}
}
@return false;
}
//////////////////////////////
// Private function to set context
//////////////////////////////
@function U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh($feature, $value) {
@if $value == 'monochrome' {
$feature: 'monochrome';
}
$append: $feature;
$append: join($append, $value, space);
$TXkgdmFyaWFibGUhIEdvIGF3YXkh: append($TXkgdmFyaWFibGUhIEdvIGF3YXkh, $append, comma);
@return true;
}
//////////////////////////////
// Private function to reset context
//////////////////////////////
@mixin TXkgcmVzZXQhIEdvIGF3YXkh {
$TXkgdmFyaWFibGUhIEdvIGF3YXkh: ();
}
//////////////////////////////
// Breakpoint Mixin
//////////////////////////////
@mixin breakpoint($breakpoint, $media: $breakpoint-default-media, $no-query: false, $base-font-size: $breakpoint-base-font-size) {
// Query and Media String Defaults
$query: false !default;
$query-holder: false !default;
$media-string: false !default;
$do-prefix: false !default;
$webkit: false !default;
$webkit-first: true !default;
$moz: false !default;
$moz-first: true !default;
$o: false !default;
$o-first: true !default;
$ms: false !default;
$ms-first: true !default;
// Holder for Count
$first: true !default;
// Reset Context
@include TXkgcmVzZXQhIEdvIGF3YXkh;
// Set Media Context
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh('media', $media);
// Initialize Query String
@if $media != 'all' or $breakpoint-force-media-all {
$media-string: "#{$media} ";
}
@else {
$media-string: "";
}
// If we have a single query, let's just work with that.
@if is_breakpoint_list($breakpoint) == false {
@each $prefix-query in $breakpoint-prefixed-queries {
@if $do-prefix == false {
$do-prefix: featureExists($prefix-query, $breakpoint);
}
}
@if $do-prefix {
@each $prfx in $breakpoint-prefixes {
@if $prfx == 'webkit' {
$webkit: breakpoint-switch($breakpoint, $media-string, true, $prfx, $base-font-size: $base-font-size);
}
@if $prfx == 'moz' {
$moz: breakpoint-switch($breakpoint, $media-string, true, $prfx, $base-font-size: $base-font-size);
}
@if $prfx == 'o' {
$o: breakpoint-switch($breakpoint, $media-string, true, $prfx, $base-font-size: $base-font-size);
}
@if $prfx == 'ms' {
$ms: breakpoint-switch($breakpoint, $media-string, true, $prfx, $base-font-size: $base-font-size);
}
}
}
@else {
$query: breakpoint-switch($breakpoint, $media-string, true, $base-font-size: $base-font-size);
}
}
@else {
// See if Prefix Query exists
@each $prefix-query in $breakpoint-prefixed-queries {
@if $do-prefix == false {
$do-prefix: featureExists($prefix-query, $breakpoint);
}
}
@if $do-prefix {
@each $prfx in $breakpoint-prefixes {
@each $bkpt in $breakpoint {
@if $prfx == 'webkit' {
@if $webkit-first {
$webkit: breakpoint-switch($bkpt, $media-string, true, $prfx, $base-font-size: $base-font-size);
$webkit-first: false;
}
@else {
$webkit: join($webkit, breakpoint-switch($bkpt, $media-string, $prefix: $prfx, $base-font-size: $base-font-size));
}
}
@if $prfx == 'moz' {
@if $moz-first {
$moz: breakpoint-switch($bkpt, $media-string, true, $prfx, $base-font-size: $base-font-size);
$moz-first: false;
}
@else {
$moz: join($moz, breakpoint-switch($bkpt, $media-string, $prefix: $prfx, $base-font-size: $base-font-size));
}
}
@if $prfx == 'o' {
@if $o-first {
$o: breakpoint-switch($bkpt, $media-string, true, $prfx, $base-font-size: $base-font-size);
$o-first: false;
}
@else {
$o: join($o, breakpoint-switch($bkpt, $media-string, $prefix: $prfx, $base-font-size: $base-font-size));
}
}
@if $prfx == 'ms' {
@if $ms-first {
$ms: breakpoint-switch($bkpt, $media-string, true, $prfx, $base-font-size: $base-font-size);
$ms-first: false;
}
@else {
$ms: join($ms, breakpoint-switch($bkpt, $media-string, $prefix: $prfx, $base-font-size: $base-font-size));
}
}
}
}
}
@else {
@each $bkpt in $breakpoint {
@if $first == true {
$query: breakpoint-switch($bkpt, $media-string, true, $base-font-size: $base-font-size);
$first: false;
}
@else {
$query: join($query, breakpoint-switch($bkpt, $media-string, $base-font-size: $base-font-size));
}
}
}
}
@if $breakpoint-no-queries {
@if $no-query {
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh('no queries', true);
@if $breakpoint-no-query-wrappers and type-of($no-query) == string {
#{$no-query} & {
@content;
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh('no query wrapper', $no-query);
}
}
@else {
@content;
}
}
}
@else {
@if $breakpoint-no-query-wrappers and type-of($no-query) == string {
#{$no-query} & {
@content;
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh('no query wrapper', $no-query);
}
}
@if $query {
@media #{$query} {
@content;
}
}
@else {
$pf-queries: $webkit, $moz, $o, $ms;
$pf-query: ();
@each $pfq in $pf-queries {
@if $pfq {
$pf-query: append($pf-query, $pfq, comma);
}
}
@media #{$pf-query} {
@content;
}
}
}
@include TXkgcmVzZXQhIEdvIGF3YXkh;
}
@function breakpoint-switch($breakpoint, $media-string, $first: false, $prefix: false, $base-font-size: $breakpoint-base-font-size) {
// Feature/Value/Length/Query Placehoders:
$feature: false !default;
$min-feature: "min-#{$breakpoint-default-pair}" !default;
$max-feature: "max-#{$breakpoint-default-pair}" !default;
$value: false !default;
$min-value: false !default;
$max-value: false !default;
$length: false !default;
$query: false !default;
$length: length($breakpoint);
// Check to see if there is only one item.
@if $length == 1 {
$value: $breakpoint;
@if type-of($breakpoint) == 'number' {
$feature: $breakpoint-default-feature;
}
// If EM Breakpoints are active, do it!
@if $breakpoint-to-ems and type-of($value) == 'number' {
$value: breakpoint-to-base-em($value, $base-font-size);
}
// Build the Query
$query: breakpoint-generate($media-string, $feature, $value, $first);
// Set Context
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh($feature, $value);
}
@else if $length == 2 {
// If both are numbers, we've got a double!
@if type-of(nth($breakpoint, 1)) == 'number' and type-of(nth($breakpoint, 2)) == 'number' {
// See which is larger.
@if nth($breakpoint, 1) > nth($breakpoint, 2) {
$min-value: nth($breakpoint, 2);
$max-value: nth($breakpoint, 1);
}
@else {
$min-value: nth($breakpoint, 1);
$max-value: nth($breakpoint, 2);
}
// If EM Breakpoints are active, do it!
@if $breakpoint-to-ems and type-of($min-value) == 'number' {
$min-value: breakpoint-to-base-em($min-value, $base-font-size);
}
@if $breakpoint-to-ems and type-of($max-value) == 'number' {
$max-value: breakpoint-to-base-em($max-value, $base-font-size);
}
// Min/Max for given
$query: breakpoint-generate($media-string, $min-feature, $min-value, $first);
$query: join($query, breakpoint-generate($media-string, $max-feature, $max-value));
// Set Context
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh($min-feature, $min-value);
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh($max-feature, $max-value);
}
@else if type-of(nth($breakpoint, 1)) == 'string' and type-of(nth($breakpoint, 2)) == 'string' {
@if breakpoint-string-value(nth($breakpoint, 1)) == true {
$feature: nth($breakpoint, 1);
$value: nth($breakpoint, 2);
}
@else {
$feature: nth($breakpoint, 2);
$value: nth($breakpoint, 1);
}
// If EM Breakpoints are active, do it!
@if $breakpoint-to-ems and type-of($value) == 'number' {
$value: breakpoint-to-base-em($value, $base-font-size);
}
// Build the Query
$query: breakpoint-generate($media-string, $feature, $value, $first);
// Set Context
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh($feature, $value);
}
@else {
// Because we can have either the first or second option be the feature, we switch on it.
@if type-of(nth($breakpoint, 1)) == string {
$feature: nth($breakpoint, 1);
$value: nth($breakpoint, 2);
}
@else if type-of(nth($breakpoint, 2)) == string {
$feature: nth($breakpoint, 2);
$value: nth($breakpoint, 1);
}
@if $feature == 'device-pixel-ratio' or $feature == 'min-device-pixel-ratio' or $feature == 'max-device-pixel-ratio' {
$feature: breakpoint-experimental($feature, $prefix);
//$value: 96 * $value * 1dpi;
// @if $feature == 'device-pixel-ratio' {
// $feature: 'resolution';
// }
// @else if $feature == 'min-device-pixel-ratio' {
// $feature: 'min-resolution';
// }
// @else if $feature == 'max-device-pixel-ratio' {
// $feature: 'max-resolution';
// }
}
// If EM Breakpoints are active, do it!
@if $breakpoint-to-ems and type-of($value) == 'number' {
$value: breakpoint-to-base-em($value, $base-font-size);
}
// Build the Query
$query: breakpoint-generate($media-string, $feature, $value, $first);
// Set Context
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh($feature, $value);
}
}
@else if $length == 3 {
@if type-of(nth($breakpoint, 1)) == 'string' {
$feature: nth($breakpoint, 1);
// See which is larger.
@if nth($breakpoint, 2) > nth($breakpoint, 3) {
$min-value: nth($breakpoint, 3);
$max-value: nth($breakpoint, 2);
}
@else {
$min-value: nth($breakpoint, 2);
$max-value: nth($breakpoint, 3);
}
}
@else {
$feature: nth($breakpoint, 3);
// See which is larger.
@if nth($breakpoint, 1) > nth($breakpoint, 2) {
$min-value: nth($breakpoint, 2);
$max-value: nth($breakpoint, 1);
}
@else {
$min-value: nth($breakpoint, 1);
$max-value: nth($breakpoint, 2);
}
}
// If EM Breakpoints are active, do it!
@if $breakpoint-to-ems and type-of($min-value) == 'number' {
$min-value: breakpoint-to-base-em($min-value, $base-font-size);
}
@if $breakpoint-to-ems and type-of($max-value) == 'number' {
$max-value: breakpoint-to-base-em($max-value, $base-font-size);
}
@if breakpoint-min-max($feature) == true {
@if $feature == 'device-pixel-ratio' {
$min-feature: breakpoint-experimental('min-#{$feature}', $prefix);
$max-feature: breakpoint-experimental('max-#{$feature}', $prefix);
}
@else {
$min-feature: 'min-#{$feature}';
$max-feature: 'max-#{$feature}';
}
// Min/Max for given
$query: breakpoint-generate($media-string, $min-feature, $min-value, $first);
$query: join($query, breakpoint-generate($media-string, $max-feature, $max-value));
// Set Context
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh($min-feature, $min-value);
$context: U2V0IHlvdXIgb3duIGRhbW4gY29udGV4dHMh($max-feature, $max-value);
}
@else {
@warn '#{$feature} cannot have a min/max value!';
}
}
@return $query;
}
@function breakpoint-generate($media, $feature, $value, $first: false) {
// Media Query string to be returned
$new-string: "";
// If it's the first item, it gets special treatment
@if $first == true {
// And Statement
$and: 'and ';
// If $media is blank (i.e. all), remove and statement
@if $media == '' {
$and: '';
}
@if $feature != false {
$new-string: #{$media}unquote("#{$and}(#{$feature}: #{$value})");
}
@else {
$new-string: #{$media}unquote("#{$and}(#{$value})");
}
}
@else {
@if $feature != false {
$new-string: unquote("and (#{$feature}: #{$value})");
}
@else {
$new-string: unquote("and (#{$value})");
}
}
@return $new-string;
}

View File

@ -0,0 +1,354 @@
/*
* These are the global generic form styles used throughout the Ghost admin,
* but mainly in the settings pages. Don't fuck with them.
*
* Table of Contents:
*
* General
* Buttons
* Split Buttons
*
*/
/* =============================================================================
General
============================================================================= */
form {
fieldset {
border: none;
margin:0 0 3em 0;
padding:0;
}
legend {
display: block;
width: 100%;
margin: 2em 0;
border-bottom:$lightbrown 1px solid;
font-size: 1.2em;
line-height: 2.0em;
color: $brown;
}
label {
display:block;
margin:1.5em 0;
padding-left:140px;
position:relative;
b {
display:inline-block;
position: absolute;
top:0.5em;
left:0;
width:120px;
font-weight:normal;
color:$darkgrey;
text-align: right;
}
}
p {
color: darken($brown, 5%);
font-size: 1em;
margin:0;
}
input, textarea, select {
width: 260px;
padding: 5px 7px;
margin: 0;
outline: 0;
font-size: 1.1em;
line-height: 1.4em;
background: #fff;
border: darken($lightbrown, 5%) 1px solid;
@include border-radius;
@include transition;
}
textarea {
width:100%;
max-width:340px;
min-width:250px;
height:auto;
min-height: 80px;
}
input, select, textarea {
margin-bottom:5px;
}
input[type="text"]:focus,
input[type="email"]:focus,
input[type="search"]:focus,
input[type="tel"]:focus,
input[type="url"]:focus,
input[type="password"]:focus,
input[type="number"]:focus,
input[type="date"]:focus,
input[type="month"]:focus,
input[type="week"]:focus,
input[type="time"]:focus,
input[type="datetime"]:focus,
input[type="datetime-local"]:focus,
textarea:focus {
border:$grey 1px solid;
background:#fff;
outline:none;
outline-width:0;
@include transition;
}
select {
width:270px;
height:30px;
line-height:30px;
}
.radio input[type="radio"],
.checkbox input[type="checkbox"] {
float: left;
width:auto;
margin-right:6px;
margin-top:4px;
font-size:1em;
}
.radio, .checkbox {
width:auto;
margin: 5px 0;
font-weight: normal;
padding:0.55em 0;
}
}//form
/* =============================================================================
Buttons
============================================================================= */
/*
* Buttons are used for primary calls to action on a page.
*
* Usage:
* <button type="button" class="button">Default</button>
*/
// This base style is used on all buttons
%button {
@include box-sizing(border-box);
min-height: 35px;
width:auto;
display: inline-block;
padding: 0.9em 1.37em;
cursor: pointer;
text-decoration: none;
color: #fff;
font-size: 11px; // Hack because Firefox sucks ass.
line-height: 13px; // Hack because Firefox sucks ass.
font-weight: 300;
text-align: center;
letter-spacing: 1px;
text-transform: uppercase;
text-shadow: none;
@include border-radius(0.2em);
border: rgba(0,0,0,0.05) 0.1em solid;
@include transition(background 0.3s ease, border-color 0.3s ease);
&:hover {
border-color: transparent;
background: #f8f8f8;
text-decoration: none;
}
}
// This is the default button style
.button,
button,
input[type="button"] {
@extend %button;
color:#777;
font-weight: normal;
background: #eee;
@include box-shadow(none);
&:hover {
border-color: rgba(0,0,0,0.1);
}
}
// Button for save/next/continue/confirm actions
.button-save,
button[type="submit"],
input[type="submit"] {
@extend %button;
background: $blue;
@include box-shadow(none);
&:hover {background: darken($blue, 10%);}
}
// Button for actions which add stuff
.button-add {
@extend %button;
background: $green;
&:hover {background: darken($green, 8%);}
}
// Button for deleting/removing stuff
.button-delete,
button[type="reset"],
input[type="reset"] {
@extend %button;
background: $red;
@include box-shadow(none);
&:hover {background: darken($red, 10%);}
}
// Alternative button with more visual attention, but no extra semantic meaning
.button-alt {
@extend %button;
background: lighten($darkgrey, 10%);
&:hover {background: $darkgrey;}
}
// This applies normal link styles to de-emphasise a button
.button-link {
@extend %button;
color: $blue;
background: transparent;
border: none;
&:hover {
background: transparent;
text-decoration: underline;
}
}
/* =============================================================================
Split Buttons
============================================================================= */
/*
* The splitbutton adds addition values to a button, via a dropdown (or drop-up).
*
* Usage:
* <section class="splitbutton">
* <button type="button" class="button">Split Up</button>
* <a class="options" href="#"><span class="hidden">Options</span></a>
* </section>
*/
// These are the base styles applied to all splitbuttons
%splitbutton {
display: inline-block;
position: relative;
font-size: 0; // hack to stop space after button
white-space: nowrap;
button {
font-size: 11px; // hack to restore font size
@include border-top-right-radius(0);
@include border-bottom-right-radius(0);
}
// This is the additional dropdown arrow, to the right of the button.
.options {
display: inline-block;
position:relative;
width: 35px;
height: 35px;
margin-left: -1px;
vertical-align: top;
text-align: center;
color: #fff;
background: #e5e5e5;
@include border-radius(0 2px 2px 0);
@include box-shadow(
rgba(0,0,0,0.02) 0 1px 0 inset,
rgba(0,0,0,0.02) -1px 0 0 inset,
rgba(0,0,0,0.02) 0 -1px 0 inset
);
@include icon($i-chevron-down, 9px) {
position: absolute;
top: 50%;
right: 50%;
margin-top: -3px;
margin-right: -5px;
@include transition(transform 0.3s ease, margin-top 0.3s ease);
};
// Spin the arrow on hover
&:hover {
@include box-shadow(none);
background: #f8f8f8;
@include icon($i-chevron-down) {
@include transform(rotate(360deg));
};
}
// If it has a class of "up" spin it an extra 180degress to point up
&.up:hover {
@include icon($i-chevron-down) {
margin-top:-4px;
@include transform(rotate(540deg));
@include transition(transform 0.6s ease);
};
}
}
}
// The default splitbutton
.splitbutton {
@extend %splitbutton;
.options {
color:#777;
&:hover {
@include box-shadow(
rgba(0,0,0,0.07) 0 1px 0 inset,
rgba(0,0,0,0.07) -1px 0 0 inset,
rgba(0,0,0,0.07) 0 -1px 0 inset
);
}
}
}
// For save/next/continue/confirm actions
.splitbutton-save {
@extend %splitbutton;
.options {
background: darken($blue, 5%);
&:hover {background: darken($blue, 10%);}
}
}
// For actions which add something
.splitbutton-add {
@extend %splitbutton;
.options {
background: darken($green, 6%);
&:hover {background: darken($green, 8%);}
}
}
// For actions which delete something
.splitbutton-delete {
@extend %splitbutton;
.options {
background: darken($red, 6%);
&:hover {background: darken($red, 10%);}
}
}
// Alternative style with more visual attention, but no extra semantic meaning
.splitbutton-alt {
@extend %splitbutton;
.options {
background: lighten($darkgrey, 4%);
&:hover {background: $darkgrey;}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,128 @@
.container {
margin: auto;
padding: 0 15px;
position: relative;
width: 100%;
}
/* 18 Column Grid
-----------------------------------------------------------------------------
Span 1: 3.66666666667%
Span 2: 9.33333333333%
Span 3: 15.0%
Span 4: 20.6666666667%
Span 5: 26.3333333333%
Span 6: 32.0%
Span 7: 37.6666666667%
Span 8: 43.3333333333%
Span 9: 49.0%
Span 10: 54.6666666667%
Span 11: 60.3333333333%
Span 12: 66.0%
Span 13: 71.6666666667%
Span 14: 77.3333333333%
Span 15: 83.0%
Span 16: 88.6666666667%
Span 17: 94.3333333333%
Span 18: 100%
----------------------------------------------------------------------------- */
/* --- Grid variables ---*/
$max_columns: 8;
$gutter: 2%;
.row {
width: 100%;
*zoom: 1;
position: relative;
}
.row [class*="span"] {
margin-bottom: 15px;
}
@media only screen and (min-width: 768px) {
.row {
margin-left: -15px;
}
.span1, .span2, .span3, .span4 {
width: 50%;
float: left;
padding-left: 15px;
}
}
@media only screen and (min-width: 1200px) {
@mixin span($num, $gutter, $max_columns) {
$one_col: (100% - ($gutter * ($max_columns - 1))) / $max_columns;
width:($one_col * $num) + ($gutter * ($num - 1));
margin-left:$gutter;
float: left;
position: relative;
}
@mixin span_first {
margin-left:0;
}
.row {
margin-left: 0;
}
.row:before,
.row:after {
display: table;
line-height: 0;
content: "";
}
.row:after {
clear: both;
}
.row [class*="span"] {
margin-bottom: 0;
padding-left: 0;
}
.row [class*="span"].bottom-margin {
margin-bottom: 20px;
}
.row [class*="span"]:first-child {
@include span_first;
}
.span1 {
@include span(1, $gutter, $max_columns);
}
.span2 {
@include span(2, $gutter, $max_columns);
}
.span3 {
@include span(3, $gutter, $max_columns);
}
.span4 {
@include span(4, $gutter, $max_columns);
}
.span5 {
@include span(5, $gutter, $max_columns);
}
.span6 {
@include span(6, $gutter, $max_columns);
}
.span7 {
@include span(7, $gutter, $max_columns);
}
.span8 {
@include span_first;
width:100%;
}
.offset1 {
margin-left: 5.66666666667%;
}
.offset2 {
margin-left: 11.33333333333%;
}
}

View File

@ -0,0 +1,207 @@
/*
* The icons used in Ghost are the Pictos set by Drew Wilson - http://pictos.css
* They are embedded via a custom icon font built with http://icomoon.io
*
* Table of Contents:
*
* Font Face
* Icon Element
* Icon Variables / Short Names
* Usage
*/
/* =============================================================================
The Font Face
============================================================================= */
/* Generated by icomoon.co */
@font-face {
font-family: 'Icons';
src:url('../fonts/icons.eot');
src:url('../fonts/icons.eot?#iefix') format('embedded-opentype'),
url('../fonts/icons.woff') format('woff'),
url('../fonts/icons.ttf') format('truetype'),
url('../fonts/icons.svg#icons') format('svg');
font-weight: normal;
font-style: normal;
}
/* =============================================================================
The Icon Element
============================================================================= */
/*
* Epic dynamic icon element by Eric Eggert, this thing is so fucking cool it's
* actually unreal. http://cl.ly/O40t
*/
%icon:before,
%icon:after {
font-family: "Icons";
font-weight: normal;
font-style: normal;
vertical-align: -7%;
text-transform:none;
speak: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
}
@mixin icon($char, $size: '', $color: '') {
@extend %icon;
&:before {
content: '#{$char}';
@if $size != '' {
font-size: $size;
}
@if $color != '' {
color: $color;
}
@content;
}
&:hover {
text-decoration:none;
}
}
/*
* Special use case for when we want to add an icon after an element rather
* than before it. For things like dropdowns.
*/
@mixin icon-after($char, $size: '', $color: '') {
@extend %icon;
&:after {
content: '#{$char}';
@if $size != '' {
font-size: $size;
}
@if $color != '' {
color: $color;
}
@content;
}
&:hover {
text-decoration:none;
}
}
/* =============================================================================
Icon Variables / Short Names
============================================================================= */
/*
* For accessibility, icon characters in the icon font are stored in Unicode's
* Private Use Area characters. This means that screen readers won't attempt to
* read them out loud. For code maintainability, we then store these Unicode
* references inside Sass variables.
*/
$i-ghost: \e000;
$i-chevron-down: \e001;
$i-users: \e002;
$i-tag: \e003;
$i-tablet: \e004;
$i-menu: \e005;
$i-settings: \e006;
$i-search: \e007;
$i-search-left: \e008;
$i-rss: \e009;
$i-preview: \e00a;
$i-plugins: \e00b;
$i-pin: \e00c;
$i-pc: \e00d;
$i-pacman: \e00e;
$i-edit: \e00f;
$i-mobile: \e010;
$i-image: \e011;
$i-mail: \e012;
$i-list: \e013;
$i-info: \e014;
$i-home: \e015;
$i-grid: \e016;
$i-fullscreen: \e017;
$i-question: \e018;
$i-external: \e019;
$i-error: \e01a;
$i-comments: \e01b;
$i-close: \e01c;
$i-chevron: \e01d;
$i-calendar: \e01e;
$i-archive: \e01f;
$i-services: \e020;
$i-appearance: \e021;
$i-video: \e022;
$i-remove: \e023;
$i-----: \e024;
$i-stats: \e025;
$i-featured: \e026;
$i-unfeatured: \e027;
$i-clock: \e028;
$i-settings2: \e029;
$i-camera: \e02a;
$i-power: \e02b;
$i-lock: \e02c;
$i-content: \e02d;
$i-user: \e02e;
$i-support: \e02f;
$i-success: \e030;
$i-notification: \e031;
$i-add: \e032;
$i-check: \e033;
$i-x: \e034;
$i-link: \e035;
$i-camera: \e036;
// Placeholder
$i: \e018;
/* =============================================================================
Usage
=============================================================================
To create a button with a label that is prefixed with a camera icon, we might
write our Sass something like this:
#button {
display: block;
width: 200px;
height: 40px;
@include icon($i-camera, 16px, #fff) {vertical-align:-10%;};
}
Thi would then output full CSS something like this:
#button {
display: block;
width: 200px;
height: 40px;
}
#button:before {
content: "\e02a";
size: 16px;
color: #fff;
font-family: "Icons";
font-weight: normal;
font-style: normal;
vertical-align: -10%;
text-transform:none;
speak: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
}
*/

View File

@ -0,0 +1,186 @@
/*
* These are Sass variables used to make our CSS more dynamic by re-using
* common property values throughout our styles. Don't overdo it.
*
* Table of Contents:
*
* Compass Shit
* Compass Plugins
* Colors
* Gradients
* Typography
* Global Styles
*
*/
/* =============================================================================
Compass Imports
============================================================================= */
// Compass - http://compass-style.org/
@import "compass";
$default-border-radius: 2px;
$default-box-shadow-color: rgba(0,0,0,0.05);
$default-box-shadow-v-offset: 1px;
$default-transition-duration: 0.3s;
/* =============================================================================
Compass Plugins
============================================================================= */
// Breakpoint - http://breakpoint-sass.com/
@import "breakpoint";
$breakpoint-default-feature: max-width;
// Max widths
$netbook: 1000px;
$tablet: 800px;
$mobile: 400px;
// Min widths
$biggerthan-widescreen: min-width 1500px, min-width 1500px;
$biggerthan-netbook: min-width 1000px, min-width 1000px;
$biggerthan-tablet: min-width 800px, min-width 800px;
$biggerthan-mobile: min-width 400px, min-width 400px;
// Heights
$letterbox: max-height 600px, max-height 600px;
// Pixel Densities
$retina: 2 device-pixel-ratio;
/* =============================================================================
Colors
============================================================================= */
$darkgrey: #242628;
$grey: #35393b;
$midgrey: #7d878a;
$lightgrey: #e2edf2;
$brown: #aaa9a2;
$midbrown: #c0bfb6;
$lightbrown: #edece4;
$blue: #5BA4E5;
$red: #e25440;
$orange: #F2A925;
$green: #9FBB58;
/* =============================================================================
Gradients
============================================================================= */
/*
* Auto Gradients
*
* If the gradient mixin is called with 1 value: gradient(#444) - then a second
* color which is 10% lighter than the entered value will be auto-generated. If
* the gradient mixin is called with 2 values: gradient(#444,#666) - then those
* two values will be used instead, as normal.
*/
@mixin gradient($color1: #aaa, $color2: none) {
@if $color2 == 'none' {
background-color: lighten($color1, 10%);
background-image: -webkit-linear-gradient(bottom, $color1, lighten($color1, 10%));
background-image: -moz-linear-gradient(bottom, $color1, lighten($color1, 10%));
background-image: -ms-linear-gradient(bottom, $color1, lighten($color1, 10%));
background-image: linear-gradient(bottom, $color1, lighten($color1, 10%));
@include box-shadow(rgba(0,0,0,0.2) 0 -1px 0 inset, rgba(0,0,0,0.1) 0 1px 0 inset);
} @else {
background-color: $color2;
background-image: -webkit-linear-gradient(bottom, $color1, $color2);
background-image: -moz-linear-gradient(bottom, $color1, $color2);
background-image: -ms-linear-gradient(bottom, $color1, $color2);
background-image: linear-gradient(to top, $color1, $color2);
@include box-shadow(rgba(0,0,0,0.2) 0 -1px 0 inset, rgba(0,0,0,0.1) 0 1px 0 inset);
}
}
// The same as the above, but with the colours reversed.
@mixin inversegradient($color1: #aaa, $color2: none) {
@if $color2 == 'none' {
background-color: $color1;
background-image: -webkit-linear-gradient(bottom, lighten($color1, 10%), $color1);
background-image: -moz-linear-gradient(bottom, lighten($color1, 10%), $color1);
background-image: -ms-linear-gradient(bottom, lighten($color1, 10%), $color1);
background-image: linear-gradient(bottom, lighten($color1, 10%), $color1);
@include box-shadow(rgba(0,0,0,0.2) 0 -1px 0 inset, rgba(0,0,0,0.1) 0 1px 0 inset);
} @else {
background-color: $color1;
background-image: -webkit-linear-gradient(bottom, $color2, $color1);
background-image: -moz-linear-gradient(bottom, $color2, $color1);
background-image: -ms-linear-gradient(bottom, $color2, $color1);
background-image: linear-gradient(to top, $color2, $color1);
@include box-shadow(rgba(0,0,0,0.2) 0 -1px 0 inset, rgba(0,0,0,0.1) 0 1px 0 inset);
}
}
/* =============================================================================
Typography
============================================================================= */
@mixin baseline {
margin: 1.6em 0;
}
//Does this really need to be a mixin?
@mixin hidden {
text-indent: -9999px;
visibility: hidden;
display: none;
}
/* =============================================================================
Global Elements
============================================================================= */
%box, .box {
padding: 15px;
margin-bottom: 15px;
background: #fff;
position: relative;
@include box-shadow;
header {
height:14px;
border-bottom: 1px solid $lightbrown;
padding-bottom: 15px;
margin-bottom: 15px;
text-transform: uppercase;
font-size:0.85em;
color: $brown;
}
footer {
height:14px;
border-top: 1px solid $lightbrown;
padding-top: 10px;
margin-top:15px;
text-transform: uppercase;
font-size:0.85em;
color: $brown;
}
header a,
footer a {
color:$brown;
&:hover {
color:$darkgrey;
text-decoration: none;
}
}
}

View File

@ -0,0 +1,396 @@
/*! normalize.css v2.1.0 | MIT License | git.io/normalize */
/* ==========================================================================
HTML5 display definitions
========================================================================== */
/**
* Correct `block` display not defined in IE 8/9.
*/
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
nav,
section,
summary {
display: block;
}
/**
* Correct `inline-block` display not defined in IE 8/9.
*/
audio,
canvas,
video {
display: inline-block;
}
/**
* Prevent modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/**
* Address styling not present in IE 8/9.
*/
[hidden] {
display: none;
}
/* ==========================================================================
Base
========================================================================== */
/**
* 1. Set default font family to sans-serif.
* 2. Prevent iOS text size adjust after orientation change, without disabling
* user zoom.
*/
html {
font-family: sans-serif; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
-ms-text-size-adjust: 100%; /* 2 */
}
/**
* Remove default margin.
*/
body {
margin: 0;
}
/* ==========================================================================
Links
========================================================================== */
/**
* Address `outline` inconsistency between Chrome and other browsers.
*/
a:focus {
outline: thin dotted;
}
/**
* Improve readability when focused and also mouse hovered in all browsers.
*/
a:active,
a:hover {
outline: 0;
}
/* ==========================================================================
Typography
========================================================================== */
/**
* Address variable `h1` font-size and margin within `section` and `article`
* contexts in Firefox 4+, Safari 5, and Chrome.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/**
* Address styling not present in IE 8/9, Safari 5, and Chrome.
*/
abbr[title] {
border-bottom: 1px dotted;
}
/**
* Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
*/
b,
strong {
font-weight: bold;
}
/**
* Address styling not present in Safari 5 and Chrome.
*/
dfn {
font-style: italic;
}
/**
* Address differences between Firefox and other browsers.
*/
hr {
-moz-box-sizing: content-box;
box-sizing: content-box;
height: 0;
}
/**
* Address styling not present in IE 8/9.
*/
mark {
background: #ff0;
color: #000;
}
/**
* Correct font family set oddly in Safari 5 and Chrome.
*/
code,
kbd,
pre,
samp {
font-family: monospace, serif;
font-size: 1em;
}
/**
* Improve readability of pre-formatted text in all browsers.
*/
pre {
white-space: pre-wrap;
}
/**
* Set consistent quote types.
*/
q {
quotes: "\201C" "\201D" "\2018" "\2019";
}
/**
* Address inconsistent and variable font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
/* ==========================================================================
Embedded content
========================================================================== */
/**
* Remove border when inside `a` element in IE 8/9.
*/
img {
border: 0;
}
/**
* Correct overflow displayed oddly in IE 9.
*/
svg:not(:root) {
overflow: hidden;
}
/* ==========================================================================
Figures
========================================================================== */
/**
* Address margin not present in IE 8/9 and Safari 5.
*/
figure {
margin: 0;
}
/* ==========================================================================
Forms
========================================================================== */
/**
* Define consistent border, margin, and padding.
*/
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
/**
* 1. Correct `color` not being inherited in IE 8/9.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
*/
legend {
border: 0; /* 1 */
padding: 0; /* 2 */
}
/**
* 1. Correct font family not being inherited in all browsers.
* 2. Correct font size not being inherited in all browsers.
* 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.
*/
button,
input,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 2 */
margin: 0; /* 3 */
}
/**
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
button,
input {
line-height: normal;
}
/**
* Address inconsistent `text-transform` inheritance for `button` and `select`.
* All other form control elements do not inherit `text-transform` values.
* Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+.
* Correct `select` style inheritance in Firefox 4+ and Opera.
*/
button,
select {
text-transform: none;
}
/**
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
* and `video` controls.
* 2. Correct inability to style clickable `input` types in iOS.
* 3. Improve usability and consistency of cursor style between image-type
* `input` and others.
*/
button,
html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button; /* 2 */
cursor: pointer; /* 3 */
}
/**
* Re-set default cursor for disabled elements.
*/
button[disabled],
html input[disabled] {
cursor: default;
}
/**
* 1. Address box sizing set to `content-box` in IE 8/9.
* 2. Remove excess padding in IE 8/9.
*/
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
* 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
* (include `-moz` to future-proof).
*/
input[type="search"] {
-webkit-appearance: textfield; /* 1 */
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box; /* 2 */
box-sizing: content-box;
}
/**
* Remove inner padding and search cancel button in Safari 5 and Chrome
* on OS X.
*/
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* Remove inner padding and border in Firefox 4+.
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
/**
* 1. Remove default vertical scrollbar in IE 8/9.
* 2. Improve readability and alignment in all browsers.
*/
textarea {
overflow: auto; /* 1 */
vertical-align: top; /* 2 */
}
/* ==========================================================================
Tables
========================================================================== */
/**
* Remove most spacing between table cells.
*/
table {
border-collapse: collapse;
border-spacing: 0;
}

View File

@ -0,0 +1,678 @@
/*!
+---------------------------------------------------------------------+
| _ _ _ |
| | |_ _ _ _ __ ___ _ __ | | __ _ | |_ ___ |
| | __|| | | || '_ \ / _ \| '_ \ | | / _` || __|/ _ \ |
| | |_ | |_| || |_) || __/| |_) || || (_| || |_| __/ |
| \__| \__, || .__/ \___|| .__/ |_| \__,_| \__|\___| |
| |___/ |_| |_| |
| |
| |
| URL: http://typeplate.com |
| VERSION: 1.0.0 |
| Github: https://github.com/typePlate/typeplate.github.com |
| AUTHORS: Zachary Kain (@zakkain) & Dennis Gaebel (@gryghostvisuals) |
| LICENSE: Creative Commmons |
| http://creativecommons.org/licenses/by/3.0 |
| |
+---------------------------------------------------------------------+
*/
// ==========================================================================
//
// $V a r i a b l e s
//
// ==========================================================================
// $B a s e T y p e
// --------------------------------------------------------------------------
$weight: normal;
$line-height: 1.65;
$font-size: 81.2; // percentage value (16 * 112.5% = 18px)
$font-base: 16 * ($font-size/100); // converts our percentage to a pixel value
$measure: $font-base * $line-height;
$font-family: Lato, sans-serif;
$font-family-serif: serif;
$font-family-mono: Inconsolata, monospace;
$font-properties: $weight, $line-height, $font-size, $font-family;
//the serif boolean var can be redeclared from another stylesheet. However
//the var must be placed after your @import "typeplate.scss";
$sans-serif-boolean: true !default;
// $C o l o r
// --------------------------------------------------------------------------
$body-copy-color: #444;
$heading-color: #222;
// $A M P E R S A N D @font-face
// --------------------------------------------------------------------------
$amp-fontface-name: Ampersand;
$amp-fontface-source: local('Georgia'), local('Garamond'), local('Palatino'), local('Book Antiqua');
$amp-fontface-fallback: local('Georgia');
// $A M P E R S A N D e l e m e n t
// --------------------------------------------------------------------------
// Allows for our ampersand element to have differing
// font-family from the ampersand unicode font-family.
$amp-font-family: Verdana, sans-serif;
// $T y p e S c a l e
// --------------------------------------------------------------------------
$tera: 117; // 117 = 18 × 6.5
$giga: 90; // 90 = 18 × 5
$mega: 72; // 72 = 18 × 4
$alpha: 60; // 60 = 18 × 3.3333
$beta: 48; // 48 = 18 × 2.6667
$gamma: 36; // 36 = 18 × 2
$delta: 24; // 24 = 18 × 1.3333
$epsilon: 21; // 21 = 18 × 1.1667
$zeta: 18; // 18 = 18 × 1
// $T y p e S c a l e U n i t
// --------------------------------------------------------------------------
$type-scale-unit-value: rem;
// $T e x t I n d e n t a t i o n
// --------------------------------------------------------------------------
$indent-val: 1.5em;
// $S t a t s T a b
// --------------------------------------------------------------------------
$stats-font-size: 1.5rem;
$stats-list-margin: 0 0.625rem 0 0;
$stats-list-padding: 0 0.625rem 0 0;
$stats-item-font-size: 0.875rem;
$stats-item-margin: 0.125rem 0 0 0;
$stats-border-style: 0.125rem solid #ccc;
// ==========================================================================
//
// $F o n t f a c e s
//
// ==========================================================================
// $U N I C O D E - R A N G E A m p e r s a n d
// --------------------------------------------------------------------------
@font-face {
font-family: '#{$amp-fontface-name}';
src: $amp-fontface-source;
unicode-range: U+0026;
}
// Ampersand fallback font for unicode range
@font-face {
font-family: '#{$amp-fontface-name}';
src: $amp-fontface-fallback;
unicode-range: U+270C;
}
// ==========================================================================
//
// $F u n c t i o n s
//
// ==========================================================================
// $C o n t e x t C a l c u l a t o r
// --------------------------------------------------------------------------
@function ems($target, $context) {
@return ($target/$context)#{em};
}
// $M o d u l a r S c a l e
// --------------------------------------------------------------------------
// http://thesassway.com/projects/modular-scale
@function modular-scale($scale, $base, $value) {
// divide a given font-size by base font-size & return a relative em value
@return ($scale/$base)#{$value};
}
@function measure-margin($scale, $measure, $value) {
// divide 1 unit of measure by given font-size & return a relative em value
@return ($measure/$scale)#{$value};
}
// ==========================================================================
//
// $M i x i n s
//
// ==========================================================================
// $M o d u l a r S c a l e
// --------------------------------------------------------------------------
// $Typographic scale
@mixin modular-scale($scale, $base, $value, $measure:"") {
font-size: $scale#{px};
font-size: modular-scale($scale, $base, $value);
@if $measure != "" {
margin-bottom: measure-margin($scale, $measure, $value);
}
}
// $B o d y C o p y
// --------------------------------------------------------------------------
@mixin base-type($weight, $line-height, $font-size, $font-family...) {
@if $sans-serif-boolean {
font: $weight #{$font-size}%/#{$line-height} $font-family;
}@else {
font: $weight #{$font-size}%/#{$line-height} $font-family-serif;
}
}
// $H y p h e n
// --------------------------------------------------------------------------
//http://trentwalton.com/2011/09/07/css-hyphenation
@mixin css-hyphens($val) {
// Accepted values: [ none | manual | auto ]
-webkit-hyphens: $val; // Safari 5.1 thru 6, iOS 4.2 thru 6
-moz-hyphens: $val; // Firefox 16 thru 20
-ms-hyphens: $val; // IE10
hyphens: $val; // W3C standard
};
// $S m a l l c a p s
// --------------------------------------------------------------------------
// http://blog.hypsometry.com/articles/true-small-capitals-with-font-face
// ISSUE#1 : https://github.com/zakkain/web-thang/issues/1
@mixin smallcaps($color, $font-weight) {
// depends on the font family.
// some font-families don't support small caps
// or don't provide them with their web font.
font-variant: small-caps;
font-weight: $font-weight;
text-transform: lowercase;
color: $color;
}
// $F o n t - S i z e - A d j u s t
// --------------------------------------------------------------------------
// correct x-height for fallback fonts: requires secret formula
// yet to be discovered. This is still wacky for support. Use
// wisely grasshopper.
@mixin font-size-adjust($adjust-value) {
// firefox 17+ only (as of Feb. 2013)
font-size-adjust: $adjust-value;
}
// $A m p e r s a n d
// --------------------------------------------------------------------------
@mixin ampersand($amp-font-family...) {
font-family: $amp-font-family;
}
%ampersand-placeholder {
@include ampersand($amp-fontface-name, $amp-font-family);
}
// Call your ampersand on any element you wish from another stylesheet
// using this Sass extend we've provided...
// @extend %ampersand-placeholder;
// $W o r d W r a p
// --------------------------------------------------------------------------
// Silent Sass Classes - A.K.A Placeholders
//
// normal: Indicates that lines may only break at normal word break points.
// break-word : Indicates that normally unbreakable words may be broken at
// arbitrary points if there are no otherwise acceptable break points in the line.
%breakword {
word-wrap: breakword;
}
%normal-wrap {
word-wrap: normal;
}
%inherit-wrap {
word-wrap: auto;
}
// $D r o p c a p s
// --------------------------------------------------------------------------
/**
* Dropcap Sass @include
* Use the following Sass @include with any selector you feel necessary.
*
@include dropcap($float: left, $font-size: 4em, $font-family: inherit, $text-indent: 0, $margin: inherit, $padding: inherit, $color: inherit, $lineHeight: 1, $bg: transparent);
*
* Extend this object into your custom stylesheet.
*
*/
// Include your '@include dropcap()' mixin and pass the following
// arguments below. Feel free to pass in arguments we've provided.
// At this time you cannot pass in font-family arguments but you're gonna
// change that anyway so why not just make that separately in your declaration.
@mixin dropcap($float: left, $font-size: 4em, $font-family: inherit, $text-indent: 0, $margin: inherit, $padding: inherit, $color: inherit, $lineHeight: 1, $bg: transparent) {
&:first-letter {
float: $float;
margin: $margin;
padding: $padding;
font-size: $font-size;
font-family: $font-family;
line-height: $lineHeight;
text-indent: $text-indent;
background: $bg;
color: $color;
}
}
// $D e f i n i t i o n L i s t
// --------------------------------------------------------------------------
// lining
// http://lea.verou.me/2012/02/flexible-multiline-definition-lists-with-2-lines-of-css
//
// dictionary-style
// http://lea.verou.me/2012/02/flexible-multiline-definition-lists-with-2-lines-of-css
@mixin definition-list-style($style) {
// lining style
@if $style == lining {
dt,
dd {
display: inline;
margin: 0;
}
dt,
dd {
& + dt {
&:before {
content: "\A";
white-space: pre;
}
}
}
dd {
& + dd {
&:before {
content: ", ";
}
}
&:before {
content: ": ";
margin-left: -0.2rem; //removes extra space between the dt and the colon
}
}
}
// dictionary-style
@if $style == dictionary-style {
dt {
display: inline;
counter-reset: definitions;
& + dt {
&:before {
content: ", ";
margin-left: -0.2rem; // removes extra space between the dt and the comma
}
}
}
dd {
display: block;
counter-increment: definitions;
&:before {
content: counter(definitions, decimal) ". ";
}
}
}
}
// ==========================================================================
//
// $T y p e l a t e S t y l i n g
//
// ==========================================================================
// $G l o b a l s
// --------------------------------------------------------------------------
html {
@include base-type($font-properties...);
}
body {
// Ala Trent Walton
@include css-hyphens(auto);
// normal: Indicates that lines may only break at normal word break points.
// break-word : Indicates that normally unbreakable words may be broken at ...
// arbitrary points if there are no otherwise acceptable break points in the line.
@extend %breakword;
color: $body-copy-color;
}
// $H e a d i n g s
// --------------------------------------------------------------------------
// styles for all headings, in the style of @csswizardry
%hN {
// voodoo to enable ligatures and kerning
text-rendering: optimizeLegibility;
// this fixes huge spaces when a heading wraps onto two lines
line-height: 1;
margin-top: 0;
}
// make a multi-dimensional array, where:
// the first value is the name of the class
// and the second value is the variable for the size
$sizes: tera $tera, giga $giga, mega $mega, alpha $alpha, beta $beta, gamma $gamma, delta $delta, epsilon $epsilon, zeta $zeta;
// for each size in the scale, create a class
@each $size in $sizes {
.#{nth($size, 1)} {
@include modular-scale(nth($size, 2), $font-base, '#{$type-scale-unit-value}', $measure);
}
}
// associate h1-h6 tags with their appropriate greek heading
h1 { @extend .alpha; @extend %hN; }
h2 { @extend .beta; @extend %hN; }
h3 { @extend .gamma; @extend %hN; }
h4 { @extend .delta; @extend %hN; }
h5 { @extend .epsilon; @extend %hN; }
h6 { @extend .zeta; @extend %hN; }
// $ P a r a g r a p h s
// --------------------------------------------------------------------------
p {
& + p {
//siblings indentation
text-indent: $indent-val;
}
}
// $C o d e b l o c k s
// --------------------------------------------------------------------------
@mixin white-space($wrap-space) {
@if $wrap-space == 'pre-wrap' {
white-space: #{-moz-}$wrap-space; // Firefox 1.0-2.0
white-space: $wrap-space; // current browsers
} @else {
white-space: $wrap-space;
}
}
pre code {
@extend %normal-wrap;
@include white-space(pre-wrap);
}
pre {
@include white-space(pre);
}
code {
@include white-space(pre);
font-family: monospace;
}
// $ S m a l l c a p s
// --------------------------------------------------------------------------
/**
* Abbreviations Markup
*
<abbr title="hyper text markup language">HMTL</abbr>
*
* Extend this object into your markup.
*
*/
abbr {
@include smallcaps(gray, 600);
&:hover {
cursor: help;
}
}
// $ H e a d i n g s C o l o r
// --------------------------------------------------------------------------
h1,
h2,
h3,
h4,
h5,
h6 {
color: $heading-color;
}
// $ D e f i n i t i o n L i s t s
// --------------------------------------------------------------------------
/**
* Lining Definition Style Markup
*
<dl class="lining">
<dt><b></b></dt>
<dd></dd>
</dl>
*
* Extend this object into your markup.
*
*/
.lining {
@include definition-list-style(lining);
}
/**
* Dictionary Definition Style Markup
*
<dl class="dictionary-style">
<dt><b></b></dt>
<dd></dd>
</dl>
*
* Extend this object into your markup.
*
*/
.dictionary-style {
@include definition-list-style(dictionary-style);
}
// $S t a t s T a b
// --------------------------------------------------------------------------
/**
* Stats Tab Markup
*
<ul class="stats-tabs">
<li><a href="#">[value]<b>[name]</b></a></li>
</ul>
*
* Extend this object into your markup.
*
*/
.stats-tabs {
padding: 0;
li {
display: inline-block;
margin: $stats-list-margin;
padding: $stats-list-padding;
border-right: $stats-border-style;
&:last-child {
margin: 0;
padding: 0;
border: none;
}
a {
display: inline-block;
font-size: $stats-font-size;
font-weight: bold;
b {
display: block;
margin: $stats-item-margin;
font-size: $stats-item-font-size;
font-weight: normal;
}
}
}
}
// $Blockquote Cites
// --------------------------------------------------------------------------
/**
* Blockquote Markup
*
<blockquote cite="">
<p>&Prime;&Prime;</p>
<cite>
<small><a href=""></a></small>
</cite>
</blockquote>
*
* Extend this object into your markup.
*
*/
@mixin cite-style($display:block, $text-align:right, $font-size: .875em) {
display: $display;
font-size: $font-size;
text-align: $text-align;
}
%cite {
@include cite-style;
}
// $Pull Quotes
// --------------------------------------------------------------------------
// http://24ways.org/2005/swooshy-curly-quotes-without-images
//
// http://todomvc.com - Thanks sindresorhus!
// https://github.com/typeplate/typeplate.github.com/issues/49
/**
* Pull Quotes Markup
*
<aside class="pull-quote">
<blockquote>
<p></p>
</blockquote>
</aside>
*
* Extend this object into your custom stylesheet.
*
*/
@mixin pull-quotes($font-size, $opacity) {
position: relative;
padding: ems($font-size, $font-size);
&:before,
&:after {
height: ems($font-size, $font-size);
opacity: $opacity;
position: absolute;
font-size: $font-size;
}
&:before {
content: '';
top: 0em;
left: 0em;
}
&:after {
content: '';
bottom: 0em;
right: 0em;
}
}
.pull-quote {
@include pull-quotes(4em, .15);
}
// $Figures
// --------------------------------------------------------------------------
/**
* Figures Markup
*
<figure>
<figcaption>
<strong>Fig. 4.2 | </strong>Type Anatomy, an excerpt from Mark Boulton's book<cite title="http://designingfortheweb.co.uk/book/part3/part3_chapter11.php">"Designing for the Web"</cite>
</figcaption>
</figure>
*
* Extend this object into your markup.
*
*/
// $Footnotes
// --------------------------------------------------------------------------
/**
* Footnote Markup : Replace 'X' with your unique number for each footnote
*
<article>
<p><sup><a href="#fn-itemX" id="fn-returnX"></a></sup></p>
<footer>
<ol class="foot-notes">
<li id="fn-itemX"><a href="#fn-returnX"></a></li>
</ol>
</footer>
</article>
*
* Extend this object into your markup.
*
*/

View File

@ -0,0 +1,53 @@
/*
* Welcome to Ghost - all styles for the Ghost platform are located within
* this set of Sass files. Use this file like a table of contents.
*/
/* ==========================================================================
Modules - These styles are re-used in many areas, and are grouped by type.
========================================================================== */
@import "modules/mixins";
/* Sass variables like colours, font sizes, basic styles. */
@import "modules/normalize";
/* Browser cross compatibility normalisation*/
@import "modules/typeplate";
/* All the styles controlling the typographic styles. */
@import "modules/grid";
/* The responsive grid structure used to control the main layout. */
@import "modules/icons";
/* All the styles controlling icons. */
@import "modules/animations";
/* Keyframe animations. */
@import "modules/global";
/* Global elements for the UI, like the header and footer. */
@import "modules/forms";
/* All the styles controlling forms and form fields. */
/* ==========================================================================
Layouts - Styles for specific admin screen layouts, grouped by screen.
========================================================================== */
@import "layouts/dashboard";
/* The default admin page, the dashboard. */
@import "layouts/manage";
/* The manage posts screen. */
@import "layouts/editor";
/* The write/edit post screen. */
@import "layouts/settings";
/* The settings screen. */
@import "layouts/login";
/* The settings screen. */

View File

@ -0,0 +1,167 @@
(function () {
"use strict";
var Ghost = require('../../ghost'),
_ = require('underscore'),
fs = require('fs'),
Showdown = require('showdown'),
converter = new Showdown.converter(),
ghost = new Ghost(),
adminNavbar,
adminControllers;
// TODO: combine path/navClass to single "slug(?)" variable with no prefix
adminNavbar = {
dashboard: {
name: 'Dashboard',
navClass: 'dashboard',
key: 'admin.navbar.dashboard',
defaultString: 'dashboard',
path: ''
},
blog: {
name: 'Content',
navClass: 'content',
key: 'admin.navbar.blog',
defaultString: 'blog',
path: '/blog'
},
add: {
name: 'New Post',
navClass: 'editor',
key: 'admin.navbar.editor',
defaultString: 'editor',
path: '/editor'
},
settings: {
name: 'Settings',
navClass: 'settings',
key: 'admin.navbar.settings',
defaultString: 'settings',
path: '/settings'
}
};
// TODO - make this a util or helper
function setSelected(list, name) {
_.each(list, function (item, key) {
item.selected = key === name;
});
return list;
}
adminControllers = {
'index': function (req, res) {
res.render('dashboard', {
bodyClass: 'dashboard',
adminNav: setSelected(adminNavbar, 'dashboard')
});
},
'editor': function (req, res) {
if (req.params.id !== undefined) {
ghost.dataProvider().posts.findOne({'id': parseInt(req.params.id, 10)}, function (error, post) {
res.render('editor', {
bodyClass: 'editor',
adminNav: setSelected(adminNavbar, 'blog'),
title: post.title,
content: post.content
});
});
} else {
res.render('editor', {
bodyClass: 'editor',
adminNav: setSelected(adminNavbar, 'add')
});
}
},
'blog': function (req, res) {
ghost.dataProvider().posts.findAll(function (error, posts) {
res.render('blog', {
bodyClass: 'manage',
adminNav: setSelected(adminNavbar, 'blog'),
posts: posts
});
});
},
'settings': function (req, res) {
res.render('settings', {
bodyClass: 'settings',
adminNav: setSelected(adminNavbar, 'settings')
});
},
'debug': { /* ugly temporary stuff for managing the app before it's properly finished */
index: function (req, res) {
res.render('debug', {
bodyClass: 'settings',
adminNav: setSelected(adminNavbar, 'settings'),
messages: req.flash(),
test: 'Hello world'
});
},
'dbdelete': function (req, res) {
fs.writeFile(__dirname + '/../ghost/data/datastore.db', '', function (error) {
if (error) {
req.flash('error', error);
} else {
req.flash('success', 'Everything got deleted');
}
res.redirect('/ghost/debug');
});
},
'dbpopulate': function (req, res) {
ghost.dataProvider().populateData(function (error) {
if (error) {
req.flash('error', error);
} else {
req.flash('success', 'Data populated');
}
res.redirect('/ghost/debug');
});
}
},
'posts': {
'index': function (req, res) {
},
'create': function (req, res) {
var entry = {
title: req.body.title,
content: req.body.markdown,
contentHtml: '',
language: ghost.config().defaultLang,
status: ghost.statuses().draft,
featured: false
};
entry.contentHtml = converter.makeHtml(entry.content);
ghost.dataProvider().posts.add(entry, function (error, post) {
if (!error) {
console.log('added', post);
res.json({id: post.id});
} else {
res.json(400, {error: post.errors});
}
});
},
'edit': function (req, res) {
var entry = {
id: parseInt(req.body.id, 10),
title: req.body.title,
content: req.body.markdown,
contentHtml: ''
};
entry.contentHtml = converter.makeHtml(entry.content);
ghost.dataProvider().posts.edit(entry, function (error, post) {
console.log('edited', post);
res.json({id: parseInt(post.id, 10)});
});
}
}
};
module.exports = adminControllers;
}());

61
core/admin/views/blog.hbs Normal file
View File

@ -0,0 +1,61 @@
{{!< default}}
<main role="main">
<section class="content-list">
<header class="floatingheader">
<section class="content-filter">
<a class="dropdown" href="#" data-toggle=".menu-drop">All Posts</a>
<ul class="menu-drop">
<li class="active"><a href="#">All Posts</a></li>
<li><a href="#">Recently Edited</a></li>
<li><a href="#">By Author...</a></li>
<li><a href="#">Search</a></li>
</ul>
</section>
<a href="/ghost/editor" class="button button-add"><span class="hidden">New Post</span></a>
</header>
<section class="content-list-content">
<ol>
{{#each posts}}
{{! #if featured class="featured"{{/if}}
<li data-id="{{id}}" data-content="{{contentHtml}}">
<a class="permalink" href="#">
<h3 class="entry-title">{{title}}</h3>
<section class="entry-meta">
<time datetime="2013-01-04" class="date">5 minutes ago</time>
{{!<span class="views">1,934</span>}}
</section>
</a>
</li>
{{/each}}
</ol>
</section>
</section>
<section class="content-preview">
<header class="floatingheader">
<a class="unfeatured" href="#"><span class="hidden">Star</span></a>
{{! TODO: JavaScript toggle featured/unfeatured}}
<span class="status">Published</span>
<span class="normal">by</span>
<span class="author">John O'Nolan</span>
<section class="post-controls">
<a class="post-edit" href="#"><span class="hidden">Edit Post</span></a>
<a class="post-settings" href="#" data-toggle=".menu-drop-right"><span class="hidden">Post Settings</span></a>
<ul class="menu-drop-right">
<li><a href="#">URL</a></li>
<li><a href="#">Something</a></li>
<li><a href="#">Delete</a></li>
</ul>
</section>
</header>
<section class="content-preview-content">
<div class="wrapper"></div>
</section>
</section>
</main>
<script src="/core/admin/assets/js/blog.js"></script>

View File

@ -0,0 +1,254 @@
{{!< default}}
<main role="main">
<div class="time widget"></div>
<div class="image widget"></div>
<div class="posts widget none">
<div class="chart">
<canvas id="poststats" width="250" height="250"></canvas>
<ul class="data">
<li><span class="ready">9</span> Ready</li>
<li><span class="pending">4</span> Pending</li>
<li><span class="draft">1</span> Draft</li>
</ul>
</div>
</div>
<div class="stats widget"></div>
<div class="facebook widget"></div>
<div class="gplus widget none"></div>
<div class="twitter widget"></div>
<div class="campaignmonitor widget none"></div>
{{!
<section class="dashboard-controls">
<div class="text left"><strong>Welcome back</strong>, John.</div>
<nav class="controls-nav">
<ul class="nav inline">
<li><a href="/ghost/editor"><span class="icon-new"></span> New Post</a></li>
<li><a href="#"><span class="icon-users"></span> Authors</a></li>
<li><a href="#"><span class="icon-analytics"></span> Analytics</a></li>
</ul>
</nav>
<div class="text right"><a href="#"><span class="icon-settings"></span><span class="hidden">Settings</span></a></div>
<div class="clearfix"></div><!--TODO: replace this later with something less shit-->
</section>
<section class="widget time-date">
<header>
London, United Kingdom
</header>
<section class="content">
<div class="time">
8:55<span>am</span>
</div>
<div class="date"><!--TODO: convert to html5 <date>-->
<span>Wednesday</span>
13 June 2012
</div>
</section>
<footer>
Timezone: UTC +1
</footer>
</section>
<section class="widget">
<header>
Top Authors This Month
</header>
<section class="content">
<table class="table">
<thead>
<tr>
<td>Name</td>
<td>Posts</td>
<td>Comments</td>
<td>tweets</td>
<td>Likes</td>
</tr>
</thead>
<tbody>
<tr>
<td><strong class="text-uppercase"><img class="user-img" src="/ghost/assets/img/user.jpg" width="34px" height="34px" alt=""> John</strong></td>
<td><strong class="callout">32</strong> <span>Posts</span></td>
<td><strong>231</strong> <span>Comments</span></td>
<td><strong>103</strong> <span>tweets</span></td>
</tr>
<tr>
<td><strong class="text-uppercase"><img class="user-img" src="/ghost/assets/img/user.jpg" width="34px" height="34px" alt=""> James</strong></td>
<td><strong>32</strong> <span>Posts</span></td>
<td><strong class="callout">231</strong> <span>Comments</span></td>
<td><strong>103</strong> <span>tweets</span></td>
</tr>
<tr>
<td><strong class="text-uppercase"><img class="user-img" src="/ghost/assets/img/user.jpg" width="34px" height="34px" alt=""> Jerry</strong></td>
<td><strong>32</strong> <span>Posts</span></td>
<td><strong>231</strong> <span>Comments</span></td>
<td><strong class="callout">103</strong> <span>tweets</span></td>
</tr>
</tbody>
</table>
</section>
<footer>
Ghost Stats
</footer>
</section>
<section class="widget post-statuses">
<header>
Post Statuses
</header>
<section class="content">
<div class="status-levels left">
<div class="scheduled" style="height: 30px;">Scheduled</div>
<div class="pending" style="height: 50px;">Pending</div>
<div class="draft" style="height: 60px;">Draft</div>
</div>
<div class="status-text left">
<div class="scheduled"><strong>5</strong> Scheduled</div>
<div class="pending"><strong>12</strong> Pending</div>
<div class="draft"><strong>32</strong> Draft</div>
</div>
</section>
<footer>
Ghost Stats
</footer>
</section>
<section class="widget total-views">
<header>
Total Page Views (Last 30 Days)
</header>
<section class="content">
<div class="widget-stats">
<span>37,921</span>
<span>
Previous <strong>32,419</strong> / <strong class="positive-text">+15.4%</strong>
</span>
</div>
</section>
<footer>
Google Analytics
</footer>
</section>
<section class="widget live-visitors">
<header>
Live Visitors
</header>
<section class="content">
<div class="widget-stats">
<span>124</span>
<span>
<strong>391</strong> max this month
</span>
</div>
</section>
<footer>
Woopra
</footer>
</section>
<section class="widget">
<header>
Twitter Followers
</header>
<section class="content">
<div class="widget-stats">
<span>12,304</span>
<span>
<strong class="positive-text">+123</strong> this month
</span>
</div>
</section>
<footer>
@ghost
</footer>
</section>
<section class="widget todays-traffic">
<header>
Todays Traffic (Actions)
</header>
<section class="content">
<ul class="nav">
<li>
<div>Post Title Excerpt Which is Li... <strong class="right">327</strong></div>
</li>
<li>
<div>My homepage <strong class="right">327</strong></div>
</li>
<li>
<div>Another long ass post about som... <strong class="right">327</strong></div>
</li>
<li>
<div>Boracay time! <strong class="right">327</strong></div>
</li>
</ul>
</section>
<footer>
Woopra
</footer>
</section>
<section class="widget">
<header>
Total Likes
</header>
<section class="content">
<div class="widget-stats">
<span>6,931</span>
<span>
<strong class="negative-text">-23</strong> this month
</span>
</div>
</section>
<footer>
Facebook
</footer>
</section>
}}
</main>
<script src="/core/admin/assets/lib/chart.min.js"></script>
<script>
$(document).ready(function(){
//$('body').click(function(){
$('.time').fadeIn(1000);
$('.image').delay(300).fadeIn(1000);
$('.posts').delay(600).fadeIn(900, function(){
var ctx = $("#poststats").get(0).getContext("2d");
var data = [
{
value: 9,
color:"#9ec14a"
},
{
value : 4,
color : "#f9e15d"
},
{
value : 2,
color : "#EB5700"
}
]
var options = {
animationEasing: 'easeOutQuart',
percentageInnerCutout: 60,
segmentStrokeColor : "#efefef"
}
var poststats = new Chart(ctx).Doughnut(data, options);
});
$('.stats').delay(800).fadeIn(1000);
$('.facebook').delay(1000).fadeIn(1000);
$('.gplus').delay(1200).fadeIn(1000);
$('.twitter').delay(1300).fadeIn(1000);
$('.campaignmonitor').delay(1400).fadeIn(1000);
//});
});
</script>

View File

@ -0,0 +1,41 @@
{{!< default}}
<main role="main">
<div class="wrapper">
<aside class="settings-sidebar" role="complementary">
<header>
<h1 class="title">Ugly Debug Tools</h1>
</header>
<nav class="settings-menu">
<ul>
<li class="Data management"><a href="#">General</a></li>
</ul>
</nav>
</aside>
<section class="settings-content">
<header>
<h2 class="title">General</h2>
<button class="button-save">Save</button>
</header>
<section class="content">
{{> flashes}}
<form id="settings-general">
<fieldset>
<label>
<b>Delete Database</b>
<a href="/ghost/debug/db/delete/" class="button-delete">Delete</a>
<p>Delete the entire database so you can start again with empty tables</p>
</label>
<label>
<b>Populate Database</b>
<a href="/ghost/debug/db/populate/" class="button-add">Populate</a>
<p>Populate the database with the default fixtures (<strong>Warning: </strong>only works on empty DB)</p>
</label>
</fieldset>
</form>
</section>
</section>
</div>
</main>

View File

@ -0,0 +1,37 @@
<!doctype html>
<!--[if lt IE 7]><html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
<!--[if (IE 7)&!(IEMobile)]><html class="no-js lt-ie9 lt-ie8" lang="en"><![endif]-->
<!--[if (IE 8)&!(IEMobile)]><html class="no-js lt-ie9" lang="en"><![endif]-->
<head>
<meta charset="utf-8">
<title>Ghost</title>
<meta name="description" content="">
<meta name="author" content="">
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="apple-mobile-web-app-capable" content="yes" />
<!-- For all browsers -->
<link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Lato:300,400,700">
<link rel="stylesheet" href="/core/admin/assets/css/screen.css">
<link rel="shortcut icon" href="/favicon.ico">
<link rel="logo" type="image/svg" href="/core/admin/assets/images/logo.svg"/>
<meta http-equiv="cleartype" content="on">
<!-- need per file scripts and styles :/ -->
<link rel="stylesheet" type="text/css" href="/core/admin/assets/lib/codemirror/codemirror.css"> <!-- TODO: Kill this - #29 -->
<!-- jQuery is for all so here for now -->
<script type="text/javascript" src="/core/admin/assets/lib/jquery/jquery.min.js"></script>
<script type="text/javascript" src="/core/admin/assets/js/toggle.js"></script>
<script type="text/javascript" src="/core/admin/assets/js/admin-ui-temp.js"></script>
</head>
<body class="{{bodyClass}}">
{{> navbar}}
{{{body}}}
</body>
</html>

View File

@ -0,0 +1,65 @@
{{!< default}}
<main role="main">
{{! TODO: Add "scrolling" class only when one of the panels is scrolled down by 5px or more }}
<header>
<section class="box entry-title">
<input type="text" id="entry-title" placeholder="{{e "editor.entry_title.placeholder" "The Post Title Gets Inserted Up Here"}}" value="{{title}}">
</section>
</header>
<section class="entry-markdown active">
<header class="floatingheader">
{{e "editor.headers.markdown.label" "Markdown"}}
<a class="markdown-help" href="#"><span class="hidden">What is Markdown?</span></a>
</header>
<section class="entry-markdown-content">
<textarea id="entry-markdown">{{content}}</textarea>
</section>
</section>{{!.entry-markdown}}
<section class="entry-preview">
<header class="floatingheader">
Preview <span class="entry-word-count">0 words</span>
</header>
<section class="entry-preview-content">
<div class="rendered-markdown">
{{!The content gets inserted in here, bitches!}}
</div>
</section>
</section>{{!.entry-preview}}
<footer id="publish-bar">
<nav>
<section id="entry-categories" href="#" class="left">
<label class="category-label" for="categories"><span class="hidden">Categories</span></label>
<div class="categories"></div>
<input type="hidden" class="category-holder" id="category-holder">
<input class="category-input" id="categories" type="text" data-populate-hidden="#category-holder" data-input-behaviour="tag" data-populate=".categories" />
<ul class="suggestions overlay" data-populate=".categories"></ul>
</section>
<div class="right">
<button id="entry-settings" href="#" class="button-link"><span class="hidden">Settings</span></button>
<section id="entry-actions" class="splitbutton-save">
<button type="button" class="button-save" data-state="save-draft">Save Draft</button>
<a class="options up" href="#"><span class="hidden">Options</span></a>
<ul class="editor-options overlay" style="display:none">
<li data-title="publish-now" data-url=""><a href="#">Publish Now</a></li>
<li data-title="queue" data-url=""><a href="#">Add to Queue</a></li>
<li data-title="publish-on" data-url=""><a href="#">Publish on...</a></li>
<li data-title="save-draft" data-url="" class="active"><a href="#">Save Draft</a></li>
</ul>
</section>
</div>
</nav>
</footer>
</main>
<script src="/core/admin/assets/lib/codemirror/codemirror.js"></script>
<script src="/core/admin/assets/lib/codemirror/mode/markdown/markdown.js"></script>
<script src="/core/admin/assets/lib/showdown/showdown.js"></script>
<script src="/core/admin/assets/lib/showdown/extensions/ghostdown.js"></script>
<script src="/core/admin/assets/lib/shortcuts.js"></script>
<script src="/core/admin/assets/js/editor.js"></script>
<script src="/core/admin/assets/js/tagui.js"></script>

View File

@ -0,0 +1,27 @@
<div id="flashed"></div>
{{#if messages}}
{{#each messages.error}}
<section class="notification-error">
{{.}}
<a class="close" href="#"><span class="hidden">Close</span></a>
</section>
{{/each}}
{{#each messages.success}}
<section class="notification-success">
{{.}}
<a class="close" href="#"><span class="hidden">Close</span></a>
</section>
{{/each}}
{{#each messages.warn}}
<section class="notification-alert">
{{.}}
<a class="close" href="#"><span class="hidden">Close</span></a>
</section>
{{/each}}
{{#each messages.info}}
<section class="notification">
{{.}}
<a class="close" href="#"><span class="hidden">Close</span></a>
</section>
{{/each}}
{{/if}}

View File

@ -0,0 +1,25 @@
<header id="global-header" class="navbar">
<a id="ghost" href="#" data-off-canvas="left"><span class="hidden">Ghost</span></a>
<nav id="global-nav" role="navigation">
<ul id="main-menu" >
{{#each adminNav}}
<li class="{{navClass}}{{#if selected}} active{{/if}}"><a href="/ghost{{path}}">{{name}}</a></li>
{{/each}}
<li id="usermenu" class="subnav">
<a href="#" data-toggle="ul">
<img class="avatar" src="/core/admin/assets/img/user.jpg" alt="Avatar" />
<span class="name">John O'Nolan</span>
</a>
<ul>
<li class="usermenu-profile"><a href="#">Your Profile</a></li>
<li class="divider"></li>
<li class="usermenu-help"><a href="#">Help / Support</a></li>
<li class="usermenu-shortcuts"><a href="#">Keyboard Shortcuts</a></li>
<li class="divider"></li>
<li class="usermenu-signout"><a href="#">Sign Out</a></li>
</ul>
</li>
</ul>
</nav>
</header>

View File

@ -0,0 +1,171 @@
{{!< default}}
<main role="main">
<div class="wrapper">
<aside class="settings-sidebar" role="complementary">
<header>
<h1 class="title">Settings</h1>
</header>
<nav class="settings-menu">
<ul>
<li class="general active"><a href="#general">General</a></li>
<li class="publishing"><a href="#content">Content</a></li>
<li class="users"><a href="#users">Users</a></li>
<li class="appearance"><a href="#">Appearance</a></li>
<li class="services"><a href="#">Connected Services</a></li>
<li class="plugins"><a href="#">Plugins</a></li>
</ul>
</nav>
</aside>
<section id="general" class="settings-content active">
<header>
<h2 class="title">General</h2>
<section class="page-actions">
<button class="button-save">Save</button>
</section>
</header>
<section class="content">
<form id="settings-general">
<fieldset>
<label>
<b>Blog Title</b>
<input id="blog-title" type="text" value="John O'Nolan" />
<p>How your blog name appears on the site</p>
</label>
<label>
<b>Blog Logo</b>
<img src="/core/admin/assets/img/logo.png" alt="logo" height"38" width="381"/>
<p>Display a logo on your site in place of blog title</p>
</label>
<label>
<b>Blog Icon</b>
<img src="/core/admin/assets/img/test-icon.png" alt="logo" height"38" width="38"/>
<p>The icon for your blog, used in your browser tab and elsewhere</p>
</label>
<label>
<b>Email Address</b>
<input id="email-address" type="text" value="john@tryghost.org" />
<p>Address to use for <a href="#">admin notifications</a></p>
<label class="checkbox">
<input type="checkbox" value="1" /> Show my email address on my public profile
</label>
</label>
<label>
<b>URL Structure</b>
<select id="url-structure" name="general[urlstructure]">
<option value="post-name">Simple Post Name</option>
<option value="date-based">Date Based</option>
<option value="number based">Number Based</option>
<option value="custom">Custom...</option>
</select>
</label>
</fieldset>
<hr />
<fieldset>
<label>
<b>Time Zone</b>
<select id="url-structure" name="general[timezone]">
<option value="1">Vienna (UTC+1)</option>
</select>
</label>
</fieldset>
</form>
</section>
</section>
<section id="content" class="settings-content">
<header>
<h2 class="title">Content</h2>
<section class="page-actions">
<button class="button-save">Save</button>
</section>
</header>
<section class="content">
<form id="settings-general">
<fieldset>
<label>
<b>Typography</b>
<select id="url-structure" name="general[urlstructure]">
<option value="post-name">Lato (Light)</option>
</select>
<p>Sexy sans-serif font that will make your toes tickle.</p>
<label class="checkbox">
<input type="checkbox" value="1" /> Load fonts directly from Google
</label>
</label>
<label>
<b>Post Options</b>
<label class="checkbox">
<input type="checkbox" value="1" /> Display Post Meta
<p>Post Author / Date / Views</p>
</label>
<label class="checkbox">
<input type="checkbox" value="1" /> Show Author Box After Post
</label>
<label class="checkbox">
<input type="checkbox" value="1" /> Enable Comments
</label>
</label>
</fieldset>
<hr />
<fieldset>
<label>
<b>SEO Title Pattern</b>
<input id="blog-title" type="text" value="[Post Name] - [Site Title]" />
<p>The pattern used to display your title tags</p>
</label>
<label>
<b>SEO Description Pattern</b>
<input id="blog-title" type="text" value="Auto" />
<p>The pattern used to display your meta descriptions</p>
</label>
<label>
<b>Google+</b>
<label class="checkbox">
<input type="checkbox" value="1" /> Connect to author profile on Google
</label>
</label>
<label>
<b>Home Page Description</b>
<textarea></textarea>
<p>Display a logo on your site in place of blog title</p>
</label>
</fieldset>
</form>
</section>
</section>
<section id="users" class="settings-content">
<header>
<h2 class="title">Users</h2>
<section class="page-actions">
<button class="button-add">Add User</button>
</section>
</header>
<section class="content">
<img src="/core/admin/assets/img/users.png" alt="users" style="width:900px;height:auto" />
</section>
</section>
</div>
</main>
<script src="/core/admin/assets/js/settings.js"></script>

View File

@ -0,0 +1,51 @@
/**
* Main controller for Ghost frontend
*/
/*global require, module */
(function () {
'use strict';
var Ghost = require('../../ghost'),
_ = require('underscore'),
ghost = new Ghost(),
frontendControllers;
frontendControllers = {
'homepage': function (req, res) {
var featureCount = 0,
postCount = 0,
data;
ghost.dataProvider().posts.findAll(function (error, posts) {
data = _.groupBy(posts, function (post) {
var group = null;
if (post.featured === true && featureCount < ghost.config().homepage.features) {
featureCount += 1;
group = 'features';
} else if (postCount < ghost.config().homepage.posts) {
postCount += 1;
group = 'posts';
}
return group;
});
ghost.doFilter('prepostsRender', data.posts, function (posts) {
res.render('index', {features: data.features, posts: posts, ghostGlobals: ghost.globals()});
});
});
},
'single': function (req, res) {
ghost.dataProvider().posts.findOne({'slug': req.params.slug}, function (error, post) {
ghost.doFilter('prePostsRender', post, function (post) {
res.render('single', {post: post, ghostGlobals: ghost.globals()});
});
});
}
};
module.exports = frontendControllers;
}());

View File

@ -0,0 +1,47 @@
(function () {
"use strict";
var _ = require('underscore'),
moment = require('moment'),
coreHelpers;
coreHelpers = function (ghost) {
/**
* [ description]
* @todo ghost core helpers + a way for themes to register them
* @param {Object} context date object
* @param {*} block
* @return {Object} A Moment time / date object
*/
ghost.registerThemeHelper('dateFormat', function (context, block) {
var f = block.hash.format || "MMM Do, YYYY";
return moment(context).format(f);
});
/**
* [ description]
*
* @param String key
* @param String default translation
* @param {Object} options
* @return String A correctly internationalised string
*/
ghost.registerThemeHelper('e', function (key, defaultString, options) {
var output;
if (ghost.config().defaultLang === 'en' && _.isEmpty(options.hash) && !ghost.config().forceI18n) {
output = defaultString;
} else {
output = ghost.polyglot().t(key, options.hash);
}
return output;
});
};
module.exports.loadCoreHelpers = coreHelpers;
}());

173
core/ghost.js Normal file
View File

@ -0,0 +1,173 @@
// # Ghost Module
// Defines core methods required to build the frontend
/**
* global module,
* require,
* __dirname
**/
(function () {
"use strict";
// ## Setup Prerequisites
var config = require('./../config'),
express = require('express'),
path = require('path'),
hbs = require('express-hbs'),
_ = require('underscore'),
Polyglot = require('node-polyglot'),
JsonDataProvider = require('./shared/models/dataProvider.json'),
jsonDataProvider = new JsonDataProvider(),
JugglingDataProvider = require('./shared/models/dataProvider.juggling'),
jugglingDataProvider = new JugglingDataProvider(),
Ghost,
instance,
filterCallbacks = {},
statuses;
// ## Article Statuses
/**
* A list of atricle status types
* @type {Object}
*/
statuses = {
'draft': 'draft',
'complete': 'complete',
'approved': 'approved',
'scheduled': 'scheduled',
'published': 'published'
};
// ## Module Methods
/**
* @method Ghost
* @returns {*}
* @constructor
*/
Ghost = function () {
var app,
globals,
polyglot;
if (!instance) {
instance = this;
// Temporary loading of settings
jsonDataProvider.globals.findAll(function (error, data) {
globals = data;
});
app = express();
polyglot = new Polyglot();
// functionality
// load Plugins...
// var f = new FancyFirstChar(ghost).init();
_.extend(instance, {
app: function () { return app; },
config: function () { return config; },
globals: function () { return globals; }, // there's no management here to be sure this has loaded
dataProvider: function () { return jugglingDataProvider; },
statuses: function () { return statuses; },
polyglot: function () { return polyglot; },
paths: function () {
return {
'activeTheme': __dirname + '/../content/' + config.themeDir + '/' + config.activeTheme + '/',
'adminViews': __dirname + '/admin/views/',
'lang': __dirname + '/lang/'
};
}
});
}
return instance;
};
/**
* @param {string} name
* @param {Function} fn
* @return {method} hbs.registerHelper
*/
Ghost.prototype.registerThemeHelper = function (name, fn) {
hbs.registerHelper(name, fn);
};
/**
* @param {string} name
* @param {Function} fn
* @return {*}
*/
Ghost.prototype.registerTheme = function (name, fn) {};
/**
* @param {string} name
* @param {Function} fn
* @return {*}
*/
Ghost.prototype.registerPlugin = function (name, fn) {};
/**
* @param {string} name
* @param {Function} fn
*/
Ghost.prototype.registerFilter = function (name, fn) {
if (!filterCallbacks.hasOwnProperty(name)) {
filterCallbacks[name] = [];
}
console.log('registering filter for ', name);
filterCallbacks[name].push(fn);
};
/**
* @param {string} name [description]
* @param {*} args
* @param {Function} callback
* @return {method} callback
*/
Ghost.prototype.doFilter = function (name, args, callback) {
var fn;
if (filterCallbacks.hasOwnProperty(name)) {
for (fn in filterCallbacks[name]) {
if (filterCallbacks[name].hasOwnProperty(fn)) {
console.log('doing filter for ', name);
args = filterCallbacks[name][fn](args);
}
}
}
callback(args);
};
/**
* Initialise Theme
*
* @todo Tod (?) Old comment
* @param {Object} app
*/
Ghost.prototype.initTheme = function (app) {
var self = this;
return function initTheme(req, res, next) {
app.set('view engine', 'hbs');
if (/(^\/ghost$|^\/ghost\/)/.test(req.url) === false) {
app.engine('hbs', hbs.express3(
{partialsDir: self.paths().activeTheme + 'partials'}
));
app.set('views', self.paths().activeTheme);
} else {
app.engine('hbs', hbs.express3({partialsDir: self.paths().adminViews + '/partials'}));
app.set('views', self.paths().adminViews);
app.use('/core/admin/assets', express['static'](path.join(__dirname, '/admin/assets')));
}
app.use(express['static'](self.paths().activeTheme));
app.use('/content/images', express['static'](path.join(__dirname, '/../content/images')));
next();
};
};
module.exports = Ghost;
}());

26
core/lang/en.json Normal file
View File

@ -0,0 +1,26 @@
{
"__SECTION__": "admin core",
"admin.navbar.dashboard": "Dashboard",
"admin.navbar.blog": "Blog",
"admin.navbar.settings": "Settings",
"__SECTION__": "icons",
"icon.category.label": "Category",
"icon.faq.label": "?",
"icon.faq.markdown.title": "What is Markdown?",
"icon.full_screen.label": "Full Screen",
"icon.full_screen.title": "Enter full screen mode",
"icon.settings.label": "Settings",
"__SECTION__": "editor",
"editor.entry_title.placeholder": "The Post Title Gets Inserted Up Here",
"editor.entry_permalink.label": "Permalink:",
"editor.entry_permalink.example_url": "http://yoursite.com/",
"editor.entry_permalink.example_slug": "the-post-title-goes-here",
"editor.headers.markdown.label": "Markdown",
"editor.headers.preview.label": "Preview",
"editor.word_count": "%{count} words",
"editor.actions.save_draft": "Save Draft",
"editor.actions.publish": "Publish"
}

26
core/lang/en_PL.json Normal file
View File

@ -0,0 +1,26 @@
{
"__SECTION__": "admin core",
"admin.navbar.dashboard": "Ashboarday",
"admin.navbar.blog": "Logbay",
"admin.navbar.settings": "Ettingsay",
"__SECTION__": "icons",
"icon.category.label": "Ategorycay",
"icon.faq.label": "?",
"icon.faq.markdown.title": "Atwhay isway Arkdownmay",
"icon.full_screen.label": "Ullfay Eenscray",
"icon.full_screen.title": "Enterway ullfay eenscrayodemay",
"icon.settings.label": "Ettingssay",
"__SECTION__": "editor",
"editor.entry_title.placeholder": "Ethay Ostpay Itletay Etsgay Insertedway Upway Erehay",
"editor.entry_permalink.label": "Ermalinkpay:",
"editor.entry_permalink.example_url": "http://oursiteyay.omcay/",
"editor.entry_permalink.example_slug": "ethay-ostpay-itletay-oesgay-erehay",
"editor.headers.markdown.label": "Arkdownmay",
"editor.headers.preview.label": "Eviewpray",
"editor.word_count": "%{count} ordsway",
"editor.actions.save_draft": "Avesay Aftdray",
"editor.actions.publish": "Ublishpay"
}

54
core/lang/i18n.js Normal file
View File

@ -0,0 +1,54 @@
(function () {
"use strict";
var fs = require('fs'),
/**
* Create new Polyglot object
* @type {Polyglot}
*/
I18n;
I18n = function (ghost) {
// TODO: validate
var lang = ghost.config().defaultLang,
path = ghost.paths().lang,
langFilePath = path + lang + '.json';
return function (req, res, next) {
if (lang === 'en') {
// TODO: do stuff here to optimise for en
}
/** TODO potentially use req.acceptedLanguages rather than the default
* TODO handle loading language file for frontend on frontend request etc
* TODO switch this mess to be promise driven */
fs.stat(langFilePath, function (error, stat) {
if (error) {
console.log('No language file found for language ' + lang + '. Defaulting to en');
lang = 'en';
}
fs.readFile(langFilePath, function (error, data) {
if (error) {
throw error;
}
try {
data = JSON.parse(data);
} catch (e) {
throw e; // TODO - do something better with the error here
}
ghost.polyglot().extend(data);
next();
});
});
};
};
module.exports.load = I18n;
}());

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,20 @@
[
{
"key": "url",
"value": "http://localhost:3333",
"createdBy": 1,
"updatedBy": 1
},
{
"key": "title",
"value": "John O'Nolan",
"createdBy": 1,
"updatedBy": 1
},
{
"key": "description",
"value": "Interactive designer, public speaker, startup advisor and writer. Living in Austria, attempting world domination via keyboard.",
"createdBy": 1,
"updatedBy": 1
}
]

View File

@ -0,0 +1,15 @@
[
{
"id": "1",
"username": "johnonolan",
"firstName": "John",
"lastName": "O'Nolan",
"emailAddress": "john@onolan.org",
"profilePicture": "logo.png",
"coverPicture": "",
"bio": "Interactive designer, public speaker, startup advisor and writer. Living in Austria, attempting world domination via keyboard.",
"url": "john.onolan.org",
"createdBy": 1,
"updatedBy": 1
}
]

View File

@ -0,0 +1,52 @@
/**
* Dummy dataProvider returns hardcoded JSON data until we finish migrating settings data to a datastore
*/
/*globals module, require */
(function () {
"use strict";
var _ = require('underscore'),
DataProvider,
blogData,
instance,
d;
blogData = {
url: 'http://localhost:3333', //'http://john.onolan.org',
title: "John O'Nolan",
description: "Interactive designer, public speaker, startup advisor and writer. Living in Austria, attempting world domination via keyboard."
};
DataProvider = function () {
if (!instance) {
instance = this;
}
return instance;
};
DataProvider.prototype.globals = {};
DataProvider.prototype.globals.data = [];
DataProvider.prototype.globals.findAll = function (callback) {
callback(null, this.data);
};
DataProvider.prototype.globals.save = function (globals, callback) {
var self = this;
_.each(globals, function (global, key) {
self.data[key] = global;
});
callback(null, globals);
};
/* Lets bootstrap with dummy data */
d = new DataProvider();
d.globals.save(blogData, function (error, globals) {});
module.exports = DataProvider;
}());

View File

@ -0,0 +1,139 @@
/**
* Provides access to data via the JugglingDb ORM
*/
/*globals module, require */
(function () {
"use strict";
var schema = require('./schema').schema,
fs = require('fs'),
_ = require('underscore'),
DataProvider,
instance;
function populateData(callback) {
// TODO: convert to promises
schema.models.Setting.findOne({}, function (error, data) {
if (data === null) {
// we haven't loaded any data yet
fs.readFile(__dirname + '/data/fixtures/users.json', function (error, data) {
if (error) {
throw error;
}
var users = JSON.parse(data);
_.each(users, function (post) {
schema.models.User.create(post, function (error, data) {
console.log('User created error', error);
console.log('User created data', data);
});
});
fs.readFile(__dirname + '/data/fixtures/posts.json', function (error, data) {
if (error) {
throw error;
}
var posts = JSON.parse(data),
post;
_.each(posts, function (_post) {
post = new schema.models.Post(_post);
post.preCreate(function () {
post.save(function (error, data) {
console.log('Post created error', error);
console.log('Post created data', data);
});
});
});
fs.readFile(__dirname + '/data/fixtures/settings.json', function (error, data) {
if (error) {
throw error;
}
var posts = JSON.parse(data);
_.each(posts, function (post) {
schema.models.Setting.create(post, function (error, data) {
console.log('Setting created error', error);
console.log('Setting created data', data);
});
});
callback();
});
});
});
} else {
callback();
}
});
}
DataProvider = function () {
if (!instance) {
instance = this;
if (process.env.forcePopulate) {
populateData();
}
}
return instance;
};
DataProvider.prototype.posts = function () {};
/**
* Naive find all
* @param callback
*/
DataProvider.prototype.posts.findAll = function (callback) {
schema.models.Post.all(callback);
};
/**
* Naive find one where args match
* @param callback
*/
DataProvider.prototype.posts.findOne = function (args, callback) {
schema.models.Post.findOne({where: args}, callback);
};
/**
* Naive add
* @param post
* @param callback
*/
DataProvider.prototype.posts.add = function (_post, callback) {
var post = new schema.models.Post(_post);
post.preCreate(function () {
post.save(callback);
});
};
/**
* Naive edit
* @param post
* @param callback
*/
DataProvider.prototype.posts.edit = function (_post, callback) {
schema.models.Post.findOne({where: {id: _post.id}}, function (error, post) {
post = _.extend(post, _post);
schema.models.Post.updateOrCreate(post, callback);
});
};
DataProvider.prototype.populateData = populateData;
module.exports = DataProvider;
}());

View File

@ -0,0 +1,111 @@
/**
* Database Schema, created with JugglingDB
*
* Vastly incomplete!
*/
/*globals module, require */
(function () {
"use strict";
var Schema = require('jugglingdb').Schema,
schema = new Schema('sqlite3', {
database: __dirname + '/../data/datastore.db'
}),
Post,
User,
Setting;
/*------------------------------------------------------------------------------------
POST / Post / Posts
------------------------------------------------------------------------------------*/
Post = schema.define('Post', {
title: String,
slug: String,
content: Schema.Text,
contentHtml: Schema.Text,
featured: Boolean,
image: String,
status: String,
language: String,
createdAt: Date,
createdBy: Number,
updatedAt: Date,
updatedBy: Number
});
Post.prototype.generateSlug = function () {
return this.title.replace(/\:/g, '').replace(/\s/g, '-').toLowerCase();
};
Post.prototype.preCreate = function (next) {
console.log('pre create 1', this);
if (this.createdAt === undefined) {
this.createdAt = new Date();
}
if (this.slug === undefined) {
this.slug = this.generateSlug();
}
console.log('pre create 2', this);
next();
};
// Validations
Post.validatesPresenceOf('title', {message: 'Post title cannot be blank'});
//Post.validatesPresenceOf('slug');
//Post.validatesPresenceOf('language', {message: 'Language cannot be blank'});
//Post.validatesUniquenessOf('slug');
//Post.validatesLengthOf('language', {min: 2, max: 5}, "The language code should be between 2 and 5 chars long, E.g. 'en' or 'en_GB' ");
Post.beforeSave = function (next, data) {
console.log('before s1', data);
// set updated
data.updatedAt = new Date();
next();
};
/*------------------------------------------------------------------------------------
USER / User / Users
------------------------------------------------------------------------------------*/
User = schema.define('User', {
username: String,
firstName: String,
lastName: String,
emailAddress: String,
profilePicture: String,
coverPicture: String,
bio: Schema.Text,
url: String,
createdAt: Date,
createdBy: Number,
updatedAt: Date,
updatedBy: Number
});
/*------------------------------------------------------------------------------------
SETTING / Setting / Settings
------------------------------------------------------------------------------------*/
Setting = schema.define('Setting', {
key: String,
value: Schema.Text,
createdAt: Date,
createdBy: Number,
updatedAt: Date,
updatedBy: Number
});
/*------------------------------------------------------------------------------------
RELATIONSHIPS
------------------------------------------------------------------------------------*/
User.hasMany(Post, {as: 'posts', foreignKey: 'createdBy'});
Post.belongsTo(User, {as: 'author', foreignKey: 'createdBy'});
schema.autoupdate();
exports.schema = schema;
}());

View File

@ -0,0 +1,16 @@
/*global require, module */
(function () {
"use strict";
var DataProvider = require('../../shared/models/dataProvider.json');
module.exports = {
'singleton': function (test) {
var provider1 = new DataProvider(),
provider2 = new DataProvider();
test.equal(provider1, provider2);
test.done();
}
};
}());

View File

@ -0,0 +1,16 @@
/*global require, module */
(function () {
"use strict";
var Ghost = require('../../ghost');
module.exports = {
'singleton': function (test) {
var ghost1 = new Ghost(),
ghost2 = new Ghost();
test.equal(ghost1, ghost2);
test.done();
}
};
}());

View File

@ -0,0 +1,252 @@
<!doctype html>
<!--[if lt IE 7]><html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
<!--[if (IE 7)&!(IEMobile)]><html class="no-js lt-ie9 lt-ie8" lang="en"><![endif]-->
<!--[if (IE 8)&!(IEMobile)]><html class="no-js lt-ie9" lang="en"><![endif]-->
<head>
<meta charset="utf-8">
<title>Ghost</title>
<meta name="description" content="">
<meta name="author" content="">
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- For all browsers -->
<link rel="stylesheet" href="../core/admin/assets/css/screen.css">
<link rel="shortcut icon" href="/favicon.ico">
<link rel="logo" type="image/svg" href="assets/images/logo.svg"/>
<meta http-equiv="cleartype" content="on">
</head>
<body class="dashboard">
<header id="global-header" class="navbar">
<a id="ghost" class="icon-ghost" href="#"><span class="hidden">Ghost</span></a>
<nav id="global-nav" role="navigation">
<ul id="main-menu">
<li class="active"><a href="#">Dashboard</a></li>
<li><a href="#">Blog</a></li>
<li><a href="#">Pages</a></li>
<li><a href="#">Settings</a></li>
<li id="user-menu" class="subnav">
<a href="#" data-toggle="ul">
<img class="avatar" src="assets/img/user.jpg" alt="Avatar" />
<span class="name">John O'Nolan</span>
</a>
<ul>
<li><a href="#">Your Profile</a></li>
<li class="divider"></li>
<li><a href="#">Help / Support</a></li>
<li><a href="#">Keyboard Shortcuts</a></li>
<li class="divider"></li>
<li><a href="#">Sign Out</a></li>
</ul>
</li>
</ul>
</nav>
</header>
<main role="main">
<section class="dashboard-controls">
<div class="text left"><strong>Welcome back</strong>, John.</div>
<nav class="controls-nav">
<ul class="nav inline">
<li><a href="#"><span class="icon-new"></span> New Post</a></li>
<li><a href="#"><span class="icon-users"></span> Authors</a></li>
<li><a href="#"><span class="icon-analytics"></span> Analytics</a></li>
</ul>
</nav>
<div class="text right"><a href="#"><span class="icon-settings"></span><span class="hidden">Settings</span></a></div>
<div class="clearfix"></div><!--TODO: replace this later with something less shit-->
</section>
<section class="widget time-date">
<header>
London, United Kingdom
</header>
<section class="content">
<div class="time">
8:55<span>am</span>
</div>
<div class="date"><!--TODO: convert to html5 <date>-->
<span>Wednesday</span>
13 June 2012
</div>
</section>
<footer>
Timezone: UTC +1
</footer>
</section>
<section class="widget">
<header>
Top Authors This Month
</header>
<section class="content">
<table class="table">
<thead>
<tr>
<td>Name</td>
<td>Posts</td>
<td>Comments</td>
<td>tweets</td>
<td>Likes</td>
</tr>
</thead>
<tbody>
<tr>
<td><strong class="text-uppercase"><img class="user-img" src="assets/img/user.jpg" width="34px" height="34px" alt=""> John</strong></td>
<td><strong class="callout">32</strong> <span>Posts</span></td>
<td><strong>231</strong> <span>Comments</span></td>
<td><strong>103</strong> <span>tweets</span></td>
</tr>
<tr>
<td><strong class="text-uppercase"><img class="user-img" src="assets/img/user.jpg" width="34px" height="34px" alt=""> James</strong></td>
<td><strong>32</strong> <span>Posts</span></td>
<td><strong class="callout">231</strong> <span>Comments</span></td>
<td><strong>103</strong> <span>tweets</span></td>
</tr>
<tr>
<td><strong class="text-uppercase"><img class="user-img" src="assets/img/user.jpg" width="34px" height="34px" alt=""> Jerry</strong></td>
<td><strong>32</strong> <span>Posts</span></td>
<td><strong>231</strong> <span>Comments</span></td>
<td><strong class="callout">103</strong> <span>tweets</span></td>
</tr>
</tbody>
</table>
</section>
<footer>
Ghost Stats
</footer>
</section>
<section class="widget post-statuses">
<header>
Post Statuses
</header>
<section class="content">
<div class="status-levels left">
<div class="scheduled" style="height: 30px;">Scheduled</div>
<div class="pending" style="height: 50px;">Pending</div>
<div class="draft" style="height: 60px;">Draft</div>
</div>
<div class="status-text left">
<div class="scheduled"><strong>5</strong> Scheduled</div>
<div class="pending"><strong>12</strong> Pending</div>
<div class="draft"><strong>32</strong> Draft</div>
</div>
</section>
<footer>
Ghost Stats
</footer>
</section>
<section class="widget total-views">
<header>
Total Page Views (Last 30 Days)
</header>
<section class="content">
<div class="widget-stats">
<span>37,921</span>
<span>
Previous <strong>32,419</strong> / <strong class="positive-text">+15.4%</strong>
</span>
</div>
</section>
<footer>
Google Analytics
</footer>
</section>
<section class="widget live-visitors">
<header>
Live Visitors
</header>
<section class="content">
<div class="widget-stats">
<span>124</span>
<span>
<strong>391</strong> max this month
</span>
</div>
</section>
<footer>
Woopra
</footer>
</section>
<section class="widget">
<header>
Twitter Followers
</header>
<section class="content">
<div class="widget-stats">
<span>12,304</span>
<span>
<strong class="positive-text">+123</strong> this month
</span>
</div>
</section>
<footer>
@ghost
</footer>
</section>
<section class="widget todays-traffic">
<header>
Todays Traffic (Actions)
</header>
<section class="content">
<ul class="nav">
<li>
<div>Post Title Excerpt Which is Li... <strong class="right">327</strong></div>
</li>
<li>
<div>My homepage <strong class="right">327</strong></div>
</li>
<li>
<div>Another long ass post about som... <strong class="right">327</strong></div>
</li>
<li>
<div>Boracay time! <strong class="right">327</strong></div>
</li>
</ul>
</section>
<footer>
Woopra
</footer>
</section>
<section class="widget">
<header>
Total Likes
</header>
<section class="content">
<div class="widget-stats">
<span>6,931</span>
<span>
<strong class="negative-text">-23</strong> this month
</span>
</div>
</section>
<footer>
Facebook
</footer>
</section>
</main>
<script type="text/javascript" src="assets/js/jquery.js"></script>
</body>
</html>

51
core/test/html/login.html Normal file
View File

@ -0,0 +1,51 @@
<!doctype html>
<!--[if lt IE 7]><html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
<!--[if (IE 7)&!(IEMobile)]><html class="no-js lt-ie9 lt-ie8" lang="en"><![endif]-->
<!--[if (IE 8)&!(IEMobile)]><html class="no-js lt-ie9" lang="en"><![endif]-->
<head>
<meta charset="utf-8">
<title>Ghost</title>
<meta name="description" content="">
<meta name="author" content="">
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- For all browsers -->
<link rel="stylesheet" href="../core/admin/assets/css/screen.css">
<link rel="shortcut icon" href="/favicon.ico">
<link rel="logo" type="image/svg" href="assets/images/logo.svg"/>
<meta http-equiv="cleartype" content="on">
</head>
<body class="ghost-login">
<header id="login-header">
</header>
<main role="main">
<img class="login-logo" src="../core/admin/assets/img/logo.png" alt="" />
<form id="login" action="#">
<div class="email-wrap">
<input class="email" type="text" placeholder="Email Address">
</div>
<div class="password-wrap">
<input class="password" type="password" placeholder="Password">
</div>
<button class="button-save" type="submit">Log in</button>
</form>
</main>
<script type="text/javascript" src="assets/js/jquery.js"></script>
</body>
</html>

221
core/test/html/manage.html Normal file
View File

@ -0,0 +1,221 @@
<!doctype html>
<!--[if lt IE 7]><html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
<!--[if (IE 7)&!(IEMobile)]><html class="no-js lt-ie9 lt-ie8" lang="en"><![endif]-->
<!--[if (IE 8)&!(IEMobile)]><html class="no-js lt-ie9" lang="en"><![endif]-->
<head>
<meta charset="utf-8">
<title>Ghost</title>
<meta name="description" content="">
<meta name="author" content="">
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- For all browsers -->
<link rel="stylesheet" href="../core/admin/assets/css/screen.css">
<link rel="shortcut icon" href="/favicon.ico">
<link rel="logo" type="image/svg" href="assets/images/logo.svg"/>
<meta http-equiv="cleartype" content="on">
</head>
<body class="manage">
<header id="global-header" class="navbar">
<a id="ghost" class="icon-ghost" href="#"><span class="hidden">Ghost</span></a>
<nav id="global-nav" role="navigation">
<ul id="main-menu">
<li class="active"><a href="#">Dashboard</a></li>
<li><a href="#">Blog</a></li>
<li><a href="#">Pages</a></li>
<li><a href="#">Settings</a></li>
<li id="user-menu" class="subnav">
<a href="#" data-toggle="ul">
<img class="avatar" src="assets/img/user.jpg" alt="Avatar" />
<span class="name">John O'Nolan</span>
</a>
<ul>
<li><a href="#">Your Profile</a></li>
<li class="divider"></li>
<li><a href="#">Help / Support</a></li>
<li><a href="#">Keyboard Shortcuts</a></li>
<li class="divider"></li>
<li><a href="#">Sign Out</a></li>
</ul>
</li>
</ul>
</nav>
</header>
<main role="main">
<div class="half-wrap left-panel">
<section class="box manage-posts">
<header>
Blog Posts <a href="#" class="right search">Search</a>
</header>
<ol class="post-list">
<li>
<a class="permalink" href="#">
<figure class="thumbnail"><img src="assets/img/user.jpg" alt="img" /></figure>
<h3 class="entry-title">Ut Enim ad Minim Veniam Quis Nostrud</h3>
<section class="entry-meta">
<time datetime="2013-01-04" class="date">Today</time>
<span class="category">News, Category</span>
<span class="views">1,934</span>
</section>
</a>
</li>
<li>
<a class="permalink" href="#">
<figure class="thumbnail"><img src="assets/img/user.jpg" alt="img" /></figure>
<h3 class="entry-title">Ut Enim ad Minim Veniam Quis Nostrud Exercitation Ullamco</h3>
<section class="entry-meta">
<time datetime="2013-01-04" class="date">Today</time>
<span class="category">News, Category</span>
<span class="views">1,934</span>
</section>
</a>
</li>
<li class="current featured">
<a class="permalink" href="#">
<figure class="thumbnail"><img src="assets/img/user.jpg" alt="img" /></figure>
<h3 class="entry-title">Ut Enim ad Minim Veniam Quis Nostrud Exercitation Ullamco</h3>
<section class="entry-meta">
<time datetime="2013-01-04" class="date">Today</time>
<span class="category">News, Category</span>
<span class="views">1,934</span>
</section>
</a>
</li>
<li>
<a class="permalink" href="#">
<figure class="thumbnail"><img src="assets/img/user.jpg" alt="img" /></figure>
<h3 class="entry-title">Ut Enim ad Minim Veniam Quis Nostrud Exercitation Ullamco</h3>
<section class="entry-meta">
<time datetime="2013-01-04" class="date">Today</time>
<span class="category">News, Category</span>
<span class="views">1,934</span>
</section>
</a>
</li>
<li>
<a class="permalink" href="#">
<figure class="thumbnail"><img src="assets/img/user.jpg" alt="img" /></figure>
<h3 class="entry-title">Ut Enim ad Minim Veniam Quis Nostrud Exercitation Ullamco</h3>
<section class="entry-meta">
<time datetime="2013-01-04" class="date">Today</time>
<span class="category">News, Category</span>
<span class="views">1,934</span>
</section>
</a>
</li>
<li class="featured">
<a class="permalink" href="#">
<figure class="thumbnail"><img src="assets/img/user.jpg" alt="img" /></figure>
<h3 class="entry-title">Ut Enim ad Minim Veniam Quis Nostrud Exercitation Ullamco</h3>
<section class="entry-meta">
<time datetime="2013-01-04" class="date">Today</time>
<span class="category">News, Category</span>
<span class="views">1,934</span>
</section>
</a>
</li>
<li>
<a class="permalink" href="#">
<figure class="thumbnail"><img src="assets/img/user.jpg" alt="img" /></figure>
<h3 class="entry-title">Ut Enim ad Minim Veniam Quis Nostrud Exercitation Ullamco</h3>
<section class="entry-meta">
<time datetime="2013-01-04" class="date">Today</time>
<span class="category">News, Category</span>
<span class="views">1,934</span>
</section>
</a>
</li>
<li>
<a class="permalink" href="#">
<figure class="thumbnail"></figure>
<h3 class="entry-title">Ut Enim ad Minim Veniam Quis Nostrud Exercitation Ullamco</h3>
<section class="entry-meta">
<time datetime="2013-01-04" class="date">Today</time>
<span class="category">News, Category</span>
<span class="views">1,934</span>
</section>
</a>
</li>
<li>
<a class="permalink" href="#">
<figure class="thumbnail"><img src="assets/img/user.jpg" alt="img" /></figure>
<h3 class="entry-title">Ut Enim ad Minim Veniam Quis Nostrud Exercitation Ullamco</h3>
<section class="entry-meta">
<time datetime="2013-01-04" class="date">Today</time>
<span class="category">News, Category</span>
<span class="views">1,934</span>
</section>
</a>
</li>
</ol>
</section>
</div>
<div class="half-wrap right-panel">
<section class="box preview-post featured">
<header>
Published + Featured
<section class="right">
<ul class="post-utility">
<li><a class="edit" href="#">Edit</a></li>
<li><a class="view" href="#">View</a></li>
<li><a class="delete" href="#">Delete</a></li>
</ul>
</section>
</header>
<section class="post-content">
<h2>Ut Enim ad Minim Veniam Quis Nostrud Exercitation Ullamco</h2>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis <a href="#">parturient</a> montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu.</p>
<h2>This is a Heading 2</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod <strong>tempor incididunt</strong> ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod <strong>tempor incididunt</strong> ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipisicing elit, Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. sed do eiusmod <strong>tempor incididunt</strong> ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod <strong>tempor incididunt</strong> ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod <strong>tempor incididunt</strong> ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
<img src="assets/img/postimg.jpg" alt="" />
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim.</p>
<ul>
<li>Lorem ipsum dolor sit amet</li>
<li>Lorem ipsum dolor sit amet</li>
<li>Lorem ipsum dolor sit amet</li>
<li>Lorem ipsum dolor sit amet</li>
<li>Lorem ipsum dolor sit amet</li>
</ul>
<h3>This is a Heading 3</h3>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
<ol>
<li>Lorem ipsum dolor sit amet</li>
<li>Lorem ipsum dolor sit amet</li>
<li>Lorem ipsum dolor sit amet</li>
<li>Lorem ipsum dolor sit amet</li>
<li>Lorem ipsum dolor sit amet</li>
</ol>
</section>
</section>
</div>
</main>
<script type="text/javascript" src="assets/js/jquery.js"></script>
</body>
</html>

View File

@ -0,0 +1,191 @@
<!doctype html>
<!--[if lt IE 7]><html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
<!--[if (IE 7)&!(IEMobile)]><html class="no-js lt-ie9 lt-ie8" lang="en"><![endif]-->
<!--[if (IE 8)&!(IEMobile)]><html class="no-js lt-ie9" lang="en"><![endif]-->
<head>
<meta charset="utf-8">
<title>Ghost</title>
<meta name="description" content="">
<meta name="author" content="">
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- For all browsers -->
<link rel="stylesheet" href="../core/admin/assets/css/screen.css">
<link rel="shortcut icon" href="/favicon.ico">
<link rel="logo" type="image/svg" href="assets/images/logo.svg"/>
<meta http-equiv="cleartype" content="on">
</head>
<body class="editor">
<header id="global-header" class="navbar">
<a id="ghost" class="icon-ghost" href="#"><span class="hidden">Ghost</span></a>
<nav id="global-nav" role="navigation">
<ul id="main-menu">
<li><a href="#">Dashboard</a></li>
<li class="active"><a href="#">Blog</a></li>
<li><a href="#">Pages</a></li>
<li><a href="#">Settings</a></li>
<li id="user-menu" class="subnav">
<a href="#" data-toggle="ul">
<img class="avatar" src="assets/img/user.jpg" alt="Avatar" />
<span class="name">John O'Nolan</span>
</a>
<ul>
<li><a href="#">Your Profile</a></li>
<li class="divider"></li>
<li><a href="#">Help / Support</a></li>
<li><a href="#">Keyboard Shortcuts</a></li>
<li class="divider"></li>
<li><a href="#">Sign Out</a></li>
</ul>
</li>
</ul>
</nav>
</header>
<main role="main">
<section class="notification">
This is a general notification. The default. Gets your attention. Tells you stuff.
<a class="close" href="#"><span class="hidden">Close</span></a>
</section>
<section class="notification-success">
The action you attempted completed successfully.
<a class="close" href="#"><span class="hidden">Close</span></a>
</section>
<section class="notification-alert">
General information. Yay.
<a class="close" href="#"><span class="hidden">Close</span></a>
</section>
<section class="notification-error">
You done fucked up good.
<a class="close" href="#"><span class="hidden">Close</span></a>
</section>
<header>
<section class="box entry-title">
<input type="text" placeholder="The Post Title Gets Inserted Up Here">
<a class="icon-fullscreen" href="#" title="Enter full screen mode"><span class="hidden">Full Screen</span></a>
</section>
<span class="entry-permalink"><strong>Permalink:</strong> http://yoursite.com/<strong>the-post-title-goes-here</strong>/</span>
</header>
<div class="wrapper">
<div class="half-wrap">
<section class="box entry-content active">
<header>
Markdown <a href="#" title="What is Markdown?" class="right icon-faq"><span class="hidden">?</span></a>
</header>
<textarea class="markdown">
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu.
##This is a Heading 2
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim.
* Lorem ipsum dolor sit amet
* Lorem ipsum dolor sit amet
* Lorem ipsum dolor sit amet
* Lorem ipsum dolor sit amet
* Lorem ipsum dolor sit amet
###This is a Heading 3
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
1. Lorem ipsum dolor sit amet
2. Lorem ipsum dolor sit amet
3. Lorem ipsum dolor sit amet
4. Lorem ipsum dolor sit amet
5. Lorem ipsum dolor sit amet
</textarea>
</section>
</div>
<div class="half-wrap">
<section class="box entry-preview">
<header>
Preview <span class="right">561 words</span>
</header>
<section class="entry-preview-content">
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis <a href="#">parturient</a> montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu.</p>
<h2>This is a Heading 2</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod <strong>tempor incididunt</strong> ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
<div class="img-placeholder">
<span>Drag image here - or <a href="#" class="btn btn-light btn-rounded">Upload</a></span>
</div>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim.</p>
<ul>
<li>Lorem ipsum dolor sit amet</li>
<li>Lorem ipsum dolor sit amet</li>
<li>Lorem ipsum dolor sit amet</li>
<li>Lorem ipsum dolor sit amet</li>
<li>Lorem ipsum dolor sit amet</li>
</ul>
<h3>This is a Heading 3</h3>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
<ol>
<li>Lorem ipsum dolor sit amet</li>
<li>Lorem ipsum dolor sit amet</li>
<li>Lorem ipsum dolor sit amet</li>
<li>Lorem ipsum dolor sit amet</li>
<li>Lorem ipsum dolor sit amet</li>
</ol>
</section>
</section>
</div>
</div>
<footer id="publish-bar">
<nav>
<a id="entry-categories" href="#" class="left"><span class="icon-tag"></span> Category: Default</a>
<div class="right">
<a id="entry-settings" href="#" class="button-settings"><span class="icon-settings"></span> <span class="hidden">Settings</span></a>
<a id="save-post" href="#" class="button button-save">Save Draft</a><a id="publish-post" href="#" class="button button-publish">Publish</a>
</div>
</nav>
</footer>
</main>
<script type="text/javascript" src="assets/js/jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$('.entry-content header, .entry-preview header').click(function(){
$('.entry-content, .entry-preview').removeClass('active');
$(this).closest('section').addClass('active');
});
});
</script>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More