├── .browserslistrc
├── .eslintrc.js
├── .github
└── workflows
│ └── tests.yml
├── .gitignore
├── README.md
├── babel.config.js
├── capacitor.config.json
├── cypress.json
├── ionic.config.json
├── jest.config.js
├── masthead.png
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
├── assets
│ ├── icon
│ │ ├── favicon.png
│ │ └── icon.png
│ └── shapes.svg
└── index.html
├── src
├── App.vue
├── data
│ └── emails.ts
├── main.ts
├── router
│ └── index.ts
├── shims-vue.d.ts
├── theme
│ └── variables.css
└── views
│ ├── Compose.vue
│ ├── Email.vue
│ └── Inbox.vue
├── tailwind.config.js
├── tests
├── e2e
│ ├── .eslintrc.js
│ ├── plugins
│ │ └── index.js
│ ├── specs
│ │ └── test.js
│ └── support
│ │ ├── commands.js
│ │ └── index.js
└── unit
│ └── example.spec.ts
├── tsconfig.json
└── vue.config.js
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not dead
4 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true
5 | },
6 | 'extends': [
7 | 'plugin:vue/vue3-essential',
8 | 'eslint:recommended',
9 | '@vue/typescript/recommended'
10 | ],
11 | parserOptions: {
12 | ecmaVersion: 2020
13 | },
14 | rules: {
15 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
16 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
17 | 'vue/no-deprecated-slot-attribute': 'off',
18 | '@typescript-eslint/no-explicit-any': 'off',
19 | },
20 | overrides: [
21 | {
22 | files: [
23 | '**/__tests__/*.{j,t}s?(x)',
24 | '**/tests/unit/**/*.spec.{j,t}s?(x)'
25 | ],
26 | env: {
27 | jest: true
28 | }
29 | }
30 | ]
31 | }
32 |
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: End-to-end tests
2 | on: [push]
3 | jobs:
4 | cypress-run:
5 | runs-on: ubuntu-16.04
6 | steps:
7 | - name: Checkout
8 | uses: actions/checkout@v2
9 | # Install NPM dependencies, cache them correctly
10 | # and run all Cypress tests
11 | - name: Cypress run
12 | uses: cypress-io/github-action@v2
13 | with:
14 | start: npm run serve
15 | # quote the url to be safe against YML parsing surprises
16 | wait-on: 'http://localhost:8100'
17 | - uses: actions/upload-artifact@v1
18 | if: failure()
19 | with:
20 | name: cypress-screenshots
21 | path: tests/e2e/screenshots
22 | # Test run video was always captured, so this action uses "always()" condition
23 | - uses: actions/upload-artifact@v1
24 | if: always()
25 | with:
26 | name: cypress-videos
27 | path: tests/e2e/videos
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Specifies intentionally untracked files to ignore when using Git
2 | # http://git-scm.com/docs/gitignore
3 |
4 | *~
5 | *.sw[mnpcod]
6 | .tmp
7 | *.tmp
8 | *.tmp.*
9 | *.sublime-project
10 | *.sublime-workspace
11 | .DS_Store
12 | Thumbs.db
13 | UserInterfaceState.xcuserstate
14 | $RECYCLE.BIN/
15 |
16 | *.log
17 | log.txt
18 | npm-debug.log*
19 |
20 | /.idea
21 | /.ionic
22 | /.sass-cache
23 | /.sourcemaps
24 | /.versions
25 | /.vscode
26 | /coverage
27 | /dist
28 | /node_modules
29 | /platforms
30 | /plugins
31 | /www
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # ionic-vue-tailwind-gmail-ui-clone
4 |
5 | An clone of the Gmail App built with Ionic, Vue and Tailwind.
6 |
7 | ### Included in this Ionic Vue Example
8 | * Custom swipe gestures
9 | * Custom scroll listeners
10 | * Inbox view
11 | * Email view
12 | * Compose view
13 | * Simple search
14 | * Side menu
15 | * Fully tested with Cypress
16 |
17 | ### To run
18 |
19 | ```javascript
20 | npm install
21 | ionic serve
22 | ```
23 |
24 | Alternatively, you can add the iOS, Android platform and run natively.
25 |
26 | ### Are you on Twitter? Follow me [@jaybird1979](https://twitter.com/jaybird1979)
27 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/capacitor.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "appId": "io.ionic.starter",
3 | "appName": "ionic-vue-tailwind-gmail-ui-clone",
4 | "bundledWebRuntime": false,
5 | "npmClient": "npm",
6 | "webDir": "dist",
7 | "plugins": {
8 | "SplashScreen": {
9 | "launchShowDuration": 0
10 | }
11 | },
12 | "cordova": {}
13 | }
14 |
--------------------------------------------------------------------------------
/cypress.json:
--------------------------------------------------------------------------------
1 | {
2 | "baseUrl": "http://localhost:8100",
3 | "pluginsFile": "tests/e2e/plugins/index.js",
4 | "scrollBehavior": "center"
5 | }
--------------------------------------------------------------------------------
/ionic.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ionic-vue-tailwind-gmail-ui-clone",
3 | "integrations": {
4 | "capacitor": {}
5 | },
6 | "type": "vue"
7 | }
8 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel',
3 | transform: {
4 | '^.+\\.vue$': 'vue-jest'
5 | },
6 | transformIgnorePatterns: ['/node_modules/(?!@ionic/vue|@ionic/vue-router)']
7 | }
8 |
--------------------------------------------------------------------------------
/masthead.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JayBizzle/ionic-vue-tailwind-gmail-ui-clone/2d7505a8a63a7e4f20661cb9663fd6ebbc964617/masthead.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ionic-vue-tailwind-gmail-ui-clone",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "test:unit": "vue-cli-service test:unit",
9 | "test:e2e": "vue-cli-service test:e2e",
10 | "lint": "vue-cli-service lint"
11 | },
12 | "dependencies": {
13 | "@capacitor/android": "^2.4.7",
14 | "@capacitor/core": "2.4.7",
15 | "@fontsource/roboto": "^4.2.3",
16 | "@ionic/vue": "^5.4.0",
17 | "@ionic/vue-router": "^5.4.0",
18 | "@tailwindcss/line-clamp": "^0.2.0",
19 | "core-js": "^3.6.5",
20 | "vue": "^3.0.0-0",
21 | "vue-router": "^4.0.0-0"
22 | },
23 | "devDependencies": {
24 | "@capacitor/cli": "2.4.7",
25 | "@tailwindcss/postcss7-compat": "^2.1.0",
26 | "@types/jest": "^24.0.19",
27 | "@typescript-eslint/eslint-plugin": "^2.33.0",
28 | "@typescript-eslint/parser": "^2.33.0",
29 | "@vue/cli-plugin-babel": "~4.5.0",
30 | "@vue/cli-plugin-e2e-cypress": "~4.5.0",
31 | "@vue/cli-plugin-eslint": "~4.5.0",
32 | "@vue/cli-plugin-router": "~4.5.0",
33 | "@vue/cli-plugin-typescript": "~4.5.0",
34 | "@vue/cli-plugin-unit-jest": "~4.5.0",
35 | "@vue/cli-service": "~4.5.0",
36 | "@vue/compiler-sfc": "^3.0.0-0",
37 | "@vue/eslint-config-typescript": "^5.0.2",
38 | "@vue/test-utils": "^2.0.0-0",
39 | "autoprefixer": "^9.8.6",
40 | "cy-mobile-commands": "^0.2.1",
41 | "cypress": "^6.8.0",
42 | "eslint": "^6.7.2",
43 | "eslint-plugin-vue": "^7.0.0-0",
44 | "npm": "^7.10.0",
45 | "postcss": "^7.0.35",
46 | "postcss-cli": "^7.1.2",
47 | "tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.1.0",
48 | "typescript": "~3.9.3",
49 | "vue-jest": "^5.0.0-0"
50 | },
51 | "description": "An Ionic project"
52 | }
53 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | }
6 | }
--------------------------------------------------------------------------------
/public/assets/icon/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JayBizzle/ionic-vue-tailwind-gmail-ui-clone/2d7505a8a63a7e4f20661cb9663fd6ebbc964617/public/assets/icon/favicon.png
--------------------------------------------------------------------------------
/public/assets/icon/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JayBizzle/ionic-vue-tailwind-gmail-ui-clone/2d7505a8a63a7e4f20661cb9663fd6ebbc964617/public/assets/icon/icon.png
--------------------------------------------------------------------------------
/public/assets/shapes.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Ionic App
6 |
7 |
8 |
9 |
10 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Gmail
6 |
7 |
12 |
All inboxes
13 |
14 |
15 |
20 |
21 | Primary
22 |
99+
23 |
24 |
25 |
26 |
31 |
32 |
Social
33 |
2 new
34 |
35 |
36 |
37 |
42 |
43 |
Promotions
44 |
99+ new
45 |
46 |
47 |
48 | Recent Labels
49 |
50 |
51 |
56 |
57 | Purchases
58 |
59 |
60 |
61 |
66 |
67 | Important Documents
68 |
69 |
70 |
71 |
76 |
77 | Family Holiday
78 |
79 |
80 |
81 |
86 |
87 | Receipts
88 |
89 |
90 |
91 | All Labels
92 |
93 |
94 |
99 |
100 | Starred
101 |
102 |
103 |
104 |
109 |
110 | Snoozed
111 |
112 |
113 |
114 |
119 |
120 | Sent
121 |
122 |
123 |
124 |
129 |
130 | Drafts
131 |
132 |
133 |
134 |
139 |
140 | Bin
141 |
142 |
143 |
144 |
149 |
150 | Spam
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 | Settings
162 |
163 |
164 |
165 |
170 |
171 | Help and feedback
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
--------------------------------------------------------------------------------
/src/data/emails.ts:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue';
2 |
3 | const data = ref([
4 | {
5 | id: 1,
6 | date: "17:45",
7 | from: "Sky",
8 | subject: "Emily, get the Samsung Galaxy S21+ 5G from £43 a month",
9 | preview: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
10 | isRead: false,
11 | avatar: null,
12 | isStarred: false,
13 | color: "bg-yellow-500",
14 | visible: true
15 | },
16 | {
17 | id: 2,
18 | date: "16:34",
19 | from: "Amazon",
20 | subject: "Emily, get the Samsung Galaxy S21+ 5G from £43 a month",
21 | preview: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
22 | isRead: false,
23 | avatar: null,
24 | isStarred: false,
25 | color: "bg-green-500",
26 | visible: true
27 | },
28 | {
29 | id: 3,
30 | date: "16:20",
31 | from: "Stackoverflow",
32 | subject: "The Overflow #69: When internal devs are your customers",
33 | preview: "Welcome to ISSUE #69 of the Overflow! This newsletter is by developers, for developers, written and curated by the Stack Overflow team and Cassidy Williams at Netlify. Our menu this week: branch out with Git, fade to black in old video games, and prevent code injection in JavaScript and Node.",
34 | isRead: false,
35 | avatar: null,
36 | isStarred: false,
37 | color: "bg-blue-500",
38 | visible: true
39 | },
40 | {
41 | id: 4,
42 | date: "12:42",
43 | from: "Adam Wathan",
44 | subject: "Tailwind UI Update: React + Vue support is here!",
45 | preview: "Hey folks, two big updates for you today! 🥳 First of all, React + Vue support for Tailwind UI is now available! Every single component can be copied as a fully functional, fully accessible React or Vue example, and easily dropped directly into your project.",
46 | isRead: false,
47 | avatar: null,
48 | isStarred: true,
49 | color: "bg-pink-500",
50 | visible: true
51 | },
52 | {
53 | id: 5,
54 | date: "09:00",
55 | from: "Visa",
56 | subject: "Coming soon: an easier way to verify you on Click to Pay with Visa",
57 | preview: "We take the security of your Visa card information very seriously. That's why we're rolling out an easier way to verify it's you. When you make a payment with Click to Pay, we currently send you a verification code via email. To make this even more accessible and convenient we may now also be sending this code by SMS. Message and data rates may apply.",
58 | isRead: false,
59 | avatar: null,
60 | isStarred: false,
61 | color: "bg-red-500",
62 | visible: true
63 | },
64 | {
65 | id: 6,
66 | date: "08:11",
67 | from: "Monzo",
68 | subject: "Vote for Monzo as Best British Bank! ❤️",
69 | preview: "Thanks to votes from our customers, we’re finalists in the British Bank Awards for Best British Bank",
70 | isRead: false,
71 | avatar: null,
72 | isStarred: false,
73 | color: "bg-gray-500",
74 | visible: true
75 | },
76 | {
77 | id: 7,
78 | date: "17:45",
79 | from: "Sky",
80 | subject: "Emily, get the Samsung Galaxy S21+ 5G from £43 a month",
81 | preview: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
82 | isRead: false,
83 | avatar: null,
84 | isStarred: false,
85 | color: "bg-yellow-500",
86 | visible: true
87 | },
88 | {
89 | id: 8,
90 | date: "16 Apr",
91 | from: "Amazon",
92 | subject: "Emily, get the Samsung Galaxy S21+ 5G from £43 a month",
93 | preview: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
94 | isRead: false,
95 | avatar: null,
96 | isStarred: false,
97 | color: "bg-green-500",
98 | visible: true
99 | },
100 | {
101 | id: 9,
102 | date: "16 Apr",
103 | from: "Stackoverflow",
104 | subject: "The Overflow #69: When internal devs are your customers",
105 | preview: "Welcome to ISSUE #69 of the Overflow! This newsletter is by developers, for developers, written and curated by the Stack Overflow team and Cassidy Williams at Netlify. Our menu this week: branch out with Git, fade to black in old video games, and prevent code injection in JavaScript and Node.",
106 | isRead: false,
107 | avatar: null,
108 | isStarred: false,
109 | color: "bg-blue-500",
110 | visible: true
111 | },
112 | {
113 | id: 10,
114 | date: "16 Apr",
115 | from: "Adam Wathan",
116 | subject: "Tailwind UI Update: React + Vue support is here!",
117 | preview: "Hey folks, two big updates for you today! 🥳 First of all, React + Vue support for Tailwind UI is now available! Every single component can be copied as a fully functional, fully accessible React or Vue example, and easily dropped directly into your project.",
118 | isRead: false,
119 | avatar: null,
120 | isStarred: false,
121 | color: "bg-pink-500",
122 | visible: true
123 | },
124 | {
125 | id: 11,
126 | date: "16 Apr",
127 | from: "Visa",
128 | subject: "Coming soon: an easier way to verify you on Click to Pay with Visa",
129 | preview: "We take the security of your Visa card information very seriously. That's why we're rolling out an easier way to verify it's you. When you make a payment with Click to Pay, we currently send you a verification code via email. To make this even more accessible and convenient we may now also be sending this code by SMS. Message and data rates may apply.",
130 | isRead: false,
131 | avatar: null,
132 | isStarred: false,
133 | color: "bg-red-500",
134 | visible: true
135 | },
136 | {
137 | id: 12,
138 | date: "16 Apr",
139 | from: "Monzo",
140 | subject: "Vote for Monzo as Best British Bank! ❤️",
141 | preview: "Thanks to votes from our customers, we’re finalists in the British Bank Awards for Best British Bank",
142 | isRead: false,
143 | avatar: null,
144 | isStarred: false,
145 | color: "bg-gray-500",
146 | visible: true
147 | },
148 | {
149 | id: 13,
150 | date: "12 Apr",
151 | from: "Monzo",
152 | subject: "Vote for Monzo as Best British Bank! ❤️",
153 | preview: "Thanks to votes from our customers, we’re finalists in the British Bank Awards for Best British Bank",
154 | isRead: false,
155 | avatar: null,
156 | isStarred: false,
157 | color: "bg-gray-500",
158 | visible: true
159 | },
160 | {
161 | id: 14,
162 | date: "12 Apr",
163 | from: "Sky",
164 | subject: "Emily, get the Samsung Galaxy S21+ 5G from £43 a month",
165 | preview: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
166 | isRead: false,
167 | avatar: null,
168 | isStarred: false,
169 | color: "bg-yellow-500",
170 | visible: true
171 | },
172 | {
173 | id: 15,
174 | date: "1 Mar",
175 | from: "Amazon",
176 | subject: "Emily, get the Samsung Galaxy S21+ 5G from £43 a month",
177 | preview: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
178 | isRead: false,
179 | avatar: null,
180 | isStarred: false,
181 | color: "bg-green-500",
182 | visible: true
183 | },
184 | {
185 | id: 16,
186 | date: "22 Feb",
187 | from: "Stackoverflow",
188 | subject: "The Overflow #69: When internal devs are your customers",
189 | preview: "Welcome to ISSUE #69 of the Overflow! This newsletter is by developers, for developers, written and curated by the Stack Overflow team and Cassidy Williams at Netlify. Our menu this week: branch out with Git, fade to black in old video games, and prevent code injection in JavaScript and Node.",
190 | isRead: false,
191 | avatar: null,
192 | isStarred: false,
193 | color: "bg-blue-500",
194 | visible: true
195 | },
196 | {
197 | id: 17,
198 | date: "21 Feb",
199 | from: "Adam Wathan",
200 | subject: "Tailwind UI Update: React + Vue support is here!",
201 | preview: "Hey folks, two big updates for you today! 🥳 First of all, React + Vue support for Tailwind UI is now available! Every single component can be copied as a fully functional, fully accessible React or Vue example, and easily dropped directly into your project.",
202 | isRead: false,
203 | avatar: null,
204 | isStarred: false,
205 | color: "bg-pink-500",
206 | visible: true
207 | },
208 | {
209 | id: 18,
210 | date: "18 Feb",
211 | from: "Visa",
212 | subject: "Coming soon: an easier way to verify you on Click to Pay with Visa",
213 | preview: "We take the security of your Visa card information very seriously. That's why we're rolling out an easier way to verify it's you. When you make a payment with Click to Pay, we currently send you a verification code via email. To make this even more accessible and convenient we may now also be sending this code by SMS. Message and data rates may apply.",
214 | isRead: false,
215 | avatar: null,
216 | isStarred: false,
217 | color: "bg-red-500",
218 | visible: true
219 | },
220 | {
221 | id: 19,
222 | date: "16 Feb",
223 | from: "Monzo",
224 | subject: "Vote for Monzo as Best British Bank! ❤️",
225 | preview: "Thanks to votes from our customers, we’re finalists in the British Bank Awards for Best British Bank",
226 | isRead: false,
227 | avatar: null,
228 | isStarred: false,
229 | color: "bg-gray-500",
230 | visible: true
231 | }
232 | ])
233 |
234 | export default { data }
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import App from './App.vue'
3 | import router from './router';
4 |
5 | import { IonicVue } from '@ionic/vue';
6 |
7 | import "@fontsource/roboto";
8 |
9 | /* Core CSS required for Ionic components to work properly */
10 | import '@ionic/vue/css/core.css';
11 |
12 | /* Basic CSS for apps built with Ionic */
13 | import '@ionic/vue/css/normalize.css';
14 | import '@ionic/vue/css/structure.css';
15 | import '@ionic/vue/css/typography.css';
16 |
17 | /* Optional CSS utils that can be commented out */
18 | import '@ionic/vue/css/padding.css';
19 | import '@ionic/vue/css/float-elements.css';
20 | import '@ionic/vue/css/text-alignment.css';
21 | import '@ionic/vue/css/text-transformation.css';
22 | import '@ionic/vue/css/flex-utils.css';
23 | import '@ionic/vue/css/display.css';
24 |
25 | /* Theme variables */
26 | import './theme/variables.css';
27 |
28 | const app = createApp(App)
29 | .use(IonicVue)
30 | .use(router);
31 |
32 | router.isReady().then(() => {
33 | app.mount('#app');
34 | });
--------------------------------------------------------------------------------
/src/router/index.ts:
--------------------------------------------------------------------------------
1 | import { createRouter, createWebHistory } from '@ionic/vue-router';
2 | import { RouteRecordRaw } from 'vue-router';
3 | import Inbox from '../views/Inbox.vue'
4 | import Email from '../views/Email.vue'
5 | import Compose from '../views/Compose.vue'
6 |
7 | const routes: Array = [
8 | {
9 | path: '/',
10 | redirect: '/inbox'
11 | },
12 | {
13 | path: '/inbox',
14 | name: 'Inbox',
15 | component: Inbox
16 | },
17 | {
18 | path: '/email/:id',
19 | name: 'Email',
20 | component: Email
21 | },
22 | {
23 | path: '/compose',
24 | name: 'Compose',
25 | component: Compose
26 | }
27 | ]
28 |
29 | const router = createRouter({
30 | history: createWebHistory(process.env.BASE_URL),
31 | routes
32 | })
33 |
34 | export default router
35 |
--------------------------------------------------------------------------------
/src/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | import { defineComponent } from 'vue'
3 | const component: ReturnType
4 | export default component
5 | }
6 |
--------------------------------------------------------------------------------
/src/theme/variables.css:
--------------------------------------------------------------------------------
1 | /* Ionic Variables and Theming. For more info, please see:
2 | http://ionicframework.com/docs/theming/ */
3 |
4 | /** Ionic CSS Variables **/
5 | :root {
6 | /** primary **/
7 | --ion-color-primary: #3880ff;
8 | --ion-color-primary-rgb: 56, 128, 255;
9 | --ion-color-primary-contrast: #ffffff;
10 | --ion-color-primary-contrast-rgb: 255, 255, 255;
11 | --ion-color-primary-shade: #3171e0;
12 | --ion-color-primary-tint: #4c8dff;
13 |
14 | /** secondary **/
15 | --ion-color-secondary: #3dc2ff;
16 | --ion-color-secondary-rgb: 61, 194, 255;
17 | --ion-color-secondary-contrast: #ffffff;
18 | --ion-color-secondary-contrast-rgb: 255, 255, 255;
19 | --ion-color-secondary-shade: #36abe0;
20 | --ion-color-secondary-tint: #50c8ff;
21 |
22 | /** tertiary **/
23 | --ion-color-tertiary: #5260ff;
24 | --ion-color-tertiary-rgb: 82, 96, 255;
25 | --ion-color-tertiary-contrast: #ffffff;
26 | --ion-color-tertiary-contrast-rgb: 255, 255, 255;
27 | --ion-color-tertiary-shade: #4854e0;
28 | --ion-color-tertiary-tint: #6370ff;
29 |
30 | /** success **/
31 | --ion-color-success: #2dd36f;
32 | --ion-color-success-rgb: 45, 211, 111;
33 | --ion-color-success-contrast: #ffffff;
34 | --ion-color-success-contrast-rgb: 255, 255, 255;
35 | --ion-color-success-shade: #28ba62;
36 | --ion-color-success-tint: #42d77d;
37 |
38 | /** warning **/
39 | --ion-color-warning: #ffc409;
40 | --ion-color-warning-rgb: 255, 196, 9;
41 | --ion-color-warning-contrast: #000000;
42 | --ion-color-warning-contrast-rgb: 0, 0, 0;
43 | --ion-color-warning-shade: #e0ac08;
44 | --ion-color-warning-tint: #ffca22;
45 |
46 | /** danger **/
47 | --ion-color-danger: #eb445a;
48 | --ion-color-danger-rgb: 235, 68, 90;
49 | --ion-color-danger-contrast: #ffffff;
50 | --ion-color-danger-contrast-rgb: 255, 255, 255;
51 | --ion-color-danger-shade: #cf3c4f;
52 | --ion-color-danger-tint: #ed576b;
53 |
54 | /** dark **/
55 | --ion-color-dark: #222428;
56 | --ion-color-dark-rgb: 34, 36, 40;
57 | --ion-color-dark-contrast: #ffffff;
58 | --ion-color-dark-contrast-rgb: 255, 255, 255;
59 | --ion-color-dark-shade: #1e2023;
60 | --ion-color-dark-tint: #383a3e;
61 |
62 | /** medium **/
63 | --ion-color-medium: #92949c;
64 | --ion-color-medium-rgb: 146, 148, 156;
65 | --ion-color-medium-contrast: #ffffff;
66 | --ion-color-medium-contrast-rgb: 255, 255, 255;
67 | --ion-color-medium-shade: #808289;
68 | --ion-color-medium-tint: #9d9fa6;
69 |
70 | /** light **/
71 | --ion-color-light: #f4f5f8;
72 | --ion-color-light-rgb: 244, 245, 248;
73 | --ion-color-light-contrast: #000000;
74 | --ion-color-light-contrast-rgb: 0, 0, 0;
75 | --ion-color-light-shade: #d7d8da;
76 | --ion-color-light-tint: #f5f6f9;
77 | }
78 |
79 | @media (prefers-color-scheme: dark) {
80 | /*
81 | * Dark Colors
82 | * -------------------------------------------
83 | */
84 |
85 | body {
86 | --ion-color-primary: #428cff;
87 | --ion-color-primary-rgb: 66,140,255;
88 | --ion-color-primary-contrast: #ffffff;
89 | --ion-color-primary-contrast-rgb: 255,255,255;
90 | --ion-color-primary-shade: #3a7be0;
91 | --ion-color-primary-tint: #5598ff;
92 |
93 | --ion-color-secondary: #50c8ff;
94 | --ion-color-secondary-rgb: 80,200,255;
95 | --ion-color-secondary-contrast: #ffffff;
96 | --ion-color-secondary-contrast-rgb: 255,255,255;
97 | --ion-color-secondary-shade: #46b0e0;
98 | --ion-color-secondary-tint: #62ceff;
99 |
100 | --ion-color-tertiary: #6a64ff;
101 | --ion-color-tertiary-rgb: 106,100,255;
102 | --ion-color-tertiary-contrast: #ffffff;
103 | --ion-color-tertiary-contrast-rgb: 255,255,255;
104 | --ion-color-tertiary-shade: #5d58e0;
105 | --ion-color-tertiary-tint: #7974ff;
106 |
107 | --ion-color-success: #2fdf75;
108 | --ion-color-success-rgb: 47,223,117;
109 | --ion-color-success-contrast: #000000;
110 | --ion-color-success-contrast-rgb: 0,0,0;
111 | --ion-color-success-shade: #29c467;
112 | --ion-color-success-tint: #44e283;
113 |
114 | --ion-color-warning: #ffd534;
115 | --ion-color-warning-rgb: 255,213,52;
116 | --ion-color-warning-contrast: #000000;
117 | --ion-color-warning-contrast-rgb: 0,0,0;
118 | --ion-color-warning-shade: #e0bb2e;
119 | --ion-color-warning-tint: #ffd948;
120 |
121 | --ion-color-danger: #ff4961;
122 | --ion-color-danger-rgb: 255,73,97;
123 | --ion-color-danger-contrast: #ffffff;
124 | --ion-color-danger-contrast-rgb: 255,255,255;
125 | --ion-color-danger-shade: #e04055;
126 | --ion-color-danger-tint: #ff5b71;
127 |
128 | --ion-color-dark: #f4f5f8;
129 | --ion-color-dark-rgb: 244,245,248;
130 | --ion-color-dark-contrast: #000000;
131 | --ion-color-dark-contrast-rgb: 0,0,0;
132 | --ion-color-dark-shade: #d7d8da;
133 | --ion-color-dark-tint: #f5f6f9;
134 |
135 | --ion-color-medium: #989aa2;
136 | --ion-color-medium-rgb: 152,154,162;
137 | --ion-color-medium-contrast: #000000;
138 | --ion-color-medium-contrast-rgb: 0,0,0;
139 | --ion-color-medium-shade: #86888f;
140 | --ion-color-medium-tint: #a2a4ab;
141 |
142 | --ion-color-light: #222428;
143 | --ion-color-light-rgb: 34,36,40;
144 | --ion-color-light-contrast: #ffffff;
145 | --ion-color-light-contrast-rgb: 255,255,255;
146 | --ion-color-light-shade: #1e2023;
147 | --ion-color-light-tint: #383a3e;
148 | }
149 |
150 | /*
151 | * iOS Dark Theme
152 | * -------------------------------------------
153 | */
154 |
155 | .ios body {
156 | --ion-background-color: #000000;
157 | --ion-background-color-rgb: 0,0,0;
158 |
159 | --ion-text-color: #ffffff;
160 | --ion-text-color-rgb: 255,255,255;
161 |
162 | --ion-color-step-50: #0d0d0d;
163 | --ion-color-step-100: #1a1a1a;
164 | --ion-color-step-150: #262626;
165 | --ion-color-step-200: #333333;
166 | --ion-color-step-250: #404040;
167 | --ion-color-step-300: #4d4d4d;
168 | --ion-color-step-350: #595959;
169 | --ion-color-step-400: #666666;
170 | --ion-color-step-450: #737373;
171 | --ion-color-step-500: #808080;
172 | --ion-color-step-550: #8c8c8c;
173 | --ion-color-step-600: #999999;
174 | --ion-color-step-650: #a6a6a6;
175 | --ion-color-step-700: #b3b3b3;
176 | --ion-color-step-750: #bfbfbf;
177 | --ion-color-step-800: #cccccc;
178 | --ion-color-step-850: #d9d9d9;
179 | --ion-color-step-900: #e6e6e6;
180 | --ion-color-step-950: #f2f2f2;
181 |
182 | --ion-item-background: #000000;
183 |
184 | --ion-card-background: #1c1c1d;
185 | }
186 |
187 | .ios ion-modal {
188 | --ion-background-color: var(--ion-color-step-100);
189 | --ion-toolbar-background: var(--ion-color-step-150);
190 | --ion-toolbar-border-color: var(--ion-color-step-250);
191 | }
192 |
193 |
194 | /*
195 | * Material Design Dark Theme
196 | * -------------------------------------------
197 | */
198 |
199 | .md body {
200 | --ion-background-color: #121212;
201 | --ion-background-color-rgb: 18,18,18;
202 |
203 | --ion-text-color: #ffffff;
204 | --ion-text-color-rgb: 255,255,255;
205 |
206 | --ion-border-color: #222222;
207 |
208 | --ion-color-step-50: #1e1e1e;
209 | --ion-color-step-100: #2a2a2a;
210 | --ion-color-step-150: #363636;
211 | --ion-color-step-200: #414141;
212 | --ion-color-step-250: #4d4d4d;
213 | --ion-color-step-300: #595959;
214 | --ion-color-step-350: #656565;
215 | --ion-color-step-400: #717171;
216 | --ion-color-step-450: #7d7d7d;
217 | --ion-color-step-500: #898989;
218 | --ion-color-step-550: #949494;
219 | --ion-color-step-600: #a0a0a0;
220 | --ion-color-step-650: #acacac;
221 | --ion-color-step-700: #b8b8b8;
222 | --ion-color-step-750: #c4c4c4;
223 | --ion-color-step-800: #d0d0d0;
224 | --ion-color-step-850: #dbdbdb;
225 | --ion-color-step-900: #e7e7e7;
226 | --ion-color-step-950: #f3f3f3;
227 |
228 | --ion-item-background: #1e1e1e;
229 |
230 | --ion-toolbar-background: #1f1f1f;
231 |
232 | --ion-tab-bar-background: #1f1f1f;
233 |
234 | --ion-card-background: #1e1e1e;
235 | }
236 | }
237 |
238 | @import "tailwindcss/base";
239 | @import "tailwindcss/components";
240 | @import "tailwindcss/utilities";
--------------------------------------------------------------------------------
/src/views/Compose.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 | Compose
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
From
28 |
ionic@framework.com
29 |
34 |
35 |
44 |
47 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/src/views/Email.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | {{ email.subject }}
29 | Inbox
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | {{ email.from.charAt(0) }}
39 |
40 |
41 |
{{ email.from }} {{ email.date }}
42 |
43 | to me
44 |
45 |
46 |
47 |
48 |
49 |
54 |
59 |
60 |
61 |
Th’art nesh thee nay lad soft lad wacken thi sen up t’foot o’ our stairs.
62 |
Nay lad where’s tha bin. Th’art nesh thee a pint ‘o mild any rooad t’foot o’ our stairs. Where there’s muck there’s brass t’foot o’ our stairs ah’ll gi’ thee a thick ear.
63 |
Ah’ll learn thi tintintin tell thi summat for nowt soft lad mardy bum. Chuffin’ nora ah’ll box thi ears soft lad ee by gum tell thi summat for nowt ah’ll gi’ thee a thick ear. Bobbar nay lad. Breadcake soft southern pansy wacken thi sen up. Be reet where’s tha bin mardy bum mardy bum.
64 |
Tell thi summat for nowt where there’s muck there’s brass shu’ thi gob. Dahn t’coil oil. That’s champion ey up will ‘e ‘eckerslike shurrup by ‘eck. Eeh. Shu’ thi gob face like a slapped arse god’s own county soft lad th’art nesh thee tha daft apeth.
65 |
66 |
Ah’ll learn thi tintintin tell thi summat for nowt soft lad mardy bum. Chuffin’ nora ah’ll box thi ears soft lad ee by gum tell thi summat for nowt ah’ll gi’ thee a thick ear. Bobbar nay lad. Breadcake soft southern pansy wacken thi sen up. Be reet where’s tha bin mardy bum mardy bum.
67 |
Tell thi summat for nowt where there’s muck there’s brass shu’ thi gob. Dahn t’coil oil. That’s champion ey up will ‘e ‘eckerslike shurrup by ‘eck. Eeh. Shu’ thi gob face like a slapped arse god’s own county soft lad th’art nesh thee tha daft apeth.
68 |
69 |
70 |
71 |
72 |
73 |
74 | Reply
75 |
76 |
77 |
78 |
79 |
80 | Reply all
81 |
82 |
83 |
84 |
85 |
86 | Forward
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/src/views/Inbox.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Compose
9 |
10 |
11 |
12 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
Primary
27 |
28 |
33 |
34 |
Promotions
35 |
Sportsdirect.com, hotukdeals, Country Golf, Marks & Spender
36 |
37 |
40 |
41 |
42 |
43 |
55 |
56 |
57 | {{ email.from.charAt(0) }}
58 |
59 |
60 |
{{ email.from }}
61 |
{{ email.subject }}
62 |
{{ email.preview }}
63 |
64 |
65 |
{{ email.date }}
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | mode: 'jit',
3 | purge: ['./src/**/*.vue'],
4 | safelist: ['bg-yellow-500', 'bg-green-500', 'bg-blue-500', 'bg-pink-500', 'bg-red-500', 'bg-gray-500'],
5 | darkMode: false, // or 'media' or 'class'
6 | theme: {
7 | extend: {
8 | fontFamily: {
9 | logo: ["Roboto", "sans-serif"]
10 | }
11 | },
12 | },
13 | variants: {
14 | extend: {},
15 | },
16 | plugins: [
17 | require('@tailwindcss/line-clamp'),
18 | ],
19 | }
20 |
--------------------------------------------------------------------------------
/tests/e2e/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [
3 | 'cypress'
4 | ],
5 | env: {
6 | mocha: true,
7 | 'cypress/globals': true
8 | },
9 | rules: {
10 | strict: 'off'
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/tests/e2e/plugins/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable arrow-body-style */
2 | // https://docs.cypress.io/guides/guides/plugins-guide.html
3 |
4 | // if you need a custom webpack configuration you can uncomment the following import
5 | // and then use the `file:preprocessor` event
6 | // as explained in the cypress docs
7 | // https://docs.cypress.io/api/plugins/preprocessors-api.html#Examples
8 |
9 | // /* eslint-disable import/no-extraneous-dependencies, global-require */
10 | // const webpack = require('@cypress/webpack-preprocessor')
11 |
12 | module.exports = (on, config) => {
13 | // on('file:preprocessor', webpack({
14 | // webpackOptions: require('@vue/cli-service/webpack.config'),
15 | // watchOptions: {}
16 | // }))
17 |
18 | return Object.assign({}, config, {
19 | fixturesFolder: 'tests/e2e/fixtures',
20 | integrationFolder: 'tests/e2e/specs',
21 | screenshotsFolder: 'tests/e2e/screenshots',
22 | videosFolder: 'tests/e2e/videos',
23 | supportFile: 'tests/e2e/support/index.js'
24 | })
25 | }
26 |
--------------------------------------------------------------------------------
/tests/e2e/specs/test.js:
--------------------------------------------------------------------------------
1 | import Emails from '../../../src/data/emails'
2 |
3 | describe('UI tests', () => {
4 | it('can display emails', () => {
5 | cy.viewport('iphone-x')
6 | cy.visit('/')
7 | cy.getByData('email').should('have.length', Emails.data.value.length)
8 | })
9 |
10 | it('can swipe to delete', () => {
11 | cy.viewport('iphone-x')
12 | cy.visit('/')
13 |
14 | cy.getByData('email').swipe({delay: 100}, [340, 0], [100, 0])
15 | cy.getByData('email').should('have.length', Emails.data.value.length -1)
16 |
17 | cy.getByData('email').swipe({delay: 100}, [100, 0], [304, 0])
18 | cy.getByData('email').should('have.length', Emails.data.value.length -1)
19 | })
20 |
21 | it('can search emails', () => {
22 | cy.viewport('iphone-x')
23 | cy.visit('/')
24 |
25 | cy.getByData('search').type('Amazon')
26 | cy.getByData('email').should('have.length', 3)
27 |
28 | cy.getByData('search').clear('Amazon')
29 | cy.getByData('email').should('have.length', Emails.data.value.length)
30 | })
31 |
32 | it('can star an email', () => {
33 | cy.viewport('iphone-x')
34 | cy.visit('/')
35 |
36 | const starred = Emails.data.value.filter(e => e.isStarred).length
37 |
38 | cy.getByData('star').first().click()
39 | cy.getByData('star').find('svg.text-yellow-500').should('have.length', starred + 1)
40 |
41 | cy.getByData('star').first().click()
42 | cy.getByData('star').find('svg.text-yellow-500').should('have.length', starred)
43 |
44 | })
45 |
46 | it('can open an email', () => {
47 | cy.viewport('iphone-x')
48 | cy.visit('/')
49 |
50 | cy.getByData('email').first().click()
51 | cy.getByData('read-view').should('contain', Emails.data.value[0].subject)
52 | cy.getByData('read-view').should('contain', Emails.data.value[0].from)
53 | cy.getByData('read-view').should('contain', Emails.data.value[0].date)
54 | })
55 |
56 | it('can delete an email from read view', () => {
57 | cy.viewport('iphone-x')
58 | cy.visit('/')
59 |
60 | cy.getByData('email').first().click()
61 | cy.url().should('contain', '/email/1')
62 | cy.getByData('delete').click()
63 | cy.getByData('email').should('have.length', Emails.data.value.length - 1)
64 | cy.url().should('contain', '/inbox')
65 | })
66 |
67 | it('can star an email from read view', () => {
68 | cy.viewport('iphone-x')
69 | cy.visit('/')
70 |
71 | const starred = Emails.data.value.filter(e => e.isStarred).length
72 |
73 | cy.getByData('email').first().click()
74 | cy.url().should('contain', '/email/1')
75 | cy.getByData('read-view--star').click().should('have.class', 'text-yellow-500')
76 | cy.getByData('read-view--back').click()
77 | cy.url().should('contain', '/inbox')
78 |
79 | cy.getByData('star').find('svg.text-yellow-500').should('have.length', starred + 1)
80 | })
81 |
82 | it('can hide/show the search bar on scroll', () => {
83 | cy.viewport('iphone-x')
84 | cy.visitMobile('/')
85 |
86 | cy.getByData('inbox').shadow().find('.inner-scroll').scrollTo('bottom', { duration: 500 })
87 | cy.getByData('search-container').should('not.be.visible')
88 | cy.getByData('inbox').shadow().find('.inner-scroll').scrollTo('top', { duration: 500 })
89 | cy.getByData('search-container').should('be.visible')
90 | })
91 | })
92 |
--------------------------------------------------------------------------------
/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 | import 'cy-mobile-commands'
27 |
28 | Cypress.Commands.add('getByData', (selector, ...args) => {
29 | return cy.get(`[data-cy=${selector}]`, ...args)
30 | })
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/tests/unit/example.spec.ts:
--------------------------------------------------------------------------------
1 | import { mount } from '@vue/test-utils'
2 | import Home from '@/views/Home.vue'
3 |
4 | describe('Home.vue', () => {
5 | it('renders home vue', () => {
6 | const wrapper = mount(Home)
7 | expect(wrapper.text()).toMatch('Ready to create an app?')
8 | })
9 | })
10 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "module": "esnext",
5 | "strict": true,
6 | "jsx": "preserve",
7 | "importHelpers": true,
8 | "moduleResolution": "node",
9 | "skipLibCheck": true,
10 | "esModuleInterop": true,
11 | "allowSyntheticDefaultImports": true,
12 | "sourceMap": true,
13 | "baseUrl": ".",
14 | "types": [
15 | "webpack-env",
16 | "jest"
17 | ],
18 | "paths": {
19 | "@/*": [
20 | "src/*"
21 | ]
22 | },
23 | "lib": [
24 | "esnext",
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 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | devServer: {
3 | progress: false,
4 | port: 8100
5 | }
6 | }
--------------------------------------------------------------------------------