diff --git a/.gitignore b/.gitignore index d16866a..d2e0a3a 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,6 @@ build/Release # Dependency directory # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git node_modules -build + +# Compiled Public Directory +public diff --git a/gulpfile.js b/Gulpfile.js similarity index 99% rename from gulpfile.js rename to Gulpfile.js index d3a76b1..44f5f45 100644 --- a/gulpfile.js +++ b/Gulpfile.js @@ -5,7 +5,6 @@ for creating multiple tasks, each task has been broken out into its own file in gulp/tasks. Any files in that directory get automatically required below. - To add a new task, simply add a new task file that directory. gulp/tasks/default.js specifies the default set of tasks to run when you run `gulp`. @@ -15,4 +14,3 @@ var requireDir = require('require-dir'); // Require all tasks in gulp/tasks, including subfolders requireDir('./gulp/tasks', { recurse: true }); - diff --git a/README.md b/README.md deleted file mode 100644 index d9d6c94..0000000 --- a/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# Week Seven - MEAN Stack II - -Last week we focussed on CRUD with Mongo, Node, and Angular. This week we're going to focus on using Angular to build a strictly client-side app, leveraging third-party APIs. You'll be expected to build on knowledge you've already learned and refactor last week's blog app to use Github Gists instead of your Node server and Mongo. - -We want this assignment to feel like a 'week on the job.' We'll be adding requirements throughout the week, on top of those listed here. - -## The spec - -The business has decided to outsource hosting of the company blog to a third party, and has decided to use Github Gists. Hosting of the app will be handled by a static web site host. - -You need to refactor the blog, removing any dependency on Node.js for the server and Mongo for the database. Replace your current Angular blog service with the [Gist API](https://developer.github.com/v3/gists/). - -### Requirements - -1. You will need to create a personal access token in your Github account - 1. [github.com/settings/tokens/new](https://github.com/settings/tokens/new) - 1. The only scopes you'll need are `gists` and `user` -1. Semantically correct HTML is required as this will be the model for prod app integration -1. Think in terms of '*components*'; if all parts of the UI were lego blocks, who would you code that? -1. All CSS measurements should use elastic units unless a pixel specific unit is required for both mobile and desktop -1. JavaScript code is expected to be written cleanly and maintainably using the best practices covered during lectures -1. Write up a description for every plugin used (no limit, but you must justify them) - 1. jQuery is not allowed. Angular's built-in DOM manipulation can manage most of what you'd need jQuery for. - -### Helpful resources - -These resources are useful, but you do _not_ need to use them. - -1. [Diff of the refactor from Monday's lecture](https://github.com/jedfoster/mean-stack-1/pull/1/files) -1. [Github.js](https://github.com/jedfoster/github) (my fork), a library that wraps the Github API - * The [original](https://github.com/michael/github) is just as good. -1. My factory to adapt Github.js for Angular [https://gist.github.com/jedfoster/f7b49fc6866fd3b4c7b5](https://gist.github.com/jedfoster/f7b49fc6866fd3b4c7b5) - -### Constraints - -1. Must work in all major browsers of latest versions; - * Desktop (IE Edge, Safari, Chrome, and Firefox) -1. All interactions must be clearly functional -1. All code must pass HTML Tidy, CSS Lint, and JSHint. - -__DO NOT__ fence yourself in with invisible constraints. Unless it is specifically listed and/or we discussed it in lecture, there is not an expectation to meet an objective that has not been set. - -## The expectation - -In this assignment, you should be able to demonstrate mastery of Angular as a platform for building client-side applications, including interacting with APIs. We're looking for you to build on best practices that you've already learned (proper HTML and CSS) as well as incorporate the new practices discussed during the course of the week. diff --git a/assignment-rules.md b/assignment-rules.md new file mode 100644 index 0000000..a5d1eb0 --- /dev/null +++ b/assignment-rules.md @@ -0,0 +1,15 @@ +# Rules for this assignment + +Please be sure to read carefully as this will be crucial for achieving the goals for this week's assignment project. + +1. I expect everyone to show up or be with their pair partner as soon as possible in the morning to review and start on the project, there is A LOT to do +1. Fork the assignment repo directly, no cross forking this time +1. Once someone has forked the repo, create the PR right away + 1. Give the PR a proper title and place `(wip)` in the title + 1. You can keep making updates to the `master` branch and push that to your repo, the PR will keep updating + 1. DO NOT submit a feature branch to the PR, only submit `master` + 1. Work in your feature branches and commit often until you are ready to merge in the code from the feature branch to `master` and the owner of the +1. In the PR, please be sure to write up a description of the project you are completing and submit the PR + 1. This will be the only PR that is used throughout this week's assignment +1. For the final assignment submission, update the PR title to remove `(wip)` and use `(final)`. Pushes to `master` after the title has been updated will be ignored, make sure you are done before you say you are done. +1. Make sure to submit the URL of the PR to Canvas for final grading diff --git a/gulp/config.js b/gulp/config.js old mode 100755 new mode 100644 index b58ac80..33397e0 --- a/gulp/config.js +++ b/gulp/config.js @@ -1,39 +1,46 @@ -var dest = "./build"; +var dest = "./public"; var src = './src'; module.exports = { javascript: { - src: src + '/js/**/*.js', + src: src + '/app/**/*.js', dest: dest + '/js/', - entry: src + '/js/app.js', - outputFilename: 'app.js' - }, - assets: { - src: src + "/assets/**/*", - dest: dest + '/assets/' + entryPoint: src + '/app/entry.js', + packedFile: 'packed.js' }, sass: { - src: src + "/css/**/*.{sass,scss}", - dest: dest + '/css/', + src: src + "/styles/**/*.{sass,scss}", + dest: dest + '/styles/', settings: { indentedSyntax: true, // Enable .sass syntax! } }, - html: { - src: src + '/**/*.html', + fonts: { + src: src + '/styles/fonts/*', + dest: dest + "/styles/fonts/", + extensions: ['woff2', 'woff', 'eot', 'ttf', 'svg'] + }, + index: { + src: src + "/index.html", dest: dest }, + html: { + src: src + "/app/**/*.html", + dest: dest + "/views/" + }, server: { src: dest, - livereload: true, + livereload: false, directoryListing: false, open: false, port: 9000 }, + ngConfig: { + dest: dest + '/js', + }, production: { - cssSrc: dest + '/css/*.css', - jsSrc: dest + '/js/*.js', - cssDest: dest + '/css/', - jsDest: dest + '/js/', + cssSrc: dest + '/styles/*.css', + jsSrc: dest + '/*.js', + dest: dest } }; diff --git a/gulp/tasks/assets.js b/gulp/tasks/assets.js deleted file mode 100644 index 460b22d..0000000 --- a/gulp/tasks/assets.js +++ /dev/null @@ -1,9 +0,0 @@ -var gulp = require('gulp'); -var config = require('../config').assets; - -gulp.task('assets', function() { - return gulp.src(config.src) - .pipe(gulp.dest(config.dest)); -}); - - diff --git a/gulp/tasks/default.js b/gulp/tasks/default.js index 7bcae83..4e42708 100644 --- a/gulp/tasks/default.js +++ b/gulp/tasks/default.js @@ -1,4 +1,3 @@ var gulp = require('gulp'); -gulp.task('default', ['sass', 'markup', 'webpack', 'watch', 'serve']); - +gulp.task('default', ['sass', 'fonts', 'ngConfig', 'index', 'html', 'webpack', 'watch', 'serve']); diff --git a/gulp/tasks/fonts.js b/gulp/tasks/fonts.js new file mode 100644 index 0000000..4347662 --- /dev/null +++ b/gulp/tasks/fonts.js @@ -0,0 +1,7 @@ +var gulp = require("gulp"); +var config = require('../config').fonts; + +gulp.task('fonts', function() { + return gulp.src(config.src) + .pipe(gulp.dest(config.dest)); +}); diff --git a/gulp/tasks/html.js b/gulp/tasks/html.js new file mode 100644 index 0000000..0b29aff --- /dev/null +++ b/gulp/tasks/html.js @@ -0,0 +1,7 @@ +var gulp = require("gulp"); +var config = require('../config').html; + +gulp.task('html', function() { + return gulp.src(config.src) + .pipe(gulp.dest(config.dest)); +}); diff --git a/gulp/tasks/index.js b/gulp/tasks/index.js new file mode 100644 index 0000000..041f2f8 --- /dev/null +++ b/gulp/tasks/index.js @@ -0,0 +1,7 @@ +var gulp = require("gulp"); +var config = require('../config').index; + +gulp.task('index', function() { + return gulp.src(config.src) + .pipe(gulp.dest(config.dest)); +}); diff --git a/gulp/tasks/javascript.js b/gulp/tasks/javascript.js deleted file mode 100644 index 04c45b0..0000000 --- a/gulp/tasks/javascript.js +++ /dev/null @@ -1,7 +0,0 @@ -var gulp = require('gulp'); -var config = require('../config').javascript; - -gulp.task('javascript', function() { - gulp.src(config.src) - .pipe(gulp.dest(config.dest)); -}); diff --git a/gulp/tasks/markup.js b/gulp/tasks/markup.js deleted file mode 100755 index 89b3eb3..0000000 --- a/gulp/tasks/markup.js +++ /dev/null @@ -1,8 +0,0 @@ -var gulp = require('gulp'); -var config = require('../config').html; - -gulp.task('markup', function() { - return gulp.src(config.src) - .pipe(gulp.dest(config.dest)); -}); - diff --git a/gulp/tasks/minifyCss.js b/gulp/tasks/minifyCss.js deleted file mode 100755 index b7745e6..0000000 --- a/gulp/tasks/minifyCss.js +++ /dev/null @@ -1,11 +0,0 @@ -var gulp = require('gulp'); -var config = require('../config').production; -var minifyCSS = require('gulp-minify-css'); -var size = require('gulp-filesize'); - -gulp.task('minifyCss', ['sass'], function() { - return gulp.src(config.cssSrc) - .pipe(minifyCSS({keepBreaks:true})) - .pipe(gulp.dest(config.cssDest)) - .pipe(size()); -}) diff --git a/gulp/tasks/ngConfig.js b/gulp/tasks/ngConfig.js new file mode 100644 index 0000000..7846929 --- /dev/null +++ b/gulp/tasks/ngConfig.js @@ -0,0 +1,16 @@ +var gulp = require('gulp'); +var ngConfig = require('gulp-ng-config'); +var config = require('../config').ngConfig; +var fs = require('fs'); + +gulp.task('ngConfig', function () { + var tokenFile = config.dest + '/token.txt'; + + // Create a temporary file with the token stored in it + fs.writeFileSync(tokenFile, '{"mytoken": "' + process.env.OAUTH_TOKEN + '"}'); + + // Generate the token config file + gulp.src(tokenFile) + .pipe(ngConfig('intellyApp.config')) + .pipe(gulp.dest(config.dest)); +}); diff --git a/gulp/tasks/production.js b/gulp/tasks/production.js deleted file mode 100755 index d9f5efd..0000000 --- a/gulp/tasks/production.js +++ /dev/null @@ -1,7 +0,0 @@ -var gulp = require('gulp'); - -// Run this to compress all the things! -gulp.task('production', function(){ - // This runs only if the karma tests pass - gulp.start(['markup', 'minifyCss', 'uglifyJs']) -}); diff --git a/gulp/tasks/sass.js b/gulp/tasks/sass.js old mode 100755 new mode 100644 index 01b6bc6..2f24254 --- a/gulp/tasks/sass.js +++ b/gulp/tasks/sass.js @@ -1,17 +1,16 @@ -var gulp = require('gulp'); -var sass = require('gulp-sass'); -var sourcemaps = require('gulp-sourcemaps'); -var handleErrors = require('../util/handleErrors'); +var gulp = require('gulp'); +var sass = require('gulp-sass'); var autoprefixer = require('gulp-autoprefixer'); +var handleErrors = require('../util/handleErrors'); var config = require('../config').sass; gulp.task('sass', function () { return gulp.src(config.src) - .pipe(sourcemaps.init()) .pipe(sass(config.settings)) + .pipe(autoprefixer({ + browsers: ['last 2 versions'], + cascade: false + })) .on('error', handleErrors) - .pipe(sourcemaps.write()) - .pipe(autoprefixer({ browsers: ['last 2 version'] })) .pipe(gulp.dest(config.dest)); }); - diff --git a/gulp/tasks/serve.js b/gulp/tasks/serve.js index 080efd7..cbcf1f8 100644 --- a/gulp/tasks/serve.js +++ b/gulp/tasks/serve.js @@ -1,12 +1,12 @@ var gulp = require('gulp'); var config = require('../config').server; -var webserver = require('gulp-webserver'); +var server = require('gulp-webserver'); gulp.task('serve', function() { console.log(config.src); gulp.src(config.src) - .pipe(webserver({ + .pipe(server({ livereload: config.livereload, directoryListing: config.directoryListing, open: config.open, diff --git a/gulp/tasks/uglifyJs.js b/gulp/tasks/uglifyJs.js deleted file mode 100755 index 33e853f..0000000 --- a/gulp/tasks/uglifyJs.js +++ /dev/null @@ -1,11 +0,0 @@ -var gulp = require('gulp'); -var config = require('../config').production; -var size = require('gulp-filesize'); -var uglify = require('gulp-uglify'); - -gulp.task('uglifyJs', ['webpack'], function() { - return gulp.src(config.jsSrc) - .pipe(uglify()) - .pipe(gulp.dest(config.jsDest)) - .pipe(size()); -}); diff --git a/gulp/tasks/watch.js b/gulp/tasks/watch.js old mode 100755 new mode 100644 index 576e992..a84ee24 --- a/gulp/tasks/watch.js +++ b/gulp/tasks/watch.js @@ -3,7 +3,6 @@ var config = require('../config'); gulp.task('watch', function() { gulp.watch(config.javascript.src, ['webpack']); - gulp.watch(config.sass.src, ['sass']); - gulp.watch(config.markup.src, ['markup']); - // Watchify will watch and recompile our JS, so no need to gulp.watch it + gulp.watch(config.sass.src, ['sass']); + gulp.watch(config.html.src, ['html']); }); diff --git a/gulp/tasks/webpack.js b/gulp/tasks/webpack.js index 373ce98..941b2e3 100644 --- a/gulp/tasks/webpack.js +++ b/gulp/tasks/webpack.js @@ -3,12 +3,12 @@ var config = require('../config').javascript; var webpack = require('webpack-stream'); gulp.task('webpack', function(callback) { - return gulp.src(config.entry) + return gulp.src(config.entryPoint) .pipe(webpack({ output: { - filename: config.outputFilename + filename: config.packedFile } })) + // .on('error', handleErrors) .pipe(gulp.dest(config.dest)); }); - diff --git a/gulp/util/handleErrors.js b/gulp/util/handleErrors.js old mode 100755 new mode 100644 index a9f2834..a6e481d --- a/gulp/util/handleErrors.js +++ b/gulp/util/handleErrors.js @@ -12,4 +12,4 @@ module.exports = function() { // Keep gulp from hanging on this task this.emit('end'); -}; \ No newline at end of file +}; diff --git a/package.json b/package.json index 50f838a..2db7734 100644 --- a/package.json +++ b/package.json @@ -1,25 +1,44 @@ { - "name": "", + "name": "mean-stack-1", "version": "1.0.0", - "description": "", + "description": "Last week we focussed on JavaScript basics. This week we're going to build up a function web application. You'll be expected to build on knowledge you've already learned (semantic HTML, Sass instead of CSS, in addition to all of the Angular work we'll be doing) and produce a \"production-ready\" blog for your assignment this week.", + "main": "server.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/pstrum/mean-stack-1.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/pstrum/mean-stack-1/issues" + }, + "homepage": "https://github.com/pstrum/mean-stack-1#readme", "dependencies": { - "gulp": "^3.8.11", - "gulp-autoprefixer": "^2.1.0", - "gulp-changed": "^1.1.1", - "gulp-filesize": "0.0.6", - "gulp-minify-css": "~0.5.1", + "angular": "^1.4.7", + "angular-cookies": "^1.4.7", + "angular-route": "^1.4.7", + "body-parser": "^1.14.1", + "connect-livereload": "^0.5.3", + "express": "^4.13.3", + "gulp": "^3.9.0", + "gulp-autoprefixer": "^3.0.2", + "gulp-express": "^0.3.5", + "gulp-livereload": "^3.8.1", + "gulp-ng-config": "^1.2.1", "gulp-notify": "^2.2.0", "gulp-rename": "^1.2.2", - "gulp-sass": "~1.3.3", - "gulp-sourcemaps": "^1.5.0", - "gulp-uglify": "^1.1.0", - "gulp-util": "^3.0.4", - "gulp-webserver": "^0.9.0", - "lodash": "^3.3.1", - "merge-stream": "^0.1.7", - "pretty-hrtime": "~1.0.0", - "require-dir": "^0.1.0", - "vinyl-source-stream": "~1.0.0", + "gulp-run": "^1.6.11", + "gulp-sass": "^2.0.4", + "gulp-webserver": "^0.9.1", + "mongoose": "^4.1.10", + "ng-showdown": "^1.0.0", + "node-bourbon": "^4.2.3", + "require-dir": "^0.3.0", + "showdown": "^1.2.3", + "webpack": "^1.12.2", "webpack-stream": "^2.1.1" } } diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..dde636c --- /dev/null +++ b/readme.md @@ -0,0 +1,44 @@ +# Week Six - MEAN Stack I + +Last week we focussed on JavaScript basics. This week we're going to build up a function web application. You'll be expected to build on knowledge you've already learned (semantic HTML, Sass instead of CSS, in addition to all of the Angular work we'll be doing) and produce a "production-ready" blog for your assignment this week. + +We want this assignment to feel like a 'week on the job.' And by that we mean, we will provide a completed comp and an expected outcome specification. It is up to you to deliver on this project specification. + +## The Comp + +You can download the view that you are to complete [here](https://github.com/SEA-Design-Dev/mean-stack-1/tree/master/comps). It is provided as a Photoshop format, if you do not have access to Photoshop, other applications like Pixelmator are able to open these layered files as well. + + +## The spec + +As a product owner, I need a functional prototype of the application. The final prototype must be visible in a desktop browser. + +Prototype is to use best practices in coding HTML/CSS as there is the potential that some or all of the code will made it into production. + +Aside from images as content, all visual assets should be produced via CSS or typography. The only background image asset allowed will be the main page header. + +The user should be able to create, read, update, and delete blog posts from the application. There should be at least two different views - one a list of available blog posts, the other a detail view of the blog post. You do not need to worry about authentication or user management for this assignment. + +### Requirements + +1. Semantically correct HTML is required as this will be the model for prod app integration +1. Think in terms of '*components*'; if all parts of the UI were lego blocks, who would you code that? +1. Images are to be cropped correctly and compression is to take performance into account +1. All CSS measurements should use elastic units unless a pixel specific unit is required for both mobile and desktop +1. JavaScript code is expected to be written cleanly and maintainably using the best practices covered during lectures +1. After checking out the repository, I must be able to run `npm install` and `gulp serve` in order to access the application locally +1. Write up a description for every plugin used (no limit, but you must justify them) + 1. jQuery is not allowed. Angular's built-in DOM manipulation can manage most of what you'd need jQuery for. + +### Constraints + +1. Must work in all major browsers of latest versions; + * Desktop (IE Edge, Safari, Chrome and Firefox) +1. All interactions must be clearly functional +1. All code must pass HTML Tidy, CSS Lint, and JSHint. + +__DO NOT__ fence yourself in with invisible constraints. Unless it is specifically listed and/or we discussed it in lecture, there is not an expectation to meet an objective that has not been set. + +## The expectation + +In this assignment, you should be able to demonstrate mastery over the basics of Angular as well as creating a simple CRUD application. We're looking for you to build on best practices that you've already learned (proper HTML and CSS) as well as incorporate the new practices discussed during the course of the week. diff --git a/src/app/app.js b/src/app/app.js new file mode 100644 index 0000000..b421aae --- /dev/null +++ b/src/app/app.js @@ -0,0 +1,51 @@ +require('angular'); +// require('ng-showdown'); +require('angular-route'); + +(function() { + + "use strict"; + + // Declare variable app, which equals a new AngularJS module + // with the name 'intelly'. ngRoute is a dependency used for + // routing and deeplinking services + var app = angular.module('intellyApp', ['ngRoute', 'intellyApp.config']); + + // $routeProvider is a provider in the ngRoute module + // used for configuring routes. + // App routes are declared with $routeProvider. + app.config(["$routeProvider", function($routeProvider) { + // The $location service parses the URL in the browser address bar (based on the window.location) and makes the URL available to your application + // This method is getter / setter. + + // Return path of current url + // Add a new route definition to the $route service. + // The route path (/blog-post) is (matched against $location.path) + // which is a getter/setter that parses the address bar url + // and makes it available to our app + $routeProvider.when('/gists', { + // This is the route object: + templateUrl: "views/blog/blog-post.html", + controller: "BlogsCtrl as vm" + }). + when('/gists/new', { + templateUrl: "views/posts/blog-post-form.html", + controller: "BlogFormCtrl as vm", + }). + when('/gists/:gist_id', { + templateUrl: "views/posts/blog-post-detail.html", + controller: "BlogCtrl as vm" + }). + when('/gists/:gist_id/edit', { + templateUrl: "views/posts/blog-post-form.html", + controller: "BlogFormCtrl as vm" + }). + when('/gists/:gist_id/destroy', { + templateUrl: "views/posts/blog-post-detail.html", + controller: "BlogFormCtrl as vm" + }). + otherwise({ + redirectTo: "/gists" + }); + }]); +})(); diff --git a/src/app/blog/blog-post.html b/src/app/blog/blog-post.html new file mode 100644 index 0000000..c9ed318 --- /dev/null +++ b/src/app/blog/blog-post.html @@ -0,0 +1,20 @@ +
+

