├── src ├── pages │ ├── user │ │ ├── user.scss │ │ ├── user.module.ts │ │ ├── user.ts │ │ └── user.html │ ├── page1 │ │ ├── page1.scss │ │ ├── page1.ts │ │ └── page1.html │ ├── page2 │ │ ├── page2.scss │ │ ├── page2.html │ │ └── page2.ts │ ├── topic │ │ ├── topic.scss │ │ ├── topic.module.ts │ │ ├── topic.ts │ │ └── topic.html │ ├── message │ │ ├── message.scss │ │ ├── message.module.ts │ │ ├── message.ts │ │ └── message.html │ ├── new-topic-modal │ │ ├── new-topic-modal.scss │ │ ├── new-topic-modal.module.ts │ │ ├── new-topic-modal.html │ │ └── new-topic-modal.ts │ └── topics │ │ ├── topics.module.ts │ │ ├── topics.scss │ │ ├── topics.html │ │ └── topics.ts ├── classes │ ├── tab.ts │ ├── topic.ts │ ├── message.ts │ └── user.ts ├── assets │ └── icon │ │ └── favicon.ico ├── app │ ├── main.ts │ ├── app.html │ ├── app.module.ts │ ├── app.scss │ └── app.component.ts ├── manifest.json ├── providers │ ├── storage-service.ts │ ├── config-service.ts │ ├── tabs-service.ts │ ├── message-service.ts │ ├── user-service.ts │ └── topic-service.ts ├── declarations.d.ts ├── service-worker.js ├── index.html └── theme │ └── variables.scss ├── resources ├── icon.png ├── splash.png ├── ios │ ├── icon │ │ ├── icon.png │ │ ├── icon-40.png │ │ ├── icon-50.png │ │ ├── icon-60.png │ │ ├── icon-72.png │ │ ├── icon-76.png │ │ ├── icon@2x.png │ │ ├── icon-40@2x.png │ │ ├── icon-40@3x.png │ │ ├── icon-50@2x.png │ │ ├── icon-60@2x.png │ │ ├── icon-60@3x.png │ │ ├── icon-72@2x.png │ │ ├── icon-76@2x.png │ │ ├── icon-83.5@2x.png │ │ ├── icon-small.png │ │ ├── icon-small@2x.png │ │ └── icon-small@3x.png │ └── splash │ │ ├── Default-667h.png │ │ ├── Default-736h.png │ │ ├── Default~iphone.png │ │ ├── Default@2x~iphone.png │ │ ├── Default-568h@2x~iphone.png │ │ ├── Default-Landscape-736h.png │ │ ├── Default-Landscape~ipad.png │ │ ├── Default-Portrait~ipad.png │ │ ├── Default-Landscape@2x~ipad.png │ │ └── Default-Portrait@2x~ipad.png └── android │ ├── icon │ ├── drawable-hdpi-icon.png │ ├── drawable-ldpi-icon.png │ ├── drawable-mdpi-icon.png │ ├── drawable-xhdpi-icon.png │ ├── drawable-xxhdpi-icon.png │ └── drawable-xxxhdpi-icon.png │ └── splash │ ├── drawable-land-hdpi-screen.png │ ├── drawable-land-ldpi-screen.png │ ├── drawable-land-mdpi-screen.png │ ├── drawable-land-xhdpi-screen.png │ ├── drawable-port-hdpi-screen.png │ ├── drawable-port-ldpi-screen.png │ ├── drawable-port-mdpi-screen.png │ ├── drawable-port-xhdpi-screen.png │ ├── drawable-land-xxhdpi-screen.png │ ├── drawable-land-xxxhdpi-screen.png │ ├── drawable-port-xxhdpi-screen.png │ └── drawable-port-xxxhdpi-screen.png ├── ionic.config.json ├── config ├── webpack.common.js └── webpack.config.js ├── tslint.json ├── .editorconfig ├── .gitignore ├── tsconfig.json ├── package.json └── config.xml /src/pages/user/user.scss: -------------------------------------------------------------------------------- 1 | page-user { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/pages/page1/page1.scss: -------------------------------------------------------------------------------- 1 | page-page1 { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/pages/page2/page2.scss: -------------------------------------------------------------------------------- 1 | page-page2 { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/pages/topic/topic.scss: -------------------------------------------------------------------------------- 1 | page-topic { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/pages/message/message.scss: -------------------------------------------------------------------------------- 1 | page-message { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/pages/new-topic-modal/new-topic-modal.scss: -------------------------------------------------------------------------------- 1 | page-new-topic-modal { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/icon.png -------------------------------------------------------------------------------- /resources/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/splash.png -------------------------------------------------------------------------------- /src/classes/tab.ts: -------------------------------------------------------------------------------- 1 | export class Tab { 2 | value: string; 3 | label: string; 4 | } 5 | 6 | 7 | -------------------------------------------------------------------------------- /resources/ios/icon/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/icon/icon.png -------------------------------------------------------------------------------- /src/assets/icon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/src/assets/icon/favicon.ico -------------------------------------------------------------------------------- /src/classes/topic.ts: -------------------------------------------------------------------------------- 1 | export class Topic { 2 | id: string; 3 | title: string; 4 | content: string; 5 | } 6 | -------------------------------------------------------------------------------- /resources/ios/icon/icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/icon/icon-40.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/icon/icon-50.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/icon/icon-60.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/icon/icon-72.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/icon/icon-76.png -------------------------------------------------------------------------------- /resources/ios/icon/icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/icon/icon@2x.png -------------------------------------------------------------------------------- /ionic.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cnodejs-ionic3", 3 | "app_id": "", 4 | "v2": true, 5 | "typescript": true 6 | } 7 | -------------------------------------------------------------------------------- /resources/ios/icon/icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/icon/icon-40@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/icon/icon-40@3x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/icon/icon-50@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/icon/icon-60@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/icon/icon-60@3x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/icon/icon-72@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/icon/icon-76@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/icon/icon-83.5@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/icon/icon-small.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/icon/icon-small@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/icon/icon-small@3x.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-667h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/splash/Default-667h.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-736h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/splash/Default-736h.png -------------------------------------------------------------------------------- /resources/ios/splash/Default~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/splash/Default~iphone.png -------------------------------------------------------------------------------- /resources/ios/splash/Default@2x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/splash/Default@2x~iphone.png -------------------------------------------------------------------------------- /resources/android/icon/drawable-hdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/android/icon/drawable-hdpi-icon.png -------------------------------------------------------------------------------- /resources/android/icon/drawable-ldpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/android/icon/drawable-ldpi-icon.png -------------------------------------------------------------------------------- /resources/android/icon/drawable-mdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/android/icon/drawable-mdpi-icon.png -------------------------------------------------------------------------------- /resources/android/icon/drawable-xhdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/android/icon/drawable-xhdpi-icon.png -------------------------------------------------------------------------------- /resources/android/icon/drawable-xxhdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/android/icon/drawable-xxhdpi-icon.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-568h@2x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/splash/Default-568h@2x~iphone.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-Landscape-736h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/splash/Default-Landscape-736h.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-Landscape~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/splash/Default-Landscape~ipad.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-Portrait~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/splash/Default-Portrait~ipad.png -------------------------------------------------------------------------------- /resources/android/icon/drawable-xxxhdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/android/icon/drawable-xxxhdpi-icon.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-Landscape@2x~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/splash/Default-Landscape@2x~ipad.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-Portrait@2x~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/ios/splash/Default-Portrait@2x~ipad.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-land-hdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/android/splash/drawable-land-hdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-land-ldpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/android/splash/drawable-land-ldpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-land-mdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/android/splash/drawable-land-mdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-land-xhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/android/splash/drawable-land-xhdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-port-hdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/android/splash/drawable-port-hdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-port-ldpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/android/splash/drawable-port-ldpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-port-mdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/android/splash/drawable-port-mdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-port-xhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/android/splash/drawable-port-xhdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-land-xxhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/android/splash/drawable-land-xxhdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-land-xxxhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/android/splash/drawable-land-xxxhdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-port-xxhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/android/splash/drawable-port-xxhdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-port-xxxhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanceli/cnodejs-ionic3/HEAD/resources/android/splash/drawable-port-xxxhdpi-screen.png -------------------------------------------------------------------------------- /config/webpack.common.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | 3 | module.exports = { 4 | plugins: [ 5 | new webpack.EnvironmentPlugin(['IONIC_ENV']) 6 | ] 7 | }; 8 | 9 | -------------------------------------------------------------------------------- /src/classes/message.ts: -------------------------------------------------------------------------------- 1 | export class Message { 2 | id: string; 3 | } 4 | export class Messages { 5 | has_read_messages: Message[]; 6 | hasnot_read_messages: Message[]; 7 | } 8 | -------------------------------------------------------------------------------- /src/app/main.ts: -------------------------------------------------------------------------------- 1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 2 | 3 | import { AppModule } from './app.module'; 4 | 5 | platformBrowserDynamic().bootstrapModule(AppModule); 6 | -------------------------------------------------------------------------------- /src/classes/user.ts: -------------------------------------------------------------------------------- 1 | export class User { 2 | id?: string; 3 | accesstoken?: string; 4 | loginname: string; 5 | avatar_url: string; 6 | githubUsername: string; 7 | create_at: string; 8 | } 9 | 10 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-duplicate-variable": true, 4 | "no-unused-variable": [ 5 | true 6 | ] 7 | }, 8 | "rulesDirectory": [ 9 | "node_modules/tslint-eslint-rules/dist/rules" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /config/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpackMerge = require('webpack-merge'); 2 | 3 | const commonConfig = require('./webpack.common.js'); 4 | const ionicConfig = require('../node_modules/@ionic/app-scripts/config/webpack.config.js'); 5 | 6 | module.exports = webpackMerge( 7 | commonConfig, 8 | ionicConfig 9 | ); 10 | -------------------------------------------------------------------------------- /src/pages/page1/page1.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | import { NavController } from 'ionic-angular'; 4 | 5 | @Component({ 6 | selector: 'page-page1', 7 | templateUrl: 'page1.html' 8 | }) 9 | export class Page1 { 10 | 11 | constructor(public navCtrl: NavController) { 12 | 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Ionic", 3 | "short_name": "Ionic", 4 | "start_url": "index.html", 5 | "display": "standalone", 6 | "icons": [{ 7 | "src": "assets/imgs/logo.png", 8 | "sizes": "512x512", 9 | "type": "image/png" 10 | }], 11 | "background_color": "#4e8ef7", 12 | "theme_color": "#4e8ef7" 13 | } -------------------------------------------------------------------------------- /src/pages/message/message.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { IonicPageModule } from 'ionic-angular'; 3 | import { MessagePage } from './message'; 4 | 5 | @NgModule({ 6 | declarations: [ 7 | MessagePage, 8 | ], 9 | imports: [ 10 | IonicPageModule.forChild(MessagePage), 11 | ], 12 | exports: [ 13 | MessagePage 14 | ] 15 | }) 16 | export class MessageModule {} 17 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent coding styles between different editors and IDEs 2 | # editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 2 9 | 10 | # We recommend you to keep these unchanged 11 | end_of_line = lf 12 | charset = utf-8 13 | trim_trailing_whitespace = true 14 | insert_final_newline = true 15 | 16 | [*.md] 17 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /src/pages/topics/topics.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { TopicsPage } from './topics'; 3 | import { IonicPageModule } from 'ionic-angular'; 4 | 5 | @NgModule({ 6 | declarations: [ 7 | TopicsPage 8 | ], 9 | imports: [ 10 | IonicPageModule.forChild(TopicsPage) 11 | ], 12 | entryComponents: [ 13 | TopicsPage 14 | ] 15 | }) 16 | export class TopicsPageModule {} 17 | 18 | -------------------------------------------------------------------------------- /src/pages/topic/topic.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { TopicPage } from './topic'; 3 | import { IonicPageModule } from 'ionic-angular'; 4 | import { MomentModule } from 'angular2-moment'; 5 | 6 | @NgModule({ 7 | declarations: [ 8 | TopicPage 9 | ], 10 | imports: [ 11 | MomentModule, 12 | IonicPageModule.forChild(TopicPage) 13 | ], 14 | entryComponents: [ 15 | TopicPage 16 | ] 17 | }) 18 | export class TopicPageModule {} 19 | -------------------------------------------------------------------------------- /src/pages/user/user.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { UserPage } from './user'; 3 | import { IonicPageModule } from 'ionic-angular'; 4 | import { MomentModule } from 'angular2-moment'; 5 | 6 | @NgModule({ 7 | declarations: [ 8 | UserPage 9 | ], 10 | imports: [ 11 | MomentModule, 12 | IonicPageModule.forChild(UserPage) 13 | ], 14 | entryComponents: [ 15 | UserPage 16 | ] 17 | }) 18 | export class UserPageModule {} 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/pages/new-topic-modal/new-topic-modal.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { IonicPageModule } from 'ionic-angular'; 3 | import { NewTopicModal } from './new-topic-modal'; 4 | 5 | console.log('aaa,', NewTopicModal) 6 | @NgModule({ 7 | declarations: [ 8 | NewTopicModal, 9 | ], 10 | imports: [ 11 | IonicPageModule.forChild(NewTopicModal) 12 | ], 13 | exports: [ 14 | NewTopicModal 15 | ] 16 | }) 17 | export class NewTopicModalModule {} 18 | -------------------------------------------------------------------------------- /src/pages/page1/page1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | Page One 7 | 8 | 9 | 10 | 11 |

Ionic Menu Starter

12 | 13 |

14 | If you get lost, the docs will show you the way. 15 |

16 | 17 | 18 |
19 | -------------------------------------------------------------------------------- /src/providers/storage-service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Http } from '@angular/http'; 3 | import 'rxjs/add/operator/map'; 4 | 5 | /* 6 | Generated class for the StorageService provider. 7 | 8 | See https://angular.io/docs/ts/latest/guide/dependency-injection.html 9 | for more info on providers and Angular 2 DI. 10 | */ 11 | @Injectable() 12 | export class StorageService { 13 | 14 | constructor(public http: Http) { 15 | console.log('Hello StorageService Provider'); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/providers/config-service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | declare const process: any; // Typescript compiler will complain without this 3 | @Injectable() 4 | 5 | export class ConfigService { 6 | public api:string; 7 | public token:string; 8 | constructor() { 9 | console.log(process); 10 | if (process.env.IONIC_ENV === 'prod') { 11 | this.api = 'https://cnodejs.org/api/v1/'; 12 | } else { 13 | this.api = 'http://localhost:3000/api/v1/'; 14 | this.token = ' 08bb9fe1-d42a-44ca-bae5-7c90585f8d7b'; 15 | } 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Specifies intentionally untracked files to ignore when using Git 2 | # http://git-scm.com/docs/gitignore 3 | 4 | *~ 5 | *.sw[mnpcod] 6 | *.log 7 | *.tmp 8 | *.tmp.* 9 | log.txt 10 | *.sublime-project 11 | *.sublime-workspace 12 | .vscode/ 13 | npm-debug.log* 14 | 15 | .idea/ 16 | .sass-cache/ 17 | .tmp/ 18 | .versions/ 19 | coverage/ 20 | dist/ 21 | node_modules/ 22 | tmp/ 23 | temp/ 24 | hooks/ 25 | platforms/ 26 | plugins/ 27 | plugins/android.json 28 | plugins/ios.json 29 | www/ 30 | $RECYCLE.BIN/ 31 | 32 | .DS_Store 33 | Thumbs.db 34 | UserInterfaceState.xcuserstate 35 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "declaration": false, 5 | "emitDecoratorMetadata": true, 6 | "experimentalDecorators": true, 7 | "lib": [ 8 | "dom", 9 | "es2015" 10 | ], 11 | "module": "es2015", 12 | "moduleResolution": "node", 13 | "sourceMap": true, 14 | "target": "es5" 15 | }, 16 | "include": [ 17 | "src/**/*.ts" 18 | ], 19 | "exclude": [ 20 | "node_modules" 21 | ], 22 | "compileOnSave": false, 23 | "atom": { 24 | "rewriteTsconfig": false 25 | } 26 | } -------------------------------------------------------------------------------- /src/pages/page2/page2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | Page Two 7 | 8 | 9 | 10 | 11 | 12 | 19 | 20 |
21 | You navigated here from {{selectedItem.title}} 22 |
23 |
24 | -------------------------------------------------------------------------------- /src/declarations.d.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Declaration files are how the Typescript compiler knows about the type information(or shape) of an object. 3 | They're what make intellisense work and make Typescript know all about your code. 4 | 5 | A wildcard module is declared below to allow third party libraries to be used in an app even if they don't 6 | provide their own type declarations. 7 | 8 | To learn more about using third party libraries in an Ionic app, check out the docs here: 9 | http://ionicframework.com/docs/v2/resources/third-party-libs/ 10 | 11 | For more info on type definition files, check out the Typescript docs here: 12 | https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html 13 | */ 14 | declare module '*'; -------------------------------------------------------------------------------- /src/providers/tabs-service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | import { Tab } from '../classes/tab'; 4 | /* 5 | Generated class for the TabsService provider. 6 | 7 | See https://angular.io/docs/ts/latest/guide/dependency-injection.html 8 | for more info on providers and Angular 2 DI. 9 | */ 10 | @Injectable() 11 | export class TabsService { 12 | tabs: Tab[] = [ 13 | { 14 | value: 'all', 15 | label: '最新' 16 | }, 17 | { 18 | value: 'share', 19 | label: '分享' 20 | }, 21 | { 22 | value: 'ask', 23 | label: '问答' 24 | }, 25 | { 26 | value: 'job', 27 | label: '招聘' 28 | }, 29 | { 30 | value: undefined, 31 | label: '其他' 32 | } 33 | ] 34 | 35 | getTabs(): Tab[] { 36 | return this.tabs; 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /src/service-worker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Check out https://googlechrome.github.io/sw-toolbox/docs/master/index.html for 3 | * more info on how to use sw-toolbox to custom configure your service worker. 4 | */ 5 | 6 | 7 | 'use strict'; 8 | importScripts('./build/sw-toolbox.js'); 9 | 10 | self.toolbox.options.cache = { 11 | name: 'ionic-cache' 12 | }; 13 | 14 | // pre-cache our key assets 15 | self.toolbox.precache( 16 | [ 17 | './build/main.js', 18 | './build/main.css', 19 | './build/polyfills.js', 20 | 'index.html', 21 | 'manifest.json' 22 | ] 23 | ); 24 | 25 | // dynamically cache any other local assets 26 | self.toolbox.router.any('/*', self.toolbox.cacheFirst); 27 | 28 | // for any other requests go to the network, cache, 29 | // and then only use that cached resource if your user goes offline 30 | self.toolbox.router.default = self.toolbox.networkFirst; -------------------------------------------------------------------------------- /src/pages/topics/topics.scss: -------------------------------------------------------------------------------- 1 | page-topics { 2 | .topics { 3 | .item-content { 4 | padding: 14px 16px 18px 72px; 5 | > img { 6 | &:not(:first-child) { 7 | -webkit-transform: translate3d(-2000px, -2000px, 0px); 8 | position: absolute; 9 | } 10 | } 11 | } 12 | .activated { 13 | .tab { 14 | &:not(.hl) { 15 | background-color: #aeaeae; 16 | color: #fff; 17 | } 18 | } 19 | } 20 | .ago, 21 | .summary { 22 | font-size: 12px; 23 | } 24 | .tab { 25 | background-color: #E5E5E5; 26 | color: #999; 27 | border-radius: 2px; 28 | padding: 2px 4px; 29 | } 30 | .hl { 31 | background-color: $node-green; 32 | color: #fff; 33 | } 34 | } 35 | .topic-content { 36 | img { 37 | max-width: 100%; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/app/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Menu 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | {{user.loginname}} 13 | 14 | 15 | 16 | 我的消息 17 | 18 | 19 | 登录 20 | 21 | 22 | 23 | 24 | 板块 25 | 26 | 27 | {{tab.label}} 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/pages/page2/page2.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | import { NavController, NavParams } from 'ionic-angular'; 4 | 5 | @Component({ 6 | selector: 'page-page2', 7 | templateUrl: 'page2.html' 8 | }) 9 | export class Page2 { 10 | selectedItem: any; 11 | icons: string[]; 12 | items: Array<{title: string, note: string, icon: string}>; 13 | 14 | constructor(public navCtrl: NavController, public navParams: NavParams) { 15 | // If we navigated to this page, we will have an item available as a nav param 16 | this.selectedItem = navParams.get('item'); 17 | 18 | // Let's populate this page with some filler content for funzies 19 | this.icons = ['flask', 'wifi', 'beer', 'football', 'basketball', 'paper-plane', 20 | 'american-football', 'boat', 'bluetooth', 'build']; 21 | 22 | this.items = []; 23 | for (let i = 1; i < 11; i++) { 24 | this.items.push({ 25 | title: 'Item ' + i, 26 | note: 'This is item #' + i, 27 | icon: this.icons[Math.floor(Math.random() * this.icons.length)] 28 | }); 29 | } 30 | } 31 | 32 | itemTapped(event, item) { 33 | // That's right, we're pushing to ourselves! 34 | this.navCtrl.push(Page2, { 35 | item: item 36 | }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule, ErrorHandler } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | import { HttpModule } from '@angular/http'; 4 | import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular'; 5 | import { IonicStorageModule } from '@ionic/storage'; 6 | import { MomentModule } from 'angular2-moment'; 7 | 8 | import { StatusBar } from '@ionic-native/status-bar'; 9 | import { SplashScreen } from '@ionic-native/splash-screen'; 10 | 11 | import { MyApp } from './app.component'; 12 | import { ConfigService } from '../providers/config-service'; 13 | 14 | import { NewTopicModal } from '../pages/new-topic-modal/new-topic-modal'; 15 | 16 | @NgModule({ 17 | declarations: [ 18 | MyApp, 19 | NewTopicModal 20 | ], 21 | imports: [ 22 | BrowserModule, 23 | HttpModule, 24 | MomentModule, 25 | IonicStorageModule.forRoot(), 26 | IonicModule.forRoot(MyApp, { 27 | locationStrategy: 'hash' 28 | }) 29 | ], 30 | bootstrap: [IonicApp], 31 | entryComponents: [ 32 | MyApp, 33 | NewTopicModal 34 | ], 35 | providers: [ 36 | StatusBar, 37 | SplashScreen, 38 | {provide: ErrorHandler, useClass: IonicErrorHandler}, 39 | ConfigService 40 | ] 41 | }) 42 | export class AppModule {} 43 | -------------------------------------------------------------------------------- /src/pages/user/user.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { NavController, NavParams, IonicPage } from 'ionic-angular'; 3 | 4 | import { User } from '../../classes/user'; 5 | import { UserService } from '../../providers/user-service'; 6 | /* 7 | Generated class for the User page. 8 | 9 | See http://ionicframework.com/docs/v2/components/#navigation for more info on 10 | Ionic pages and navigation. 11 | */ 12 | @IonicPage({ 13 | name: 'user', 14 | segment: 'user/:loginName' 15 | }) 16 | @Component({ 17 | selector: 'page-user', 18 | templateUrl: 'user.html', 19 | providers: [UserService] 20 | }) 21 | export class UserPage { 22 | 23 | user: User 24 | 25 | constructor(public navCtrl: NavController, public navParams: NavParams, private userService: UserService) { 26 | } 27 | 28 | ionViewDidLoad() { 29 | console.log('ionViewDidLoad UserPage'); 30 | } 31 | 32 | ngOnInit(): void { 33 | this.getUser() 34 | } 35 | 36 | getUser(): void { 37 | this.userService.getByLoginName(this.navParams.get('loginName')).then( 38 | (user) => { 39 | this.user = user 40 | console.log(this.user) 41 | } 42 | ); 43 | } 44 | 45 | gotoTopicPage(id: string): void { 46 | console.log('go to topic', id); 47 | this.navCtrl.push('topic', {id: id}); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/pages/new-topic-modal/new-topic-modal.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | NewTopicModal 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |
23 | 30 | 33 | 36 |
37 |
38 | 39 |
40 | -------------------------------------------------------------------------------- /src/pages/topics/topics.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | Topics 7 | 8 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |

{{topic.title}}

23 |

24 | {{topic.tab}} 25 | 置顶 26 | 精华 27 | {{topic.author.loginname}} 28 | 29 | 30 |

31 |
32 |
33 | 34 | 35 | 36 |
37 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/app/app.scss: -------------------------------------------------------------------------------- 1 | // http://ionicframework.com/docs/v2/theming/ 2 | 3 | 4 | // App Global Sass 5 | // -------------------------------------------------- 6 | // Put style rules here that you want to apply globally. These 7 | // styles are for the entire app and not just one component. 8 | // Additionally, this file can be also used as an entry point 9 | // to import other Sass files to be included in the output CSS. 10 | // 11 | // Shared Sass variables, which can be used to adjust Ionic's 12 | // default Sass variables, belong in "theme/variables.scss". 13 | // 14 | // To declare rules for a specific mode, create a child rule 15 | // for the .md, .ios, or .wp mode classes. The mode class is 16 | // automatically applied to the element in the app. 17 | .item { 18 | left: 0; 19 | right: 0; 20 | } 21 | .item-divider { 22 | color: #555; 23 | font-weight: normal; 24 | font-size: 14px; 25 | } 26 | .item-gap { 27 | border: 0 none; 28 | min-height: 0px; 29 | } 30 | .item-loading { 31 | text-align: center; 32 | color: #aaa; 33 | } 34 | .saverMode { 35 | .item-avatar { 36 | padding-left: 14px; 37 | &.item-complex { 38 | padding-left: 0; 39 | } 40 | > img { 41 | &:first-child { 42 | -webkit-transform: translate3d(-2000px, -2000px, 0px); 43 | } 44 | } 45 | .item-content { 46 | padding-left: 14px; 47 | padding-right: 16px; 48 | > img { 49 | &:first-child { 50 | -webkit-transform: translate3d(-2000px, -2000px, 0px); 51 | } 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/pages/topic/topic.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { NavController, NavParams, IonicPage } from 'ionic-angular'; 3 | 4 | import { Topic } from '../../classes/topic'; 5 | import { TopicService } from '../../providers/topic-service'; 6 | /* 7 | Generated class for the Topic page. 8 | 9 | See http://ionicframework.com/docs/v2/components/#navigation for more info on 10 | Ionic pages and navigation. 11 | */ 12 | @IonicPage({ 13 | name: 'topic', 14 | segment: 'topic/:id' 15 | }) 16 | @Component({ 17 | selector: 'page-topic', 18 | templateUrl: 'topic.html', 19 | providers: [TopicService] 20 | }) 21 | export class TopicPage { 22 | 23 | topic: Topic 24 | 25 | constructor( 26 | public navCtrl: NavController, 27 | public navParams: NavParams, 28 | private topicService: TopicService 29 | ) { 30 | } 31 | 32 | ionViewDidLoad() { 33 | console.log('ionViewDidLoad TopicPage'); 34 | } 35 | 36 | ngOnInit(): void { 37 | this.getTopic(); 38 | } 39 | 40 | doRefresh(refresher): void { 41 | this.getTopic().then( 42 | (topic) => { 43 | refresher.complete(); 44 | } 45 | ); 46 | } 47 | 48 | getTopic(): Promise { 49 | return this.topicService.getTopicById(this.navParams.get('id')).then( 50 | (topic) => { 51 | this.topic = topic 52 | console.log(this.topic) 53 | } 54 | ); 55 | } 56 | 57 | gotoUserPage(loginName: String): void { 58 | console.log('goto user', loginName); 59 | this.navCtrl.push('user', {loginName: loginName}) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/pages/message/message.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { IonicPage, NavController, NavParams } from 'ionic-angular'; 3 | 4 | import { Message, Messages } from '../../classes/message'; 5 | import { MessageService } from '../../providers/message-service'; 6 | /** 7 | * Generated class for the MessagePage page. 8 | * 9 | * See http://ionicframework.com/docs/components/#navigation for more info 10 | * on Ionic pages and navigation. 11 | */ 12 | @IonicPage({ 13 | name: 'message', 14 | segment: 'message' 15 | }) 16 | @Component({ 17 | selector: 'page-message', 18 | templateUrl: 'message.html', 19 | providers: [MessageService] 20 | }) 21 | export class MessagePage { 22 | 23 | messages: Messages; 24 | 25 | constructor( 26 | public navCtrl: NavController, 27 | public navParams: NavParams, 28 | private messageService: MessageService 29 | ) { 30 | } 31 | 32 | ionViewDidLoad() { 33 | console.log('ionViewDidLoad MessagePage'); 34 | } 35 | 36 | ngOnInit(): void { 37 | this.loadMessage(); 38 | } 39 | 40 | loadMessage() { 41 | this.messageService.getMessages().then((messages) => { 42 | console.log(messages); 43 | this.messages = messages; 44 | console.log(this); 45 | }); 46 | } 47 | 48 | gotoUserPage(loginName: String): void { 49 | console.log('goto user', loginName); 50 | this.navCtrl.push('user', {loginName: loginName}); 51 | } 52 | 53 | gotoTopicPage(id: String): void { 54 | console.log('goto topic', id); 55 | this.navCtrl.push('topic', {id: id}); 56 | } 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/pages/user/user.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | User 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | {{user.loginname}} 23 | {{user.score}}积分 24 |

25 | 注册于:{{user.create_at | amTimeAgo}} 26 |

27 |
28 | 29 | 最近主题 30 | 31 | 32 |

{{topic.title}}

33 |

34 | {{topic.author.loginname}} 35 | 36 | {{topic.last_reply_at | amTimeAgo}} 37 | 38 |

39 |
40 | 41 | 最近回复 42 | 43 | 44 | 45 |

{{topic.title}}

46 |

47 | {{topic.author.loginname}} 48 | 49 | {{topic.last_reply_at | amTimeAgo}} 50 | 51 |

52 |
53 |
54 | 55 |
56 | -------------------------------------------------------------------------------- /src/pages/new-topic-modal/new-topic-modal.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { IonicPage, ViewController } from 'ionic-angular'; 3 | 4 | import { TabsService } from '../../providers/tabs-service'; 5 | import { TopicService } from '../../providers/topic-service'; 6 | import { UserService } from '../../providers/user-service'; 7 | import { Tab } from '../../classes/tab'; 8 | 9 | /** 10 | * Generated class for the NewTopicModal page. 11 | * 12 | * See http://ionicframework.com/docs/components/#navigation for more info 13 | * on Ionic pages and navigation. 14 | */ 15 | @IonicPage() 16 | @Component({ 17 | selector: 'page-new-topic-modal', 18 | templateUrl: 'new-topic-modal.html', 19 | providers: [ 20 | UserService, 21 | TabsService, 22 | TopicService 23 | ] 24 | }) 25 | export class NewTopicModal { 26 | 27 | tabs: Tab[]; 28 | newTopicData: any = { 29 | tab: 'share', 30 | title: '', 31 | content: '' 32 | }; 33 | newTopicId:string; 34 | 35 | constructor( 36 | private userService: UserService, 37 | private tabsService: TabsService, 38 | private topicService: TopicService, 39 | public viewCtrl: ViewController 40 | ) { 41 | this.tabs = this.tabsService.getTabs(); 42 | } 43 | 44 | ionViewDidLoad() { 45 | console.log('ionViewDidLoad NewTopicModal'); 46 | } 47 | 48 | closeModal() { 49 | this.viewCtrl.dismiss(); 50 | } 51 | saveNewTopic() { 52 | console.log('new topic data:', this.newTopicData); 53 | this.topicService.saveNewTopic(this.newTopicData).then((response) => { 54 | this.newTopicId = response['topic_id']; 55 | this.closeModal(); 56 | }); 57 | }; 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/pages/topic/topic.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | Topic 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |
22 |
23 |

{{topic.title}}

24 |
25 | 26 | 27 | 28 | {{topic.author.loginname}} 29 | 30 | 31 | {{ topic.last_reply_at | amTimeAgo }} 32 | 33 |
34 |
35 |
36 |
37 |
38 | 39 | 40 | 41 | {{reply.author.loginname}} 42 |
43 | 44 | {{ reply.create_at | amTimeAgo }} 45 | 46 | 47 | 48 | {{reply.ups.length}} 49 |   50 | 51 |
52 |
53 |
54 | 55 |
56 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cnodejs-ionic3", 3 | "version": "3.0.0", 4 | "author": "Lance Li", 5 | "homepage": "https://github.com/lanceli/cnodejs-ionic3", 6 | "private": true, 7 | "scripts": { 8 | "clean": "ionic-app-scripts clean", 9 | "build": "ionic-app-scripts build", 10 | "ionic:build": "ionic-app-scripts build", 11 | "ionic:serve": "ionic-app-scripts serve" 12 | }, 13 | "dependencies": { 14 | "@angular/common": "4.0.0", 15 | "@angular/compiler": "4.0.0", 16 | "@angular/compiler-cli": "4.0.0", 17 | "@angular/core": "4.0.0", 18 | "@angular/forms": "4.0.0", 19 | "@angular/http": "4.0.0", 20 | "@angular/platform-browser": "4.0.0", 21 | "@angular/platform-browser-dynamic": "4.0.0", 22 | "@ionic-native/core": "3.4.2", 23 | "@ionic-native/splash-screen": "3.4.2", 24 | "@ionic-native/status-bar": "3.4.2", 25 | "@ionic/storage": "2.0.1", 26 | "angular2-moment": "^1.3.3", 27 | "ionic-angular": "3.0.1", 28 | "ionicons": "3.0.0", 29 | "rxjs": "5.1.1", 30 | "sw-toolbox": "3.4.0", 31 | "webpack-merge": "^4.1.0", 32 | "zone.js": "0.8.4" 33 | }, 34 | "devDependencies": { 35 | "@ionic/app-scripts": "1.3.0", 36 | "typescript": "2.2.1" 37 | }, 38 | "cordovaPlugins": [ 39 | "cordova-plugin-whitelist", 40 | "cordova-plugin-console", 41 | "cordova-plugin-statusbar", 42 | "cordova-plugin-device", 43 | "cordova-plugin-splashscreen", 44 | "ionic-plugin-keyboard" 45 | ], 46 | "cordovaPlatforms": [ 47 | "ios", 48 | { 49 | "platform": "ios", 50 | "version": "", 51 | "locator": "ios" 52 | } 53 | ], 54 | "config": { 55 | "ionic_webpack": "./config/webpack.config.js" 56 | }, 57 | "description": "cnodejs-ionic2: An Ionic project" 58 | } 59 | -------------------------------------------------------------------------------- /src/pages/message/message.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | Message 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 未读消息 20 | 21 | 22 | 23 | {{message.author.loginname}} 24 | 25 | 回复了 26 | 27 | 28 | 在 29 | 30 | {{message.topic.title}} 31 | 32 | 中@了你 33 | 34 | 35 | 36 | 37 | 已读消息 38 | 39 | 40 | 41 | {{message.author.loginname}} 42 | 43 | 回复了 44 | 45 | 46 | 在 47 | 48 | {{message.topic.title}} 49 | 50 | 中@了你 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/providers/message-service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Http } from '@angular/http'; 3 | import 'rxjs/add/operator/map'; 4 | import 'rxjs/add/operator/toPromise'; 5 | 6 | import { ConfigService } from './config-service'; 7 | import { Message, Messages } from '../classes/message'; 8 | import { UserService } from './user-service'; 9 | 10 | /* 11 | Generated class for the MessageService provider. 12 | 13 | See https://angular.io/docs/ts/latest/guide/dependency-injection.html 14 | for more info on providers and Angular 2 DI. 15 | */ 16 | @Injectable() 17 | export class MessageService { 18 | private countUrl: string 19 | private messagesUrl: string 20 | 21 | constructor(public http: Http, public configService: ConfigService, private userService: UserService) { 22 | console.log('Hello MessageService Provider'); 23 | this.countUrl = this.configService.api + 'message/count'; 24 | this.messagesUrl = this.configService.api + 'messages'; 25 | } 26 | 27 | getMessageCount(): Promise { 28 | 29 | console.log('get messages count'); 30 | return this.userService.getCurrentUser().then((currentUser) => { 31 | return this.http.get(this.countUrl, { 32 | params: { 33 | accesstoken: currentUser.accesstoken 34 | } 35 | }).toPromise().then( 36 | (resposne) => { 37 | console.log(resposne); 38 | return resposne.json().data; 39 | } 40 | ); 41 | }); 42 | } 43 | 44 | getMessages(): Promise { 45 | console.log('get messages'); 46 | return this.userService.getCurrentUser().then((currentUser) => { 47 | return this.http.get(this.messagesUrl, { 48 | params: { 49 | accesstoken: currentUser.accesstoken 50 | } 51 | }).toPromise().then( 52 | (resposne) => { 53 | return resposne.json().data as Messages; 54 | } 55 | ); 56 | }); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | CNodeJs 4 | 5 | Ionic app for https://cnodejs.org 6 | 7 | 8 | Lance Li 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/pages/topics/topics.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { NavController, NavParams, IonicPage, ModalController } from 'ionic-angular'; 3 | 4 | import { Topic } from '../../classes/topic'; 5 | import { NewTopicModal } from '../new-topic-modal/new-topic-modal'; 6 | 7 | import { TopicService } from '../../providers/topic-service'; 8 | 9 | /* 10 | Generated class for the Topics page. 11 | 12 | See http://ionicframework.com/docs/v2/components/#navigation for more info on 13 | Ionic pages and navigation. 14 | */ 15 | 16 | @IonicPage({ 17 | name: 'topics', 18 | segment: 'topics/:tab' 19 | }) 20 | @Component({ 21 | selector: 'page-topics', 22 | templateUrl: 'topics.html', 23 | providers: [TopicService] 24 | }) 25 | export class TopicsPage { 26 | 27 | topics: Topic[] = []; 28 | 29 | 30 | constructor( 31 | public navCtrl: NavController, 32 | public navParams: NavParams, 33 | private topicService: TopicService, 34 | public modalCtrl: ModalController 35 | ) { 36 | } 37 | 38 | ngOnInit(): void { 39 | let newTab = this.navParams.get('tab'); 40 | if (newTab) { 41 | console.log('changing tab'); 42 | this.topicService.currentTab = newTab; 43 | } 44 | console.log('current tab', this.topicService.currentTab); 45 | this.doRefresh(); 46 | } 47 | 48 | ionViewDidLoad() { 49 | console.log('ionViewDidLoad TopicsPage'); 50 | } 51 | 52 | onSelect(topic: Topic): void { 53 | console.log(topic) 54 | this.navCtrl.push('topic', {id: topic.id}) 55 | } 56 | 57 | getTopics(): void { 58 | this.topicService.getTopics().then( 59 | topics => this.topics = topics 60 | ); 61 | } 62 | 63 | doRefresh(refresher = undefined): void { 64 | console.log('do refresh') 65 | this.topicService.refresh().then( 66 | (topics) => { 67 | this.topics = topics; 68 | if (refresher) { 69 | refresher.complete(); 70 | } 71 | } 72 | ); 73 | } 74 | 75 | loadMore(infiniteScroll): void { 76 | console.log('do infinite'); 77 | this.topicService.pagination().then( 78 | (topics) => { 79 | this.topics = this.topics.concat(topics) 80 | infiniteScroll.complete(); 81 | } 82 | ); 83 | } 84 | 85 | showNewTopicModal (): void { 86 | console.log('new topic modal'); 87 | 88 | let modal = this.modalCtrl.create(NewTopicModal); 89 | modal.present(); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/theme/variables.scss: -------------------------------------------------------------------------------- 1 | // Ionic Variables and Theming. For more info, please see: 2 | // http://ionicframework.com/docs/v2/theming/ 3 | $font-path: "../assets/fonts"; 4 | 5 | @import "ionic.globals"; 6 | 7 | 8 | // Shared Variables 9 | // -------------------------------------------------- 10 | // To customize the look and feel of this app, you can override 11 | // the Sass variables found in Ionic's source scss files. 12 | // To view all the possible Ionic variables, see: 13 | // http://ionicframework.com/docs/v2/theming/overriding-ionic-variables/ 14 | 15 | 16 | 17 | 18 | // Named Color Variables 19 | // -------------------------------------------------- 20 | // Named colors makes it easy to reuse colors on various components. 21 | // It's highly recommended to change the default colors 22 | // to match your app's branding. Ionic uses a Sass map of 23 | // colors so you can add, rename and remove colors as needed. 24 | // The "primary" color is the only required color in the map. 25 | 26 | $colors: ( 27 | primary: #387ef5, 28 | secondary: #32db64, 29 | danger: #f53d3d, 30 | light: #f4f4f4, 31 | dark: #222 32 | ); 33 | 34 | 35 | // App iOS Variables 36 | // -------------------------------------------------- 37 | // iOS only Sass variables can go here 38 | 39 | 40 | 41 | 42 | // App Material Design Variables 43 | // -------------------------------------------------- 44 | // Material Design only Sass variables can go here 45 | 46 | 47 | 48 | 49 | // App Windows Variables 50 | // -------------------------------------------------- 51 | // Windows only Sass variables can go here 52 | 53 | 54 | 55 | 56 | // App Theme 57 | // -------------------------------------------------- 58 | // Ionic apps can have different themes applied, which can 59 | // then be future customized. This import comes last 60 | // so that the above variables are used and Ionic's 61 | // default are overridden. 62 | 63 | @import "ionic.theme.default"; 64 | 65 | 66 | // Ionicons 67 | // -------------------------------------------------- 68 | // The premium icon font for Ionic. For more info, please see: 69 | // http://ionicframework.com/docs/v2/ionicons/ 70 | 71 | @import "ionic.ionicons"; 72 | 73 | 74 | // Fonts 75 | // -------------------------------------------------- 76 | 77 | @import "roboto"; 78 | @import "noto-sans"; 79 | 80 | // Colors 81 | // ------------------------------- 82 | 83 | $node-green: #80bd01; 84 | $node-black: #444; 85 | -------------------------------------------------------------------------------- /src/providers/user-service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Http, Headers, RequestOptions } from '@angular/http'; 3 | import { Storage } from '@ionic/storage'; 4 | import 'rxjs/add/operator/map'; 5 | import 'rxjs/add/operator/toPromise'; 6 | 7 | import { ConfigService } from './config-service'; 8 | import { User } from '../classes/user'; 9 | 10 | /* 11 | Generated class for the UserService provider. 12 | 13 | See https://angular.io/docs/ts/latest/guide/dependency-injection.html 14 | for more info on providers and Angular 2 DI. 15 | */ 16 | @Injectable() 17 | export class UserService { 18 | private userUrl: string 19 | private authUrl: string 20 | private user: User 21 | private storageKey = 'user' 22 | 23 | constructor(public http: Http, public storage: Storage, public configService: ConfigService) { 24 | console.log('Hello UserService Provider'); 25 | this.userUrl = configService.api + 'user'; 26 | this.authUrl = configService.api + 'accesstoken'; 27 | } 28 | 29 | getCurrentUser(): Promise { 30 | console.log('current user:', this.user); 31 | if (this.user) { 32 | return new Promise((resolve, reject) => { 33 | resolve(this.user); 34 | }); 35 | } else { 36 | return this.storage.get(this.storageKey).then((user) => { 37 | console.log('user storage', user); 38 | this.user = user; 39 | return this.user; 40 | }); 41 | } 42 | } 43 | 44 | getByLoginName(loginName: string): Promise { 45 | return this.http.get(`${this.userUrl}/${loginName}`) 46 | .toPromise() 47 | .then( 48 | (resposne) => { 49 | console.log(resposne); 50 | return resposne.json().data as User; 51 | } 52 | ) 53 | } 54 | 55 | login(accesstoken: string): Promise { 56 | let body = JSON.stringify({ 57 | accesstoken: accesstoken 58 | }); 59 | let headers = new Headers({ 60 | 'content-type': 'application/json' 61 | }); 62 | let options = new RequestOptions({ 63 | headers: headers 64 | }); 65 | return this.http.post(this.authUrl, body, options).toPromise().then((response) => { 66 | //$log.debug('post accesstoken:', response); 67 | let authResp = response.json(); 68 | this.user = authResp as User; 69 | return this.getByLoginName(authResp.loginname).then((user) => { 70 | this.user = user; 71 | this.user.id = authResp.id; 72 | this.user.accesstoken = accesstoken; 73 | this.user.loginname = authResp.loginname; 74 | 75 | this.storage.ready().then(() => { 76 | this.storage.set(this.storageKey, user); 77 | }); 78 | return this.user; 79 | }); 80 | }); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/providers/topic-service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Http, Headers, RequestOptions } from '@angular/http'; 3 | import 'rxjs/add/operator/map'; 4 | import 'rxjs/add/operator/toPromise'; 5 | 6 | import { ConfigService } from '../providers/config-service'; 7 | import { Topic } from '../classes/topic'; 8 | 9 | import { UserService } from './user-service'; 10 | 11 | /* 12 | Generated class for the TopicService provider. 13 | 14 | See https://angular.io/docs/ts/latest/guide/dependency-injection.html 15 | for more info on providers and Angular 2 DI. 16 | */ 17 | @Injectable() 18 | export class TopicService { 19 | private topicsUrl: string 20 | private topicUrl: string 21 | currentTab: string = 'all' 22 | private nextPage: number = 2 23 | private hasNextPage: boolean = true 24 | topics: Topic[] = [] 25 | 26 | constructor( 27 | public http: Http, 28 | public configService: ConfigService, 29 | private userService: UserService 30 | ) { 31 | console.log('Hello TopicService Provider'); 32 | this.topicsUrl = configService.api + 'topics'; 33 | this.topicUrl = configService.api + 'topic'; 34 | } 35 | 36 | getTopicById(id: string): Promise{ 37 | return this.http.get(`${this.topicUrl}/${id}`) 38 | .toPromise() 39 | .then( 40 | (resposne) => { 41 | console.log(resposne); 42 | return resposne.json().data as Topic 43 | } 44 | ) 45 | } 46 | getTopics(tab: string = 'all', page: number = 1, limit: number = 40): Promise { 47 | return this.http.get(`${this.topicsUrl}?tab=${tab}&page=${page}&limit=${limit}`) 48 | .toPromise() 49 | .then( 50 | (resposne) => { 51 | console.log(resposne); 52 | return resposne.json().data as Topic[] 53 | } 54 | ); 55 | } 56 | 57 | refresh(): Promise { 58 | console.log(`current tab: ${this.currentTab}, page number 1`); 59 | return this.getTopics(this.currentTab, 1).then( 60 | (topics) => { 61 | this.nextPage = 2 62 | this.hasNextPage = true 63 | this.topics = topics 64 | return Promise.resolve(this.topics); 65 | } 66 | ); 67 | } 68 | 69 | pagination(): Promise { 70 | console.log(`current tab: ${this.currentTab}, next page number ${this.nextPage}`); 71 | return this.getTopics(this.currentTab, this.nextPage).then( 72 | (topics) => { 73 | if (topics.length < 10) { 74 | this.hasNextPage = false 75 | } 76 | this.nextPage++; 77 | this.topics = this.topics.concat(topics) 78 | return Promise.resolve(this.topics); 79 | } 80 | ); 81 | } 82 | saveNewTopic(newTopicData) { 83 | let body = JSON.stringify(newTopicData); 84 | let headers = new Headers({ 85 | 'content-type': 'application/json' 86 | }); 87 | let options = new RequestOptions({ 88 | headers: headers 89 | }); 90 | return this.userService.getCurrentUser().then((currentUser) => { 91 | return this.http.post(`${this.topicsUrl}?accesstoken=${currentUser.accesstoken}`, body, options).toPromise() 92 | }) 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, ViewChild } from '@angular/core'; 2 | import { Nav, Platform, AlertController } from 'ionic-angular'; 3 | import { StatusBar } from '@ionic-native/status-bar'; 4 | import { SplashScreen } from '@ionic-native/splash-screen'; 5 | 6 | import { ConfigService } from '../providers/config-service'; 7 | 8 | import { TabsService } from '../providers/tabs-service'; 9 | import { UserService } from '../providers/user-service'; 10 | import { MessageService } from '../providers/message-service'; 11 | import { Tab } from '../classes/tab'; 12 | import { User } from '../classes/user'; 13 | 14 | 15 | @Component({ 16 | templateUrl: 'app.html', 17 | providers: [ 18 | TabsService, 19 | UserService, 20 | MessageService 21 | ] 22 | }) 23 | export class MyApp { 24 | @ViewChild(Nav) nav: Nav; 25 | 26 | rootPage: any; 27 | 28 | tabs: Tab[]; 29 | 30 | user: User; 31 | messagesCount: 0; 32 | 33 | constructor( 34 | public platform: Platform, 35 | statusBar: StatusBar, 36 | splashScreen: SplashScreen, 37 | private configService: ConfigService, 38 | private tabsService: TabsService, 39 | private userService: UserService, 40 | private messageService: MessageService, 41 | private alertCtrl: AlertController 42 | ) { 43 | platform.ready().then(() => { 44 | // Okay, so the platform is ready and our plugins are available. 45 | // Here you can do any higher level native things you might need. 46 | statusBar.styleDefault(); 47 | splashScreen.hide(); 48 | }); 49 | } 50 | 51 | initializeApp() { 52 | } 53 | 54 | ngOnInit() { 55 | console.log('ng on init'); 56 | } 57 | 58 | ngAfterViewInit() { 59 | console.log('ng after view init'); 60 | 61 | this.userService.getCurrentUser().then((user) => { 62 | this.user = user; 63 | }); 64 | this.tabs = this.tabsService.getTabs(); 65 | this.nav.setRoot('topics', { 66 | tab: this.tabs[0].value 67 | }); 68 | } 69 | 70 | openTab(tab: any) { 71 | console.log('open tab', tab) 72 | this.nav.setRoot('topics', { 73 | tab: tab.value 74 | }); 75 | } 76 | 77 | gotoUserPage(loginName: String) { 78 | console.log('goto user', loginName); 79 | this.nav.setRoot('user', {loginName: loginName}) 80 | } 81 | 82 | gotoMessagePage() { 83 | console.log('go to message page') 84 | this.nav.setRoot('message'); 85 | } 86 | 87 | getMessageCount() { 88 | this.messageService.getMessageCount().then((response) => { 89 | this.messagesCount = response.data; 90 | //setBadge($scope.messagesCount); 91 | }, function(response) { 92 | //$log.log('get messages count fail', response); 93 | }); 94 | }; 95 | 96 | // login action callback 97 | loginCallback(user: User) { 98 | console.log('login callback', arguments); 99 | this.user = user; 100 | this.getMessageCount(); 101 | } 102 | 103 | login() { 104 | console.log('login'); 105 | // login automatic if have token 106 | if (this.configService.token) { 107 | this.userService.login(this.configService.token).then((response) => { 108 | this.loginCallback(response); 109 | }); 110 | } else { 111 | let alert = this.alertCtrl.create({ 112 | title: '输入Access Token', 113 | subTitle: 'PC端登录cnodejs.org后,在设置页可以找到Access Token', 114 | inputs: [ 115 | { 116 | name: 'token', 117 | placeholder: 'Token' 118 | } 119 | ], 120 | buttons: [ 121 | { 122 | text: '取消', 123 | role: 'cancel', 124 | handler: data => { 125 | console.log('Cancel clicked'); 126 | } 127 | }, 128 | { 129 | text: '提交', 130 | handler: data => { 131 | console.log(data); 132 | if (data.token) { 133 | this.userService.login(data.token).then((response) => { 134 | this.loginCallback(response); 135 | }); 136 | } 137 | } 138 | } 139 | ] 140 | }); 141 | alert.present(); 142 | } 143 | } 144 | } 145 | --------------------------------------------------------------------------------