From 9b031817c6b6c6cff929aa702bbea9caa4eaec79 Mon Sep 17 00:00:00 2001 From: pastorsj Date: Sun, 15 Oct 2017 18:31:54 -0400 Subject: [PATCH 1/9] Added simple card layout with bulma --- src/app/_services/authentication.service.ts | 2 +- src/app/articles/articles.component.html | 50 ++++++++++++++------- src/app/articles/articles.component.scss | 4 ++ src/app/editor/editor.component.html | 4 +- src/app/nav-bar/nav-bar.component.ts | 4 +- src/index.html | 1 + 6 files changed, 44 insertions(+), 21 deletions(-) diff --git a/src/app/_services/authentication.service.ts b/src/app/_services/authentication.service.ts index 6ffd22c..dd87b6b 100644 --- a/src/app/_services/authentication.service.ts +++ b/src/app/_services/authentication.service.ts @@ -74,7 +74,7 @@ export class AuthenticationService { reject(`Error ${error}`); }); } else { - reject('No token available'); + reject(); } }) } diff --git a/src/app/articles/articles.component.html b/src/app/articles/articles.component.html index da7577d..30a06e9 100644 --- a/src/app/articles/articles.component.html +++ b/src/app/articles/articles.component.html @@ -1,19 +1,35 @@
- - - - - {{article?.title}} - - -

- {{article?.description}} -

-
- - - -
-
-
+
+
+
+
+ + + {{article?.title}} + + +

+ {{article?.description}} +

+
+ + + +
+
+
+ + + About + + +

+ This site was developed by... +