{{ gist.description }}

+

• {{ file.filename | limitTo:150 }}...

+ +
+ Read More +
+
+

No Posts! Want to create one?

+ + diff --git a/src/app/blog/blog.service.js b/src/app/blog/blog.service.js new file mode 100644 index 0000000..803fef5 --- /dev/null +++ b/src/app/blog/blog.service.js @@ -0,0 +1,53 @@ +require('../app.js'); + +// Organize and share code +(function () { + + "use strict"; + + // Name the service and specify the $http service as a dependency -- inject it to use it + angular.module("intellyApp").service("GistsService", ["$http", "mytoken", function ($http, mytoken) { + // Declare urlRoot + var urlRoot = "https://api.github.com/"; + var username = "petemaverickmitchell"; + + // Declare gist object with 4 methods + var Gist = { + // Get function with gist ID as argument + // Function will return a promise + get: function (id) { + // Determine if a reference (gist ID) is defined + if (angular.isDefined(id)) { + // Send in the URL with ID to the get method + return $http.get(urlRoot + "gists/" + id, { + headers: {"Authorization": "token " + mytoken} + }); + } else { + // Send in the base URL + // return $http.get(urlRoot + "/users/jedfoster/gists"); + return $http.get(urlRoot + "users/" + username + "/gists", { + headers: {"Authorization": "token " + mytoken} + }); + } + }, + + update: function (model) { + return $http.patch(urlRoot + "gists/" + model.id, model, { + headers: {"Authorization": "token " + mytoken} + }); + }, + create: function (model) { + return $http.post(urlRoot + "gists", model, { + headers: {"Authorization": "token " + mytoken} + }); + }, + delete: function (id) { + return $http.delete(urlRoot + "gists/" + id, { + headers: {"Authorization": "token " + mytoken} + }); + } + }; + // Service must return the object + return Gist; + }]); +}()); diff --git a/src/app/blog/blogs.ctrl.js b/src/app/blog/blogs.ctrl.js new file mode 100644 index 0000000..ac4b57b --- /dev/null +++ b/src/app/blog/blogs.ctrl.js @@ -0,0 +1,73 @@ +require('../app.js'); +require('./blogs.filter.js'); + +(function() { + + 'use strict'; + + angular.module('intellyApp').controller("BlogsCtrl", ["GistsService", "$anchorScroll", "$location", "$routeParams", "$log", function(GistsService, $anchorScroll, $location, $routeParams, $log) { + + var vm = this; + + // Initialize the controller + initialize(); + + vm.pagination = { + currentPage: 0, + perPage: 5, + getOffset: function () { + return vm.pagination.currentPage * vm.pagination.perPage; + }, + prevPage: function () { + vm.pagination.currentPage--; + toBreadcrumbs(); + }, + nextPage: function () { + vm.pagination.currentPage++; + toBreadcrumbs(); + } + }; + + function initialize () { + getgists(); + } + + function getgists () { + // Run the get method from the GistsService service + // Then (or success) send in a callback with the response (from promise) + GistsService.get($routeParams.gist_id).then(successHandler, errorHandler); + + function successHandler(response) { + // Store the data in the gists array + // Set the property 'gists' (array) equal to an array of objects + + vm.gists = response.data; + + vm.status = response.status; + + $log.info("response", response); + $log.info(vm.status); + } + + function errorHandler(response) { + $log.error("response", response); + } + } + + function deleteBlog (blog) { + GistsService.delete(blog).then(function () { + getBlogs(); + }); + } + + function toBreadcrumbs () { + // set the location.hash to the id of + // the element you wish to scroll to. + $location.hash('blog-scroll'); + + // call $anchorScroll() + $anchorScroll(); + } + + }]); +}()); diff --git a/src/app/blog/blogs.filter.js b/src/app/blog/blogs.filter.js new file mode 100644 index 0000000..694bc6b --- /dev/null +++ b/src/app/blog/blogs.filter.js @@ -0,0 +1,25 @@ +require('../app.js'); + +(function() { + + 'use strict'; + + angular.module("intellyApp").filter("offset", function ($filter) { + return function(input, start) { + if (input) { + start = parseInt(start, 10); + return input.slice(start); + } + }; + }); + + angular.module("intellyApp").filter("pager", function ($filter) { + return function (results, pagerObj) { + var filteredResults; + filteredResults = $filter("offset")(results, pagerObj.getOffset()); + filteredResults = $filter("limitTo")(filteredResults, pagerObj.perPage); + return filteredResults; + }; + }); + +})(); diff --git a/src/app/entry.js b/src/app/entry.js new file mode 100644 index 0000000..35ef81e --- /dev/null +++ b/src/app/entry.js @@ -0,0 +1,6 @@ +require('./app.js'); +require('./posts/blog.ctrl.js'); +require('./blog/blogs.ctrl.js'); +require('./posts/blog_form.ctrl.js'); +require('./blog/blog.service.js'); + diff --git a/src/app/models/blog-post.js b/src/app/models/blog-post.js new file mode 100644 index 0000000..92d985a --- /dev/null +++ b/src/app/models/blog-post.js @@ -0,0 +1,18 @@ +// Require mongoose +var mongoose = require('mongoose'); + +// Each schema maps to a MongoDB collection +// and defines the shape of the documents within that collection. +// Get a reference to Schema and define our blog. +var Schema = mongoose.Schema; + +var blogSchema = new Schema ({ + description: String, + author: String, + content: String, + comments: [{ body: String, date: Date}], + date: { type: Date, default: Date.now} +}); + +// Allow access in server.js to use in our app +module.exports = mongoose.model('Blog', blogSchema); diff --git a/src/app/posts/blog-post-detail.html b/src/app/posts/blog-post-detail.html new file mode 100644 index 0000000..1b66e03 --- /dev/null +++ b/src/app/posts/blog-post-detail.html @@ -0,0 +1,17 @@ +
+

