├── cypress.json ├── babel.config.js ├── public ├── favicon.ico ├── img │ └── icons │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── mstile-150x150.png │ │ ├── apple-touch-icon.png │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon-120x120.png │ │ ├── apple-touch-icon-152x152.png │ │ ├── apple-touch-icon-180x180.png │ │ ├── apple-touch-icon-60x60.png │ │ ├── apple-touch-icon-76x76.png │ │ ├── msapplication-icon-144x144.png │ │ └── safari-pinned-tab.svg ├── manifest.json └── index.html ├── src ├── assets │ └── logo.png ├── shims-vue.d.ts ├── api │ └── api.ts ├── store.ts ├── views │ ├── About.vue │ ├── Home.vue │ └── GirlsView.vue ├── shims-tsx.d.ts ├── main.ts ├── types │ ├── girls.ts │ └── home.ts ├── registerServiceWorker.ts ├── router.ts ├── App.vue ├── store │ ├── girls.ts │ └── home.ts └── components │ └── HomeList.vue ├── tests ├── e2e │ ├── specs │ │ └── test.js │ ├── plugins │ │ └── index.js │ └── support │ │ ├── index.js │ │ └── commands.js └── unit │ └── HelloWorld.spec.ts ├── README.md ├── .gitignore ├── tslint.json ├── tsconfig.json └── package.json /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "pluginsFile": "tests/e2e/plugins/index.js" 3 | } 4 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ztplz/gankio/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ztplz/gankio/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import Vue from 'vue'; 3 | export default Vue; 4 | } 5 | -------------------------------------------------------------------------------- /public/img/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ztplz/gankio/HEAD/public/img/icons/favicon-16x16.png -------------------------------------------------------------------------------- /public/img/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ztplz/gankio/HEAD/public/img/icons/favicon-32x32.png -------------------------------------------------------------------------------- /public/img/icons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ztplz/gankio/HEAD/public/img/icons/mstile-150x150.png -------------------------------------------------------------------------------- /public/img/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ztplz/gankio/HEAD/public/img/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /public/img/icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ztplz/gankio/HEAD/public/img/icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/img/icons/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ztplz/gankio/HEAD/public/img/icons/android-chrome-512x512.png -------------------------------------------------------------------------------- /public/img/icons/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ztplz/gankio/HEAD/public/img/icons/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /public/img/icons/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ztplz/gankio/HEAD/public/img/icons/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /public/img/icons/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ztplz/gankio/HEAD/public/img/icons/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /public/img/icons/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ztplz/gankio/HEAD/public/img/icons/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /public/img/icons/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ztplz/gankio/HEAD/public/img/icons/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /public/img/icons/msapplication-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ztplz/gankio/HEAD/public/img/icons/msapplication-icon-144x144.png -------------------------------------------------------------------------------- /src/api/api.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | export const getData = async (url: string, count: number, pageIndex: number): Promise => { 4 | url = `${url}/${count}/${pageIndex}`; 5 | 6 | return axios.get(url); 7 | }; 8 | -------------------------------------------------------------------------------- /tests/e2e/specs/test.js: -------------------------------------------------------------------------------- 1 | // https://docs.cypress.io/api/introduction/api.html 2 | 3 | describe('My First Test', () => { 4 | it('Visits the app root url', () => { 5 | cy.visit('/') 6 | cy.contains('h1', 'Welcome to Your Vue.js + TypeScript App') 7 | }) 8 | }) 9 | -------------------------------------------------------------------------------- /src/store.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | import Home from './store/home'; 4 | import Girls from './store/girls'; 5 | 6 | Vue.use(Vuex); 7 | 8 | export default new Vuex.Store({ 9 | modules: { 10 | Home, 11 | Girls, 12 | }, 13 | }); 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gankio 2 | 一个Vue3.0 demo, 使用typescript。 3 | 4 | # 简介 5 | 使用vue-cli3.0生成项目,使用typescript 6 | 7 | [线上预览地址](http://39.108.143.204/#/) 8 | 9 | 如果是pc 建议开发者工具里用移动端模式观看 10 | 11 | # 本地下载使用方法 12 | 13 | clone仓库到本地 14 | 15 | 进入项目根目录,执行npm install安装项目依赖 16 | 17 | 启动项目 npm run serve 18 | -------------------------------------------------------------------------------- /src/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | /tests/e2e/videos/ 6 | /tests/e2e/screenshots/ 7 | 8 | # local env files 9 | .env.local 10 | .env.*.local 11 | 12 | # Log files 13 | npm-debug.log* 14 | yarn-debug.log* 15 | yarn-error.log* 16 | 17 | # Editor directories and files 18 | .idea 19 | .vscode 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw* 25 | -------------------------------------------------------------------------------- /src/shims-tsx.d.ts: -------------------------------------------------------------------------------- 1 | import Vue, { VNode } from 'vue'; 2 | 3 | declare global { 4 | namespace JSX { 5 | // tslint:disable no-empty-interface 6 | interface Element extends VNode {} 7 | // tslint:disable no-empty-interface 8 | interface ElementClass extends Vue {} 9 | interface IntrinsicElements { 10 | [elem: string]: any; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import App from './App.vue'; 3 | import router from './router'; 4 | import store from './store'; 5 | import './registerServiceWorker'; 6 | import Vant from 'vant'; 7 | import 'vant/lib/vant-css/index.css'; 8 | 9 | Vue.config.productionTip = false; 10 | 11 | Vue.use(Vant); 12 | 13 | new Vue({ 14 | router, 15 | store, 16 | render: (h) => h(App), 17 | }).$mount('#app'); 18 | -------------------------------------------------------------------------------- /tests/e2e/plugins/index.js: -------------------------------------------------------------------------------- 1 | // https://docs.cypress.io/guides/guides/plugins-guide.html 2 | 3 | module.exports = (on, config) => { 4 | return Object.assign({}, config, { 5 | fixturesFolder: 'tests/e2e/fixtures', 6 | integrationFolder: 'tests/e2e/specs', 7 | screenshotsFolder: 'tests/e2e/screenshots', 8 | videosFolder: 'tests/e2e/videos', 9 | supportFile: 'tests/e2e/support/index.js' 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /tests/unit/HelloWorld.spec.ts: -------------------------------------------------------------------------------- 1 | import { shallowMount } from '@vue/test-utils'; 2 | import HelloWorld from '@/components/HelloWorld.vue'; 3 | 4 | describe('HelloWorld.vue', () => { 5 | it('renders props.msg when passed', () => { 6 | const msg = 'new message'; 7 | const wrapper = shallowMount(HelloWorld, { 8 | propsData: { msg }, 9 | }); 10 | expect(wrapper.text()).toMatch(msg); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gankio", 3 | "short_name": "gankio", 4 | "icons": [ 5 | { 6 | "src": "/img/icons/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/img/icons/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "start_url": "/index.html", 17 | "display": "standalone", 18 | "background_color": "#000000", 19 | "theme_color": "#4DBA87" 20 | } 21 | -------------------------------------------------------------------------------- /src/types/girls.ts: -------------------------------------------------------------------------------- 1 | export interface GirlsItem { 2 | _id: string; 3 | createdAt: string; 4 | desc: string; 5 | publishedAt: string; 6 | source: string; 7 | type: string; 8 | url: string; 9 | used: boolean; 10 | who: string; 11 | } 12 | 13 | export interface GirlsData { 14 | error: boolean; 15 | results: GirlsItem[]; 16 | } 17 | 18 | export interface State { 19 | isLoading: boolean; 20 | isLoadingMore: boolean; 21 | hasError: boolean; 22 | pageIndex: number; 23 | data: GirlsItem[] | never[]; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "warning", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "linterOptions": { 7 | "exclude": [ 8 | "node_modules/**" 9 | ] 10 | }, 11 | "rules": { 12 | "quotemark": [true, "single"], 13 | "indent": [true, "spaces", 2], 14 | "interface-name": false, 15 | "ordered-imports": false, 16 | "object-literal-sort-keys": false, 17 | "no-consecutive-blank-lines": false, 18 | "no-shadowed-variable": false, 19 | "no-trailing-whitespace": false 20 | } 21 | } -------------------------------------------------------------------------------- /src/types/home.ts: -------------------------------------------------------------------------------- 1 | export interface DataItem { 2 | _id: string; 3 | createdAt: string; 4 | desc: string; 5 | image?: string[]; 6 | publishedAt: string; 7 | source: string; 8 | type: string; 9 | url: string; 10 | used: boolean; 11 | who: string; 12 | } 13 | 14 | export interface Data { 15 | error: boolean; 16 | results: DataItem[]; 17 | } 18 | 19 | export interface State { 20 | isLoading: boolean; 21 | isRefreshing: boolean; 22 | isLoadingMore: boolean; 23 | hasError: boolean; 24 | pageIndex: number; 25 | data: DataItem[] | never[]; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | gankio 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 25 | -------------------------------------------------------------------------------- /tests/e2e/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /src/registerServiceWorker.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-console */ 2 | 3 | import { register } from 'register-service-worker'; 4 | 5 | if (process.env.NODE_ENV === 'production') { 6 | register(`${process.env.BASE_URL}service-worker.js`, { 7 | ready() { 8 | console.log( 9 | 'App is being served from cache by a service worker.\n' + 10 | 'For more details, visit https://goo.gl/AFskqB', 11 | ); 12 | }, 13 | cached() { 14 | console.log('Content has been cached for offline use.'); 15 | }, 16 | updated() { 17 | console.log('New content is available; please refresh.'); 18 | }, 19 | offline() { 20 | console.log('No internet connection found. App is running in offline mode.'); 21 | }, 22 | error(error) { 23 | console.error('Error during service worker registration:', error); 24 | }, 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "strict": true, 6 | "jsx": "preserve", 7 | "importHelpers": true, 8 | "moduleResolution": "node", 9 | "experimentalDecorators": true, 10 | "emitDecoratorMetadata": true, 11 | "allowSyntheticDefaultImports": true, 12 | "sourceMap": true, 13 | "baseUrl": ".", 14 | "types": [ 15 | "node", 16 | "jest" 17 | ], 18 | "paths": { 19 | "@/*": [ 20 | "src/*" 21 | ] 22 | }, 23 | "lib": [ 24 | "es2015", 25 | "dom", 26 | "dom.iterable", 27 | "scripthost" 28 | ] 29 | }, 30 | "include": [ 31 | "src/**/*.ts", 32 | "src/**/*.tsx", 33 | "src/**/*.vue", 34 | "tests/**/*.ts", 35 | "tests/**/*.tsx" 36 | ], 37 | "exclude": [ 38 | "node_modules" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /tests/e2e/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add("login", (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This is will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /src/router.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Router from 'vue-router'; 3 | import Home from './views/Home.vue'; 4 | import GirlsView from './views/GirlsView.vue'; 5 | import About from './views/About.vue'; 6 | 7 | Vue.use(Router); 8 | 9 | export default new Router({ 10 | routes: [ 11 | { 12 | path: '/', 13 | name: 'home', 14 | component: Home, 15 | // children: [ 16 | // { 17 | // path: "/home", 18 | // name: 'Home', 19 | // component: Home, 20 | // }, 21 | // { 22 | // path: "/girlsView", 23 | // name: 'girlsView', 24 | // component: GirlsView, 25 | // }, 26 | // { 27 | // path: "/about", 28 | // name: 'About', 29 | // component: About, 30 | // }, 31 | // ] 32 | }, 33 | // { 34 | // path: '/home', 35 | // name: 'home', 36 | // component: Home, 37 | // }, 38 | { 39 | path: '/girlsView', 40 | name: 'girlsView', 41 | component: GirlsView, 42 | }, 43 | { 44 | path: '/about', 45 | name: 'about', 46 | component: About, 47 | }, 48 | ], 49 | }); 50 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 50 | 51 | 78 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gankio", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint", 9 | "test:unit": "vue-cli-service test:unit", 10 | "test:e2e": "vue-cli-service test:e2e" 11 | }, 12 | "dependencies": { 13 | "axios": "^0.18.0", 14 | "lodash": "^4.17.10", 15 | "moment": "^2.22.2", 16 | "register-service-worker": "^1.0.0", 17 | "vant": "^1.1.8", 18 | "vue": "^2.5.16", 19 | "vue-class-component": "^6.0.0", 20 | "vue-property-decorator": "^6.0.0", 21 | "vue-router": "^3.0.1", 22 | "vuex": "^3.0.1", 23 | "vuex-class": "^0.3.1" 24 | }, 25 | "devDependencies": { 26 | "@types/jest": "^22.0.1", 27 | "@vue/cli-plugin-babel": "^3.0.0-beta.15", 28 | "@vue/cli-plugin-e2e-cypress": "^3.0.0-beta.15", 29 | "@vue/cli-plugin-pwa": "^3.0.0-beta.15", 30 | "@vue/cli-plugin-typescript": "^3.0.0-beta.15", 31 | "@vue/cli-plugin-unit-jest": "^3.0.0-beta.15", 32 | "@vue/cli-service": "^3.0.0-beta.15", 33 | "@vue/test-utils": "^1.0.0-beta.16", 34 | "babel-core": "7.0.0-bridge.0", 35 | "node-sass": "^4.9.0", 36 | "sass-loader": "^7.0.1", 37 | "ts-jest": "^22.4.6", 38 | "vue-template-compiler": "^2.5.16" 39 | }, 40 | "postcss": { 41 | "plugins": { 42 | "autoprefixer": {} 43 | } 44 | }, 45 | "browserslist": [ 46 | "> 1%", 47 | "last 2 versions", 48 | "not ie <= 8" 49 | ], 50 | "jest": { 51 | "moduleFileExtensions": [ 52 | "ts", 53 | "tsx", 54 | "js", 55 | "jsx", 56 | "json", 57 | "vue" 58 | ], 59 | "transform": { 60 | "^.+\\.vue$": "vue-jest", 61 | ".+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$": "jest-transform-stub", 62 | "^.+\\.tsx?$": "ts-jest" 63 | }, 64 | "moduleNameMapper": { 65 | "^@/(.*)$": "/src/$1" 66 | }, 67 | "snapshotSerializers": [ 68 | "jest-serializer-vue" 69 | ], 70 | "testMatch": [ 71 | "/(tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx))" 72 | ] 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/store/girls.ts: -------------------------------------------------------------------------------- 1 | import { MutationTree, ActionTree } from 'vuex'; 2 | import { GirlsItem, GirlsData, State } from '../types/girls'; 3 | import { getData } from '../api/api'; 4 | 5 | const state: State = { 6 | isLoading: false, 7 | isLoadingMore: false, 8 | hasError: false, 9 | pageIndex: 1, 10 | data: [], 11 | }; 12 | 13 | const actions: ActionTree = { 14 | async getGirlsData({ commit }): Promise { 15 | commit('getData'); 16 | try { 17 | const res = await getData('http://gank.io/api/data/福利', 10, 1); 18 | if (res.status === 200 && res.data.results.length !== 0) { 19 | commit('getDataSuccess', res.data.results); 20 | } 21 | } catch (error) { 22 | commit('getDataFailure'); 23 | } 24 | }, 25 | async getMoreGirlsData({ commit }): Promise { 26 | try { 27 | const res = await getData('http://gank.io/api/data/福利', 10, state.pageIndex); 28 | if (res.status === 200 && res.data.results.length !== 0) { 29 | commit('getMoreDataSuccess', res.data.results); 30 | } 31 | } catch (error) { 32 | commit('getMoreDataFailure'); 33 | } 34 | }, 35 | }; 36 | 37 | const mutations: MutationTree = { 38 | getData(state: State): void { 39 | state.isLoading = true; 40 | state.pageIndex = 1; 41 | state.hasError = false; 42 | }, 43 | getDataSuccess(state: State, res: GirlsItem[]): void { 44 | state.isLoading = false; 45 | state.hasError = false; 46 | state.pageIndex++; 47 | state.data = res; 48 | }, 49 | getDataFailure(state: State): void { 50 | state.isLoading = false; 51 | state.hasError = true; 52 | }, 53 | getMoreData(state: State): void { 54 | state.isLoadingMore = true; 55 | state.hasError = false; 56 | }, 57 | getMoreDataSuccess(state: State, res: GirlsItem[]): void { 58 | state.isLoadingMore = false; 59 | state.hasError = false; 60 | state.pageIndex++; 61 | state.data = (state.data as GirlsData['results']).concat(res); 62 | }, 63 | getMoreDataFailure(state: State): void { 64 | state.isLoading = false; 65 | state.pageIndex--; 66 | state.hasError = true; 67 | }, 68 | }; 69 | 70 | export default { 71 | namespaced: true, 72 | state, 73 | actions, 74 | mutations, 75 | }; 76 | -------------------------------------------------------------------------------- /src/views/GirlsView.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 82 | 83 | 117 | 118 | -------------------------------------------------------------------------------- /src/components/HomeList.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 107 | 108 | 157 | -------------------------------------------------------------------------------- /src/store/home.ts: -------------------------------------------------------------------------------- 1 | import { MutationTree, ActionTree } from 'vuex'; 2 | import { DataItem, State } from '../types/home'; 3 | import { getData } from '../api/api'; 4 | 5 | const state: State[] = [ 6 | { 7 | isLoading: false, 8 | isRefreshing: false, 9 | isLoadingMore: false, 10 | hasError: false, 11 | pageIndex: 1, 12 | data: [], 13 | }, 14 | { 15 | isLoading: false, 16 | isRefreshing: false, 17 | isLoadingMore: false, 18 | hasError: false, 19 | pageIndex: 1, 20 | data: [], 21 | }, 22 | { 23 | isLoading: false, 24 | isRefreshing: false, 25 | isLoadingMore: false, 26 | hasError: false, 27 | pageIndex: 1, 28 | data: [], 29 | }, 30 | { 31 | isLoading: false, 32 | isRefreshing: false, 33 | isLoadingMore: false, 34 | hasError: false, 35 | pageIndex: 1, 36 | data: [], 37 | }, 38 | { 39 | isLoading: false, 40 | isRefreshing: false, 41 | isLoadingMore: false, 42 | hasError: false, 43 | pageIndex: 1, 44 | data: [], 45 | }, 46 | ]; 47 | 48 | const actions: ActionTree = { 49 | async getHomeData( 50 | { commit }, 51 | {tabIndex, tabTitle}: {tabIndex: number, tabTitle: string}, 52 | ): Promise { 53 | commit('getData', tabIndex); 54 | try { 55 | const url = `http://gank.io/api/data/${tabTitle}`; 56 | const res = await getData(url, 10, 1); 57 | if (res.status === 200 && res.data.results.length !== 0) { 58 | commit('getDataSuccess', {tabIndex, res: res.data.results}); 59 | } 60 | } catch (error) { 61 | commit('getDataFailure', tabIndex); 62 | } 63 | }, 64 | async refreshHomeData( 65 | { commit }, 66 | {tabIndex, tabTitle}: {tabIndex: number, tabTitle: string}, 67 | ): Promise { 68 | commit('refreshData', tabIndex); 69 | 70 | try { 71 | const url = `http://gank.io/api/data/${tabTitle}`; 72 | const res = await getData(url, 10, 1); 73 | if (res.status === 200 && res.data.results.length !== 0) { 74 | commit('refreshDataSuccess', {tabIndex, res: res.data.results}); 75 | } 76 | } catch (error) { 77 | commit('refreshDataFailure', tabIndex); 78 | } 79 | }, 80 | async getMoreHomeData( 81 | { commit }, 82 | {tabIndex, tabTitle, pageIndex}: {tabIndex: number, tabTitle: string, pageIndex: number}, 83 | ): Promise { 84 | commit('getMoreData', tabIndex); 85 | 86 | try { 87 | const url = `http://gank.io/api/data/${tabTitle}`; 88 | const res = await getData(url, 10, state[tabIndex].pageIndex); 89 | if (res.status === 200 && res.data.results.length !== 0) { 90 | commit('getMoreDataSuccess', {tabIndex, res: res.data.results}); 91 | } 92 | } catch (error) { 93 | commit('getMoreDataFailure', tabIndex); 94 | } 95 | }, 96 | }; 97 | 98 | const mutations: MutationTree = { 99 | getData(state: State[], tabIndex): void { 100 | state[tabIndex].isLoading = true; 101 | state[tabIndex].hasError = false; 102 | state[tabIndex].pageIndex = 1; 103 | }, 104 | getDataSuccess(state: State[], {tabIndex, res}: {tabIndex: number, res: DataItem[]}): void { 105 | state[tabIndex].isLoading = false; 106 | state[tabIndex].hasError = false; 107 | state[tabIndex].pageIndex++; 108 | state[tabIndex].data = res; 109 | }, 110 | getDataFailure(state: State[], tabIndex: number): void { 111 | state[tabIndex].isLoading = false; 112 | state[tabIndex].hasError = true; 113 | }, 114 | refreshData(state: State[], tabIndex): void { 115 | state[tabIndex].isRefreshing = true; 116 | state[tabIndex].hasError = false; 117 | state[tabIndex].pageIndex = 1; 118 | }, 119 | refreshDataSuccess(state: State[], {tabIndex, res}: {tabIndex: number, res: DataItem[]}): void { 120 | state[tabIndex].isRefreshing = false; 121 | state[tabIndex].hasError = false; 122 | state[tabIndex].pageIndex++; 123 | state[tabIndex].data = res; 124 | }, 125 | refreshDataFailure(state: State[], tabIndex: number): void { 126 | state[tabIndex].isRefreshing = false; 127 | state[tabIndex].hasError = true; 128 | }, 129 | getMoreData(state: State[], tabIndex: number): void { 130 | state[tabIndex].isLoadingMore = true; 131 | state[tabIndex].hasError = false; 132 | }, 133 | getMoreDataSuccess(state: State[], {tabIndex, res}: {tabIndex: number, res: DataItem[]}): void { 134 | state[tabIndex].isLoadingMore = false; 135 | state[tabIndex].hasError = false; 136 | state[tabIndex].pageIndex++; 137 | state[tabIndex].data = (state[tabIndex].data as DataItem[]).concat(res); 138 | }, 139 | getMoreDataFailure(state: State[], tabIndex: number): void { 140 | state[tabIndex].isLoading = false; 141 | state[tabIndex].hasError = true; 142 | }, 143 | }; 144 | 145 | export default { 146 | namespaced: true, 147 | state, 148 | actions, 149 | mutations, 150 | }; 151 | -------------------------------------------------------------------------------- /public/img/icons/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | 10 | 12 | 148 | 149 | 150 | --------------------------------------------------------------------------------