1
0
mirror of https://github.com/locomotivemtl/locomotive-boilerplate.git synced 2026-01-15 00:55:08 +08:00

Merge pull request #1 from mducharme/master

Unification Gruntfile, htaccess et classes PHP (+ controleurs index.php / charcoal.php) de base.
This commit is contained in:
Mathieu Ducharme
2014-10-13 21:56:26 -04:00
66 changed files with 2973 additions and 25 deletions

View File

@@ -1,4 +1,4 @@
locomotive-boilerplate Charcoal-Boilerplate
====================== ======================
Boilerplate for projects by Locomotive. Boilerplate for [`Charcoal`](#http://charcoal.locomotive.ca) projects by Locomotive.

41
clone.sh Executable file
View File

@@ -0,0 +1,41 @@
# !/bin/bash
if [ "$#" -ne 1 ]
then
echo "Usage: \"sh clone.sh {project-name}\"";
exit 1
fi
echo "Creating project \"$1\"";
project=$1
mkdir $project 2> /dev/null;
cp -R project-x/* $project 2> /dev/null;
cp project-x/.* $project 2> /dev/null;
find $project/ -type d -name .svn -exec rm {} \; 2> /dev/null;
find $project/ -type d -name node_modules -exec rm -rf {} \; 2> /dev/null;
#find $1/ -name *boilerplate* -exec sed -i -e 's/boilerplate/$1/g' {} \;
module=$project;
module="$(tr '[:lower:]' '[:upper:]' <<< ${module:0:1})${module:1}"
for file in $(grep -irl "boilerplate" $project/*)
do
sed -e "s/boilerplate/$project/g" $file > /tmp/clone-$project-tempfile.tmp;
mv /tmp/clone-$project-tempfile.tmp $file;
done
for file in $(grep -irl "Boilerplate" $project/*)
do
sed -e "s/Boilerplate/$module/g" $file > /tmp/clone-$project-tempfile.tmp;
mv /tmp/clone-$project-tempfile.tmp $file;
done
find $project/ -name "*boilerplate*" | while read f; do
mv "$f" "${f/boilerplate/$project}" 2> /dev/null;
done
find $project/ -name "*boilerplate*" | while read f; do
mv "$f" "${f/boilerplate/$project}" 2> /dev/null;
done

123
project-x/.htaccess Normal file
View File

@@ -0,0 +1,123 @@
<FilesMatch "\.(ttf|otf|eot|woff|font.css)$">
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
</IfModule>
</FilesMatch>
<IfModule mod_deflate.c>
<IfModule mod_setenvif.c>
<IfModule mod_headers.c>
SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s,?\s(gzip|deflate)?|X{4,13}|~{4,13}|-{4,13})$ HAVE_Accept-Encoding
RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding
</IfModule>
</IfModule>
<IfModule filter_module>
FilterDeclare COMPRESS
FilterProvider COMPRESS DEFLATE resp=Content-Type /text/(html|css|javascript|plain|x(ml|-component))/
FilterProvider COMPRESS DEFLATE resp=Content-Type /application/(javascript|json|xml|x-javascript)/
FilterChain COMPRESS
FilterProtocol COMPRESS change=yes;byteranges=no
</IfModule>
<IfModule !mod_filter.c>
# Legacy versions of Apache
AddOutputFilterByType DEFLATE text/html text/plain text/css application/json
AddOutputFilterByType DEFLATE text/javascript application/javascript application/x-javascript
AddOutputFilterByType DEFLATE text/xml application/xml text/x-component
</IfModule>
<FilesMatch "\.(ttf|otf|eot|svg|woff)$" >
SetOutputFilter DEFLATE
</FilesMatch>
</IfModule>
<IfModule mod_expires.c>
ExpiresActive on
ExpiresDefault "access plus 1 month"
ExpiresByType text/cache-manifest "access plus 0 seconds"
ExpiresByType text/html "access plus 0 seconds"
ExpiresByType text/xml "access plus 0 seconds"
ExpiresByType application/xml "access plus 0 seconds"
ExpiresByType application/json "access plus 1 day"
ExpiresByType application/rss+xml "access plus 1 hour"
ExpiresByType image/x-icon "access plus 1 week"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/jpg "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType video/ogg "access plus 1 month"
ExpiresByType audio/ogg "access plus 1 month"
ExpiresByType video/mp4 "access plus 1 month"
ExpiresByType video/webm "access plus 1 month"
ExpiresByType audio/webm "access plus 1 month"
ExpiresByType text/x-component "access plus 1 month"
ExpiresByType font/truetype "access plus 1 month"
ExpiresByType font/opentype "access plus 1 month"
ExpiresByType application/x-font-woff "access plus 1 month"
ExpiresByType image/svg+xml "access plus 1 month"
ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
ExpiresByType text/css "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
ExpiresByType text/javascript "access plus 1 year"
<IfModule mod_headers.c>
Header append Cache-Control "public"
</IfModule>
</IfModule>
<IfModule mod_headers.c>
Header unset ETag
</IfModule>
FileETag None
<IfModule mod_rewrite.c>
RewriteRule get-asset-(\w*) admin/assets?t=$1&%{QUERY_STRING} [L,NC]
Options +FollowSymlinks
RewriteEngine On
</IfModule>
Options -MultiViews
ErrorDocument 400 /400.php
ErrorDocument 401 /401.php
ErrorDocument 402 /402.php
ErrorDocument 403 /403.php
ErrorDocument 404 /404.php
AddDefaultCharset utf-8
AddCharset utf-8 .html .css .js .xml .json .rss
Options -Indexes
<IfModule mod_rewrite.c>
RewriteRule "(^|/)\." - [F]
# Sections
RewriteRule ^.*-([a-zA-Z]{2})-([0-9]+) index.php?%{query_string}&s=$2&lang=$1
# Charcoal
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ charcoal.php?action=$1&%{QUERY_STRING} [PT,L]
</IfModule>

View File

@@ -4,6 +4,77 @@ module.exports = function(grunt) {
grunt.initConfig({ grunt.initConfig({
pkg: grunt.file.readJSON( 'package.json' ), pkg: grunt.file.readJSON( 'package.json' ),
// jsonlint: Validate JSON files
jsonlint:{
project:{
src:[
'*.json',
'config/*.json',
'config/**/*.json',
'modules/**/config/*.json',
'modules/**/config/**/*.json'
]
},
charcoal:{
src:[
'charcoal/*.json',
'charcoal/core/config/*.json',
'charcoal/core/config/**/*.json',
'charcoal/modules/**/config/*.json',
'charcoal/modules/**/config/**/*.json'
]
}
},
// jshint: Validate javascript files with JSHint
jshint:{
gruntfile:{
src:[
// Self-test
'Gruntfile.js'
]
},
project:{
src:[
'modules/**/assets/scripts/src/*.js',
'modules/**/assets/scripts/src/**/*.js'
]
},
charcoal:{
src:[
'charcoal/core/assets/scripts/src/*.js',
'charcoal/core/assets/scripts/src/**/*.js',
'charcoal/modules/**/assets/scripts/src/*.js',
'charcoal/modules/**/assets/scripts/src/**/*.js'
]
}
},
// phplint: A simple wrapper around the php -l <filename> command.
phplint:{
options: {
swapPath: '/tmp',
phpArgs : {
// add -f for fatal errors
'-lf': null
}
},
project: [
'modules/**/code/*.php',
'modules/**/code/**/*.php',
'modules/**/assets/templates/*.php',
'modules/**/assets/templates/**/*.php'
],
charcoal: [
'charcoal/core/code/*.php',
'charcoal/core/code/**/*.php',
'charcoal/modules/**/code/*.php',
'charcoal/modules/**/code/**/*.php'
]
},
// watch: Run tasks whenever watched files change
watch: { watch: {
css: { css: {
files: ['assets/styles/src/**/*.scss'], files: ['assets/styles/src/**/*.scss'],
@@ -14,6 +85,8 @@ module.exports = function(grunt) {
} }
} }
}, },
// sass: Compile Sass to CSS.
sass: { sass: {
dist: { dist: {
files: { files: {
@@ -21,6 +94,8 @@ module.exports = function(grunt) {
} }
} }
}, },
// csscomb: Sort CSS properties in specific order.
csscomb: { csscomb: {
build: { build: {
expand: true, expand: true,
@@ -29,6 +104,8 @@ module.exports = function(grunt) {
dest: 'assets/styles/src/' dest: 'assets/styles/src/'
} }
}, },
// autoprefixer: Parse CSS and add vendor prefixes to CSS rules using values from the Can I Use website
autoprefixer: { autoprefixer: {
build: { build: {
options: { options: {
@@ -44,6 +121,8 @@ module.exports = function(grunt) {
] ]
} }
}, },
// notify: Automatic Notifications when Grunt tasks fail (or succeed)
notify: { notify: {
watch: { watch: {
options: { options: {
@@ -52,6 +131,8 @@ module.exports = function(grunt) {
} }
} }
}, },
// concat: Concatenate files
concat: { concat: {
global: { global: {
src: [ src: [
@@ -69,6 +150,8 @@ module.exports = function(grunt) {
dest: 'assets/scripts/dist/home.js', dest: 'assets/scripts/dist/home.js',
}*/ }*/
}, },
// uglify: Minify (javascript)files with UglifyJS
uglify: { uglify: {
my_target: { my_target: {
files: { files: {
@@ -76,18 +159,24 @@ module.exports = function(grunt) {
} }
} }
}, },
imagemin: { // Task
// imagemin: Minify PNG and JPEG images.
imagemin: {
dynamic: { dynamic: {
files: [{ files: [{
expand: true, expand: true,
cwd: 'assets/images/', cwd: 'assets/images/',
src: ['*.{png,jpg,gif}'], src: ['*.{png,jpg,gif}'],
dest: 'assets/images/' dest: 'assets/images/'
}] }]
} }
} }
}); });
// Load plugin(s)
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-jsonlint');
grunt.loadNpmTasks("grunt-phplint");
grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-contrib-watch');
//grunt.loadNpmTasks('grunt-contrib-sass'); //grunt.loadNpmTasks('grunt-contrib-sass');
grunt.loadNpmTasks('grunt-sass'); grunt.loadNpmTasks('grunt-sass');
@@ -96,11 +185,36 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-csscomb'); grunt.loadNpmTasks('grunt-csscomb');
grunt.loadNpmTasks("grunt-markdown-pdf");
grunt.registerTask('default', [
// Javasript
'jshint',
'jsonlint',
'concat',
'uglify',
grunt.registerTask('default', ['watch']); // PHP
grunt.registerTask('build', ['uglify', 'imagemin']); 'phplint',
grunt.registerTask('c', ['csscomb']);
grunt.registerTask('s', ['sass']); // CSS
'csscomb',
'sass',
'autoprefixer',
// Utilities
'watch'
]);
grunt.registerTask('build', [
'concat',
'uglify',
'imagemin'
]);
grunt.registerTask('c', [
'csscomb'
]);
grunt.registerTask('s', [
'sass'
]);
}; };

16
project-x/charcoal.php Normal file
View File

@@ -0,0 +1,16 @@
<?php
/**
* Default front-end section controller
* Simply delegates initiation to the Boilerplate Module.
*/
// Project configuration and Charcoal instanciation
include 'config/config.php';
// Charcoal init
Charcoal::init();
// Project init (front-page controller)
$opts = [];
Boilerplate_Module::init($opts);

View File

@@ -0,0 +1,51 @@
{
"project_name":"Boilerplate",
"databases":{
"local":{
"database":"boilerplate",
"username":"root",
"password":""
},
"lab":{
"database":"",
"username":"",
"password":""
},
"live":{
"database":"",
"username":"",
"password":""
}
},
"default_database":"local",
"languages":{
"fr":{
"active":true
},
"en":{
"active":true
}
},
"default_language":"fr",
"modules":{
"admin":{},
"cms":{},
"newsletter":{},
"boilerplate":{}
},
"objects":{
},
"apis":{
},
"url_options":{
"use_rewrite":true
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* config.php
*/
// Error reporting
error_reporting(E_ALL & ~E_STRICT);
ini_set('display_errors', true);
// Environment defaults
date_default_timezone_set('America/Montreal');
// Main Charcoal include. This is where the Charcoal autoloader is defined.
include __DIR__.'/../charcoal/charcoal.php';
// JSON Configuration
Charcoal::add_config(__DIR__.'/config.json');
// Configuration overwrite
Charcoal::$config['ROOT'] = realpath(__DIR__).'/../';
Charcoal::$config['URL'] = 'http://'.$_SERVER['HTTP_HOST'].'/';

View File

@@ -1,22 +1,43 @@
<!doctype html> <!doctype html>
<html lang="fr"> <html lang="{{lang}}">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<base href="{{URL}}">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Project-x</title>
<link rel="icon" type="image/png" href="assets/images/favicon-16.png" sizes="16x16"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/png" href="assets/images/favicon-32.png" sizes="32x32"> <title>{{meta_title}}</title>
<link rel="apple-touch-icon-precomposed" href="assets/images/favicon-152.png">
<link rel="icon" type="image/png" href="{{#assets.images}}favicon-16.png{{/assets.images}}" sizes="16x16">
<link rel="icon" type="image/png" href="{{#assets.images}}favicon-32.png{{/assets.images}}" sizes="32x32">
<link rel="apple-touch-icon-precomposed" href="{{#assets.images}}favicon-152.png{{/assets.images}}">
<!--[if IE]><link rel="shortcut icon" href="assets/images/favicon-32.ico"><![endif]--> <!--[if IE]><link rel="shortcut icon" href="assets/images/favicon-32.ico"><![endif]-->
<link rel="stylesheet" href="assets/styles/dist/main.css"> <link rel="stylesheet" href="{{#assets.styles}}main.css{{/assets.styles}}">
<meta name="description" content="{{meta_description}}">
{{opengraph_tags}}
{{!-- Only include analytics if it is set in the configuration --}}
{{#cfg.google_analytics}}
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', '{{cfg.google_analytics}}', 'auto');
ga('send', 'pageview');
</script>
{{/cfg.google_analytics}}
{{!-- A final chance to have custom headers tags (like styles or scripts) in the controllers --}}
{{extra_header_content}}
</head> </head>
<body> <body>
<script src="assets/scripts/dist/main.js"></script> <!--<script src="modules/{{module}}/assets/scripts/dist/main.js"></script>-->
</body> </body>
</html> </html>

18
project-x/index.php Normal file
View File

@@ -0,0 +1,18 @@
<?php
/**
* Default front-end section controller
* Simply delegates initiation to the Boilerplate Module.
*/
// Project configuration and Charcoal instanciation
include 'config/config.php';
// Charcoal init
Charcoal::init();
// Project init (front-page controller)
$opts = [
'default_section' => Boilerplate_Config::get_latest()->default_section
];
Boilerplate_Module::init($opts);

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 13 13"><path fill="#222" d="M13 1.4l-1.5-1.4-5 5.1-5.1-5.1-1.4 1.4 5.1 5.2-5.1 5 1.5 1.4 5-5 5 5 1.4-1.4-5-5z"/></svg>

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="7.3" viewBox="0 0 13 7.3"><path fill="#3C3C3B" d="M6.5 7.3l3.3-3.7 3.2-3.6h-13l3.3 3.6z"/></svg>

After

Width:  |  Height:  |  Size: 155 B

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,630 @@
/**
* Project-x / Public Site
* ==========================================================================
*
*/
/* ==========================================================================
Imports
========================================================================== */
/* ==========================================================================
Settings
========================================================================== */
/* Typography
========================================================================== */
/* Colour Palette
========================================================================== */
/* Spacings
========================================================================== */
/* Z-index
========================================================================== */
/* Screen widths
========================================================================== */
/* Transitions
========================================================================== */
/*! normalize.css v3.0.1 | MIT License | git.io/normalize */
/**
* 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; }
/* HTML5 display definitions
========================================================================== */
/**
* Correct `block` display not defined for any HTML5 element in IE 8/9.
* Correct `block` display not defined for `details` or `summary` in IE 10/11 and Firefox.
* Correct `block` display not defined for `main` in IE 11.
*/
article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary {
display: block; }
/**
* 1. Correct `inline-block` display not defined in IE 8/9.
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
*/
audio, canvas, progress, video {
display: inline-block;
/* 1 */
vertical-align: baseline;
/* 2 */ }
/**
* Prevent modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
audio:not([controls]) {
display: none;
height: 0; }
/**
* Address `[hidden]` styling not present in IE 8/9/10.
* Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
*/
[hidden], template {
display: none; }
/* Links
========================================================================== */
/**
* Remove the gray background color from active links in IE 10.
*/
a {
background: transparent; }
/**
* Improve readability when focused and also mouse hovered in all browsers.
*/
a:active, a:hover {
outline: 0; }
/* Text-level semantics
========================================================================== */
/**
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
*/
abbr[title] {
border-bottom: 1px dotted; }
/**
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
*/
b, strong {
font-weight: bold; }
/**
* Address styling not present in Safari and Chrome.
*/
dfn {
font-style: italic; }
/**
* Address variable `h1` font-size and margin within `section` and `article`
* contexts in Firefox 4+, Safari, and Chrome.
*/
h1 {
font-size: 2em;
margin: 0.67em 0; }
/**
* Address styling not present in IE 8/9.
*/
mark {
color: #000000;
background: #FFFF00; }
/**
* 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/10.
*/
img {
border: 0; }
/**
* Correct overflow not hidden in IE 9/10/11.
*/
svg:not(:root) {
overflow: hidden; }
/* Grouping content
========================================================================== */
/**
* Address margin not present in IE 8/9 and Safari.
*/
figure {
margin: 1em 40px; }
/**
* Address differences between Firefox and other browsers.
*/
hr {
box-sizing: content-box;
height: 0; }
/**
* Contain overflow in all browsers.
*/
pre {
overflow: auto; }
/**
* Address odd `em`-unit font size rendering in all browsers.
*/
code, kbd, pre, samp {
font-family: monospace, monospace;
font-size: 1em; }
/* Forms
========================================================================== */
/**
* Known limitation: by default, Chrome and Safari on OS X allow very limited
* styling of `select`, unless a `border` property is set.
*/
/**
* 1. Correct color not being inherited.
* Known issue: affects color of disabled elements.
* 2. Correct font properties not being inherited.
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
*/
button, input, optgroup, select, textarea {
font: inherit;
/* 2 */
margin: 0;
/* 3 */
color: inherit;
/* 1 */ }
/**
* Address `overflow` set to `hidden` in IE 8/9/10/11.
*/
button {
overflow: visible; }
/**
* 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 Firefox, IE 8/9/10/11, and Opera.
* Correct `select` style inheritance in Firefox.
*/
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"], input[type="reset"], input[type="submit"] {
cursor: pointer;
/* 3 */
-webkit-appearance: button;
/* 2 */ }
/**
* Re-set default cursor for disabled elements.
*/
button[disabled], html input[disabled] {
cursor: default; }
/**
* Remove inner padding and border in Firefox 4+.
*/
button::-moz-focus-inner, input::-moz-focus-inner {
padding: 0;
border: 0; }
/**
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
input {
line-height: normal; }
/**
* It's recommended that you don't attempt to style these elements.
* Firefox's implementation doesn't respect box-sizing, padding, or width.
*
* 1. Address box sizing set to `content-box` in IE 8/9/10.
* 2. Remove excess padding in IE 8/9/10.
*/
input[type="checkbox"], input[type="radio"] {
box-sizing: border-box;
/* 1 */
padding: 0;
/* 2 */ }
/**
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
* `font-size` values of the `input`, it causes the cursor style of the
* decrement button to change from `default` to `text`.
*/
input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button {
height: auto; }
/**
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome
* (include `-moz` to future-proof).
*/
input[type="search"] {
/* 2 */
box-sizing: content-box;
-webkit-appearance: textfield;
/* 1 */ }
/**
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
* Safari (but not Chrome) clips the cancel button when the search input has
* padding (and `textfield` appearance).
*/
input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none; }
/**
* Define consistent border, margin, and padding.
*/
fieldset {
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
border: 1px solid #C0C0C0; }
/**
* 1. Correct `color` not being inherited in IE 8/9/10/11.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
*/
legend {
padding: 0;
/* 2 */
border: 0;
/* 1 */ }
/**
* Remove default vertical scrollbar in IE 8/9/10/11.
*/
textarea {
overflow: auto; }
/**
* Don't inherit the `font-weight` (applied by a rule above).
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
*/
optgroup {
font-weight: bold; }
/* Tables
========================================================================== */
/**
* Remove most spacing between table cells.
*/
table {
border-spacing: 0;
border-collapse: collapse; }
td, th {
padding: 0; }
/* ==========================================================================
Fonts
========================================================================== */
/* ==========================================================================
Base
========================================================================== */
*, *:before, *:after {
box-sizing: inherit; }
html {
font-family: sans-serif;
font-size: 16px;
line-height: 1.4;
box-sizing: border-box;
font-size: 16px;
font-family: sans-serif;
line-height: 1.4;
color: #222222; }
::-moz-selection {
background: #B3D4FC;
text-shadow: none; }
::selection {
background: #B3D4FC;
text-shadow: none; }
hr {
display: block;
height: 1px;
margin: 1em 0;
padding: 0;
border: 0;
border-top: 1px solid #CCCCCC; }
img, svg {
max-width: 100%;
vertical-align: middle; }
textarea {
resize: vertical; }
a {
color: #1A0DAB; }
a:hover {
color: #11097c; }
.container {
position: relative;
margin: 0 auto; }
/* ==========================================================================
Grid
========================================================================== */
.grid {
font-size: 0;
position: relative;
margin-left: -20px; }
.grid--full {
margin-left: 0; }
.grid--full .grid__item, .grid--full .whole, .grid--full .half, .grid--full .third, .grid--full .two-thirds, .grid--full .quarter, .grid--full .fifth {
margin-bottom: 0;
padding-left: 0; }
.grid__item, .whole, .half, .third, .two-thirds, .quarter, .fifth {
display: inline-block;
width: 100%;
margin-bottom: 20px;
padding-left: 20px;
vertical-align: top; }
@media (min-width: 1024px) {
.half {
width: 50%; } }
@media (min-width: 1024px) {
.third {
width: span(0.33333); } }
@media (min-width: 1024px) {
.two-thirds {
width: span(0.66667); } }
@media (min-width: 768px) {
.quarter {
width: 50%; } }
@media (min-width: 1024px) {
.quarter {
width: span(0.25); } }
@media (min-width: 768px) {
.fifth {
width: 50%; } }
@media (min-width: 1024px) {
.fifth {
width: span(0.2); } }
/* ==========================================================================
Headings
========================================================================== */
h1, .h1, .alpha {
font-size: 32px;
line-height: 1.2;
margin-top: 0; }
h2, .h2, .beta {
font-size: 24px;
line-height: 1.2;
margin-top: 0; }
h3, .h3, .gamma {
font-size: 19px;
line-height: 1.2;
margin-top: 0; }
h4, .h4, .delta {
font-size: 16px;
line-height: 1.2;
margin-top: 0; }
h5, .h5, .epsilon {
font-size: 13px;
line-height: 1.2;
margin-top: 0; }
h6, .h6, .zeta {
font-size: 11px;
line-height: 1.2;
margin-top: 0; }
/* ==========================================================================
Forms | http://codepen.io/AntoineBoulanger/pen/uBJmi
========================================================================== */
/* Input
========================================================================== */
.input, .select__input, .checkbox__check {
background-color: #cccccc;
display: block;
width: 100%;
color: #000000;
border: none;
border-radius: 0;
outline: none;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none; }
/* Select
========================================================================== */
.select {
display: block;
position: relative; }
.select:after {
content: "";
position: absolute;
top: 0;
right: 0;
width: 30px;
height: 100%;
display: block;
background-color: #ccc;
background-image: url('../../images/select-arrow.svg');
background-repeat: no-repeat;
background-position: center;
pointer-events: none; }
.select__input {
padding-right: 30px; }
.select__input::-ms-expand {
display: none; }
/* Checkbox
========================================================================== */
.checkbox {
display: inline-block; }
.checkbox__input {
display: none; }
.checkbox__input:checked + .checkbox__check:after {
visibility: visible; }
.checkbox__check {
display: inline-block;
width: 25px;
height: 25px; }
.checkbox__check:after {
content: "";
display: block;
background-image: url('../../images/check.svg');
background-repeat: no-repeat;
background-position: center;
width: 25px;
height: 25px;
visibility: hidden; }
/* ==========================================================================
Functions
========================================================================== */
/* ==========================================================================
Mixins
========================================================================== */
/* ==========================================================================
Helpers
========================================================================== */
.clearfix:before, .clearfix:after {
display: table;
content: " "; }
.clearfix:after {
clear: both; }
.center-vertically {
height: 100%;
text-align: center; }
.center-vertically:before {
display: inline-block;
height: 100%;
content: "";
vertical-align: middle; }
.center-vertically > * {
display: inline-block;
vertical-align: middle; }
/* ==========================================================================
Trumps
========================================================================== */
.left {
float: left !important; }
.right {
float: right !important; }
.align-left {
text-align: left !important; }
.align-right {
text-align: right !important; }
.align-center {
text-align: center !important; }
.is-visible {
visibility: visible !important;
opacity: 1 !important; }
.is-hidden {
visibility: hidden !important;
opacity: 0 !important; }
/* Accessibility
========================================================================== */
/*
* Hide visually and from screen readers: h5bp.com/u
*/
.hidden {
display: none !important;
visibility: hidden; }
/*
* Hide only visually, but have it available for screen readers: h5bp.com/v
*/
.visuallyhidden {
position: absolute;
overflow: hidden;
clip: rect(0 0 0 0);
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
border: 0; }
/*
* Extends the .visuallyhidden class to allow the element to be focusable
* when navigated to via the keyboard: h5bp.com/p
*/
.visuallyhidden.focusable:active, .visuallyhidden.focusable:focus {
position: static;
overflow: visible;
clip: auto;
width: auto;
height: auto;
margin: 0; }
/*
* Hide visually and from screen readers, but maintain layout
*/
.invisible {
visibility: hidden; }

View File

@@ -0,0 +1,21 @@
/* ==========================================================================
Imports
========================================================================== */
@import
"settings"
, "vendors/jacket"
, "base/normalize"
, "base/fonts"
, "base/base"
, "base/grid"
, "base/headings"
, "base/forms"
, "tools/functions"
, "tools/mixins"
, "generic/helpers"
, "generic/trumps"
;

View File

@@ -0,0 +1,60 @@
/* ==========================================================================
Settings
========================================================================== */
/* Typography
========================================================================== */
$font-size: 16px;
$line-height: 1.4;
$font-family: sans-serif;
$color: #222222;
//
$heading1: 32px; // .alpha
$heading2: 24px; // .beta
$heading3: 19px; // .gamma
$heading4: 16px; // .delta
$heading5: 13px; // .epsilon
$heading6: 11px; // .zeta
$heading-line-height: 1.2;
//
$milli-size: 10px !default;
$micro-size: 8px !default;
/* Colour Palette
========================================================================== */
$black: #000000;
$white: #FFFFFF;
//
$link: #1A0DAB;
$link-hover: darken(#1A0DAB, 10%);
/* Spacings
========================================================================== */
$margin10: 10px;
$margin20: 20px;
$margin30: 30px;
$margin40: 40px;
/* Z-index
========================================================================== */
$z-index1: 50;
$z-index2: 150;
$z-index3: 250;
/* Screen widths
========================================================================== */
$from-tablet: 768px;
$to-tablet: $from-tablet - 1;
$from-desktop: 1024px;
$to-desktop: $from-desktop - 1;
$from-laptop: 1280px;
$to-laptop: $from-laptop - 1;
$from-wide: 1680px;
$to-wide: $from-wide - 1;
/* Transitions
========================================================================== */
$speed: 0.3s;

View File

@@ -0,0 +1,59 @@
/* ==========================================================================
Base
========================================================================== */
*, *:before, *:after {
box-sizing: inherit;
}
html {
font-family: $font-family;
font-family: $font-family;
font-size: $font-size;
font-size: $font-size;
line-height: $line-height;
line-height: $line-height;
box-sizing: border-box;
color: $color;
}
::selection {
background: #B3D4FC;
text-shadow: none;
}
hr {
display: block;
height: 1px;
margin: 1em 0;
padding: 0;
border: 0;
border-top: 1px solid #CCCCCC;
}
img, svg {
max-width: 100%;
vertical-align: middle;
}
textarea {
resize: vertical;
}
a {
color: $link;
&:hover {
color: $link-hover;
}
}
.container {
position: relative;
margin: 0 auto;
}

View File

@@ -0,0 +1,3 @@
/* ==========================================================================
Fonts
========================================================================== */

View File

@@ -0,0 +1,103 @@
/* ==========================================================================
Forms | http://codepen.io/AntoineBoulanger/pen/uBJmi
========================================================================== */
/* Input
========================================================================== */
.input {
display: block;
width: 100%;
color: $black;
border: none;
border-radius: 0;
outline: none;
background-color: #CCCCCC;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
/* Select
========================================================================== */
// Wrapper
.select {
position: relative;
display: block;
// Select arrow
&:after {
position: absolute;
top: 0;
right: 0;
display: block;
width: 30px;
height: 100%;
content: "";
pointer-events: none;
background-color: #CCCCCC;
background-image: url("../../images/select-arrow.svg");
background-repeat: no-repeat;
background-position: center;
}
}
// Select
.select__input {
padding-right: 30px;
@extend .input;
&::-ms-expand {
display: none;
}
}
/* Checkbox
========================================================================== */
// Wrapper
.checkbox {
display: inline-block;
}
// Real input hidden
.checkbox__input {
display: none;
&:checked {
+ .checkbox__check {
&:after {
visibility: visible;
}
}
}
}
// Fake input visible
.checkbox__check {
display: inline-block;
width: 25px;
height: 25px;
@extend .input;
&:after {
display: block;
visibility: hidden;
width: 25px;
height: 25px;
content: "";
background-image: url("../../images/check.svg");
background-repeat: no-repeat;
background-position: center;
}
}

View File

@@ -0,0 +1,81 @@
/* ==========================================================================
Grid
========================================================================== */
.grid {
font-size: 0;
position: relative;
margin-left: -$margin20;
}
.grid--full {
margin-left: 0;
.grid__item {
margin-bottom: 0;
padding-left: 0;
}
}
.grid__item {
display: inline-block;
width: 100%;
margin-bottom: $margin20;
padding-left: $margin20;
vertical-align: top;
}
.whole {
@extend .grid__item;
}
.half {
@extend .grid__item;
@media (min-width: $from-desktop) {
width: 50%;
}
}
.third {
@extend .grid__item;
@media (min-width: $from-desktop) {
width: span(1/3);
}
}
.two-thirds {
@extend .grid__item;
@media (min-width: $from-desktop) {
width: span(2/3);
}
}
.quarter {
@extend .grid__item;
@media (min-width: $from-tablet) {
width: 50%;
}
@media (min-width: $from-desktop) {
width: span(1/4);
}
}
.fifth {
@extend .grid__item;
@media (min-width: $from-tablet) {
width: 50%;
}
@media (min-width: $from-desktop) {
width: span(1/5);
}
}

View File

@@ -0,0 +1,44 @@
/* ==========================================================================
Headings
========================================================================== */
h1, .h1, .alpha {
font-size: $heading1;
line-height: $heading-line-height;
margin-top: 0;
}
h2, .h2, .beta {
font-size: $heading2;
line-height: $heading-line-height;
margin-top: 0;
}
h3, .h3, .gamma {
font-size: $heading3;
line-height: $heading-line-height;
margin-top: 0;
}
h4, .h4, .delta {
font-size: $heading4;
line-height: $heading-line-height;
margin-top: 0;
}
h5, .h5, .epsilon {
font-size: $heading5;
line-height: $heading-line-height;
margin-top: 0;
}
h6, .h6, .zeta {
font-size: $heading6;
line-height: $heading-line-height;
margin-top: 0;
}

View File

@@ -0,0 +1,404 @@
/*! normalize.css v3.0.1 | MIT License | git.io/normalize */
/**
* 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;
}
/* HTML5 display definitions
========================================================================== */
/**
* Correct `block` display not defined for any HTML5 element in IE 8/9.
* Correct `block` display not defined for `details` or `summary` in IE 10/11 and Firefox.
* Correct `block` display not defined for `main` in IE 11.
*/
article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary {
display: block;
}
/**
* 1. Correct `inline-block` display not defined in IE 8/9.
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
*/
audio, canvas, progress, video {
display: inline-block; /* 1 */
vertical-align: baseline; /* 2 */
}
/**
* Prevent modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/**
* Address `[hidden]` styling not present in IE 8/9/10.
* Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
*/
[hidden], template {
display: none;
}
/* Links
========================================================================== */
/**
* Remove the gray background color from active links in IE 10.
*/
a {
background: transparent;
}
/**
* Improve readability when focused and also mouse hovered in all browsers.
*/
a:active, a:hover {
outline: 0;
}
/* Text-level semantics
========================================================================== */
/**
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
*/
abbr[title] {
border-bottom: 1px dotted;
}
/**
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
*/
b, strong {
font-weight: bold;
}
/**
* Address styling not present in Safari and Chrome.
*/
dfn {
font-style: italic;
}
/**
* Address variable `h1` font-size and margin within `section` and `article`
* contexts in Firefox 4+, Safari, and Chrome.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/**
* Address styling not present in IE 8/9.
*/
mark {
color: #000000;
background: #FFFF00;
}
/**
* 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/10.
*/
img {
border: 0;
}
/**
* Correct overflow not hidden in IE 9/10/11.
*/
svg:not(:root) {
overflow: hidden;
}
/* Grouping content
========================================================================== */
/**
* Address margin not present in IE 8/9 and Safari.
*/
figure {
margin: 1em 40px;
}
/**
* Address differences between Firefox and other browsers.
*/
hr {
-moz-box-sizing: content-box;
box-sizing: content-box;
height: 0;
}
/**
* Contain overflow in all browsers.
*/
pre {
overflow: auto;
}
/**
* Address odd `em`-unit font size rendering in all browsers.
*/
code, kbd, pre, samp {
font-family: monospace, monospace;
font-size: 1em;
}
/* Forms
========================================================================== */
/**
* Known limitation: by default, Chrome and Safari on OS X allow very limited
* styling of `select`, unless a `border` property is set.
*/
/**
* 1. Correct color not being inherited.
* Known issue: affects color of disabled elements.
* 2. Correct font properties not being inherited.
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
*/
button, input, optgroup, select, textarea {
font: inherit; /* 2 */
margin: 0; /* 3 */
color: inherit; /* 1 */
}
/**
* Address `overflow` set to `hidden` in IE 8/9/10/11.
*/
button {
overflow: visible;
}
/**
* 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 Firefox, IE 8/9/10/11, and Opera.
* Correct `select` style inheritance in Firefox.
*/
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"] {
cursor: pointer; /* 3 */
-webkit-appearance: button; /* 2 */
}
/**
* Re-set default cursor for disabled elements.
*/
button[disabled], html input[disabled] {
cursor: default;
}
/**
* Remove inner padding and border in Firefox 4+.
*/
button::-moz-focus-inner, input::-moz-focus-inner {
padding: 0;
border: 0;
}
/**
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
input {
line-height: normal;
}
/**
* It's recommended that you don't attempt to style these elements.
* Firefox's implementation doesn't respect box-sizing, padding, or width.
*
* 1. Address box sizing set to `content-box` in IE 8/9/10.
* 2. Remove excess padding in IE 8/9/10.
*/
input[type="checkbox"], input[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
* `font-size` values of the `input`, it causes the cursor style of the
* decrement button to change from `default` to `text`.
*/
input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome
* (include `-moz` to future-proof).
*/
input[type="search"] {
-webkit-box-sizing: content-box; /* 2 */
-moz-box-sizing: content-box;
box-sizing: content-box;
-webkit-appearance: textfield; /* 1 */
}
/**
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
* Safari (but not Chrome) clips the cancel button when the search input has
* padding (and `textfield` appearance).
*/
input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* Define consistent border, margin, and padding.
*/
fieldset {
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
border: 1px solid #C0C0C0;
}
/**
* 1. Correct `color` not being inherited in IE 8/9/10/11.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
*/
legend {
padding: 0; /* 2 */
border: 0; /* 1 */
}
/**
* Remove default vertical scrollbar in IE 8/9/10/11.
*/
textarea {
overflow: auto;
}
/**
* Don't inherit the `font-weight` (applied by a rule above).
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
*/
optgroup {
font-weight: bold;
}
/* Tables
========================================================================== */
/**
* Remove most spacing between table cells.
*/
table {
border-spacing: 0;
border-collapse: collapse;
}
td, th {
padding: 0;
}

View File

@@ -0,0 +1,33 @@
/* ==========================================================================
Helpers
========================================================================== */
.clearfix:before, .clearfix:after {
display: table;
content: " ";
}
.clearfix:after {
clear: both;
}
.center-vertically {
height: 100%;
text-align: center;
&:before {
display: inline-block;
height: 100%;
content: "";
vertical-align: middle;
}
> * {
display: inline-block;
vertical-align: middle;
}
}

View File

@@ -0,0 +1,87 @@
/* ==========================================================================
Trumps
========================================================================== */
.left {
float: left !important;
}
.right {
float: right !important;
}
.align-left {
text-align: left !important;
}
.align-right {
text-align: right !important;
}
.align-center {
text-align: center !important;
}
.is-visible {
visibility: visible !important;
opacity: 1 !important;
}
.is-hidden {
visibility: hidden !important;
opacity: 0 !important;
}
/* Accessibility
========================================================================== */
/*
* Hide visually and from screen readers: h5bp.com/u
*/
.hidden {
display: none !important;
visibility: hidden;
}
/*
* Hide only visually, but have it available for screen readers: h5bp.com/v
*/
.visuallyhidden {
position: absolute;
overflow: hidden;
clip: rect(0 0 0 0);
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
border: 0;
}
/*
* Extends the .visuallyhidden class to allow the element to be focusable
* when navigated to via the keyboard: h5bp.com/p
*/
.visuallyhidden.focusable:active, .visuallyhidden.focusable:focus {
position: static;
overflow: visible;
clip: auto;
width: auto;
height: auto;
margin: 0;
}
/*
* Hide visually and from screen readers, but maintain layout
*/
.invisible {
visibility: hidden;
}

View File

@@ -0,0 +1,8 @@
/**
* Project-x / Public Site
* ==========================================================================
*
*/
$jacket: vanilla;
@import "import";

View File

@@ -0,0 +1,14 @@
/* ==========================================================================
Functions
========================================================================== */
@function em($px, $base: $font-size) {
@return ($px / $base) * 1em;
}
@function rem($px, $base: $font-size) {
@return ($px / $base) * 1rem;
}
@function span($fraction) {
@return $fraction * 100%;
}

View File

@@ -0,0 +1,3 @@
/* ==========================================================================
Mixins
========================================================================== */

View File

@@ -0,0 +1,112 @@
///////////////////////////////////////////////////////////
// Jacket
// Conditional Styles with Sass. Dress you CSS appropriately.
///////////////////////////////////////////////////////////
// Jacket is a Compass component that prints and hides styles based on
// context variables you set in your stylesheet. Write and maintain a master
// stylesheet, then output custom tailored stylesheets for modern and legacy
// browsers, site and app builds, or any other context you can think of.
///////////////////////////////////////////////////////////
// Settings variables
///////////////////////////////////////////////////////////
// Default list of jacket contexts.
$jacket: null !default;
// Private variable used by jacket-context().
$jckt-context: null;
///////////////////////////////////////////////////////////
// Jacket mixin
// Takes a list of jacket contexts.
// Outputs a block of styles if a context is set.
///////////////////////////////////////////////////////////
@mixin jacket($contexts...) {
$naked: false;
$selectors: ();
$filtered: ();
$selector-string: '';
// Set the global context variable.
$jckt-context: $contexts;
// If jacket is a single context and selector list, encapsulate.
@if list-separator($jacket) == 'space' {
$jacket: $jacket, null;
}
// Test if a jacket context and jacket value match.
@each $item in $jacket {
@each $context in $contexts {
@if index($context, nth($item, 1)) {
// Gather wrapping selectors.
@if length($item) == 1 {
$naked: true;
}
@if length($item) == 2 {
$selectors: append($selectors, nth($item, 2) + ' &');
}
}
}
}
// Filter out duplicate selectors.
// If reject() is added to Sass we can remove the $filtered holder variable.
@each $selector in $selectors {
@if index($filtered, $selector) == false {
$filtered: append($filtered, $selector);
}
}
// Build the selector string.
@each $selector in $filtered {
@if $selector-string != '' {
$selector-string: $selector-string + ", ";
}
$selector-string: $selector-string + $selector;
}
// If the weather is right, output that jacketed code!
@if $naked {
@content;
}
@if $selector-string != '' {
#{$selector-string} {
@content;
}
}
}
///////////////////////////////////////////////////////////
// Jacket function
// Takes a list of jacket contexts.
// Outputs a value if a context is set.
///////////////////////////////////////////////////////////
@function jacket($value, $contexts...) {
@each $item in $jacket {
@each $context in $contexts {
@if index($context, nth($item, 1)) {
// If the weather is right, return the value!
@return $value;
}
}
}
// Else return null. If null is the only value for a selector, the selector
// will not be printed.
@return null;
}
///////////////////////////////////////////////////////////
// Jacket Context function
// Takes a jacket context value. Use when code inside a jacket
// needs to know if a specific jacket context is set.
///////////////////////////////////////////////////////////
@function jacket-context($context) {
@return if(index($jckt-context, $context), true, false);
}

View File

@@ -0,0 +1,123 @@
<?php
/**
* Boilerplate Action - Contact
*
* This action handles the "contact" form from the contact template
*
* It validates a CSRF token and create a CMS_Contact object from the POST data.
*
* ## Expected POST values:
* - csrf-token, string - A CSRF token (Charcoal::token() with ident "boilerplate.contact")
* - lastname
* - firstname
* - phone
* - email
* - subject
* - message
* - lang
*
* ## Optional POST values
* - referer, string - The URL to go back to
*
* ## CMS_Contact
* Contacts can be seen in the charcoal backend at url:
* [/admin/object-list-dashboard?obj_type=CMS_Contact]
*
* ## CMS_Contact_Category
* This action is bound to the CMS_Contact_Category object with id=1. This category:
* - Send confirmation email automatically
* - With email template boilerplate.contact-confirmation
* - May have CC and BCC to administratotors
*
* This object can be seen int he charcoal backend at url:
* [/admin/object-edit-dashboard?obj_type=CMS_Contact_Category&obj_id=1]
*
* ## TODOs
* - Support ajax request / json response
*
* @category Boilerplate
* @package Boilerplate.Action
* @subpackage Actions
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2012-08-01
* @link http://locomotive.ca
* @since Version 2014-07-01
*/
// Get referer
$referer = '';
if(isset($_POST['referer'])) {
$referer = filter_input(INPUT_POST, 'referer', FILTER_SANITIZE_STRING);
}
else if(isset($_SERVER['HTTP_REFERER'])) {
$referer = $_SERVER['HTTP_REFERER'];
}
else {
// None set: Use contact form
$referer = Charcoal::obj('CMS_Section')->load_from('ident', 'contact')->url();
}
function _header_error($msg='')
{
global $referer;
if(headers_sent()) {
// Error, cant send headers. Should never happened
die();
}
header('Location: '.$referer.'?contact-success=0&msg='.urlencode($msg));
die();
}
function _header_success($msg='')
{
global $referer;
if(headers_sent()) {
// Error, cant send headers. Should never happened
die();
}
header('Location: '.$referer.'?contact-success=1&msg='.urlencode($msg));
die();
die();
}
// Validate CSRF token
$csrf_token = filter_input(INPUT_POST, 'csrf-token', FILTER_SANITIZE_STRING);
if(!Charcoal::token_validate($csrf_token, 'boilerplate.contact')) {
Charcoal::feedback('error', 'send_contact', _t("Your session has expired. Please try again"));
_headers_error();
}
// Create and save the Contact object
$contact = Charcoal::obj('CMS_Contact');
$contact->from_flat_data($_POST);
// Hardcoded to the general contact category
$contact->category = 1;
$validations = $contact->validate();
if(!$validations){
//pre($contact);
// Saving the contact sends the email confirmatino automatically, according to the category
$contact_id = $contact->save();
if($contact_id) {
_header_success()_t("Successful.");
}
else {
_headers_error(_t("Error saving contact"));
}
}
else {
$msg = '';
foreach($validations as $property=>$messages){
foreach($messages as $m){
$msg .= $m.'<br />';
}
}
_headers_error($msg);
}

View File

@@ -0,0 +1,13 @@
<?php
/**
*
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Objects
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/

View File

@@ -0,0 +1,38 @@
<?php
/**
* Contact form section
*
* @category Boilerplate
* @package Boilerplate.Templates
* @subpackage Templates
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
?>
{{>boilerplate.inc.header}}
<section class="contact {{section.ident}}">
<h1>{{section.p.title}}</h1>
<h2>{{section.p.subtitle}}</h2>
<div class="section-summary">
{{section.p.summary.display}}
</div>
<div class="section-description">
{{section.p.content.display}}
</div>
<form method="post">
</form>
</section>
{{>boilerplate.inc.footer}}

View File

@@ -0,0 +1,35 @@
<?php
/**
*
* @category Boilerplate
* @package Boilerplate.Templates
* @subpackage Templates
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
?>
{{>boilerplate.inc.header}}
<section class="content {{section.ident}}">
<h1>{{section.p.title}}</h1>
<h2>{{section.p.subtitle}}</h2>
<div class="section-summary">
{{section.p.summary.display}}
</div>
<div class="section-description">
{{section.p.content.display}}
</div>
</section>
{{>boilerplate.inc.footer}}

View File

@@ -0,0 +1,25 @@
<?php
/**
*
* @category Boilerplate
* @package Boilerplate.Templates
* @subpackage Templates
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
?>
{{>boilerplate.inc.header}}
<section class="home {{section.ident}}">
<h1>{{section.p.title}}</h1>
</section>
{{>boilerplate.inc.footer}}

View File

@@ -0,0 +1,4 @@
<!--<script src="modules/{{module}}/assets/scripts/dist/main.js"></script>-->
</body>
</html>

View File

@@ -0,0 +1,38 @@
<!doctype html>
<html lang="{{lang}}">
<head>
<meta charset="utf-8">
<base href="{{URL}}">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{meta_title}}</title>
<link rel="icon" type="image/png" href="{{#assets.images}}favicon-16.png{{/assets.images}}" sizes="16x16">
<link rel="icon" type="image/png" href="{{#assets.images}}favicon-32.png{{/assets.images}}" sizes="32x32">
<link rel="apple-touch-icon-precomposed" href="{{#assets.images}}favicon-152.png{{/assets.images}}">
<!--[if IE]><link rel="shortcut icon" href="assets/images/favicon-32.ico"><![endif]-->
<link rel="stylesheet" href="modules/{{module}}/assets/styles/dist/main.css">
<meta name="description" content="{{meta_description}}">
{{opengraph_tags}}
{{! Only include analytics if it is set in the configuration}}
{{#cfg.google_analytics}}
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', '{{cfg.google_analytics}}', 'auto');
ga('send', 'pageview');
</script>
{{/cfg.google_analytics}}
{{!A final chance to have custom headers tags (like styles or scripts) in the controllers}}
{{extra_header_content}}
</head>
<body>

View File

@@ -0,0 +1,181 @@
<?php
/**
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Objects
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
/**
* Boilerplate configuration
*
* The latest (current) object can always be used by calling:
* ```php
* $cfg = \Boilerplate\Config::get_latest();
* ```
*
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Objects
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
class Boilerplate_Config extends \Charcoal_Object
{
/**
* Google Analytics code
* @var string $google_analytics
* @see Property_String
*/
public $google_analytics;
/**
* Default section
* The section to load when reaching the default base URL.
* Also, usually the section to load when clicking on the main link / logo
* @var mixed $default_section
* @see Property_Object
* @see CMS_Section
*/
public $default_section;
/**
* Default lang
* @var string $default_lang
* @see Property_Lang
*/
public $default_lang;
/**
* URL of the related facebook page
* @var string $social_facebook_url
* @see Property_Url
*/
public $social_facebook_url;
/**
* URL of the related twitter account
* @var string $social_twitter_url
* @see Property_Url
*/
public $social_twitter_url;
/**
* URL of the related google+ page
* @var string $social_facebook_url
* @see Property_Url
*/
public $social_google_url;
/**
* URL of the related instagram page
* @var string $social_instagram_url
* @see Property_Url
*/
public $social_instagram_url;
/**
* URL of the related flickr page
* @var string $social_flickr_url
* @see Property_Url
*/
public $social_flickr_url;
/**
* URL of the related youtube page
* @var string $social_youtube_url
* @see Property_Url
*/
public $social_youtube_url;
/**
* Default title, if none is specified
* - l10n: true
* @var mixed $meta_default_title
* @see Property_String
*/
public $meta_default_title;
/**
* Default title, if none is specified
* - l10n: true
* @var mixed $meta_default_prefix
* @see Property_String
*/
public $meta_title_prefix;
/**
* Default title, if none is specified
* - l10n: true
* @var mixed $meta_default_suffix
* @see Property_String
*/
public $meta_title_suffix;
/**
* Default title, if none is specified
* - l10n: true
* @var mixed $meta_default_description
* @see Property_Text
*/
public $meta_default_description;
/**
* Default title, if none is specified
* - l10n: true
* - upload_path: "uploads/config/meta_image/"
* @var mixed $meta_default_image
* @see Property_Image
*/
public $meta_default_image;
/**
* Default meta-keywords, if none is specified
* - l10n: true
* - multiple: true
* @var mixed $meta_default_keywords
* @see Property_String
*/
public $meta_default_keywords;
/**
* Static getter of the latest config
*
* This is the preferred way of loading the Configuration object.
*
* It will only be loaded 1 time from the configuration, otherwie, it will be stored
* in a static variable.
*
* @return static Corim_Config
* @todo Use APC instead of static, if available
*/
static public function get_latest()
{
static $_cached;
$cache_key = 'latest_boilerplate_config';
if($_cached instanceof self) {
// Load from static if possible
return $_cached;
}
else {
// Load from DB otherwise
$_cached = Charcoal::obj( __CLASS__ );
$_cached->load_latest();
return $_cached;
}
}
/**
* @return Corim_Config
*/
public function load_latest()
{
// Hardcoded to ID 1
$this->load_key('id', 1);
// Chainable
return $this;
}
}

View File

@@ -0,0 +1,87 @@
<?php
/**
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Objects
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
/**
* The Boilerplate Module class
*
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Objects
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
class Boilerplate_Module extends Charcoal_Module
{
/**
* Module initialisation
*
* This function should act as both the initialization of the module and the front-page main controller.
*
* ## Options
* - default_action
* - default_section
* - default_lang
*
* @param array $opts
*
* @return null
*/
static public function init($opts=null)
{
// Make sure a session is started at all time. For tokens, some cache, user data, etc.
if (!session_id()) {
session_start();
}
// Get the latest configuration
$default_action = isset($opts['default_action']) ? $opts['default_action'] : '';
$default_section_id = isset($opts['default_section']) ? $opts['default_section'] : 0;
$default_lang = isset($opts['default_lang']) ? $opts['default_lang'] : 'fr';
// Load the action or section from the $_GET
$action = isset($_GET['action']) ? filter_input(INPUT_GET, 'action', FILTER_SANITIZE_STRING) : $default_action;
$section_id = isset($_GET['s']) ? filter_input(INPUT_GET, 's', FILTER_SANITIZE_STRING) : $default_section_id;
// Set up the language and the required CSV file
$lang = isset($_GET['lang']) ? filter_input(INPUT_GET, 'lang', FILTER_SANITIZE_STRING) : $default_lang;
$l = Charcoal_L10n::get();
$l->set_lang($lang);
$l->add_resource_csv('boilerplate', $lang);
if($section_id) {
// By section
$section_loader = new Charcoal\Object_Loader('CMS_Section');
$section = $section_loader->{$section_id};
pre($section);
if($section->template) {
// What to do?
}
echo Charcoal_Template::get($section->template)->render();
}
else if($action) {
// By action
\Charcoal::exec($action, $_REQUEST);
}
else {
// By nothing (404 page not found). This should never happen
die('404');
}
}
}

View File

@@ -0,0 +1,211 @@
<?php
/**
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Objects
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
/**
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Objects
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
class Boilerplate_Template_Controller extends Charcoal\Template_Controller
{
/**
* Keep a copy of the current section
*/
private $_section;
/**
* Keep a copy of the Section Object loader
* @var \Charcoal\Object_Loader
*/
private $_sections_loader;
/**
* Keep a copy of the Template loader
* @var \Charcoal\Template_Loader
*/
private $_templates_loader;
/**
* Keep a copy of the Widget Loader
* @var \Charcoal\Widget_Loader
*/
private $_widgets_loader;
/**
* Get the current project's main module
*
* @return string
*/
public function module()
{
return 'boilerplate';
}
/**
* Get the current
* (Previously, this would have been `Charcoal::$vars['section']`)
*
* @return CMS_Section
*/
public function section()
{
if(isset($this->_section)) {
return $this->_section;
}
$section_id = isset($_GET['s']) ? filter_input(INPUT_GET, 's', FILTER_SANITIZE_STRING) : '';
$section = \Charcoal::obj('CMS_Section');
if($section_id) {
$section->load($section_id);
}
$this->_section = $section;
return $section;
}
/**
* Get a `CMS_Section` Object Loader
*
* - Use "ident" as a key, so it can be called with {{sections.ident}}
* - Cache the result, so this almost never touches the DB.
*
* ## The `\Charcoal\Object_Loader` object
* Read the documentation on `\Charcoal\Object_Loader` for more details.
* In short, it allows to call the objects with `->texts()->ident;` // `{{sections.ident}}` to return (and load on-the-fly, if required)
* the `CMS_Text` object with the `ident` "ident".
*
* @return \Charcoal\Object_Loader
* @see CMS_Section
*/
public function sections()
{
if(!$this->_sections_loader) {
// Load the object, if it was not.
$this->_sections_loader = new \Charcoal\Object_Loader('CMS_Section', 'ident', 'cache');
}
return $this->_sections_loader;
}
/**
* Get a "CMS_Text" Object Loader
* - Use "ident" as a key, so it can be called with {{sections.ident}}
* - Cache the result, so this almost never touches the DB.
*
* ## The `\Charcoal\Object_Loader` object
* Read the documentation on `\Charcoal\Object_Loader` for more details.
* In short, it allows to call the objects with `->sections()->ident;` to return (and load on-the-fly, if required)
* the `CMS_Section` object with the `ident` "ident".
*
* @return \Charcoal\Object_Loader
* @see CMS_Text
*/
public function texts()
{
if(!$this->_texts_loader) {
// Load the (text loader) object, if it was not.
$this->_texts_loader = new \Charcoal\Object_Loader('CMS_Text', 'ident', 'cache');
}
return $this->_texts_loader;
}
/**
* Get the latest Config instance from DB / cache
*
* @return Config
*/
public function cfg()
{
return Config::get_latest();
}
/**
* Return the base URL
* Previously, this would have been `Charcoal::$config['URL']` (which still works)
*
* @return string
*/
public function URL()
{
return \Charcoal::$config['URL'];
}
/**
* Test templating.
*
* Allow to hide content under dev_mode
*
* @return boolean
*/
public function dev_mode()
{
return false;
}
/**
* Returns the current language (2-character / ISO-639-1)
*
* @return string
*/
public function lang()
{
return _l();
}
/**
* Assets getters
*
* This method returns an array of lambda functions, which in turn takes the argument
*
* ## Using with mustache
* In short, this allows to get an asset with the following mustache tag:
* - `{{#assets.images}}test.png{{/assets.images}}
*
* ## Asset types
* - images
* - styles
* - scripts
* - fonts
* - files
* Read the documentation on \Charcoal\Asset for more details on how assets are loaded relative to the filesystem.
*
* @return array
* @see \Charcoal\Asset
*/
public function assets($asset_mode='url')
{
$ret = [
'images' => function($txt) use ($asset_mode) {
return new \Charcoal\Asset('images', $txt, $asset_mode);
},
'styles' => function($txt) use ($asset_mode) {
return new \Charcoal\Asset('styles', $txt, $asset_mode);
},
'scripts' => function($txt) use ($asset_mode) {
return new \Charcoal\Asset('scripts', $txt, $asset_mode);
},
'fonts' => function($txt) use ($asset_mode) {
return new \Charcoal\Asset('fonts', $txt, $asset_mode);
},
'files' => function($txt) use ($asset_mode) {
return new \Charcoal\Asset('files', $txt, $asset_mode);
}
];
return $ret;
}
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Controllers
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
/**
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Controllers
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
class Template_Controller_Boilerplate_Contact extends Boilerplate_Template_Controller
{
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Controllers
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
/**
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Controllers
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
class Template_Controller_Boilerplate_Content extends Boilerplate_Template_Controller
{
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Controllers
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
/**
* @category Boilerplate
* @package Boilerplate.Objects
* @subpackage Controllers
*
* @author Mathieu Ducharme <mat@locomotive.ca>
* @copyright 2014 Locomotive
* @version 2014-10-01
* @link http://locomotive.ca
* @since Version 2014-10-01
*/
class Template_Controller_Boilerplate_Home extends Boilerplate_Template_Controller
{
}

View File

@@ -0,0 +1,3 @@
{
}

View File

@@ -0,0 +1,3 @@
{
}

View File

@@ -0,0 +1,5 @@
{
"url_options":{
"use_rewrite":true
}
}

View File

@@ -0,0 +1,3 @@
{
}

View File

@@ -0,0 +1,3 @@
{
}

View File

@@ -9,6 +9,9 @@
"devDependencies": { "devDependencies": {
"grunt": "0.4.5", "grunt": "0.4.5",
"load-grunt-tasks": "0.6.0", "load-grunt-tasks": "0.6.0",
"grunt-contrib-jshint": "^0.10.0",
"grunt-jsonlint": "^1.0.4",
"grunt-phplint": "0.0.5",
"grunt-contrib-watch": "0.6.1", "grunt-contrib-watch": "0.6.1",
"grunt-contrib-sass": "0.8.1", "grunt-contrib-sass": "0.8.1",
"grunt-sass": "0.14.0", "grunt-sass": "0.14.0",
@@ -17,7 +20,7 @@
"grunt-contrib-concat": "0.5.0", "grunt-contrib-concat": "0.5.0",
"grunt-contrib-uglify": "0.6.0", "grunt-contrib-uglify": "0.6.0",
"grunt-contrib-imagemin": "0.8.1", "grunt-contrib-imagemin": "0.8.1",
"grunt-csscomb": "3.0.0" "grunt-csscomb": "3.0.0",
"grunt-markdown-pdf": "^2.1.1"
} }
} }