├── angular-cli.json ├── e2e ├── app.e2e-spec.ts ├── app.po.ts └── tsconfig.json ├── karma.conf.js ├── package.json ├── protractor.conf.js ├── src ├── app │ ├── app.component.html │ ├── app.component.scss │ ├── app.component.spec.ts │ ├── app.component.ts │ ├── app.module.ts │ ├── app.routing.ts │ ├── article │ │ ├── article-detail │ │ │ ├── article-detail.component.html │ │ │ ├── article-detail.component.scss │ │ │ ├── article-detail.component.spec.ts │ │ │ ├── article-detail.component.ts │ │ │ ├── article-detail.service.spec.ts │ │ │ ├── article-detail.service.ts │ │ │ ├── comment.ts │ │ │ └── detail.ts │ │ ├── article-list │ │ │ ├── article-list.component.html │ │ │ ├── article-list.component.scss │ │ │ ├── article-list.component.spec.ts │ │ │ ├── article-list.component.ts │ │ │ ├── article-list.service.spec.ts │ │ │ ├── article-list.service.ts │ │ │ └── list.ts │ │ ├── article-main │ │ │ ├── article-main.component.html │ │ │ ├── article-main.component.scss │ │ │ ├── article-main.component.spec.ts │ │ │ └── article-main.component.ts │ │ ├── article.module.ts │ │ ├── article.routing.ts │ │ └── showdown │ │ │ ├── index.ts │ │ │ ├── showdown.component.html │ │ │ ├── showdown.component.scss │ │ │ ├── showdown.component.spec.ts │ │ │ └── showdown.component.ts │ ├── home │ │ ├── home.component.html │ │ ├── home.component.scss │ │ ├── home.component.spec.ts │ │ ├── home.component.ts │ │ ├── home.service.spec.ts │ │ ├── home.service.ts │ │ └── option.ts │ ├── index.ts │ ├── menu │ │ ├── menu.component.html │ │ ├── menu.component.scss │ │ ├── menu.component.spec.ts │ │ ├── menu.component.ts │ │ ├── menu.service.spec.ts │ │ └── menu.service.ts │ ├── search │ │ ├── articles.ts │ │ ├── search.component.html │ │ ├── search.component.scss │ │ ├── search.component.spec.ts │ │ ├── search.component.ts │ │ ├── search.service.spec.ts │ │ └── search.service.ts │ ├── shared │ │ ├── component │ │ │ ├── back │ │ │ │ ├── back.component.html │ │ │ │ ├── back.component.scss │ │ │ │ ├── back.component.spec.ts │ │ │ │ ├── back.component.ts │ │ │ │ └── index.ts │ │ │ ├── breadcrumb │ │ │ │ ├── breadcrumb.component.html │ │ │ │ ├── breadcrumb.component.scss │ │ │ │ ├── breadcrumb.component.spec.ts │ │ │ │ ├── breadcrumb.component.ts │ │ │ │ └── index.ts │ │ │ ├── copyright │ │ │ │ ├── copyright.component.html │ │ │ │ ├── copyright.component.scss │ │ │ │ ├── copyright.component.spec.ts │ │ │ │ ├── copyright.component.ts │ │ │ │ └── index.ts │ │ │ ├── mdeditor │ │ │ │ ├── index.ts │ │ │ │ ├── mdeditor.component.html │ │ │ │ ├── mdeditor.component.scss │ │ │ │ ├── mdeditor.component.spec.ts │ │ │ │ └── mdeditor.component.ts │ │ │ ├── pagination │ │ │ │ ├── index.ts │ │ │ │ ├── pagination.component.html │ │ │ │ ├── pagination.component.scss │ │ │ │ ├── pagination.component.spec.ts │ │ │ │ └── pagination.component.ts │ │ │ └── tags │ │ │ │ ├── index.ts │ │ │ │ ├── tags.component.html │ │ │ │ ├── tags.component.scss │ │ │ │ ├── tags.component.spec.ts │ │ │ │ └── tags.component.ts │ │ ├── directive │ │ │ └── local │ │ │ │ ├── index.ts │ │ │ │ ├── local.directive.spec.ts │ │ │ │ └── local.directive.ts │ │ ├── index.ts │ │ ├── pipe │ │ │ ├── safe-style │ │ │ │ ├── index.ts │ │ │ │ ├── safe-style.pipe.spec.ts │ │ │ │ └── safe-style.pipe.ts │ │ │ └── sanitize │ │ │ │ ├── index.ts │ │ │ │ ├── sanitize-html.pipe.spec.ts │ │ │ │ └── sanitize-html.pipe.ts │ │ ├── service │ │ │ ├── admin │ │ │ │ ├── admin.service.spec.ts │ │ │ │ ├── admin.service.ts │ │ │ │ └── index.ts │ │ │ ├── auth │ │ │ │ ├── auth.service.spec.ts │ │ │ │ ├── auth.service.ts │ │ │ │ └── index.ts │ │ │ ├── locker │ │ │ │ ├── index.ts │ │ │ │ ├── locker.service.spec.ts │ │ │ │ └── locker.service.ts │ │ │ ├── mission │ │ │ │ ├── index.ts │ │ │ │ ├── mission.service.spec.ts │ │ │ │ └── mission.service.ts │ │ │ └── static │ │ │ │ ├── index.ts │ │ │ │ ├── static.service.spec.ts │ │ │ │ └── static.service.ts │ │ └── shared.module.ts │ └── user │ │ ├── user-console │ │ ├── console-admin │ │ │ ├── admin-check │ │ │ │ ├── admin-check.component.html │ │ │ │ ├── admin-check.component.scss │ │ │ │ ├── admin-check.component.spec.ts │ │ │ │ ├── admin-check.component.ts │ │ │ │ ├── check.service.spec.ts │ │ │ │ ├── check.service.ts │ │ │ │ └── list.ts │ │ │ ├── admin-main │ │ │ │ ├── admin-main.component.html │ │ │ │ ├── admin-main.component.scss │ │ │ │ ├── admin-main.component.spec.ts │ │ │ │ └── admin-main.component.ts │ │ │ ├── admin-member │ │ │ │ ├── admin-member.component.html │ │ │ │ ├── admin-member.component.scss │ │ │ │ ├── admin-member.component.spec.ts │ │ │ │ └── admin-member.component.ts │ │ │ ├── admin-menu │ │ │ │ ├── admin-menu.component.html │ │ │ │ ├── admin-menu.component.scss │ │ │ │ ├── admin-menu.component.spec.ts │ │ │ │ └── admin-menu.component.ts │ │ │ ├── admin-option │ │ │ │ ├── admin-option.component.html │ │ │ │ ├── admin-option.component.scss │ │ │ │ ├── admin-option.component.spec.ts │ │ │ │ ├── admin-option.component.ts │ │ │ │ ├── option.service.spec.ts │ │ │ │ ├── option.service.ts │ │ │ │ └── option.ts │ │ │ ├── admin-recommend │ │ │ │ ├── admin-recommend.component.html │ │ │ │ ├── admin-recommend.component.scss │ │ │ │ ├── admin-recommend.component.spec.ts │ │ │ │ ├── admin-recommend.component.ts │ │ │ │ ├── list.ts │ │ │ │ ├── option.ts │ │ │ │ ├── recommend.service.spec.ts │ │ │ │ └── recommend.service.ts │ │ │ ├── admin.module.ts │ │ │ └── admin.routing.ts │ │ ├── console-editor │ │ │ ├── console-editor.component.html │ │ │ ├── console-editor.component.scss │ │ │ ├── console-editor.component.spec.ts │ │ │ ├── console-editor.component.ts │ │ │ └── index.ts │ │ ├── console-main │ │ │ ├── console-main.component.html │ │ │ ├── console-main.component.scss │ │ │ ├── console-main.component.spec.ts │ │ │ └── console-main.component.ts │ │ ├── console-reply │ │ │ ├── console-reply.component.html │ │ │ ├── console-reply.component.scss │ │ │ ├── console-reply.component.spec.ts │ │ │ ├── console-reply.component.ts │ │ │ ├── console-reply.service.spec.ts │ │ │ ├── console-reply.service.ts │ │ │ └── reply.ts │ │ ├── console-setting │ │ │ ├── console-setting.component.html │ │ │ ├── console-setting.component.scss │ │ │ ├── console-setting.component.spec.ts │ │ │ ├── console-setting.component.ts │ │ │ ├── setting.service.spec.ts │ │ │ └── setting.service.ts │ │ ├── console-subject │ │ │ ├── console-subject.component.html │ │ │ ├── console-subject.component.scss │ │ │ ├── console-subject.component.spec.ts │ │ │ ├── console-subject.component.ts │ │ │ ├── console-subject.service.spec.ts │ │ │ ├── console-subject.service.ts │ │ │ └── subject.ts │ │ ├── console-write │ │ │ ├── console-write.component.html │ │ │ ├── console-write.component.scss │ │ │ ├── console-write.component.spec.ts │ │ │ ├── console-write.component.ts │ │ │ ├── console-write.service.spec.ts │ │ │ └── console-write.service.ts │ │ ├── console.module.ts │ │ └── console.routing.ts │ │ ├── user-login │ │ ├── login.component.html │ │ ├── login.component.scss │ │ ├── login.component.spec.ts │ │ ├── login.component.ts │ │ ├── login.service.spec.ts │ │ ├── login.service.ts │ │ └── user.ts │ │ ├── user-main │ │ ├── user-main.component.html │ │ ├── user-main.component.scss │ │ ├── user-main.component.spec.ts │ │ └── user-main.component.ts │ │ ├── user-register │ │ ├── register.component.html │ │ ├── register.component.scss │ │ ├── register.component.spec.ts │ │ ├── register.component.ts │ │ ├── register.service.spec.ts │ │ ├── register.service.ts │ │ └── user.ts │ │ ├── user.module.ts │ │ └── user.routing.ts ├── assets │ ├── .gitkeep │ ├── .npmignore │ ├── css │ │ ├── atom-one-dark.css │ │ ├── iconfont.css │ │ ├── markdown.scss │ │ ├── simplemde.css │ │ └── skeleton.css │ ├── fonts │ │ ├── en_US.aff │ │ ├── en_US.dic │ │ ├── futura.ttf │ │ ├── iconfont.css │ │ ├── iconfont.eot │ │ ├── iconfont.js │ │ ├── iconfont.svg │ │ ├── iconfont.ttf │ │ ├── iconfont.woff │ │ └── material.woff2 │ ├── images │ │ ├── default_bg.jpeg │ │ └── default_photo.png │ └── sass │ │ ├── _normalize.scss │ │ ├── _theme.scss │ │ ├── _variables.scss │ │ ├── _vendor-prefixes.scss │ │ └── master.scss ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── main.ts ├── polyfills.ts ├── styles.css ├── test.ts ├── tsconfig.json └── typings.d.ts ├── static-deploy.js └── tslint.json /angular-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "project": { 3 | "version": "1.0.0-beta.22", 4 | "name": "sails-blog-frontend" 5 | }, 6 | "apps": [ 7 | { 8 | "root": "src", 9 | "outDir": "dist", 10 | "assets": [ 11 | "assets", 12 | "favicon.ico" 13 | ], 14 | "index": "index.html", 15 | "main": "main.ts", 16 | "test": "test.ts", 17 | "tsconfig": "tsconfig.json", 18 | "prefix": "app", 19 | "mobile": false, 20 | "styles": [ 21 | "styles.css", 22 | "../node_modules/ng2-toasty/style.css", 23 | "assets/sass/master.scss" 24 | ], 25 | "scripts": [], 26 | "environments": { 27 | "source": "environments/environment.ts", 28 | "dev": "environments/environment.ts", 29 | "prod": "environments/environment.prod.ts" 30 | } 31 | } 32 | ], 33 | "addons": [], 34 | "packages": [], 35 | "e2e": { 36 | "protractor": { 37 | "config": "./protractor.conf.js" 38 | } 39 | }, 40 | "test": { 41 | "karma": { 42 | "config": "./karma.conf.js" 43 | } 44 | }, 45 | "defaults": { 46 | "styleExt": "scss", 47 | "prefixInterfaces": false, 48 | "inline": { 49 | "style": false, 50 | "template": false 51 | }, 52 | "spec": { 53 | "class": false, 54 | "component": true, 55 | "directive": true, 56 | "module": false, 57 | "pipe": true, 58 | "service": true 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { NgPage } from './app.po'; 2 | 3 | describe('ng App', function() { 4 | let page: NgPage; 5 | 6 | beforeEach(() => { 7 | page = new NgPage(); 8 | }); 9 | 10 | it('should display message saying app works', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('app works!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, element, by } from 'protractor'; 2 | 3 | export class NgPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "declaration": false, 5 | "emitDecoratorMetadata": true, 6 | "experimentalDecorators": true, 7 | "module": "commonjs", 8 | "moduleResolution": "node", 9 | "outDir": "../dist/out-tsc-e2e", 10 | "sourceMap": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "../node_modules/@types" 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/0.13/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', 'angular-cli'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-remap-istanbul'), 12 | require('angular-cli/plugins/karma') 13 | ], 14 | files: [ 15 | { pattern: './src/test.ts', watched: false } 16 | ], 17 | preprocessors: { 18 | './src/test.ts': ['angular-cli'] 19 | }, 20 | remapIstanbulReporter: { 21 | reports: { 22 | html: 'coverage', 23 | lcovonly: './coverage/coverage.lcov' 24 | } 25 | }, 26 | angularCli: { 27 | config: './angular-cli.json', 28 | environment: 'dev' 29 | }, 30 | reporters: ['progress', 'karma-remap-istanbul'], 31 | port: 9876, 32 | colors: true, 33 | logLevel: config.LOG_INFO, 34 | autoWatch: true, 35 | browsers: ['Chrome'], 36 | singleRun: false 37 | }); 38 | }; 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tcome-frontend", 3 | "version": "1.1.0", 4 | "license": "MIT", 5 | "angular-cli": {}, 6 | "scripts": { 7 | "start": "ng serve -port 3001 -dev", 8 | "start_pro": "ng serve -port 3001 -prod", 9 | "lint": "tslint \"src/**/*.ts\"", 10 | "test": "ng test", 11 | "pree2e": "webdriver-manager update", 12 | "e2e": "protractor", 13 | "build": "ng build -prod -aot", 14 | "build-static": "node static-deploy.js" 15 | }, 16 | "private": true, 17 | "dependencies": { 18 | "@angular/common": "~4.0.0-beta.3", 19 | "@angular/compiler": "~4.0.0-beta.3", 20 | "@angular/core": "~4.0.0-beta.3", 21 | "@angular/forms": "~4.0.0-beta.3", 22 | "@angular/http": "~4.0.0-beta.3", 23 | "@angular/material": "^2.0.0-beta.1", 24 | "@angular/platform-browser": "~4.0.0-beta.3", 25 | "@angular/platform-browser-dynamic": "~4.0.0-beta.3", 26 | "@angular/router": "~4.0.0-beta.3", 27 | "angular2-moment": "^1.0.0", 28 | "core-js": "^2.4.1", 29 | "highlight": "^0.2.4", 30 | "highlight.js": "^9.9.0", 31 | "markdown": "^0.5.0", 32 | "moment": "^2.17.1", 33 | "ng2-responsive": "^0.8.3", 34 | "ng2-toasty": "^2.2.2", 35 | "remarkable": "^1.7.1", 36 | "rxjs": "^5.0.3", 37 | "showdown": "^1.5.4", 38 | "simplemde": "^1.11.2", 39 | "ts-helpers": "^1.1.1", 40 | "zone.js": "^0.7.2" 41 | }, 42 | "devDependencies": { 43 | "@angular/compiler-cli": "^2.3.1", 44 | "@types/jasmine": "^2.2.30", 45 | "@types/node": "^6.0.42", 46 | "angular-cli": "1.0.0-beta.25.5", 47 | "codelyzer": "~2.0.0-beta.4", 48 | "jasmine-core": "2.5.2", 49 | "jasmine-spec-reporter": "3.2.0", 50 | "karma": "1.4.0", 51 | "karma-chrome-launcher": "^2.0.0", 52 | "karma-cli": "^1.0.1", 53 | "karma-jasmine": "^1.0.2", 54 | "karma-remap-istanbul": "^0.4.0", 55 | "node-sass": "^3.10.1", 56 | "protractor": "5.0.0", 57 | "qiniu": "^6.1.13", 58 | "ts-node": "2.0.0", 59 | "tslint": "4.3.1", 60 | "typescript": "2.1.5", 61 | "webdriver-manager": "10.2.5" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/docs/referenceConf.js 3 | 4 | /*global jasmine */ 5 | var SpecReporter = require('jasmine-spec-reporter'); 6 | 7 | exports.config = { 8 | allScriptsTimeout: 11000, 9 | specs: [ 10 | './e2e/**/*.e2e-spec.ts' 11 | ], 12 | capabilities: { 13 | 'browserName': 'chrome' 14 | }, 15 | directConnect: true, 16 | baseUrl: 'http://localhost:4200/', 17 | framework: 'jasmine', 18 | jasmineNodeOpts: { 19 | showColors: true, 20 | defaultTimeoutInterval: 30000, 21 | print: function() {} 22 | }, 23 | useAllAngular2AppRoots: true, 24 | beforeLaunch: function() { 25 | require('ts-node').register({ 26 | project: 'e2e' 27 | }); 28 | }, 29 | onPrepare: function() { 30 | jasmine.getEnv().addReporter(new SpecReporter()); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
6 | 7 |
8 | 9 | 10 |
11 | 12 | 13 |
14 | 15 | 16 |
17 | 18 |
19 | 20 |
21 | 22 |
23 | 24 | 25 |
26 | 27 | 28 |
-------------------------------------------------------------------------------- /src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | @import "../assets/sass/variables"; 2 | // 主页相关样式 3 | // 4 | 5 | .app-body { 6 | height: 100%; 7 | flex: 1; 8 | display: flex; 9 | flex-flow: row; 10 | >.app-list { 11 | position: fixed; 12 | top: 0; 13 | left: 0; 14 | bottom: 0; 15 | width: 350px; 16 | height: 100%; 17 | z-index: 10; 18 | } 19 | >.app-content { 20 | flex: 1; 21 | overflow-x: hidden; 22 | height: 100%; 23 | margin-left: 350px; 24 | background: #FCFCFC; 25 | } 26 | } 27 | 28 | 29 | 30 | 31 | // mobile 32 | 33 | 34 | .mobile-body { 35 | width: 100%; 36 | height: 100%; 37 | flex: 1; 38 | display: flex; 39 | flex-flow: row; 40 | >.mobile-list { 41 | 42 | } 43 | >.mobile-content { 44 | flex: 1; 45 | overflow-x: hidden; 46 | height: 100%; 47 | background: #FCFCFC; 48 | padding-top: 50px; 49 | } 50 | } -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | 3 | import { TestBed, async } from '@angular/core/testing'; 4 | import { AppComponent } from './app.component'; 5 | 6 | describe('App: Ng', () => { 7 | beforeEach(() => { 8 | TestBed.configureTestingModule({ 9 | declarations: [ 10 | AppComponent 11 | ], 12 | }); 13 | }); 14 | 15 | it('should create the app', async(() => { 16 | let fixture = TestBed.createComponent(AppComponent); 17 | let app = fixture.debugElement.componentInstance; 18 | expect(app).toBeTruthy(); 19 | })); 20 | 21 | it(`should have as title 'app works!'`, async(() => { 22 | let fixture = TestBed.createComponent(AppComponent); 23 | let app = fixture.debugElement.componentInstance; 24 | expect(app.title).toEqual('app works!'); 25 | })); 26 | 27 | it('should render title in a h1 tag', async(() => { 28 | let fixture = TestBed.createComponent(AppComponent); 29 | fixture.detectChanges(); 30 | let compiled = fixture.debugElement.nativeElement; 31 | expect(compiled.querySelector('h1').textContent).toContain('app works!'); 32 | })); 33 | }); 34 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, AfterViewInit, ViewChild} from '@angular/core' 2 | import {Title} from '@angular/platform-browser' 3 | 4 | import {MissionService} from './shared/service/mission' 5 | import {StaticService} from './shared/service/static' 6 | 7 | @Component({ 8 | selector: 'app-root', 9 | templateUrl: './app.component.html', 10 | styleUrls: ['./app.component.scss'], 11 | providers: [] 12 | }) 13 | export class AppComponent{ 14 | constructor ( 15 | private missionService: MissionService, 16 | private titleService: Title, 17 | private staticService: StaticService 18 | ){ 19 | // 订阅子组件通知 通知至所有子组件 20 | missionService.missionConfirmed$.subscribe( 21 | astronaut =>{ 22 | missionService.announceMission(astronaut) 23 | } 24 | ) 25 | } 26 | 27 | ngAfterViewInit (){ 28 | this.titleService.setTitle('欢迎-维特博客') 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import {BrowserModule} from '@angular/platform-browser' 2 | import {CommonModule} from '@angular/common' 3 | import {FormsModule} from '@angular/forms' 4 | import {NgModule} from '@angular/core' 5 | import {HttpModule} from '@angular/http' 6 | import {RouterModule} from '@angular/router' 7 | import {MomentModule} from 'angular2-moment' 8 | import {ToastyModule} from 'ng2-toasty'; 9 | import {SharedModule} from './shared/shared.module' 10 | import {ResponsiveModule, ResponsiveConfig} from 'ng2-responsive' 11 | 12 | import {AppComponent} from './app.component' 13 | import {AppRoutingModule} from './app.routing' 14 | import {MenuComponent} from './menu/menu.component' 15 | import {HomeComponent} from './home/home.component' 16 | import {SearchComponent} from './search/search.component' 17 | import {AuthService} from './shared/service/auth' 18 | import {AdminService} from './shared/service/admin' 19 | import {LockerService} from './shared/service/locker' 20 | import {MissionService} from './shared/service/mission' 21 | import {StaticService} from './shared/service/static' 22 | 23 | const config = { 24 | breakPoints: { 25 | xs: {max: 600}, 26 | sm: {min: 601, max: 959}, 27 | md: {min: 960, max: 1279}, 28 | lg: {min: 1280, max: 1919}, 29 | xl: {min: 1920} 30 | }, 31 | debounceTime: 100 32 | }; 33 | 34 | export function ResponsiveDefinition (){ 35 | return new ResponsiveConfig(config); 36 | } 37 | 38 | @NgModule({ 39 | imports: [ 40 | ToastyModule.forRoot(), 41 | ResponsiveModule, 42 | BrowserModule, 43 | CommonModule, 44 | FormsModule, 45 | RouterModule, 46 | HttpModule, 47 | SharedModule.forRoot(), 48 | MomentModule, 49 | AppRoutingModule, 50 | ], 51 | declarations: [ 52 | AppComponent, 53 | MenuComponent, 54 | HomeComponent, 55 | SearchComponent, 56 | ], 57 | providers: [ 58 | MissionService, 59 | LockerService, 60 | AuthService, 61 | AdminService, 62 | { 63 | provide: ResponsiveConfig, 64 | useFactory: ResponsiveDefinition 65 | } 66 | ], 67 | bootstrap: [AppComponent], 68 | }) 69 | export class AppModule { 70 | constructor (){ 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/app/app.routing.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by WittBulter on 16/8/17. 3 | */ 4 | 5 | import {NgModule} from '@angular/core' 6 | import {Routes, RouterModule} from '@angular/router' 7 | 8 | import {HomeComponent} from './home/home.component' 9 | import {SearchComponent} from './search/search.component' 10 | 11 | export const appRoutes: Routes = [ 12 | {path: '', component: HomeComponent}, 13 | {path: 'welcome', component: HomeComponent}, 14 | {path: 'search', component: SearchComponent}, 15 | {path: 'articles', loadChildren: './article/article.module#ArticleModule', data: {preload: true}}, 16 | {path: 'user', loadChildren: './user/user.module#UserModule', data: {preload: false}}, 17 | ] 18 | 19 | @NgModule({ 20 | imports: [RouterModule.forRoot(appRoutes, { useHash: false })], 21 | exports: [RouterModule] 22 | }) 23 | export class AppRoutingModule { 24 | } -------------------------------------------------------------------------------- /src/app/article/article-detail/article-detail.component.html: -------------------------------------------------------------------------------- 1 |
6 | 7 | 8 |
9 |
10 |
11 |

{{detail.title}}

12 |

13 | {{detail.authorName}} - 14 | {{detail.createdAt | amDateFormat:'LL'}} - 15 | {{detail.readTotal}} viewed 16 |

17 |
18 |
19 |
20 |
21 |
22 | {{tag}} 23 |
24 | 25 |
26 | 32 | 33 |
34 |
35 | {{comment&& comment.length > 0? comment.length: '暂无'}} 评论 36 |
37 | 52 |
53 | 暂时还未有评论 54 |
55 |
56 | 57 |
58 | 59 | 提交回复 60 |
61 |
62 |
63 |
64 |
65 |

已提交评论。

66 | 我们希望每一次评论都是深思熟虑的,所以对连续评论作出了一些限制。 67 |
68 | 69 |
70 | 71 | -------------------------------------------------------------------------------- /src/app/article/article-detail/article-detail.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | 3 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 4 | import { By } from '@angular/platform-browser'; 5 | import { DebugElement } from '@angular/core'; 6 | 7 | import { ArticleDetailComponent } from './article-detail.component'; 8 | 9 | describe('ArticleDetailComponent', () => { 10 | let component: ArticleDetailComponent; 11 | let fixture: ComponentFixture; 12 | 13 | beforeEach(async(() => { 14 | TestBed.configureTestingModule({ 15 | declarations: [ ArticleDetailComponent ] 16 | }) 17 | .compileComponents(); 18 | })); 19 | 20 | beforeEach(() => { 21 | fixture = TestBed.createComponent(ArticleDetailComponent); 22 | component = fixture.componentInstance; 23 | fixture.detectChanges(); 24 | }); 25 | 26 | it('should create', () => { 27 | expect(component).toBeTruthy(); 28 | }); 29 | }); 30 | 31 | -------------------------------------------------------------------------------- /src/app/article/article-detail/article-detail.service.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | 3 | import {TestBed, async, inject} from '@angular/core/testing'; 4 | import {ArticleDetailService} from './article-detail.service'; 5 | 6 | describe('Service: Detail', () =>{ 7 | beforeEach(() =>{ 8 | TestBed.configureTestingModule({ 9 | providers: [ArticleDetailService] 10 | }); 11 | }); 12 | 13 | it('should ...', inject([ArticleDetailService], (service: ArticleDetailService) =>{ 14 | expect(service).toBeTruthy(); 15 | })); 16 | }); 17 | -------------------------------------------------------------------------------- /src/app/article/article-detail/article-detail.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {Http, Response} from '@angular/http' 3 | import {Observable} from 'rxjs/Observable' 4 | import 'rxjs/Rx' 5 | 6 | import {StaticService} from '../../shared/service/static' 7 | import {Detail} from './detail' 8 | import {Comment} from './comment' 9 | 10 | @Injectable() 11 | export class ArticleDetailService { 12 | 13 | constructor(private http: Http, 14 | private staticService: StaticService) { 15 | } 16 | 17 | private detailUrl = this.staticService.makeApi('articles') 18 | 19 | getDetail (id: string): Observable { 20 | return this.http.get(`${this.detailUrl}/${id}`, this.staticService.options()) 21 | .map(this.staticService.extractData) 22 | .catch(this.handleError) 23 | } 24 | getComment (id: string): Observable { 25 | return this.http.get(`${this.detailUrl}/${id}/comment`, this.staticService.options()) 26 | .map(this.staticService.extractData) 27 | .catch(this.handleError) 28 | } 29 | postComment (id: string, content: any): Observable { 30 | 31 | return this.http.post(`${this.detailUrl}/${id}/comment`, content, this.staticService.options()) 32 | .map(this.staticService.extractData) 33 | .catch(this.handleError) 34 | } 35 | 36 | private handleError (error: any){ 37 | if(error instanceof Response) { 38 | return Observable.throw(error.status || '服务器错误'); 39 | } 40 | return Observable.throw(error || '服务器错误') 41 | } 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/app/article/article-detail/comment.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by WittBulter on 2016/12/11. 3 | */ 4 | 5 | export class Comment { 6 | authorId: string 7 | authorName: string 8 | content: string 9 | createdAt: string 10 | id: string 11 | avatar?: string 12 | } -------------------------------------------------------------------------------- /src/app/article/article-detail/detail.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by WittBulter on 2016/10/21. 3 | * Detail Model 4 | */ 5 | 6 | export class Detail { 7 | id: string // id 8 | title: string // 标题 9 | content: string // 详情 10 | authorId: string // 作者id 11 | authorName: string // 作者名 12 | avatar?: string 13 | thumbnail?: string 14 | 15 | createdAt: string // 创建日期 16 | updatedAt: string // 更新日期 17 | tags: string[] // 标签 18 | readTotal: number // 阅读数 19 | commentTotal: number // 评论数 20 | } -------------------------------------------------------------------------------- /src/app/article/article-list/article-list.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
    4 |
  • 5 |
    6 |

    {{item.title}}

    7 |

    {{item.abstract | slice: 0:130}}

    8 |
    9 |

    {{item.authorName}} - {{item.createdAt | amDateFormat:'MM-DD-YYYY'}} - {{item.readTotal}} views

    10 | 11 |
    12 |
    13 |
    14 | 15 |
    16 |
  • 17 |
18 | 19 |
20 | 21 |
22 |
    23 |
  • 24 |

    {{item.title}}

    25 |

    {{item.abstract | slice: 0:100}}

    26 |
    27 |

    {{item.authorName}} - {{item.createdAt | amDateFormat:'LL'}}

    28 |

    {{item.readTotal}}views

    29 |
    30 |
  • 31 |
32 | 33 |
-------------------------------------------------------------------------------- /src/app/article/article-list/article-list.component.scss: -------------------------------------------------------------------------------- 1 | .article-list-box { 2 | width: 90%; 3 | max-width: 950px; 4 | min-width: 500px; 5 | height: auto; 6 | margin: 0 auto; 7 | padding: 20px 0; 8 | } 9 | ul.article-list{ 10 | width: 100%; 11 | height: auto; 12 | >li { 13 | width: 100%; 14 | height: 195px; 15 | border-bottom: 1px solid #E6E6E6; 16 | padding: 22px 0; 17 | font-family: -apple-system, "Hiragino Sans GB", "Hiragino Sans GB W3", Helvetica, "Microsoft YaHei", sans-serif; 18 | &:last-child { 19 | border-bottom: none; 20 | } 21 | .profiles { 22 | width: 65%; 23 | height: 100%; 24 | float: left; 25 | position: relative; 26 | padding-right: 12px; 27 | &.no-thumbnail { 28 | width: 100%; 29 | } 30 | h3 { 31 | font-size: 24px; 32 | font-weight: normal; 33 | line-height: 30px; 34 | color: #333; 35 | margin-bottom: 8px; 36 | cursor: pointer; 37 | -webkit-transition: all 0.15s; 38 | -moz-transition: all 0.15s; 39 | -o-transition: all 0.15s; 40 | transition: all 0.15s; 41 | &:hover { 42 | color: #458fd2; 43 | } 44 | } 45 | p { 46 | font-size: 15px; 47 | color: #828181; 48 | } 49 | .additional { 50 | position: absolute; 51 | padding-right: 12px; 52 | bottom: 0; 53 | left: 0; 54 | right: 0; 55 | width: 100%; 56 | overflow: hidden; 57 | p.author { 58 | float: left; 59 | font-size: 14px; 60 | color: #c7c7c7; 61 | } 62 | p.views { 63 | float: right; 64 | } 65 | } 66 | } 67 | .thumbnail { 68 | width: 35%; 69 | height: 100%; 70 | float: right; 71 | img { 72 | width: 100%; 73 | height: 100%; 74 | } 75 | } 76 | } 77 | } 78 | 79 | 80 | 81 | // mobile 82 | .mobile-article-list { 83 | width:100%; 84 | height: auto; 85 | margin: 0 auto; 86 | padding: 0 8px; 87 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen-Sans", "Ubuntu", "Cantarell", "Helvetica Neue", sans-serif; 88 | >ul{ 89 | width: 100%; 90 | >li { 91 | width: 100%; 92 | height: auto; 93 | border-bottom: 1px solid #E6E6E6; 94 | padding: 15px 0; 95 | 96 | h3 { 97 | font-size: 18px; 98 | font-weight: normal; 99 | line-height: 20px; 100 | color: #4094C7; 101 | margin-bottom: 5px; 102 | cursor: pointer; 103 | } 104 | p { 105 | font-size: 13px; 106 | } 107 | .mobile-article-list-additional { 108 | padding-top: 10px; 109 | width: 100%; 110 | overflow: hidden; 111 | color: #9ba9b5; 112 | p.author { 113 | float: left; 114 | font-size: 12px; 115 | } 116 | p.views { 117 | float: right; 118 | font-size: 12px; 119 | } 120 | } 121 | } 122 | } 123 | } 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /src/app/article/article-list/article-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | 3 | import {TestBed, async} from '@angular/core/testing'; 4 | import {ArticleListComponent} from './article-list.component'; 5 | 6 | describe('Component: list', () =>{ 7 | it('should create an instance', () =>{ 8 | let component = new ArticleListComponent(); 9 | expect(component).toBeTruthy(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /src/app/article/article-list/article-list.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core' 2 | import {Title} from '@angular/platform-browser' 3 | import {Router, ActivatedRoute, Params} from '@angular/router' 4 | import {StaticService} from '../../shared/service/static' 5 | 6 | import {List} from './list' 7 | import {ArticleListService} from './article-list.service' 8 | 9 | @Component({ 10 | selector: 'app-article-list', 11 | templateUrl: './article-list.component.html', 12 | styleUrls: ['./article-list.component.scss'], 13 | providers: [ArticleListService] 14 | }) 15 | export class ArticleListComponent implements OnInit { 16 | 17 | constructor( 18 | private listService: ArticleListService, 19 | private titleService: Title, 20 | private router: Router, 21 | private route: ActivatedRoute, 22 | private staticService: StaticService 23 | ) {} 24 | 25 | list: List[] 26 | errorMessage: string 27 | public activePage: number = 1 28 | public listOver: boolean = false 29 | 30 | getList(pageSize:number = 1) { 31 | this.activePage = ~~pageSize? pageSize: 1 32 | this.listService.getList(this.activePage) 33 | .subscribe( 34 | res => { 35 | if (res&& res.list){ 36 | this.list = res.list 37 | this.checkOver(res.total) 38 | } 39 | }, 40 | error => { 41 | this.errorMessage = error.json().message 42 | } 43 | ) 44 | } 45 | checkOver (total: number){ 46 | if (total&& total / 15 <= this.activePage){ 47 | return this.listOver = true 48 | } 49 | this.listOver = false 50 | } 51 | 52 | goNext (path){ 53 | this.router.navigate(['/articles/list', path]) 54 | } 55 | pageNext (page: number){ 56 | this.router.navigate(['/articles/list/page', page]) 57 | } 58 | 59 | ngOnInit() { 60 | this.titleService.setTitle('文章列表-维特博客') 61 | this.route.params 62 | .forEach((params: Params) => this.getList(+params['p'])) 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/app/article/article-list/article-list.service.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | 3 | import {TestBed, async, inject} from '@angular/core/testing'; 4 | import {ArticleListService} from './article-list.service'; 5 | 6 | describe('Service: articleListService', () => { 7 | beforeEach(() => { 8 | TestBed.configureTestingModule({ 9 | providers: [ArticleListService] 10 | }); 11 | }); 12 | 13 | it('should ...', inject([ArticleListService], (service: ArticleListService) => { 14 | expect(service).toBeTruthy(); 15 | })); 16 | }); 17 | -------------------------------------------------------------------------------- /src/app/article/article-list/article-list.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core' 2 | import {Http, Response} from '@angular/http' 3 | import {Observable} from 'rxjs/Observable' 4 | import {Headers, RequestOptions} from '@angular/http' 5 | import 'rxjs/Rx' 6 | 7 | import {List} from './list' 8 | import {StaticService} from '../../shared/service/static' 9 | 10 | @Injectable() 11 | export class ArticleListService { 12 | 13 | constructor ( 14 | private http: Http, 15 | private staticService: StaticService 16 | ){ 17 | } 18 | 19 | private listUrl = this.staticService.makeApi('articles') 20 | 21 | getList (pageSize): Observable{ 22 | return this.http.get(`${this.listUrl}?page=${pageSize}`) 23 | .map(this.extractData) 24 | .catch(this.handleError) 25 | } 26 | 27 | public extractData(res: Response) { 28 | // 存在总数限制,通知其他组件 29 | const total = res.headers.get('total') 30 | 31 | if (res.status != 204) return {list: res.json(), total: ~~total} || {} 32 | return {} 33 | } 34 | 35 | private handleError (error: any){ 36 | return Observable.throw(error || '服务器错误') 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/app/article/article-list/list.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by WittBulter on 2016/10/19. 3 | * List Model 4 | */ 5 | 6 | export class List { 7 | id: string // id 8 | title: string // 标题 9 | createdAt: string // 创建日期 10 | readTotal: number // 阅读数 11 | commentTotal: number // 评论数 12 | authorName: string // 用户姓名 13 | thumbnail?: string 14 | } -------------------------------------------------------------------------------- /src/app/article/article-main/article-main.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/article/article-main/article-main.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unix/tcome-frontend/78c14565ed740a46e92c7e1a9754c552ce317438/src/app/article/article-main/article-main.component.scss -------------------------------------------------------------------------------- /src/app/article/article-main/article-main.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { By } from '@angular/platform-browser'; 4 | import { DebugElement } from '@angular/core'; 5 | 6 | import { ArticleMainComponent } from './article-main.component'; 7 | 8 | describe('ArticleMainComponent', () => { 9 | let component: ArticleMainComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | declarations: [ ArticleMainComponent ] 15 | }) 16 | .compileComponents(); 17 | })); 18 | 19 | beforeEach(() => { 20 | fixture = TestBed.createComponent(ArticleMainComponent); 21 | component = fixture.componentInstance; 22 | fixture.detectChanges(); 23 | }); 24 | 25 | it('should create', () => { 26 | expect(component).toBeTruthy(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/app/article/article-main/article-main.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-article-main', 5 | templateUrl: './article-main.component.html', 6 | styleUrls: ['./article-main.component.scss'] 7 | }) 8 | export class ArticleMainComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/app/article/article.module.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by WittBulter on 2017/1/25. 3 | * @description :: article module 4 | */ 5 | import {NgModule} from '@angular/core' 6 | import {CommonModule} from '@angular/common' 7 | import {FormsModule} from '@angular/forms' 8 | import {HttpModule} from '@angular/http' 9 | import {MomentModule} from 'angular2-moment' 10 | import {SharedModule} from '../shared/shared.module' 11 | import {ResponsiveModule} from 'ng2-responsive' 12 | 13 | import {ArticleRoutingModule} from './article.routing' 14 | import {ShowdownComponent} from './showdown/showdown.component' 15 | import {ArticleMainComponent} from './article-main/article-main.component' 16 | import {ArticleListComponent} from './article-list/article-list.component' 17 | import {ArticleDetailComponent} from './article-detail/article-detail.component' 18 | 19 | @NgModule({ 20 | declarations: [ 21 | ArticleMainComponent, 22 | ShowdownComponent, 23 | ArticleListComponent, 24 | ArticleDetailComponent 25 | ], 26 | imports: [ 27 | SharedModule, 28 | CommonModule, 29 | FormsModule, 30 | HttpModule, 31 | MomentModule, 32 | ArticleRoutingModule, 33 | ResponsiveModule 34 | ], 35 | exports: [ArticleMainComponent], 36 | providers: [] 37 | }) 38 | export class ArticleModule { 39 | } -------------------------------------------------------------------------------- /src/app/article/article.routing.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by WittBulter on 2017/1/25. 3 | * @description :: article route 4 | */ 5 | import {NgModule} from '@angular/core' 6 | import {Routes, RouterModule} from '@angular/router' 7 | 8 | import {ArticleMainComponent} from './article-main/article-main.component' 9 | import {ArticleListComponent} from './article-list/article-list.component' 10 | import {ArticleDetailComponent} from './article-detail/article-detail.component' 11 | 12 | const userRoutes: Routes = [{ 13 | path: '', component: ArticleMainComponent, 14 | children: [{ 15 | path: '', redirectTo:'list',pathMatch:'full' 16 | },{ 17 | path: 'list', component: ArticleListComponent 18 | },{ 19 | path: 'list/page/:p', component: ArticleListComponent 20 | },{ 21 | path: 'list/:id', component: ArticleDetailComponent 22 | }] 23 | }] 24 | 25 | @NgModule({ 26 | imports: [RouterModule.forChild(userRoutes)], 27 | exports: [RouterModule] 28 | }) 29 | export class ArticleRoutingModule { 30 | } -------------------------------------------------------------------------------- /src/app/article/showdown/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by WittBulter on 2016/12/24. 3 | */ 4 | 5 | import {ShowdownComponent} from './showdown.component' 6 | 7 | export {ShowdownComponent} -------------------------------------------------------------------------------- /src/app/article/showdown/showdown.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | -------------------------------------------------------------------------------- /src/app/article/showdown/showdown.component.scss: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/app/article/showdown/showdown.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { By } from '@angular/platform-browser'; 4 | import { DebugElement } from '@angular/core'; 5 | 6 | import { ShowdownComponent } from './showdown.component'; 7 | 8 | describe('ShowdownComponent', () => { 9 | let component: ShowdownComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | declarations: [ ShowdownComponent ] 15 | }) 16 | .compileComponents(); 17 | })); 18 | 19 | beforeEach(() => { 20 | fixture = TestBed.createComponent(ShowdownComponent); 21 | component = fixture.componentInstance; 22 | fixture.detectChanges(); 23 | }); 24 | 25 | it('should create', () => { 26 | expect(component).toBeTruthy(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/app/article/showdown/showdown.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input, AfterViewInit, OnInit} from '@angular/core' 2 | 3 | const Remarkable = require('remarkable') 4 | const hljs = require('highlight.js') 5 | 6 | @Component({ 7 | selector: 'app-showdown', 8 | templateUrl: './showdown.component.html', 9 | styleUrls: ['./showdown.component.scss'] 10 | }) 11 | export class ShowdownComponent implements OnInit { 12 | 13 | constructor (){ 14 | } 15 | 16 | @Input() html: string = '' 17 | public innerHTML: any 18 | 19 | ngOnInit (){ 20 | const md = new Remarkable({ 21 | highlight: (str, lang) =>{ 22 | if (lang && hljs.getLanguage(lang)) { 23 | try { 24 | return hljs.highlight(lang, str).value; 25 | } catch (err) {} 26 | } 27 | try { 28 | return hljs.highlightAuto(str).value; 29 | } catch (err) { 30 | 31 | } 32 | return '' 33 | } 34 | }) 35 | this.innerHTML = md.render(this.html) 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/app/home/home.component.html: -------------------------------------------------------------------------------- 1 |
2 | 12 |
13 |

{{option.blogName?option.blogName: 'NEW BLOG'}}

14 |

{{option.blogSubhead}}

15 |
16 |
17 | 18 |
19 |
20 |

{{option.blogName?option.blogName: 'NEW BLOG'}} Today's Special

21 |

{{option.blogSubhead}}

22 |
23 |
    24 |
  • 25 |

    {{item.title}}

    26 |

    {{item.readTotal}}views / {{item.commentTotal}}comment

    27 |

    -- {{item.authorName}}

    28 |
  • 29 |
30 |
31 |

使用电脑访问可获得最佳体验!

32 |
33 |
34 | 35 | -------------------------------------------------------------------------------- /src/app/home/home.component.scss: -------------------------------------------------------------------------------- 1 | 2 | .content { 3 | width: 1100px; 4 | margin: 0 auto; 5 | padding-left: 200px; 6 | padding-top: 150px; 7 | overflow: hidden; 8 | .recommended { 9 | width: 50%; 10 | float: left; 11 | padding-right: 20px; 12 | border-right: 2px solid #eee; 13 | min-height: 300px; 14 | padding-bottom: 50px; 15 | h2 { 16 | font-family: "futura-pt", sans-serif; 17 | font-weight: normal; 18 | font-size: 26px; 19 | text-align: right; 20 | line-height: 2.2; 21 | color: #404040; 22 | } 23 | > ul { 24 | width: 100%; 25 | li { 26 | width: 100%; 27 | text-align: right; 28 | margin-bottom: 10px; 29 | h3 { 30 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen-Sans", "Ubuntu", "Cantarell", "Helvetica Neue", sans-serif; 31 | font-weight: 300; 32 | font-size: 20px; 33 | a { 34 | color: #4094C7; 35 | text-decoration: none; 36 | } 37 | } 38 | p { 39 | font-size: 13px; 40 | color: #ccc; 41 | line-height: 1; 42 | } 43 | } 44 | } 45 | } 46 | .welcome { 47 | width: 50%; 48 | float: right; 49 | padding-left: 10px; 50 | padding-top: 30px; 51 | overflow: hidden; 52 | font-family: "futura-pt", sans-serif; 53 | h1 { 54 | font-weight: normal; 55 | font-size: 30px; 56 | color: #404040; 57 | line-height: 2.2; 58 | } 59 | p { 60 | font-size: 18px; 61 | font-weight: normal; 62 | color: #404040; 63 | border-bottom: 1px solid #eee; 64 | display: inline-block; 65 | word-wrap: break-word; 66 | } 67 | } 68 | 69 | } 70 | 71 | //mobile 72 | 73 | .mobile-home { 74 | width: 100%; 75 | height: auto; 76 | padding-left: 6%; 77 | .mobile-home-title { 78 | font-family: "futura-pt", sans-serif; 79 | margin-top: 20px; 80 | h1 { 81 | font-weight: normal; 82 | font-size: 22px; 83 | color: #404040; 84 | line-height: 2.2; 85 | border-bottom: 2px solid #eee; 86 | >span { 87 | font-size: 14px; 88 | } 89 | } 90 | p { 91 | font-size: 14px; 92 | font-weight: normal; 93 | color: #404040; 94 | display: inline-block; 95 | word-wrap: break-word; 96 | } 97 | } 98 | .mobile-home-list { 99 | width: 100%; 100 | margin-top: 30px; 101 | >li { 102 | width: 100%; 103 | text-align: left; 104 | margin-bottom: 10px; 105 | h3 { 106 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen-Sans", "Ubuntu", "Cantarell", "Helvetica Neue", sans-serif; 107 | font-weight: 300; 108 | font-size: 16px; 109 | a { 110 | color: #4094C7; 111 | text-decoration: none; 112 | } 113 | } 114 | p { 115 | font-size: 13px; 116 | color: #ccc; 117 | line-height: 1; 118 | } 119 | } 120 | } 121 | 122 | } 123 | 124 | .mobile-home-tips{ 125 | width: 100%; 126 | position: fixed; 127 | left: 0; 128 | right: 0; 129 | bottom: 5px; 130 | text-align: center; 131 | font-size: 14px; 132 | font-weight: 300; 133 | color: #ccc; 134 | } 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /src/app/home/home.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { By } from '@angular/platform-browser'; 4 | import { DebugElement } from '@angular/core'; 5 | 6 | import { HomeComponent } from './home.component'; 7 | 8 | describe('HomeComponent', () => { 9 | let component: HomeComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | declarations: [ HomeComponent ] 15 | }) 16 | .compileComponents(); 17 | })); 18 | 19 | beforeEach(() => { 20 | fixture = TestBed.createComponent(HomeComponent); 21 | component = fixture.componentInstance; 22 | fixture.detectChanges(); 23 | }); 24 | 25 | it('should create', () => { 26 | expect(component).toBeTruthy(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/app/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core' 2 | import {Title} from '@angular/platform-browser' 3 | 4 | import {HomeService} from './home.service' 5 | import {Option} from './option' 6 | 7 | @Component({ 8 | selector: 'app-home', 9 | templateUrl: './home.component.html', 10 | styleUrls: ['./home.component.scss'], 11 | providers: [HomeService] 12 | }) 13 | export class HomeComponent implements OnInit { 14 | 15 | constructor ( 16 | private titleService: Title, 17 | private homeService: HomeService 18 | ){ 19 | } 20 | public option: Option 21 | 22 | getOption (){ 23 | this.homeService.getOption() 24 | .subscribe( 25 | option => { 26 | this.option = option 27 | }, 28 | error =>{ 29 | console.log(error); 30 | } 31 | ) 32 | } 33 | 34 | ngOnInit (){ 35 | this.titleService.setTitle('欢迎-维特博客') 36 | this.getOption() 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/app/home/home.service.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | 3 | import { TestBed, async, inject } from '@angular/core/testing'; 4 | import { HomeService } from './home.service'; 5 | 6 | describe('HomeService', () => { 7 | beforeEach(() => { 8 | TestBed.configureTestingModule({ 9 | providers: [HomeService] 10 | }); 11 | }); 12 | 13 | it('should ...', inject([HomeService], (service: HomeService) => { 14 | expect(service).toBeTruthy(); 15 | })); 16 | }); 17 | -------------------------------------------------------------------------------- /src/app/home/home.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core' 2 | import {Http, Response} from '@angular/http' 3 | import {Observable} from 'rxjs/Observable' 4 | import 'rxjs/Rx' 5 | 6 | import {StaticService} from '../shared/service/static' 7 | import {Option} from './option' 8 | 9 | @Injectable() 10 | export class HomeService { 11 | 12 | constructor (private http: Http, 13 | private staticService: StaticService){ 14 | } 15 | 16 | private optionLink = this.staticService.makeApi('option') 17 | 18 | getOption ():Observable