+
+
+
+
+
+
\ No newline at end of file diff --git a/src/app/articles/articles.component.scss b/src/app/articles/articles.component.scss index e6ef60a..3c7f7af 100644 --- a/src/app/articles/articles.component.scss +++ b/src/app/articles/articles.component.scss @@ -1,4 +1,8 @@ .articles { margin-left: 3vw; margin-top: 2vh; +} + +.main { + background-color: red; } \ No newline at end of file diff --git a/src/app/editor/editor.component.html b/src/app/editor/editor.component.html index 6d2b123..9503618 100644 --- a/src/app/editor/editor.component.html +++ b/src/app/editor/editor.component.html @@ -11,12 +11,12 @@ Article Description is required - + {{ tag }} cancel - + diff --git a/src/app/nav-bar/nav-bar.component.ts b/src/app/nav-bar/nav-bar.component.ts index 8bdf83b..582ad41 100755 --- a/src/app/nav-bar/nav-bar.component.ts +++ b/src/app/nav-bar/nav-bar.component.ts @@ -45,7 +45,9 @@ export class NavBarComponent implements OnInit { this.image = this.authorService.getProfilePicture(); }) .catch(error => { - console.error('Error', error); + if (error) { + console.error('Error', error); + } this.logout(); }); } diff --git a/src/index.html b/src/index.html index 93e2c0a..bd44546 100755 --- a/src/index.html +++ b/src/index.html @@ -6,6 +6,7 @@ + From 400d0b2e10cc4fdf18cae17b5266dedc1ff04889 Mon Sep 17 00:00:00 2001 From: pastorsj Date: Sun, 15 Oct 2017 21:33:36 -0400 Subject: [PATCH 2/9] Added about section with links to frontend and backend repositories --- src/app/_models/Article.ts | 2 +- src/app/articles/articles.component.html | 87 +++++++++++++++--------- src/app/articles/articles.component.scss | 4 +- 3 files changed, 58 insertions(+), 35 deletions(-) diff --git a/src/app/_models/Article.ts b/src/app/_models/Article.ts index 589c469..cb4849b 100644 --- a/src/app/_models/Article.ts +++ b/src/app/_models/Article.ts @@ -2,7 +2,7 @@ export class Article { _id: number; title: string; description: string; - datePosted: string; + datePosted: Date; text: string; author: string; tags: Array; diff --git a/src/app/articles/articles.component.html b/src/app/articles/articles.component.html index 30a06e9..13cdc7f 100644 --- a/src/app/articles/articles.component.html +++ b/src/app/articles/articles.component.html @@ -1,35 +1,58 @@
-
-
-
-
- - - {{article?.title}} - - -

- {{article?.description}} -

-
- - - -
-
-
- - - About - - -

- This site was developed by... -

-
-
-
+
+
+
+
+ + + + {{article?.title}} + + + By {{article?.author}} {{article?.datePosted | date:'longDate'}} + + + + {{article?.description}} + + + + +
-
-
+
+ + + About + + +

+ This site was developed by Sam Pastoriza + and James Edwards. + We wanted a blog that was self sustaining and easily modifiable. + We are using the Angular framework developed by Google and a combination of + Angular Material and Bulma to style and layout the site respectively. An express based + backend application utilizes MongoDb and Redis to store data on users and articles. The + blog is completely open-sourced on Github and contributers are more than welcome. The end goal + is a fully functional blog mainly covering technical topics, but can be reused + as a base for other blogs. +

+
+ + + + developer_board + Blog + + + developer_board + Backend Api + + + +
+
+
+
+
\ No newline at end of file diff --git a/src/app/articles/articles.component.scss b/src/app/articles/articles.component.scss index 3c7f7af..879c43b 100644 --- a/src/app/articles/articles.component.scss +++ b/src/app/articles/articles.component.scss @@ -3,6 +3,6 @@ margin-top: 2vh; } -.main { - background-color: red; +.repo:hover { + background-color: #bdbdbd; } \ No newline at end of file From 471c271e9a709c38992bf8e7f3ebc4c680c4832a Mon Sep 17 00:00:00 2001 From: pastorsj Date: Mon, 16 Oct 2017 20:55:37 -0400 Subject: [PATCH 3/9] Added space between about section and tag section and added tag card with http calls to populate card --- src/app/_services/tags.service.ts | 53 ++++++++++++++++++++++++ src/app/app.module.ts | 3 ++ src/app/articles/articles.component.html | 14 ++++++- src/app/articles/articles.component.scss | 4 ++ src/app/articles/articles.component.ts | 13 ++++++ 5 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 src/app/_services/tags.service.ts diff --git a/src/app/_services/tags.service.ts b/src/app/_services/tags.service.ts new file mode 100644 index 0000000..25137cf --- /dev/null +++ b/src/app/_services/tags.service.ts @@ -0,0 +1,53 @@ +import { Injectable } from '@angular/core'; +import { Http, Response, RequestOptions, Headers } from '@angular/http'; + +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/operator/catch'; +import 'rxjs/add/operator/map'; + +import { AuthenticationService } from '../_services/authentication.service'; +import { Article } from '../_models/Article'; +import { environment } from '../../environments/environment'; + +@Injectable() +export class TagService { + + private tagUrl = environment.URL + '/tags/'; + + constructor( + private http: Http, + private auth: AuthenticationService + ) { } + + getAllTags(): Observable> { + return this.http.get(this.tagUrl) + .map(this.extractData) + .catch(this.handleError); + } + + getArticlesByTag(tag: string): Observable
{ + return this.http.get(this.tagUrl + tag) + .map(this.extractData) + .catch(this.handleError); + } + + private extractData(res: Response) { + const body = res.json(); + return body.data || { }; + } + + private handleError (error: Response | any) { + // In a real world app, you might use a remote logging infrastructure + let errMsg: string; + if (error instanceof Response) { + const body = error.json() || ''; + const err = body.error || JSON.stringify(body); + errMsg = `${error.status} - ${error.statusText || ''} ${err}`; + } else { + errMsg = error.message ? error.message : error.toString(); + } + console.error(errMsg); + return Observable.throw(errMsg); + } + +} diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 553db31..0aecf05 100755 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -25,6 +25,8 @@ import { EditorService } from './_services/editor.service'; import { ArticleService } from './_services/article.service'; import { AuthorService } from './_services/author.service'; import { ImagesService } from './_services/images.service'; +import { TagService } from './_services/tags.service'; + import { FileValidator } from './_directives/fileValidator.directive'; import { FileValueAccessor } from './_directives/fileValueAccessor.directive'; @@ -78,6 +80,7 @@ import { MaterialModule } from './material.module'; ArticleService, AuthorService, ImagesService, + TagService, BaseRequestOptions ], bootstrap: [ diff --git a/src/app/articles/articles.component.html b/src/app/articles/articles.component.html index 13cdc7f..3de8fa6 100644 --- a/src/app/articles/articles.component.html +++ b/src/app/articles/articles.component.html @@ -3,7 +3,7 @@
- + {{article?.title}} @@ -21,7 +21,7 @@
- + About @@ -51,6 +51,16 @@ + + + Tags + + + + {{ tag }} + + +
diff --git a/src/app/articles/articles.component.scss b/src/app/articles/articles.component.scss index 879c43b..b6c5edd 100644 --- a/src/app/articles/articles.component.scss +++ b/src/app/articles/articles.component.scss @@ -5,4 +5,8 @@ .repo:hover { background-color: #bdbdbd; +} + +.card-sections { + margin-bottom: 20px; } \ No newline at end of file diff --git a/src/app/articles/articles.component.ts b/src/app/articles/articles.component.ts index ebf23bc..68aed87 100644 --- a/src/app/articles/articles.component.ts +++ b/src/app/articles/articles.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { ArticleService } from '../_services/article.service'; import { Router } from '@angular/router'; +import { TagService } from '../_services/tags.service'; @Component({ selector: 'app-articles', @@ -11,14 +12,22 @@ import { Router } from '@angular/router'; export class ArticlesComponent implements OnInit { public articles; + public tags: Promise>; + private tagData: Object; constructor( private articleService: ArticleService, + private tagService: TagService, private router: Router ) { } ngOnInit() { this.articles = this.articleService.getAllArticles(); + this.tagService.getAllTags() + .subscribe((tags) => { + this.tagData = tags; + this.tags = Promise.resolve(Object.keys(tags)); + }); } selectedArticle(e) { @@ -26,4 +35,8 @@ export class ArticlesComponent implements OnInit { this.router.navigate(['article', e._id]); } + getArticlesByTag(tag: string) { + this.articles = this.tagService.getArticlesByTag(tag); + } + } From d2cd7c43f339ab1cc07b18b9a1906612f3d5814d Mon Sep 17 00:00:00 2001 From: pastorsj Date: Tue, 17 Oct 2017 21:41:09 -0400 Subject: [PATCH 4/9] Added simple tag component --- src/app/app.module.ts | 4 +++- src/app/articles/articles.component.html | 11 +++++++---- src/app/articles/articles.component.ts | 9 ++++++++- src/app/articles/tag/tag.component.html | 1 + src/app/articles/tag/tag.component.scss | 3 +++ src/app/articles/tag/tag.component.ts | 23 +++++++++++++++++++++++ 6 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 src/app/articles/tag/tag.component.html create mode 100644 src/app/articles/tag/tag.component.scss create mode 100644 src/app/articles/tag/tag.component.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 0aecf05..197eba0 100755 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -18,6 +18,7 @@ import {Router} from './app.routing'; import { EditorComponent } from './editor/editor.component'; import { UserArticlesComponent } from './user-articles/user-articles.component'; import { CreateArticleModalComponent } from './create-article-modal/create-article-modal.component'; +import { TagComponent } from './articles/tag/tag.component'; import { AuthGuard } from './_guards/auth.guard'; import { AuthenticationService } from './_services/authentication.service'; @@ -51,7 +52,8 @@ import { MaterialModule } from './material.module'; DeleteArticleModalComponent, SettingsModalComponent, FileValidator, - FileValueAccessor + FileValueAccessor, + TagComponent ], imports: [ BrowserAnimationsModule, diff --git a/src/app/articles/articles.component.html b/src/app/articles/articles.component.html index 3de8fa6..a965bd5 100644 --- a/src/app/articles/articles.component.html +++ b/src/app/articles/articles.component.html @@ -28,7 +28,7 @@

This site was developed by Sam Pastoriza - and James Edwards. + and James Edwards. We wanted a blog that was self sustaining and easily modifiable. We are using the Angular framework developed by Google and a combination of Angular Material and Bulma to style and layout the site respectively. An express based @@ -56,9 +56,12 @@ Tags - - {{ tag }} - + + diff --git a/src/app/articles/articles.component.ts b/src/app/articles/articles.component.ts index 68aed87..f725c4c 100644 --- a/src/app/articles/articles.component.ts +++ b/src/app/articles/articles.component.ts @@ -3,6 +3,7 @@ import { Component, OnInit } from '@angular/core'; import { ArticleService } from '../_services/article.service'; import { Router } from '@angular/router'; import { TagService } from '../_services/tags.service'; +import { TagComponent } from './tag/tag.component'; @Component({ selector: 'app-articles', @@ -13,7 +14,8 @@ export class ArticlesComponent implements OnInit { public articles; public tags: Promise>; - private tagData: Object; + public tagData: Object; + public maxSize: Number constructor( private articleService: ArticleService, @@ -27,6 +29,11 @@ export class ArticlesComponent implements OnInit { .subscribe((tags) => { this.tagData = tags; this.tags = Promise.resolve(Object.keys(tags)); + this.maxSize = Object.keys(tags).map((tag) => { + return parseInt(tags[tag], 10); + }).reduce((accumulator, currentValue) => { + return Math.max(accumulator, currentValue); + }, 0); }); } diff --git a/src/app/articles/tag/tag.component.html b/src/app/articles/tag/tag.component.html new file mode 100644 index 0000000..a01dc08 --- /dev/null +++ b/src/app/articles/tag/tag.component.html @@ -0,0 +1 @@ + {{tag}} \ No newline at end of file diff --git a/src/app/articles/tag/tag.component.scss b/src/app/articles/tag/tag.component.scss new file mode 100644 index 0000000..7604f1e --- /dev/null +++ b/src/app/articles/tag/tag.component.scss @@ -0,0 +1,3 @@ +:host { + color: blue; +} \ No newline at end of file diff --git a/src/app/articles/tag/tag.component.ts b/src/app/articles/tag/tag.component.ts new file mode 100644 index 0000000..023f8d1 --- /dev/null +++ b/src/app/articles/tag/tag.component.ts @@ -0,0 +1,23 @@ +import { Component, Input, HostBinding, OnChanges } from '@angular/core'; + +import { Router } from '@angular/router'; + +const MAX_SIZE = 30; + +@Component({ + selector: 'tag', + templateUrl: './tag.component.html', + styleUrls: ['./tag.component.scss'] +}) +export class TagComponent implements OnChanges { + @Input() tag: string; + @Input() fontSize: number; + @Input() maxSize: number; + + @HostBinding('style.font-size.pt') size: number; + + ngOnChanges() { + this.size = (this.fontSize / this.maxSize) * MAX_SIZE + console.log('size', this.size); + } +} From 2502ec7cbe1e4da64d06f2b588d669a7bb3d6e80 Mon Sep 17 00:00:00 2001 From: pastorsj Date: Wed, 18 Oct 2017 19:31:29 -0400 Subject: [PATCH 5/9] Added a search by title component on main page --- .gitignore | 3 ++- src/app/_models/ArticleList.ts | 5 +++++ src/app/_services/article.service.ts | 13 ++++++++++--- src/app/articles/articles.component.html | 19 +++++++++++++++++-- src/app/articles/articles.component.scss | 9 +++++++++ src/app/articles/articles.component.ts | 14 +++++++++++++- src/app/editor/editor.component.ts | 2 -- 7 files changed, 56 insertions(+), 9 deletions(-) create mode 100644 src/app/_models/ArticleList.ts diff --git a/.gitignore b/.gitignore index 02a9545..b3d1f47 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ typings/ npm-debug.log dist/ -*.pem \ No newline at end of file +*.pem +*.rdb \ No newline at end of file diff --git a/src/app/_models/ArticleList.ts b/src/app/_models/ArticleList.ts new file mode 100644 index 0000000..d45bd0a --- /dev/null +++ b/src/app/_models/ArticleList.ts @@ -0,0 +1,5 @@ +export class ArticleList { + _id: number; + title: string; + tags: Array; +} diff --git a/src/app/_services/article.service.ts b/src/app/_services/article.service.ts index 0f14e5a..0ef4ac4 100644 --- a/src/app/_services/article.service.ts +++ b/src/app/_services/article.service.ts @@ -7,12 +7,13 @@ import 'rxjs/add/operator/map'; import { AuthenticationService } from '../_services/authentication.service'; import { Article } from '../_models/Article'; +import { ArticleList } from '../_models/ArticleList'; import { environment } from '../../environments/environment'; @Injectable() export class ArticleService { - private editorUrl = environment.URL + '/blog/'; + private blogUrl = environment.URL + '/blog/'; private title = ''; private id: string; @@ -35,13 +36,19 @@ export class ArticleService { const options = new RequestOptions({ headers }); - return this.http.get(this.editorUrl, options) + return this.http.get(this.blogUrl, options) .map(this.extractData) .catch(this.handleError); } getArticle(id: number): Observable

{ - return this.http.get(this.editorUrl + id) + return this.http.get(this.blogUrl + id) + .map(this.extractData) + .catch(this.handleError); + } + + getArticlesByTitle(title: string): Observable { + return this.http.get(this.blogUrl + 'title/' + title) .map(this.extractData) .catch(this.handleError); } diff --git a/src/app/articles/articles.component.html b/src/app/articles/articles.component.html index a965bd5..d57b7c6 100644 --- a/src/app/articles/articles.component.html +++ b/src/app/articles/articles.component.html @@ -21,14 +21,29 @@
+ + + Search Articles By Title + + + + + + + {{ article.title }} + + + + + About

- This site was developed by Sam Pastoriza - and James Edwards. + This site was developed by Sam Pastoriza + and James Edwards. We wanted a blog that was self sustaining and easily modifiable. We are using the Angular framework developed by Google and a combination of Angular Material and Bulma to style and layout the site respectively. An express based diff --git a/src/app/articles/articles.component.scss b/src/app/articles/articles.component.scss index b6c5edd..909eb59 100644 --- a/src/app/articles/articles.component.scss +++ b/src/app/articles/articles.component.scss @@ -9,4 +9,13 @@ .card-sections { margin-bottom: 20px; +} + +.title-search { + width: 100%; + max-height: 100px; +} + +.article-option { + font-size: 10pt; } \ No newline at end of file diff --git a/src/app/articles/articles.component.ts b/src/app/articles/articles.component.ts index f725c4c..e27784d 100644 --- a/src/app/articles/articles.component.ts +++ b/src/app/articles/articles.component.ts @@ -1,9 +1,12 @@ import { Component, OnInit } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; + import { ArticleService } from '../_services/article.service'; import { Router } from '@angular/router'; import { TagService } from '../_services/tags.service'; import { TagComponent } from './tag/tag.component'; +import { ArticleList } from '../_models/ArticleList'; @Component({ selector: 'app-articles', @@ -16,6 +19,7 @@ export class ArticlesComponent implements OnInit { public tags: Promise>; public tagData: Object; public maxSize: Number + public filteredArticles: Observable; constructor( private articleService: ArticleService, @@ -42,8 +46,16 @@ export class ArticlesComponent implements OnInit { this.router.navigate(['article', e._id]); } - getArticlesByTag(tag: string) { + getArticlesByTitle(tag: string) { this.articles = this.tagService.getArticlesByTag(tag); } + filterArticles(title: string) { + this.filteredArticles = this.articleService.getArticlesByTitle(title); + } + + articleSelected(article: ArticleList) { + console.log('Article selected', article); + } + } diff --git a/src/app/editor/editor.component.ts b/src/app/editor/editor.component.ts index d1f4ab4..013ed7e 100644 --- a/src/app/editor/editor.component.ts +++ b/src/app/editor/editor.component.ts @@ -13,8 +13,6 @@ import initializeFroalaGistPlugin from '../_plugins/gist.plugin' import { environment } from '../../environments/environment'; -declare var $: any; - @Component({ selector: 'app-editor', templateUrl: './editor.component.html', From 248639b811e68dc50db5f9255d1c1ff5d1af0f0d Mon Sep 17 00:00:00 2001 From: pastorsj Date: Wed, 18 Oct 2017 21:04:45 -0400 Subject: [PATCH 6/9] Fixed tags issues, updated article model --- src/app/_models/Article.ts | 3 ++- src/app/articles/articles.component.html | 2 +- src/app/articles/articles.component.ts | 4 ++-- src/app/articles/tag/tag.component.ts | 9 ++++----- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/app/_models/Article.ts b/src/app/_models/Article.ts index cb4849b..4d75afe 100644 --- a/src/app/_models/Article.ts +++ b/src/app/_models/Article.ts @@ -1,9 +1,10 @@ +import { Author } from './Author'; export class Article { _id: number; title: string; description: string; datePosted: Date; text: string; - author: string; + author: Author; tags: Array; } diff --git a/src/app/articles/articles.component.html b/src/app/articles/articles.component.html index d57b7c6..cbc6f8a 100644 --- a/src/app/articles/articles.component.html +++ b/src/app/articles/articles.component.html @@ -9,7 +9,7 @@ {{article?.title}} - By {{article?.author}} {{article?.datePosted | date:'longDate'}} + By {{article?.author?.name}}, {{article?.datePosted | date:'longDate'}} diff --git a/src/app/articles/articles.component.ts b/src/app/articles/articles.component.ts index e27784d..d6f977f 100644 --- a/src/app/articles/articles.component.ts +++ b/src/app/articles/articles.component.ts @@ -46,7 +46,7 @@ export class ArticlesComponent implements OnInit { this.router.navigate(['article', e._id]); } - getArticlesByTitle(tag: string) { + getArticlesByTag(tag: string) { this.articles = this.tagService.getArticlesByTag(tag); } @@ -55,7 +55,7 @@ export class ArticlesComponent implements OnInit { } articleSelected(article: ArticleList) { - console.log('Article selected', article); + this.router.navigate(['article', article._id]); } } diff --git a/src/app/articles/tag/tag.component.ts b/src/app/articles/tag/tag.component.ts index 023f8d1..3daa93a 100644 --- a/src/app/articles/tag/tag.component.ts +++ b/src/app/articles/tag/tag.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, HostBinding, OnChanges } from '@angular/core'; +import { Component, Input, HostBinding, OnInit } from '@angular/core'; import { Router } from '@angular/router'; @@ -9,15 +9,14 @@ const MAX_SIZE = 30; templateUrl: './tag.component.html', styleUrls: ['./tag.component.scss'] }) -export class TagComponent implements OnChanges { +export class TagComponent implements OnInit { @Input() tag: string; @Input() fontSize: number; @Input() maxSize: number; @HostBinding('style.font-size.pt') size: number; - ngOnChanges() { - this.size = (this.fontSize / this.maxSize) * MAX_SIZE - console.log('size', this.size); + ngOnInit() { + this.size = (this.fontSize / this.maxSize) * MAX_SIZE; } } From 6b247e0b561ddbb85f55246c66850a3ce7dab5c6 Mon Sep 17 00:00:00 2001 From: pastorsj Date: Thu, 19 Oct 2017 18:52:47 -0400 Subject: [PATCH 7/9] Added progress spinner for user settings modal --- src/app/editor/editor.component.scss | 21 ------------------- src/app/material.module.ts | 4 +++- .../settings-modal.component.html | 9 ++++++-- .../settings-modal.component.scss | 7 +++++++ .../settings-modal.component.ts | 9 +++++++- src/styles.css | 20 ++++++++++++++++++ 6 files changed, 45 insertions(+), 25 deletions(-) diff --git a/src/app/editor/editor.component.scss b/src/app/editor/editor.component.scss index 9c20c25..cc703fd 100644 --- a/src/app/editor/editor.component.scss +++ b/src/app/editor/editor.component.scss @@ -24,25 +24,4 @@ .editor-form { margin-left: 1vw; margin-right: 1vw; -} - -.vertical-spacer { - width: 100%; - display: block; - clear: all; - padding-top: 2em; -} - -.vertical-half-spacer { - width: 100%; - display: block; - clear: all; - padding-top: 1em; -} - -.vertical-quarter-spacer { - width: 100%; - display: block; - clear: all; - padding-top: 0.5em; } \ No newline at end of file diff --git a/src/app/material.module.ts b/src/app/material.module.ts index ab3f9fd..6966462 100644 --- a/src/app/material.module.ts +++ b/src/app/material.module.ts @@ -2,7 +2,7 @@ import { NgModule } from '@angular/core'; import { MatAutocompleteModule, MatGridListModule, MatDialogModule, MatInputModule, MatSelectModule, MatMenuModule, MatSidenavModule, MatToolbarModule, MatListModule, MatCardModule, MatButtonModule, MatIconModule, MatSnackBarModule, MatTableModule, - NoConflictStyleCompatibilityMode, MatChipsModule } from '@angular/material'; + NoConflictStyleCompatibilityMode, MatChipsModule, MatProgressSpinnerModule } from '@angular/material'; @NgModule({ imports: [ @@ -21,6 +21,7 @@ import { MatAutocompleteModule, MatGridListModule, MatDialogModule, MatInputModu MatSnackBarModule, MatTableModule, MatChipsModule, + MatProgressSpinnerModule, NoConflictStyleCompatibilityMode ], exports: [ @@ -39,6 +40,7 @@ import { MatAutocompleteModule, MatGridListModule, MatDialogModule, MatInputModu MatSnackBarModule, MatTableModule, MatChipsModule, + MatProgressSpinnerModule, NoConflictStyleCompatibilityMode ] }) diff --git a/src/app/settings-modal/settings-modal.component.html b/src/app/settings-modal/settings-modal.component.html index 00f9ab2..9b6afb1 100644 --- a/src/app/settings-modal/settings-modal.component.html +++ b/src/app/settings-modal/settings-modal.component.html @@ -1,8 +1,13 @@ - +

User Settings

-
+
+ +
+ Saving User Settings... +
+ diff --git a/src/app/settings-modal/settings-modal.component.scss b/src/app/settings-modal/settings-modal.component.scss index 59d8078..c8fccc7 100644 --- a/src/app/settings-modal/settings-modal.component.scss +++ b/src/app/settings-modal/settings-modal.component.scss @@ -30,4 +30,11 @@ background: white; cursor: inherit; display: block; +} + +.spinner { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; } \ No newline at end of file diff --git a/src/app/settings-modal/settings-modal.component.ts b/src/app/settings-modal/settings-modal.component.ts index 21b79d2..6ad3396 100644 --- a/src/app/settings-modal/settings-modal.component.ts +++ b/src/app/settings-modal/settings-modal.component.ts @@ -16,6 +16,7 @@ export class SettingsModalComponent implements OnInit { settingsGroup: FormGroup; fileContent: any; username: string; + public saveInProgress: boolean; constructor( fb: FormBuilder, @@ -42,11 +43,13 @@ export class SettingsModalComponent implements OnInit { this.username = author.username; }, error => { console.error('Error', error); - }) + }); + this.saveInProgress = false; } saveSettings(formValue: any, isFormValid: boolean) { if (isFormValid) { + this.saveInProgress = true; const name = formValue['name']; const email = formValue['email']; const profilePicture = formValue['profilePicture']; @@ -56,11 +59,13 @@ export class SettingsModalComponent implements OnInit { formData.append('profilePicture', file); this.authorService.updateUserSettings(this.username, name, email, formData) .subscribe(result => { + this.saveInProgress = false; this.snackBar.open('Updated user settings', '', { duration: 4000 }); this.dialogRef.close({name, image: result.image || ''}); }, error => { + this.saveInProgress = false; console.error('Error', error); this.snackBar.open(`Error updating user settings ${error}`, '', { duration: 4000 @@ -69,11 +74,13 @@ export class SettingsModalComponent implements OnInit { } else { this.authorService.updateUserSettings(this.username, name, email) .subscribe(result => { + this.saveInProgress = false; this.snackBar.open('Updated user settings', '', { duration: 4000 }); this.dialogRef.close({name}); }, error => { + this.saveInProgress = false; console.error('Error', error); this.snackBar.open(`Error updating user settings ${error}`, '', { duration: 4000 diff --git a/src/styles.css b/src/styles.css index 90d4ee0..42c1c23 100755 --- a/src/styles.css +++ b/src/styles.css @@ -1 +1,21 @@ /* You can add global styles to this file, and also import other style files */ +.vertical-spacer { + width: 100%; + display: block; + clear: all; + padding-top: 2em; +} + +.vertical-half-spacer { + width: 100%; + display: block; + clear: all; + padding-top: 1em; +} + +.vertical-quarter-spacer { + width: 100%; + display: block; + clear: all; + padding-top: 0.5em; +} \ No newline at end of file From 7d9dd0315a5652c0ca56ff74034863e03eab73a2 Mon Sep 17 00:00:00 2001 From: pastorsj Date: Thu, 19 Oct 2017 22:02:31 -0400 Subject: [PATCH 8/9] Added button to upload cover photo for an article --- src/app/_services/editor.service.ts | 24 ++++++++++------- src/app/editor/editor.component.html | 4 +++ src/app/editor/editor.component.ts | 39 ++++++++++++++++++---------- 3 files changed, 45 insertions(+), 22 deletions(-) diff --git a/src/app/_services/editor.service.ts b/src/app/_services/editor.service.ts index bcb2345..fe1567b 100644 --- a/src/app/_services/editor.service.ts +++ b/src/app/_services/editor.service.ts @@ -58,26 +58,32 @@ export class EditorService { .catch(this.handleError); } - saveArticle(edits: string, tags: string[]): Observable { + saveArticle(edits: string, title: string, description: string, tags: string[], coverPhoto?: FormData): Observable { const headers = new Headers(); - headers.append('Content-Type', 'application/json'); headers.append('Authorization', 'Bearer ' + this.auth.token); + const options = new RequestOptions({ headers }); + const author = JSON.parse(localStorage.getItem('currentUser')); const post = { text: edits, - title: this.title, - description: this.description, + title: title, + description: description, tags, author: author.username }; - const options = new RequestOptions({ headers }); - - return this.http.put(this.editorUrl + this.id, post, options) - .map(this.extractData) - .catch(this.handleError); + if (coverPhoto) { + return Observable.forkJoin( + this.http.put(this.editorUrl + this.id, post, options).map(this.extractData).catch(this.handleError), + this.http.post(this.editorUrl + this.id, coverPhoto, options).map(this.extractData).catch(this.handleError) + ); + } else { + return Observable.forkJoin( + this.http.put(this.editorUrl + this.id, post, options).map(this.extractData).catch(this.handleError) + ); + } } deleteArticle(article): Observable { diff --git a/src/app/editor/editor.component.html b/src/app/editor/editor.component.html index 9503618..eebf101 100644 --- a/src/app/editor/editor.component.html +++ b/src/app/editor/editor.component.html @@ -26,6 +26,10 @@ +
diff --git a/src/app/editor/editor.component.ts b/src/app/editor/editor.component.ts index 013ed7e..6b35583 100644 --- a/src/app/editor/editor.component.ts +++ b/src/app/editor/editor.component.ts @@ -12,6 +12,7 @@ import { ImagesService } from '../_services/images.service'; import initializeFroalaGistPlugin from '../_plugins/gist.plugin' import { environment } from '../../environments/environment'; +import { FileValidator } from '../_directives/fileValidator.directive'; @Component({ selector: 'app-editor', @@ -72,7 +73,8 @@ export class EditorComponent implements OnInit { this.formGroup = this.fb.group({ 'articleTitle': new FormControl('', Validators.required), 'articleDescription': new FormControl('', Validators.required), - 'tags': new FormControl('') + 'tags': new FormControl(''), + 'coverPhoto': new FormControl('', [FileValidator.validate]) }); } @@ -106,7 +108,8 @@ export class EditorComponent implements OnInit { this.formGroup.setValue({ 'articleTitle': article.title, 'articleDescription': article.description, - 'tags': '' + 'tags': '', + 'coverPhoto': {} }); if (article.tags instanceof Array) { this.selectedTags = new Set(article.tags); @@ -124,25 +127,35 @@ export class EditorComponent implements OnInit { if (isFormValid) { const articleTitle = formValue['articleTitle']; const articleDescription = formValue['articleDescription']; + const coverPhoto = formValue['coverPhoto']; const tags = Array.from(this.selectedTags); - this.editorService.setArticleTitle(articleTitle); - this.editorService.setArticleDescription(articleDescription); - - this.editorService.saveArticle(this.content, tags) + if (coverPhoto.target) { + const formData = new FormData(); + const file = coverPhoto.target.files[0]; + formData.append('coverPhoto', file); + this.editorService.saveArticle(this.content, articleTitle, articleDescription, tags, formData) .subscribe(result => { - if (result['text'] === this.content) { - this.snackBar.open('Successfully saved article', '', { - duration: 4000 - }); - } else { - console.error('Failed to save article, please try again'); - } + this.snackBar.open('Successfully saved article', '', { + duration: 4000 + }); + }, error => { + this.snackBar.open('There was an error while attempting to save this article', '', { + duration: 4000 + }); + }); + } else { + this.editorService.saveArticle(this.content, articleTitle, articleDescription, tags) + .subscribe(result => { + this.snackBar.open('Successfully saved article', '', { + duration: 4000 + }); }, error => { this.snackBar.open('There was an error while attempting to save this article', '', { duration: 4000 }); }); + } } else { console.error('Form is not valid', formValue); } From ad793d4cf5610cf4419b049c49d9b803b4f03bca Mon Sep 17 00:00:00 2001 From: pastorsj Date: Fri, 20 Oct 2017 19:59:20 -0400 Subject: [PATCH 9/9] Added cover photo to article list, updated file selector, rounded off profile picture corners --- src/app/articles/articles.component.html | 3 +- src/app/articles/articles.component.scss | 5 ++ src/app/editor/editor.component.html | 76 ++++++++++--------- src/app/editor/editor.component.scss | 27 ++++++- src/app/nav-bar/nav-bar.component.html | 32 ++++---- src/app/nav-bar/nav-bar.component.scss | 3 +- .../settings-modal.component.html | 9 ++- .../settings-modal.component.scss | 1 - 8 files changed, 94 insertions(+), 62 deletions(-) diff --git a/src/app/articles/articles.component.html b/src/app/articles/articles.component.html index cbc6f8a..798f785 100644 --- a/src/app/articles/articles.component.html +++ b/src/app/articles/articles.component.html @@ -12,6 +12,7 @@ By {{article?.author?.name}}, {{article?.datePosted | date:'longDate'}} + {{article?.description}} @@ -48,7 +49,7 @@ We are using the Angular framework developed by Google and a combination of Angular Material and Bulma to style and layout the site respectively. An express based backend application utilizes MongoDb and Redis to store data on users and articles. The - blog is completely open-sourced on Github and contributers are more than welcome. The end goal + blog is completely open-sourced on GitHub and contributers are more than welcome. The end goal is a fully functional blog mainly covering technical topics, but can be reused as a base for other blogs.

diff --git a/src/app/articles/articles.component.scss b/src/app/articles/articles.component.scss index 909eb59..264594f 100644 --- a/src/app/articles/articles.component.scss +++ b/src/app/articles/articles.component.scss @@ -18,4 +18,9 @@ .article-option { font-size: 10pt; +} + +.cover-photo { + max-width: 100%; + height: auto; } \ No newline at end of file diff --git a/src/app/editor/editor.component.html b/src/app/editor/editor.component.html index eebf101..c7dddb9 100644 --- a/src/app/editor/editor.component.html +++ b/src/app/editor/editor.component.html @@ -1,37 +1,43 @@
-
- - - - Article Title is required - - - - - Article Description is required - - - - - {{ tag }} - cancel - - - - - - - - {{ tag }} - - - - -
-
-
-
+
+
+
+ + + + Article Title is required + + + + + Article Description is required + + + + + {{ tag }} + cancel + + + + + + + + {{ tag }} + + + + +
+ +
+
+
+
+
diff --git a/src/app/editor/editor.component.scss b/src/app/editor/editor.component.scss index cc703fd..14eec0c 100644 --- a/src/app/editor/editor.component.scss +++ b/src/app/editor/editor.component.scss @@ -1,9 +1,7 @@ .editor { display: flex; justify-content: center; - align-items: center; - flex-direction: column; - margin-top: 7vh; + flex-direction: row; } .save { @@ -18,10 +16,31 @@ } .form-container { - text-align: center; + text-align: left; } .editor-form { margin-left: 1vw; margin-right: 1vw; +} + +.btn-file { + position: relative; + overflow: hidden; +} + +.btn-file input[type=file] { + position: absolute; + top: 0; + right: 0; + min-width: 100%; + min-height: 100%; + font-size: 100px; + text-align: right; + filter: alpha(opacity=0); + opacity: 0; + outline: none; + background: white; + cursor: inherit; + display: block; } \ No newline at end of file diff --git a/src/app/nav-bar/nav-bar.component.html b/src/app/nav-bar/nav-bar.component.html index 308982a..82fc1da 100755 --- a/src/app/nav-bar/nav-bar.component.html +++ b/src/app/nav-bar/nav-bar.component.html @@ -5,22 +5,22 @@ {{title}}
- Login - Register - Your Articles - - - - - + + + +
diff --git a/src/app/nav-bar/nav-bar.component.scss b/src/app/nav-bar/nav-bar.component.scss index 8c8b341..b202be0 100755 --- a/src/app/nav-bar/nav-bar.component.scss +++ b/src/app/nav-bar/nav-bar.component.scss @@ -9,8 +9,9 @@ } #profile-picture { - padding-inline-start: 5px; + margin-left: 5px; width: 30px; height: 30px; object-fit: contain; + border-radius: 15px; } diff --git a/src/app/settings-modal/settings-modal.component.html b/src/app/settings-modal/settings-modal.component.html index 9b6afb1..f6b7ff2 100644 --- a/src/app/settings-modal/settings-modal.component.html +++ b/src/app/settings-modal/settings-modal.component.html @@ -17,10 +17,11 @@ Email is required - + diff --git a/src/app/settings-modal/settings-modal.component.scss b/src/app/settings-modal/settings-modal.component.scss index c8fccc7..c853947 100644 --- a/src/app/settings-modal/settings-modal.component.scss +++ b/src/app/settings-modal/settings-modal.component.scss @@ -23,7 +23,6 @@ min-width: 100%; min-height: 100%; font-size: 100px; - text-align: right; filter: alpha(opacity=0); opacity: 0; outline: none;