{{ vm.gist.description }}

+
+

{{ file.filename }}

+

{{ file.content }}

+

+ +
+ Edit + Home +
+
diff --git a/src/app/posts/blog-post-form.html b/src/app/posts/blog-post-form.html new file mode 100644 index 0000000..d9f3f70 --- /dev/null +++ b/src/app/posts/blog-post-form.html @@ -0,0 +1,19 @@ +
+
+ + + + + +
+
+

Your Post:

+

{{ vm.gist.description }}

+

{{ vm.gistFilename }}

+

{{ vm.gist.files[vm.gistFilename].content }}

+
+
diff --git a/src/app/posts/blog.ctrl.js b/src/app/posts/blog.ctrl.js new file mode 100644 index 0000000..9ef42fd --- /dev/null +++ b/src/app/posts/blog.ctrl.js @@ -0,0 +1,32 @@ +require('../app.js'); + +(function () { + + "use strict"; + + angular.module("intellyApp").controller("BlogCtrl", ["GistsService", "$routeParams", "$log", function (GistsService, $routeParams, $log, $showdown) { + + var vm = this; + + initialize(); + + function initialize() { + /*** Retrieve the current set of route parameters ***/ + // Determine if the route parameters is defined by + // using $location service to parse the url and return object + GistsService.get($routeParams.gist_id).then(successHandler, errorHandler); + + function successHandler(response) { + // Route parameters are defined, $location service parses the url - return as object + // Set vm.gist equal to the object returned + vm.gist = response.data; + + $log.info("response", response); + } + + function errorHandler(response) { + $log.error("response", response); + } + } + }]); +}()); diff --git a/src/app/posts/blog_form.ctrl.js b/src/app/posts/blog_form.ctrl.js new file mode 100644 index 0000000..94c4981 --- /dev/null +++ b/src/app/posts/blog_form.ctrl.js @@ -0,0 +1,98 @@ +require('../app.js'); + +(function () { + + "use strict"; + + + // on initialize check to see if there is an id in the url + + + angular.module("intellyApp").controller("BlogFormCtrl", ["GistsService", "$routeParams", "$location", "$http", "$log", function (GistsService, $routeParams, $location, $http, $log) { + + var vm = this; + + var urlRoot = "/api/blog-post"; + + vm.save = submitForm; + + vm.gist = {}; + vm.gist.files = {}; + + vm.delete = deleteBlog; + + initialize(); + + function initialize() { + + if ($routeParams.gist_id) { + GistsService.get($routeParams.gist_id).then(successHandler, errorHandler); + } else { + vm.gistFilename = Object.keys(vm.gist.files)[0]; + } + + function successHandler(response) { + + vm.gist = response.data; + vm.gistFilename = Object.keys(vm.gist.files)[0]; + + $log.info("response", response); + } + + function errorHandler(response) { + $log.error("response", response); + } + } + + function getgists () { + // Run the get method from the GistsService service + // Then (or success) send in a callback with the response (from promise) + GistsService.get($routeParams.gist_id).then(successHandler, errorHandler); + + function successHandler(response) { + // Store the data in the gists array + // Set the property 'gists' (array) equal to an array of objects + + vm.gists = response.data; + + $log.info("response", response); + } + + function errorHandler(response) { + $log.error("response", response); + } + } + + function submitForm () { + + var method; + + method = $routeParams.gist_id ? "update" : "create"; + + // Pass in the vm.gist object, which is the data param for the POST method + GistsService[method](vm.gist).then(successHandler, errorHandler); + + function successHandler (response) { + $location.path("/gists/" + response.data.id); + $log.info("response", response.data.id); + } + + function errorHandler(response) { + $log.error("response", response); + } + } + + function deleteBlog (gist_id) { + GistsService.delete(gist_id).then(successHandler, errorHandler); + + function successHandler(response) { + $log.info("response", response); + $location.path("/gists/"); + } + + function errorHandler(response) { + $log.error("response", response); + } + } + }]); +}()); diff --git a/src/assets/.gitkeep b/src/assets/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/css/.gitkeep b/src/css/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..0a3a355 --- /dev/null +++ b/src/index.html @@ -0,0 +1,81 @@ + + + + + + Intelly + + + + + + +
+

intelly

+ +
+
+
+

Gists

+

The secular cooling that must someday overtake our planet has already gone far indeed with our neighbour. Its physical condition is still largely a mystery, but we know now that even in its equatorial

+
+
+ + +
+
+ +
+
+

Serene in their assurance of their empire over matter

+

No one would have believed in the last years of the nine- teenth century that this world was being watched keenly and closely by intelligences greater than man’s

+ Contact now + Learn more +
+
+ + + + + diff --git a/src/js/.gitkeep b/src/js/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/styles/base/_INDEX.scss b/src/styles/base/_INDEX.scss new file mode 100644 index 0000000..daccee9 --- /dev/null +++ b/src/styles/base/_INDEX.scss @@ -0,0 +1,4 @@ +@import "reset"; +@import "base"; +@import "icons"; +@import "typography"; diff --git a/src/styles/base/_base.scss b/src/styles/base/_base.scss new file mode 100644 index 0000000..7cbf8d6 --- /dev/null +++ b/src/styles/base/_base.scss @@ -0,0 +1,7 @@ +a { + color: color(primary); + } + +li { + display: inline; +} diff --git a/src/styles/base/_icons.scss b/src/styles/base/_icons.scss new file mode 100644 index 0000000..ce5f17a --- /dev/null +++ b/src/styles/base/_icons.scss @@ -0,0 +1,29 @@ +[class^="icon-"], [class*=" icon-"] { + font-family: 'icomoon'; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-linkedin-with-circle:before { + content: "\e800"; +} +.icon-google-plus:before { + content: "\e801"; +} +.icon-facebook:before { + content: "\e802"; +} +.icon-twitter:before { + content: "\e803"; +} +.icon-pinterest:before { + content: "\e804"; +} diff --git a/src/styles/base/_reset.scss b/src/styles/base/_reset.scss new file mode 100644 index 0000000..07db64b --- /dev/null +++ b/src/styles/base/_reset.scss @@ -0,0 +1,29 @@ +* { + box-sizing: border-box; +} + +[ng-cloak] { + visibility: hidden; +} + +body { + width: 100%; + margin: 0 auto; +} + +ul { + padding: 0; +} + +li, a { + text-decoration: none; +} + +li { + list-style: none; +} + +h1, h2, p, figure, blockquote { + margin: 0; + font-weight: normal; +} diff --git a/src/styles/base/_typography.scss b/src/styles/base/_typography.scss new file mode 100644 index 0000000..7b5b476 --- /dev/null +++ b/src/styles/base/_typography.scss @@ -0,0 +1,10 @@ +@font-face { + font-family: 'icomoon'; + src:url('/styles/fonts/icomoon.eot?vjxn5v'); + src:url('/styles/fonts/icomoon.eot?vjxn5v#iefix') format('embedded-opentype'), + url('/styles/fonts/icomoon.ttf?vjxn5v') format('truetype'), + url('/styles/fonts/icomoon.woff?vjxn5v') format('woff'), + url('/styles/fonts/icomoon.svg?vjxn5v#icomoon') format('svg'); + font-weight: normal; + font-style: normal; +} diff --git a/src/styles/components/_INDEX.scss b/src/styles/components/_INDEX.scss new file mode 100644 index 0000000..e142504 --- /dev/null +++ b/src/styles/components/_INDEX.scss @@ -0,0 +1,11 @@ +@import "buttons"; +@import "logo-header"; +@import "navigation"; +@import "page-title-description"; +@import "social_icon.scss"; +@import "blog"; +@import "footer"; +@import "feature"; +@import "create-post"; +@import "post-preview"; +@import "code"; diff --git a/src/styles/components/_blog.scss b/src/styles/components/_blog.scss new file mode 100644 index 0000000..e3d574f --- /dev/null +++ b/src/styles/components/_blog.scss @@ -0,0 +1,110 @@ +.blog { + background-color: color(base); + + .no-show { + display: block; + font-family: $font-primary; + a { + color: color(secondary); + } + + h2 { + font-size: font-size(2); + margin-top: 1em; + margin-bottom: 1em; + } + } + + .breadcrumbs { + border-bottom: 1px solid shades-primary(2); + + h1 { + display: inline-block; + font-family: $font-primary; + font-size: font-size(0); + font-weight: font-weight(bold); + } + + ul { + display: inline-block; + } + + li { + padding-right: 10px; + padding-left: 10px; + font-family: $font-primary; + font-size: font-size(0); + color: shades-primary(2); + text-align: right; + } + } + + .blog-post { + padding: 0 0 5em; + text-align: left; + border-bottom: 1px solid shades-primary(2); + + h1 { + font-family: $font-primary; + font-size: 3em; + padding-left: 0; + padding-bottom: 1em; + } + + p { + font-family: $font-primary; + font-weight: weight(light); + font-size: font-size(2); + color: shades-primary(2); + line-height: 2.75rem; + padding-bottom: 1em; + white-space: pre-wrap; + } + + img { + display: inline-block; + max-width: 3em; + border-radius: 50%; + + } + + li { + display: inline-block; + font-family: $font-primary; + text-align: left; + font-style: italic; + color: shades-primary(2); + padding-left: 0; + padding-right: 10px; + + a { + color: shades-primary(1); + } + } + + li:before { + content: "•"; + padding-right: 10px; + } + + li:first-child:before { + display: none; + } + + li:nth-child(2):before { + display: none; + } + + ul { + display: inline; + } + } + + nav { + padding-top: 1em; + + li { + padding: 0 2px; + } + } +} diff --git a/src/styles/components/_buttons.scss b/src/styles/components/_buttons.scss new file mode 100644 index 0000000..9a5a1d0 --- /dev/null +++ b/src/styles/components/_buttons.scss @@ -0,0 +1,48 @@ +@mixin button($background, $text-color, $size) { + text-transform: uppercase; + background: $background; + color: $text-color; + border: 1px solid black; + border-radius: 5px; + padding-top: 1em; + padding-bottom: 1em; + padding-left: $size; + padding-right: $size; + margin-left: .25em; + margin-right: .25em; + font-family: $font-primary; + font-size: font-size(0); +} + +.button-big, +.button-read { + @include button(black, white, 2em); +} + +.button-change, +.button-create, +.button-feature:hover { + background: white; + color: black; +} + +.button-feature:hover { + font-weight: weight(regular) +} + +.button-feature { + display: inline-block; + background: transparent; + border: 1px solid white; + font-weight: weight(regular); + margin-bottom: 1em; +} + +.button-small { + @include button(white, black, 1em); +} + +.button-small:hover { + background: black; + color: white; +} diff --git a/src/styles/components/_code.scss b/src/styles/components/_code.scss new file mode 100644 index 0000000..ee7e237 --- /dev/null +++ b/src/styles/components/_code.scss @@ -0,0 +1,4 @@ +code { + font-size: font-size(0); + color: black; +} diff --git a/src/styles/components/_create-post.scss b/src/styles/components/_create-post.scss new file mode 100644 index 0000000..5784dac --- /dev/null +++ b/src/styles/components/_create-post.scss @@ -0,0 +1,41 @@ +%form-style { + font-family: $font-primary; + font-size: font-size(0); + border: 1px solid color(secondary); + border-radius: 5px; +} + +.create-post { + label { + display: inline-block; + font-family: $font-primary; + font-size: font-size(1); + } + li a { + display: inline-block; + } + + input { + @extend %form-style; + padding: .3em .3em; + } + textarea { + @extend %form-style; + padding: .3em .3em; + min-height: 20em; + } + input[type=text] { + padding: .5em; + } + input[type=submit] { + font-size: font-size(0); + padding: 1em 2em; + } + input[type=submit]:hover { + cursor: pointer; + } + input[type=checkbox] { + display: inline-block; + width: 2em; + } +} diff --git a/src/styles/components/_feature.scss b/src/styles/components/_feature.scss new file mode 100644 index 0000000..245f222 --- /dev/null +++ b/src/styles/components/_feature.scss @@ -0,0 +1,21 @@ +.feature { + font-family: $font-primary; + text-align: center; + background-color: color(accent); + h1 { + font-weight: weight(regular); + font-size: 3em; + line-height: 1; + color: color(base); + } + p { + font-weight: weight(regular); + font-size: font-size(1); + line-height: 2.25; + color: shades-accent(1); + } + .button-feature { + padding-top: 1em; + padding-bottom: 1em; + } +} diff --git a/src/styles/components/_footer.scss b/src/styles/components/_footer.scss new file mode 100644 index 0000000..0c3f296 --- /dev/null +++ b/src/styles/components/_footer.scss @@ -0,0 +1,27 @@ +footer { + padding: 2em 0; + + .footer-top { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + padding: 2em; + border-bottom: 1px solid shades-primary(4); + + a { + font-family: $font-primary; + } + } + + .footer-bottom { + text-align: center; + margin: 2em auto; + + li { + font-size: .917em; + font-family: $font-primary; + padding: 0 .5em; + } + } +} diff --git a/src/styles/components/_logo-header.scss b/src/styles/components/_logo-header.scss new file mode 100644 index 0000000..263341a --- /dev/null +++ b/src/styles/components/_logo-header.scss @@ -0,0 +1,12 @@ +header { + display: flex; + justify-content: space-between; + @extend %section-padding-top-bottom; + + h1 { + font-family: $font-primary; + font-weight: weight(medium); + font-size: font-size(3); + color: color(base); + } +} diff --git a/src/styles/components/_navigation.scss b/src/styles/components/_navigation.scss new file mode 100644 index 0000000..507d81b --- /dev/null +++ b/src/styles/components/_navigation.scss @@ -0,0 +1,20 @@ +.top-navigation { + font-family: $font-primary; + font-weight: weight(regular); + font-size: font-size(0); + text-transform: uppercase; + letter-spacing: 0.238em; + li:before { + content: "•"; + color: color(base); + } + li:first-child:before { + display: none; + } + a { + color: color(base); + } + a:hover { + color: color(accent); + } +} diff --git a/src/styles/components/_page-title-description.scss b/src/styles/components/_page-title-description.scss new file mode 100644 index 0000000..af55383 --- /dev/null +++ b/src/styles/components/_page-title-description.scss @@ -0,0 +1,16 @@ +.title-description { + font-family: $font-secondary; + background-color: color(accent); + border-bottom: 2px solid shades-accent(-1); + h1 { + font-weight: weight(regular); + font-size: 3.33em; + color: color(primary); + } + p { + font-weight: weight(light); + font-size: font-size(3); + line-height: 3.5rem; + color: shades-accent(-2); + } +}; diff --git a/src/styles/components/_post-preview.scss b/src/styles/components/_post-preview.scss new file mode 100644 index 0000000..70299f8 --- /dev/null +++ b/src/styles/components/_post-preview.scss @@ -0,0 +1,22 @@ +.post-preview { + + h1 { + font-family: $font-primary; + padding: 0; + font-size: font-size(3); + } + h2 { + font-family: $font-primary; + font-size: font-size(2); + padding-bottom: 1em; + } + p { + font-family: $font-primary; + font-weight: weight(light); + font-size: font-size(1); + color: shades-primary(2); + line-height: 2rem; + padding-bottom: 1em; + white-space: pre-wrap; + } +} diff --git a/src/styles/components/_social_icon.scss b/src/styles/components/_social_icon.scss new file mode 100644 index 0000000..65c1406 --- /dev/null +++ b/src/styles/components/_social_icon.scss @@ -0,0 +1,41 @@ +.icon-circle { + border-radius: 50%; + width: 8em ; + height: 8em; + padding-top: 3.5em; + padding-bottom: 2.5em; + padding-right: 1.2em; + padding-left: 1.2em; + border: .12em solid color(secondary); + position: relative; + display: block; + text-align: center; +} +.social-link-footer { + + li { + margin-right: 2em; + display: inline-block; + &:hover { + .icon-text { + color: color(accent); + } + } + .icon-circle { + .footer-icon { + left: 0; + bottom: 1.8em; + position: absolute; + font-size: 3em; + color: color(primary); + background-color: color(base); + } + } + } +} +.icon-text { + color: color(primary); + font-family: Ubuntu; + font-size: font-size(0); + font-weight: weight(bold); +} diff --git a/src/styles/fonts/icomoon.eot b/src/styles/fonts/icomoon.eot new file mode 100755 index 0000000..e1dc3f0 Binary files /dev/null and b/src/styles/fonts/icomoon.eot differ diff --git a/src/styles/fonts/icomoon.svg b/src/styles/fonts/icomoon.svg new file mode 100755 index 0000000..ecf19cf --- /dev/null +++ b/src/styles/fonts/icomoon.svg @@ -0,0 +1,15 @@ + + + +Generated by IcoMoon + + + + + + + + + + + \ No newline at end of file diff --git a/src/styles/fonts/icomoon.ttf b/src/styles/fonts/icomoon.ttf new file mode 100755 index 0000000..4090050 Binary files /dev/null and b/src/styles/fonts/icomoon.ttf differ diff --git a/src/styles/fonts/icomoon.woff b/src/styles/fonts/icomoon.woff new file mode 100755 index 0000000..88ae927 Binary files /dev/null and b/src/styles/fonts/icomoon.woff differ diff --git a/src/styles/layout/_INDEX.scss b/src/styles/layout/_INDEX.scss new file mode 100644 index 0000000..2da8672 --- /dev/null +++ b/src/styles/layout/_INDEX.scss @@ -0,0 +1,5 @@ +@import "header"; +@import "navigation-top"; +@import "page-title-description"; +@import "blog"; +@import "feature"; diff --git a/src/styles/layout/_blog.scss b/src/styles/layout/_blog.scss new file mode 100644 index 0000000..3a8f6da --- /dev/null +++ b/src/styles/layout/_blog.scss @@ -0,0 +1,110 @@ +.blog { + margin-bottom: 6em; + + .breadcrumbs { + @extend %flex-box; + padding: 1em 6em; + ul { + margin: 0; + } + } + + .no-show { + margin: 3em auto; + text-align: center; + } + + .blog-post { + margin: 6em 20% 5em; + + div { + float: right; + } + + ul { + width: 75%; + margin: 0; + float: none; + } + li { + vertical-align: middle; + } + .button-read { + float: right; + } + } + + nav { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + width: 60%; + margin: 0 auto; + + ul { + display: inline; + min-width: 175px; + + } + } + + .button-create { + display: block; + max-width: 12em; + margin: 2em auto 0; + } + + .blog-form { + display: flex; + justify-content: space-around; + padding: 0 10%; + } + + .post-preview { + display: none; + width: 30em; + + h1 { + margin-top: 0; + margin-bottom: 1em; + } + + @media screen and (min-width: 800px) { + display: block; + width: 30em; + margin: 2em 1em; + } + } + + .create-post { + display: block; + width: 30em; + margin: 2em 1em; + + @media screen and (max-width: 35em) { + width: 95%; + } + + input { + display: block; + } + input[type=text], textarea { + width: 100%; + margin-bottom: font-size(1); + } + input[type=checkbox] { + margin-bottom: font-size(1); + } + ul { + display: flex; + justify-content: space-between; + margin: 0; + width: 100%; + height: 4em; + } + li { + display: inline-block; + } + } +} diff --git a/src/styles/layout/_feature.scss b/src/styles/layout/_feature.scss new file mode 100644 index 0000000..811a96d --- /dev/null +++ b/src/styles/layout/_feature.scss @@ -0,0 +1,14 @@ +.feature { + @extend %section-padding-top-bottom; + h1 { + margin-bottom: font-size(4); + } + p { + max-width: 38em; + margin: 0 auto font-size(4); + } + .button-feature { + margin-left: font-size(1); + margin-right: font-size(1); + } +} diff --git a/src/styles/layout/_header.scss b/src/styles/layout/_header.scss new file mode 100644 index 0000000..9f86807 --- /dev/null +++ b/src/styles/layout/_header.scss @@ -0,0 +1,7 @@ +header { + background-color: color(primary); + @extend %flex-box; + h1 { + display: inline-block; + } +} diff --git a/src/styles/layout/_navigation-top.scss b/src/styles/layout/_navigation-top.scss new file mode 100644 index 0000000..bc17742 --- /dev/null +++ b/src/styles/layout/_navigation-top.scss @@ -0,0 +1,18 @@ +.top-navigation { + display: inline-block; + ul { + display: flex; + justify-content: space-between; + flex-wrap: wrap; + margin-left: font-size(1); + } + li { + display: inline-block; + } + li:before { + padding: 0 font-size(-1); + } + a { + margin: 0; + } +} diff --git a/src/styles/layout/_page-title-description.scss b/src/styles/layout/_page-title-description.scss new file mode 100644 index 0000000..13207b4 --- /dev/null +++ b/src/styles/layout/_page-title-description.scss @@ -0,0 +1,13 @@ +.title-description { + @extend %section-padding-top-bottom; + @extend %flex-box; + flex-direction: column; + justify-content: flex-start; + + h1 { + margin-bottom: font-size(1); + } + p { + max-width: 70rem; + } +} diff --git a/src/styles/main.scss b/src/styles/main.scss new file mode 100644 index 0000000..fc0e187 --- /dev/null +++ b/src/styles/main.scss @@ -0,0 +1,4 @@ +@import "utils/INDEX"; +@import "base/INDEX"; +@import "layout/INDEX"; +@import "components/INDEX"; diff --git a/src/styles/utils/_INDEX.scss b/src/styles/utils/_INDEX.scss new file mode 100644 index 0000000..df91727 --- /dev/null +++ b/src/styles/utils/_INDEX.scss @@ -0,0 +1,3 @@ +@import "variables"; +@import "functions"; +@import "placeholders"; diff --git a/src/styles/utils/_functions.scss b/src/styles/utils/_functions.scss new file mode 100644 index 0000000..6f8556e --- /dev/null +++ b/src/styles/utils/_functions.scss @@ -0,0 +1,23 @@ +@function color($key: 'primary') { + @return map-get($theme-colors, $key); +} + +@function shades-primary($key: '1') { + @return map-get($shades-primary, $key); +} + +@function shades-accent($key: '1') { + @return map-get($shades-accent, $key); +} + +@function weight($key: 'regular') { + @return map-get($font-weights, $key); +} + +@function font-size($key: '0') { + @return map-get($modular-scale, $key); +} + +@function fonts($key: 'primary') { + @return map-get($fonts, $key); +} diff --git a/src/styles/utils/_placeholders.scss b/src/styles/utils/_placeholders.scss new file mode 100644 index 0000000..e8bf496 --- /dev/null +++ b/src/styles/utils/_placeholders.scss @@ -0,0 +1,11 @@ +%section-padding-top-bottom, { + padding: 6em 6em; +} +%flex-box { + display:flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; + align-content: flex-start; + align-items: flex-start; +} diff --git a/src/styles/utils/_variables.scss b/src/styles/utils/_variables.scss new file mode 100644 index 0000000..6f8f297 --- /dev/null +++ b/src/styles/utils/_variables.scss @@ -0,0 +1,43 @@ +$break: 50em; + +$theme-colors: ( + primary: #1e1d24, + accent: #97f1e7, + secondary: #bbbbbd, + base: #ffffff +); + +$shades-primary: ( + 1: mix(white, map-get($theme-colors, primary), 52.5%), + 2: mix(white, map-get($theme-colors, primary), 70%), + 3: mix(white, map-get($theme-colors, primary), 77%), + 4: mix(white, map-get($theme-colors, primary), 80%), + 5: mix(white, map-get($theme-colors, primary), 90%) +); + +$shades-accent: ( + -2: mix(black, map-get($theme-colors, accent), 40%), + -1: mix(black, map-get($theme-colors, accent), 15.4%), + 1: mix(white, map-get($theme-colors, accent), 50%) +); + +$font-primary: 'Ubuntu', sans-serif; +$font-secondary: 'Roboto Slab', sans-serif; + +$base-font-size: 16px; + +$modular-scale: ( + -1: 0.75rem, + 0: $base-font-size, + 1: 1.333rem, + 2: 1.777rem, + 3: 2.369rem, + 4: 3.157rem +); + +$font-weights: ( + light: 300, + regular: 400, + medium: 500, + bold: 700 +); diff --git a/styleguide.md b/styleguide.md new file mode 100644 index 0000000..211f978 --- /dev/null +++ b/styleguide.md @@ -0,0 +1,122 @@ +# Style Guide + +## Color Palette + +### Monochromatic Theme Colors + +``` +$theme-colors: ( + primary: #1e1d24, // + accent: #97f1e7, // + secondary: #bbbbbd, // + base: #ffffff // White +); +``` + +Example: +`color: color(primary);` + +### Misc. Colors + +``` +$shades-primary: ( + 1: mix(white, color(primary), 52.5%), + 2: mix(white, color(primary), 70%), + 3: mix(white, color(primary), 77%), + 4: mix(white, color(primary), 80%), + 5: mix(white, color(primary), 90%) +); +``` + +Example: +`border-color: shades-primary(1);` + +``` +$shades-accent: ( + -2: mix(black, color(accent), 40%), + -1: mix(black, color(accent), 15.4%); + 1: mix(white, color(accent), 50%); +); +``` + +Example: +`border-color: shades-accent(-1);` + +## Typography + +### Font Families + +``` +Ubuntu +Robotoslab +``` + +### Font Weights + +``` +$font-weights: ( + light: 300, + regular: 400, + medium: 500, + bold: 700 +); +``` + +Example: +`font-weight: weight(light);` + +### Font Sizes + +``` +Base: 24px; + +$modular-scale: ( // Perfect Fourth + -1: 0.75rem, + 0: 1rem, + 1: 1.333rem, + 2: 1.777rem, + 3: 2.369rem, + 4: 3.157rem +); +``` + +Example: +`font-size: font-size(3);` + +## Guide: Colors & Typography by Section + +### Colors +Header Background: color(primary); +Logo color: color(base); +Header Text: color(base); +Page Header: color(primary); +Page Description: shades-accent(-2); +Share & Social Links: shades-primary(3); +Blog Summary & Meta: shades-primary(2); +Prev, Next, 1/2/3: shades-primary(1); +Last Section P: shades-accent(1); +Contact Text: #000; +Footer Text: #000; +Border Bottom Page Description: shades-accent(-1); +Border Bottom Breadcrumbs, Border top footer: shades-primary(4); +Border Bottom Blog Post: shades-primary(5); +Border Prev/Next: shades-primary(1); +Social Links Border: shades-primary(2); + +### Font Styles +Logo: ---------- Ubuntu, Medium, 56pt font-size(3); +Navigation: ----- Ubuntu, Regular, 24pt font-size(0); +Page Header: ---- Robotoslab, Regular, 80pt 3.33em; +Page Desc: ------ Robotoslab, Light, 56pt font-size(3); 3.5em line-height +Breadcrumbs: ---- Ubuntu, bold, 24pt font-size(0); +Share: ---------- Ubuntu, medium, 24pt font-size(0); +Post h1: -------- Ubuntu, regular, 72pt 3em; +Post P: --------- Ubuntu, light, 42pt font-size(2); 2.75em line-height +Post Meta: ------ Ubuntu, light italic, 32pt font-size(1); +Post Read More:-- Ubuntu, medium, 24pt font-size(0); +Last Sect. h1: -- Ubuntu, medium, 72pt 3em; +Last Sect. p: --- Ubuntu, regular, 32pt font-size(1); 2.25em line-height +Last Sect. button:Ubuntu, medium, 28pt 1.167em; +Contact links: -- Ubuntu, regular, 36pt 1.5em; +Social links: --- Ubuntu, bold, 24pt font-size(0); +Footer: --------- Ubuntu, Regular, 22pt .917em;