From 2596015a65dfb83f0f5945057058b38e8f6f2ad1 Mon Sep 17 00:00:00 2001 From: Juha Komulainen Date: Tue, 6 May 2014 14:03:54 +0300 Subject: [PATCH] Started demo app. --- .idea/inspectionProfiles/Project_Default.xml | 51 +++++ .../inspectionProfiles/profiles_settings.xml | 7 + .idea/jsLibraryMappings.xml | 7 + frontend/.bowerrc | 3 + frontend/.jshintrc | 9 + frontend/bower.json | 15 ++ frontend/build.gradle | 50 +++++ frontend/gulpfile.js | 197 ++++++++++++++++++ frontend/package.json | 75 +++++++ frontend/src/css/_blog.scss | 163 +++++++++++++++ frontend/src/css/_external.scss | 11 + frontend/src/css/default.scss | 2 + frontend/src/js/config.js | 10 + frontend/src/js/controllers/controllers.js | 7 + .../src/js/controllers/main-controller.js | 26 +++ .../src/js/controllers/post-controller.js | 14 ++ .../src/js/controllers/sidebar-controller.js | 47 +++++ .../src/js/directives/active-on-location.js | 18 ++ frontend/src/js/directives/directives.js | 7 + frontend/src/js/filters/filters.js | 5 + frontend/src/js/main.js | 34 +++ frontend/src/js/routes.js | 7 + frontend/src/js/services/services.js | 5 + frontend/src/templates/nav/sidebar.html | 19 ++ frontend/src/templates/nav/topnav.html | 8 + frontend/src/templates/views/main.html | 11 + frontend/src/templates/views/post.html | 22 ++ frontend/src/views/index.hbs | 31 +++ settings.gradle | 2 +- web-api/build.gradle | 5 + 30 files changed, 867 insertions(+), 1 deletion(-) create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/jsLibraryMappings.xml create mode 100644 frontend/.bowerrc create mode 100644 frontend/.jshintrc create mode 100644 frontend/bower.json create mode 100644 frontend/build.gradle create mode 100644 frontend/gulpfile.js create mode 100644 frontend/package.json create mode 100644 frontend/src/css/_blog.scss create mode 100644 frontend/src/css/_external.scss create mode 100644 frontend/src/css/default.scss create mode 100644 frontend/src/js/config.js create mode 100644 frontend/src/js/controllers/controllers.js create mode 100644 frontend/src/js/controllers/main-controller.js create mode 100644 frontend/src/js/controllers/post-controller.js create mode 100644 frontend/src/js/controllers/sidebar-controller.js create mode 100644 frontend/src/js/directives/active-on-location.js create mode 100644 frontend/src/js/directives/directives.js create mode 100644 frontend/src/js/filters/filters.js create mode 100644 frontend/src/js/main.js create mode 100644 frontend/src/js/routes.js create mode 100644 frontend/src/js/services/services.js create mode 100644 frontend/src/templates/nav/sidebar.html create mode 100644 frontend/src/templates/nav/topnav.html create mode 100644 frontend/src/templates/views/main.html create mode 100644 frontend/src/templates/views/post.html create mode 100644 frontend/src/views/index.hbs diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..b879557 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,51 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..3b31283 --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml new file mode 100644 index 0000000..01c3f40 --- /dev/null +++ b/.idea/jsLibraryMappings.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/.bowerrc b/frontend/.bowerrc new file mode 100644 index 0000000..0bee623 --- /dev/null +++ b/frontend/.bowerrc @@ -0,0 +1,3 @@ +{ + "directory": "build/bower_components" +} \ No newline at end of file diff --git a/frontend/.jshintrc b/frontend/.jshintrc new file mode 100644 index 0000000..cf0dc70 --- /dev/null +++ b/frontend/.jshintrc @@ -0,0 +1,9 @@ +{ + "browser": true, + "globalstrict": true, + "esnext": true, + + "predef": [ + "require", "module", "exports", "confirm" + ] +} diff --git a/frontend/bower.json b/frontend/bower.json new file mode 100644 index 0000000..ec74478 --- /dev/null +++ b/frontend/bower.json @@ -0,0 +1,15 @@ +{ + "name": "yoke", + "license": "proprietary", + "private": true, + "dependencies": { + "angular-route": "1.2.16", + "angular-i18n": "1.2.16", + "angular-sanitize": "1.2.16", + "angular-bootstrap": "0.10.0", + "bootstrap": "3.1.1", + "stomp-websocket": "2.3.1", + "sockjs": "0.3.4", + "font-awesome": "4.0.3" + } +} diff --git a/frontend/build.gradle b/frontend/build.gradle new file mode 100644 index 0000000..f934d18 --- /dev/null +++ b/frontend/build.gradle @@ -0,0 +1,50 @@ +buildscript { + repositories { + mavenCentral() + jcenter() + } + dependencies { + classpath 'com.moowork.gradle:gradle-node-plugin:0.5' + } +} + +apply plugin: 'base' +apply plugin: 'node' + +repositories { + mavenCentral() + jcenter() +} + +task gulpBuild(type: NodeTask, dependsOn: 'npmInstall') { + inputs.dir 'src' + inputs.files 'gulpfile.js', 'bower.json', 'package.json' + outputs.dir 'build/gulp/optimized' + + script = file('node_modules/.bin/gulp') + args = ['build-production'] +} + +task gulpServe(type: NodeTask, dependsOn: 'npmInstall') { + script = file('node_modules/.bin/gulp') + args = ['default'] +} + +task deleteNodeModules(type: Delete) { + delete 'node_modules' +} + +clean.dependsOn deleteNodeModules + +task build { + dependsOn gulpBuild +} + +task serve { + dependsOn gulpServe +} + +node { + version = '0.10.26' + download = true +} diff --git a/frontend/gulpfile.js b/frontend/gulpfile.js new file mode 100644 index 0000000..85e0bf9 --- /dev/null +++ b/frontend/gulpfile.js @@ -0,0 +1,197 @@ +"use strict"; + +var gulp = require('gulp'); +var clean = require('gulp-clean'); +var path = require('path'); +var browserify = require('browserify'); +var es6ify = require('es6ify'); +var source = require('vinyl-source-stream'); +var express = require('express'); +var http = require('http'); +var morgan = require('morgan'); +var livereload = require('gulp-livereload'); +var gulpOpen = require('gulp-open'); +var sass = require('gulp-sass'); +var size = require('gulp-size'); +var notify = require('gulp-notify'); +var templateCache = require('gulp-angular-templatecache'); +var rename = require("gulp-rename"); +var handlebars = require('gulp-compile-handlebars'); +var envifyCustom = require('envify/custom'); +var revall = require('gulp-rev-all'); +var uglify = require('gulp-uglify'); +var gulpif = require('gulp-if'); +var streamify = require('gulp-streamify'); + +var config = { + production: false, + port: '3000' +}; + +var paths = { + sass: './src/css/*.scss', + templates: './src/templates/**/*.html', + views: './src/views/**/*.hbs', + build: { + dest: './build/gulp/static', + tmp: './build/gulp/tmp' + }, + vendor: { + stylesheets: [ + './build/bower_components/bootstrap/dist/css/bootstrap.min.css', + './build/bower_components/font-awesome/css/font-awesome.min.css' + ], + fonts: [ + './build/bower_components/bootstrap/dist/fonts/*', + './build/bower_components/font-awesome/fonts/*' + ] + } +}; + +var handleErrors = function() { + // Send error to notification center with gulp-notify + notify.onError({ + title: "Compile Error", + message: "<%= error.message %>" + }).apply(this, arguments); + + // Keep gulp from hanging on this task + this.emit('end'); +}; + +gulp.task('browserify', ['compile-angular-templates'], function () { + var env = { + API_BASE: config.production ? '/api' : 'http://localhost:8080/api' + }; + + var bundleStream = browserify() + .add(es6ify.runtime) + .transform(es6ify.configure(/^(?!.*(node_modules|bower_components))+.+\.js$/)) + .transform(envifyCustom(env)) + .require(require.resolve('./src/js/main.js'), { entry: true }) + .bundle({debug: !config.production}); + + return bundleStream + .on('error', handleErrors) + .pipe(source('bundle.js')) + .pipe(gulpif(config.production, streamify(uglify()))) + .pipe(streamify(size({showFiles: true}))) + .pipe(gulp.dest(path.join(paths.build.dest, 'js'))); +}); + +gulp.task('serve', ['watch'], function() { + + /** @type Object */ + var app = express(); + + app.use(morgan('dev')); + app.use(express.static(paths.build.dest)); + + http.createServer(app).listen(config.port); + + app.get(/^\/(post)(\/.*)?$/, function(req, res) { + res.sendfile(path.join(paths.build.dest, 'index.html')); + }); + + /** @type Object */ + var lrServer = livereload(); + gulp.watch(path.join(paths.build.dest, '**')).on('change', function(file) { + lrServer.changed(file.path); + }); +}); + +gulp.task('open', ['serve'], function(cb) { + + var options = { + url: "http://localhost:" + config.port, + app: "Google Chrome" + }; + + gulp.src(path.join(paths.build.dest, 'index.html')).pipe(gulpOpen("", options)); + cb(); +}); + +gulp.task('sass', function() { + var options = { }; + if (config.production) { + options.outputStyle = 'compressed'; + } else { + options.outputStyle = 'nested'; + options.sourceComments = 'map'; + } + + return gulp.src(paths.sass) + .pipe(sass(options)) + .pipe(size({showFiles: true})) + .pipe(gulp.dest(path.join(paths.build.dest, 'css'))) + .on('error', handleErrors); +}); + +gulp.task('vendor-css', function() { + return gulp.src(paths.vendor.stylesheets) + .pipe(gulp.dest(path.join(paths.build.dest, 'css'))) + .on('error', handleErrors); +}); + +gulp.task('fonts', function() { + return gulp.src(paths.vendor.fonts) + .pipe(gulp.dest(path.join(paths.build.dest, 'fonts'))) + .on('error', handleErrors); +}); + +gulp.task('styles', ['sass', 'vendor-css', 'fonts']); + +gulp.task('watch', ['build'], function() { + gulp.watch(['./src/js/**/*.js', './build/gulp/tmp/templates.js'], ['browserify']); + gulp.watch(paths.sass, ['sass']); + gulp.watch(paths.templates, ['compile-angular-templates']); + gulp.watch(paths.views, ['compile-views']); +}); + +gulp.task('compile-views', function() { + return gulp.src(paths.views) + .pipe(handlebars({})) + .pipe(rename(function(path) { + path.extname = '.html'; + })) + .pipe(gulp.dest(paths.build.dest)); +}); + +gulp.task('compile-angular-templates', function () { + gulp.src(paths.templates) + .pipe(templateCache({ + 'module': 'blogular.templates', + 'standalone': true, + 'root': '/templates/' + })) + .pipe(size({showFiles: true})) + .pipe(gulp.dest(paths.build.tmp)); +}); + +gulp.task('templates', ['compile-views', 'compile-angular-templates']); + +gulp.task('clean', function () { + return gulp.src(['build/gulp'], { read: false }).pipe(clean()); +}); + +gulp.task('build', ['browserify', 'styles', 'templates']); + +gulp.task('optimize', ['build'], function() { + gulp.src(path.join(paths.build.dest, '**')) + .pipe(revall({ ignoredExtensions: ['.html'] })) + .pipe(gulp.dest('./build/gulp/optimized')); +}); + +gulp.task('build-production', ['clean'], function() { + config.production = true; + gulp.start('optimize'); +}); + +gulp.task('build-development', ['clean'], function() { + config.production = false; + gulp.start('build'); +}); + +gulp.task('default', ['clean'], function () { + gulp.start('open'); +}); diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..21a3bb2 --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,75 @@ +{ + "name": "blogular", + "description": "npm packages needed to build blogular", + "private": true, + "version": "0.0.0", + "dependencies": { + "angular": "1.2.16", + "jquery": "2.1.0", + "lodash": "2.4.1" + }, + "devDependencies": { + "node-sass": "0.8.4", + "browserify-shim": "3.4.1", + "browserify": "3.36.0", + "connect": "2.14.3", + "gulp-changed": "0.3.0", + "gulp-compass": "1.1.8", + "gulp-imagemin": "0.1.5", + "gulp-livereload": "1.2.0", + "gulp-notify": "1.2.4", + "gulp-open": "0.2.8", + "gulp": "3.6.0", + "vinyl-source-stream": "0.1.1", + "gulp-sass": "0.7.1", + "gulp-angular-templatecache": "1.1.3", + "express": "4.1.1", + "morgan": "1.0.1", + "bower": "1.3.3", + "es6ify": "1.1.0", + "gulp-size": "0.3.1", + "http-proxy": "1.1.2", + "gulp-clean": "0.2.4", + "gulp-compile-handlebars": "0.2.0", + "gulp-rename": "1.2.0", + "envify": "1.2.1", + "gulp-rev-all": "0.1.5", + "gulp-uglify": "0.2.1", + "gulp-if": "1.1.0", + "gulp-streamify": "0.0.5" + }, + "browserify": { + "transform": [ + "browserify-shim" + ] + }, + "browserify-shim": { + "angular": { + "exports": "angular", + "depends": [ + "jquery:$" + ] + }, + "sockjs": { + "exports": "SockJS" + }, + "stomp": { + "exports": "Stomp" + } + }, + "scripts": { + "install": "./node_modules/.bin/bower install" + }, + "browser": { + "angular": "./build/bower_components/angular/angular.js", + "angular-route": "./build/bower_components/angular-route/angular-route.js", + "angular-resource": "./build/bower_components/angular-resource/angular-resource.js", + "angular-sanitize": "./build/bower_components/angular-sanitize/angular-sanitize.js", + "angular-i18n/angular-locale_fi": "./build/bower_components/angular-i18n/angular-locale_fi.js", + "angular-bootstrap/ui-bootstrap-tpls": "./build/bower_components/angular-bootstrap/ui-bootstrap-tpls.js", + "bootstrap": "./build/bower_components/bootstrap/dist/js/bootstrap.js", + "sockjs": "./build/bower_components/sockjs/sockjs.js", + "stomp": "./build/bower_components/stomp-websocket/lib/stomp.js", + "templates": "./build/gulp/tmp/templates.js" + } +} diff --git a/frontend/src/css/_blog.scss b/frontend/src/css/_blog.scss new file mode 100644 index 0000000..08e0a8d --- /dev/null +++ b/frontend/src/css/_blog.scss @@ -0,0 +1,163 @@ +/* + * Globals + */ + +body { + font-family: Georgia, "Times New Roman", Times, serif; + color: #555; +} + +h1, .h1, +h2, .h2, +h3, .h3, +h4, .h4, +h5, .h5, +h6, .h6 { + margin-top: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: normal; + color: #333; +} + + +/* + * Override Bootstrap's default container. + */ + +@media (min-width: 1200px) { + .container { + width: 970px; + } +} + + +/* + * Masthead for nav + */ + +.blog-masthead { + background-color: #428bca; + box-shadow: inset 0 -2px 5px rgba(0,0,0,.1); +} + +/* Nav links */ +.blog-nav-item { + position: relative; + display: inline-block; + padding: 10px; + font-weight: 500; + color: #cdddeb; +} +.blog-nav-item:hover, +.blog-nav-item:focus { + color: #fff; + text-decoration: none; +} + +/* Active state gets a caret at the bottom */ +.blog-nav .active { + color: #fff; +} +.blog-nav .active:after { + position: absolute; + bottom: 0; + left: 50%; + width: 0; + height: 0; + margin-left: -5px; + vertical-align: middle; + content: " "; + border-right: 5px solid transparent; + border-bottom: 5px solid; + border-left: 5px solid transparent; +} + + +/* + * Blog name and description + */ + +.blog-header { + padding-top: 20px; + padding-bottom: 20px; +} +.blog-title { + margin-top: 30px; + margin-bottom: 0; + font-size: 60px; + font-weight: normal; +} +.blog-description { + font-size: 20px; + color: #999; +} + + +/* + * Main column and sidebar layout + */ + +.blog-main { + font-size: 18px; + line-height: 1.5; +} + +/* Sidebar modules for boxing content */ +.sidebar-module { + padding: 15px; + margin: 0 -15px 15px; +} +.sidebar-module-inset { + padding: 15px; + background-color: #f5f5f5; + border-radius: 4px; +} +.sidebar-module-inset p:last-child, +.sidebar-module-inset ul:last-child, +.sidebar-module-inset ol:last-child { + margin-bottom: 0; +} + + + +/* Pagination */ +.pager { + margin-bottom: 60px; + text-align: left; +} +.pager > li > a { + width: 140px; + padding: 10px 20px; + text-align: center; + border-radius: 30px; +} + + +/* + * Blog posts + */ + +.blog-post { + margin-bottom: 60px; +} +.blog-post-title { + margin-bottom: 5px; + font-size: 40px; +} +.blog-post-meta { + margin-bottom: 20px; + color: #999; +} + + +/* + * Footer + */ + +.blog-footer { + padding: 40px 0; + color: #999; + text-align: center; + background-color: #f9f9f9; + border-top: 1px solid #e5e5e5; +} diff --git a/frontend/src/css/_external.scss b/frontend/src/css/_external.scss new file mode 100644 index 0000000..5d92e53 --- /dev/null +++ b/frontend/src/css/_external.scss @@ -0,0 +1,11 @@ +// Style rules to support external components + +// Cloaking for AngularJS +[ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { + display: none !important +} + +// Proper pointer behaviour for Angular-UI +.nav, .pagination, .carousel, .panel-title a { + cursor: pointer; +} diff --git a/frontend/src/css/default.scss b/frontend/src/css/default.scss new file mode 100644 index 0000000..ef90597 --- /dev/null +++ b/frontend/src/css/default.scss @@ -0,0 +1,2 @@ +@import 'external'; +@import 'blog'; diff --git a/frontend/src/js/config.js b/frontend/src/js/config.js new file mode 100644 index 0000000..33f43fa --- /dev/null +++ b/frontend/src/js/config.js @@ -0,0 +1,10 @@ +"use strict"; + +var process = require('process'); + +// This will be replaced at build time by envify +var apiBase = process.env.API_BASE; + +module.exports = { + apiBase: apiBase +}; diff --git a/frontend/src/js/controllers/controllers.js b/frontend/src/js/controllers/controllers.js new file mode 100644 index 0000000..a338258 --- /dev/null +++ b/frontend/src/js/controllers/controllers.js @@ -0,0 +1,7 @@ +"use strict"; + +module.exports = require('angular').module('blogular.controllers', []); + +require('./main-controller'); +require('./post-controller'); +require('./sidebar-controller'); diff --git a/frontend/src/js/controllers/main-controller.js b/frontend/src/js/controllers/main-controller.js new file mode 100644 index 0000000..9c8d2f9 --- /dev/null +++ b/frontend/src/js/controllers/main-controller.js @@ -0,0 +1,26 @@ +"use strict"; + +var controllers = require('angular').module('blogular.controllers'); + +controllers.controller('MainController', ['$scope', ($scope) => { + $scope.posts = [ + { + title: 'Sample blog post', + author: 'Mark', + body: '

This blog post shows a few different types of content that\'s supported and styled with Bootstrap. Basic typography, images, and code are all supported.

\n
\n

Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Sed posuere consectetur est at lobortis. Cras mattis consectetur purus sit amet fermentum.

\n
\n

Curabitur blandit tempus porttitor. Nullam quis risus eget urna mollis ornare vel eu leo. Nullam id dolor id nibh ultricies vehicula ut id elit.

\n
\n

Etiam porta sem malesuada magna mollis euismod. Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.

\n

Heading

\n

Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.

\n

Sub-heading

\n

Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.

\n
Example code block
\n

Aenean lacinia bibendum nulla sed consectetur. Etiam porta sem malesuada magna mollis euismod. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa.

\n

Sub-heading

\n

Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean lacinia bibendum nulla sed consectetur. Etiam porta sem malesuada magna mollis euismod. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.

\n \n

Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue.

\n
    \n
  1. Vestibulum id ligula porta felis euismod semper.
  2. \n
  3. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
  4. \n
  5. Maecenas sed diam eget risus varius blandit sit amet non magna.
  6. \n
\n

Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis.

', + date: new Date(2014, 0, 1) + }, + { + title: 'Another blog post', + author: 'Jacob', + body: '

Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Sed posuere consectetur est at lobortis. Cras mattis consectetur purus sit amet fermentum.

\n
\n

Curabitur blandit tempus porttitor. Nullam quis risus eget urna mollis ornare vel eu leo. Nullam id dolor id nibh ultricies vehicula ut id elit.

\n
\n

Etiam porta sem malesuada magna mollis euismod. Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.

\n

Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.

\n', + date: new Date(2013, 11, 23) + }, + { + title: 'New feature', + author: 'Chris', + body: '

Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean lacinia bibendum nulla sed consectetur. Etiam porta sem malesuada magna mollis euismod. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.

\n\n

Etiam porta sem malesuada magna mollis euismod. Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.

\n

Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue.

\n', + date: new Date(2013, 11, 14) + } + ]; +}]); diff --git a/frontend/src/js/controllers/post-controller.js b/frontend/src/js/controllers/post-controller.js new file mode 100644 index 0000000..e95844c --- /dev/null +++ b/frontend/src/js/controllers/post-controller.js @@ -0,0 +1,14 @@ +"use strict"; + +var controllers = require('angular').module('blogular.controllers'); + +controllers.controller('PostController', ['$scope', '$location', ($scope, $location) => { + $scope.newPost = { + title: '', + text: '' + }; + + $scope.savePost = () => { + $location.path('/'); + } +}]); diff --git a/frontend/src/js/controllers/sidebar-controller.js b/frontend/src/js/controllers/sidebar-controller.js new file mode 100644 index 0000000..2709597 --- /dev/null +++ b/frontend/src/js/controllers/sidebar-controller.js @@ -0,0 +1,47 @@ +"use strict"; + +var controllers = require('angular').module('blogular.controllers'); + +controllers.controller('SidebarController', ['$scope', ($scope) => { + $scope.sidebar = { + about: '

Etiam porta sem malesuada magna mollis euismod. Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.

', + + archiveLinks: [ + "2014-01-01", + "2013-12-01", + "2013-11-01", + "2013-10-01", + "2013-09-01", + "2013-08-01", + "2013-07-01", + "2013-06-01", + "2013-05-01", + "2013-04-01", + "2013-03-01", + "2013-02-01" + ], + + externalLinks: [ + { + title: 'Bitbucket', + href: 'https://bitbucket.org/evidentsolutions', + icon: 'twitter' + }, + { + title: 'GitHub', + href: 'https://bitbucket.org/evidentsolutions', + icon: 'github' + }, + { + title: 'Twitter', + href: 'https://twitter.com/EvidentSolution', + icon: 'twitter' + }, + { + title: 'Facebook', + href: 'https://www.facebook.com/evidentsolutions', + icon: 'facebook' + } + ] + }; +}]); diff --git a/frontend/src/js/directives/active-on-location.js b/frontend/src/js/directives/active-on-location.js new file mode 100644 index 0000000..15925a3 --- /dev/null +++ b/frontend/src/js/directives/active-on-location.js @@ -0,0 +1,18 @@ +"use strict"; + +var directives = require('angular').module('blogular.directives'); + +/** + * A directive which toggles 'active' class of its containing element if current location + * matches the href of the element. + */ +directives.directive('activeOnLocation', ['$location', ($location) => { + return ($scope, $element) => { + function updateActiveState() { + $element.toggleClass("active", $location.path() == $element.attr('href')); + } + + updateActiveState(); + $scope.$on('$locationChangeSuccess', updateActiveState); + }; +}]); diff --git a/frontend/src/js/directives/directives.js b/frontend/src/js/directives/directives.js new file mode 100644 index 0000000..c8c658f --- /dev/null +++ b/frontend/src/js/directives/directives.js @@ -0,0 +1,7 @@ +"use strict"; + +var directives = require('angular').module('blogular.directives', []); + +require('./active-on-location'); + +module.exports = directives; diff --git a/frontend/src/js/filters/filters.js b/frontend/src/js/filters/filters.js new file mode 100644 index 0000000..19929cc --- /dev/null +++ b/frontend/src/js/filters/filters.js @@ -0,0 +1,5 @@ +"use strict"; + +var filters = require('angular').module('blogular.filters', []); + +module.exports = filters; diff --git a/frontend/src/js/main.js b/frontend/src/js/main.js new file mode 100644 index 0000000..ef73d40 --- /dev/null +++ b/frontend/src/js/main.js @@ -0,0 +1,34 @@ +"use strict"; + +window._ = require('lodash'); +window.jQuery = require('jquery'); +var angular = require('angular'); + +require('angular-route'); +require('angular-sanitize'); +require('angular-i18n/angular-locale_fi'); +require('bootstrap'); +require('angular-bootstrap/ui-bootstrap-tpls'); +require('templates'); + +var app = angular.module('blogular', [ + 'ngRoute', + 'ngSanitize', + 'ui.bootstrap.modal', + 'ui.bootstrap.tabs', + 'ui.bootstrap.dropdownToggle', + 'ui.bootstrap.tpls', + 'blogular.templates', + require('./controllers/controllers').name, + require('./directives/directives').name, + require('./filters/filters').name, + require('./services/services').name +]); + +app.config(['$locationProvider', '$routeProvider', ($locationProvider, $routeProvider) => { + $locationProvider.html5Mode(true); + + require('./routes').initializeRoutes($routeProvider); +}]); + +module.exports = app; diff --git a/frontend/src/js/routes.js b/frontend/src/js/routes.js new file mode 100644 index 0000000..5db4d6d --- /dev/null +++ b/frontend/src/js/routes.js @@ -0,0 +1,7 @@ +"use strict"; + +exports.initializeRoutes = ($routeProvider) => { + $routeProvider + .when('/', { controller: 'MainController', templateUrl: '/templates/views/main.html' }) + .when('/post', { controller: 'PostController', templateUrl: '/templates/views/post.html' }); +}; diff --git a/frontend/src/js/services/services.js b/frontend/src/js/services/services.js new file mode 100644 index 0000000..8898bb3 --- /dev/null +++ b/frontend/src/js/services/services.js @@ -0,0 +1,5 @@ +"use strict"; + +var services = require('angular').module('visualisti.services', []); + +module.exports = services; diff --git a/frontend/src/templates/nav/sidebar.html b/frontend/src/templates/nav/sidebar.html new file mode 100644 index 0000000..512191e --- /dev/null +++ b/frontend/src/templates/nav/sidebar.html @@ -0,0 +1,19 @@ +
+ + + +
diff --git a/frontend/src/templates/nav/topnav.html b/frontend/src/templates/nav/topnav.html new file mode 100644 index 0000000..6c3db07 --- /dev/null +++ b/frontend/src/templates/nav/topnav.html @@ -0,0 +1,8 @@ +
+
+ +
+
diff --git a/frontend/src/templates/views/main.html b/frontend/src/templates/views/main.html new file mode 100644 index 0000000..f09273d --- /dev/null +++ b/frontend/src/templates/views/main.html @@ -0,0 +1,11 @@ +
+

{{post.title}}

+ + +
+
+ + diff --git a/frontend/src/templates/views/post.html b/frontend/src/templates/views/post.html new file mode 100644 index 0000000..fd3fd55 --- /dev/null +++ b/frontend/src/templates/views/post.html @@ -0,0 +1,22 @@ +
+ +

New Post

+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
diff --git a/frontend/src/views/index.hbs b/frontend/src/views/index.hbs new file mode 100644 index 0000000..2c48821 --- /dev/null +++ b/frontend/src/views/index.hbs @@ -0,0 +1,31 @@ + + + + Blogular + + + + + + + + + + +
+
+

Blogular

+

A simple AngularJS example application.

+
+ +
+
+
+
+ +
+
+ + + + diff --git a/settings.gradle b/settings.gradle index be356e7..38a1df9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,3 @@ rootProject.name = 'blogular' -include ':web-api' +include ':frontend', ':web-api' diff --git a/web-api/build.gradle b/web-api/build.gradle index 244b55d..fd45b8b 100644 --- a/web-api/build.gradle +++ b/web-api/build.gradle @@ -41,3 +41,8 @@ dependencies { compile.exclude module: 'commons-logging' } } + +war { + from webAppDir + from project(':frontend').tasks.gulpBuild +}