/src/$1'
15 | },
16 | snapshotSerializers: [
17 | 'jest-serializer-vue'
18 | ],
19 | testMatch: [
20 | '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
21 | ],
22 | testURL: 'http://localhost/'
23 | }
24 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-storybook-example",
3 | "description": "Storybook.js Vue example based on Vue-CLI-3",
4 | "version": "0.1.0",
5 | "author": {
6 | "name": "I Nengah Januartha",
7 | "email": "janumedia@gmail.com"
8 | },
9 | "license": "MIT",
10 | "keywords": [
11 | "storybook",
12 | "vue",
13 | "vue-cli",
14 | "webpack",
15 | "babel",
16 | "es6",
17 | "jest",
18 | "ui-tests",
19 | "test-framework"
20 | ],
21 | "private": true,
22 | "scripts": {
23 | "serve": "vue-cli-service serve",
24 | "build": "vue-cli-service build",
25 | "lint": "vue-cli-service lint",
26 | "test:unit": "vue-cli-service test:unit",
27 | "storybook": "start-storybook -p 9001 -c .storybook -s public",
28 | "storybook:build": "build-storybook -c .storybook -o .out -s public"
29 | },
30 | "dependencies": {
31 | "vue": "^2.5.21",
32 | "vue-router": "^3.0.2"
33 | },
34 | "devDependencies": {
35 | "@storybook/addon-actions": "^4.1.4",
36 | "@storybook/addon-knobs": "^4.1.4",
37 | "@storybook/addon-links": "^4.1.4",
38 | "@storybook/addon-options": "^4.1.4",
39 | "@storybook/addon-storysource": "^4.1.4",
40 | "@storybook/addon-viewport": "^4.1.4",
41 | "@storybook/vue": "^4.1.4",
42 | "@vue/babel-plugin-transform-vue-jsx": "^1.0.0-beta.2",
43 | "@vue/babel-preset-jsx": "^1.0.0-beta.2",
44 | "@vue/babel-sugar-functional-vue": "^1.0.0-beta.2",
45 | "@vue/cli-plugin-babel": "^3.0.1",
46 | "@vue/cli-plugin-eslint": "^3.0.1",
47 | "@vue/cli-plugin-unit-jest": "^3.0.1",
48 | "@vue/cli-service": "^3.0.1",
49 | "@vue/test-utils": "^1.0.0-beta.20",
50 | "babel-core": "7.0.0-bridge.0",
51 | "babel-eslint": "^10.0.1",
52 | "babel-jest": "^23.6.0",
53 | "babel-preset-vue": "^2.0.2",
54 | "eslint": "^5.8.0",
55 | "eslint-plugin-vue": "^5.0.0",
56 | "node-sass": "^4.9.0",
57 | "sass-loader": "^7.0.1",
58 | "storybook-vue-router": "^1.0.2",
59 | "vue-template-compiler": "^2.5.21"
60 | },
61 | "resolutions": {
62 | "kind-of": "^6.0.3",
63 | "acorn": "^6.4.1",
64 | "minimist": "^0.2.1",
65 | "websocket-extensions": "^0.1.4"
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {}
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/public/assets/image-placeholder.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janumedia/vue-storybook-example/c22ac54c00a11a54df085be1e0723262f93a742b/public/favicon.ico
--------------------------------------------------------------------------------
/public/images/image-placeholder-example.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janumedia/vue-storybook-example/c22ac54c00a11a54df085be1e0723262f93a742b/public/images/image-placeholder-example.jpg
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | vue-storybook-example
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/public/video/sintel/captions.vtt:
--------------------------------------------------------------------------------
1 | WEBVTT
2 |
3 | 00:00:01.000 --> 00:00:02.042
4 | (drumbeat)
5 |
6 | 00:00:07.167 --> 00:00:12.025
7 | (plaintive violin solo playing)
8 |
9 | 00:00:15.000 --> 00:00:18.183
10 | (wind whistling)
11 |
12 | 00:00:24.167 --> 00:00:27.025
13 | (orchestra music swells)
14 |
15 | 00:00:43.033 --> 00:00:43.192
16 | (weapons clash)
17 |
18 | 00:00:44.000 --> 00:00:44.175
19 | (gasps)
20 |
21 | 00:00:44.183 --> 00:00:45.158
22 | (grunts)
23 |
24 | 00:00:45.167 --> 00:00:47.058
25 | (groaning)
26 |
27 | 00:00:54.192 --> 00:00:55.150
28 | (blade rings)
29 |
30 | 00:00:55.158 --> 00:00:57.008
31 | (bellowing)
32 |
33 | 00:00:57.017 --> 00:00:58.067
34 | (grunting)
35 |
36 | 00:00:59.075 --> 00:01:00.133
37 | (panting)
38 |
39 | 00:01:05.108 --> 00:01:06.125
40 | (cries out in agony)
41 |
42 | 00:01:08.050 --> 00:01:09.058
43 | (panting)
44 |
45 | 00:01:12.092 --> 00:01:13.142
46 | (panting)
47 |
48 | 00:01:14.017 --> 00:01:18.125
49 | (orchestra plays ominous low notes)
50 |
51 | 00:01:31.058 --> 00:01:35.133
52 | (plaintive violin solo returns)
53 |
54 | 00:01:46.158 --> 00:01:49.058
55 | This blade has a dark past.
56 |
57 | 00:01:51.092 --> 00:01:54.108
58 | It has shed much innocent blood.
59 |
60 | 00:01:57.083 --> 00:02:00.000
61 | You're a fool for traveling alone
62 | so completely unprepared.
63 |
64 | 00:02:01.100 --> 00:02:03.033
65 | You're lucky your blood's still flowing.
66 |
67 | 00:02:04.183 --> 00:02:06.075
68 | Thank you.
69 |
70 | 00:02:07.075 --> 00:02:08.125
71 | So...
72 |
73 | 00:02:09.050 --> 00:02:11.142
74 | What brings you to the land of the gatekeepers?
75 |
76 | 00:02:13.025 --> 00:02:16.150
77 | I'm... I'm searching for someone.
78 |
79 | 00:02:18.042 --> 00:02:19.092
80 | Someone very dear?
81 |
82 | 00:02:19.183 --> 00:02:21.008
83 | A kindred spirit?
84 |
85 | 00:02:23.033 --> 00:02:24.142
86 | A dragon.
87 |
88 | 00:02:26.117 --> 00:02:27.167
89 | (fire crackling)
90 |
91 | 00:02:29.000 --> 00:02:31.092
92 | A dangerous quest for a lone hunter.
93 |
94 | 00:02:31.133 --> 00:02:32.183
95 | (birds cawing)
96 |
97 | 00:02:33.100 --> 00:02:35.167
98 | I've been alone for as long as I can remember.
99 |
100 | 00:02:44.083 --> 00:02:47.100
101 | (flies buzzing)
102 |
103 | 00:02:49.008 --> 00:02:50.058
104 | (birds cawing)
105 |
106 | 00:02:52.192 --> 00:02:54.042
107 | (sniffs)
108 |
109 | 00:02:55.000 --> 00:02:56.075
110 | (hollow thump)
111 |
112 | 00:03:01.000 --> 00:03:02.017
113 | (gasps)
114 |
115 | 00:03:02.025 --> 00:03:04.092
116 | (whimpering)
117 |
118 | 00:03:08.108 --> 00:03:09.167
119 | (squeaking)
120 |
121 | 00:03:12.058 --> 00:03:14.133
122 | (whimpering)
123 |
124 | 00:03:15.058 --> 00:03:16.092
125 | Shh.
126 |
127 | 00:03:22.000 --> 00:03:23.033
128 | (sniffing)
129 |
130 | 00:03:25.017 --> 00:03:26.008
131 | (shrieking)
132 |
133 | 00:03:26.017 --> 00:03:27.067
134 | Shh. Hey, shh-shh.
135 |
136 | 00:03:27.183 --> 00:03:29.042
137 | We're almost done.
138 |
139 | 00:03:30.092 --> 00:03:31.167
140 | Hey, sit still.
141 |
142 | 00:03:37.183 --> 00:03:39.108
143 | (chuckles gently)
144 |
145 | 00:03:47.133 --> 00:03:49.075
146 | Good night, Scales.
147 |
148 | 00:03:54.042 --> 00:03:58.083
149 | (gentle music playing)
150 |
151 | 00:04:08.067 --> 00:04:09.117
152 | (chicken clucking)
153 |
154 | 00:04:09.158 --> 00:04:11.000
155 | SINTEL:
156 | Get him, Scales!
157 |
158 | 00:04:11.008 --> 00:04:12.075
159 | Come on! Get him!
160 |
161 | 00:04:14.167 --> 00:04:15.183
162 | (clucking)
163 |
164 | 00:04:15.192 --> 00:04:17.067
165 | (laughing softly as she runs)
166 |
167 | 00:04:17.167 --> 00:04:18.183
168 | Ooh!
169 |
170 | 00:04:24.092 --> 00:04:25.142
171 | Scales?
172 |
173 | 00:04:29.075 --> 00:04:30.100
174 | (chicken clucks)
175 |
176 | 00:04:41.108 --> 00:04:42.158
177 | (flock cawing)
178 |
179 | 00:04:43.117 --> 00:04:45.158
180 | (wings fluttering)
181 |
182 | 00:04:47.125 --> 00:04:49.083
183 | (panting)
184 |
185 | 00:04:52.042 --> 00:04:54.125
186 | (orchestra music swells)
187 |
188 | 00:04:59.100 --> 00:05:00.150
189 | (sintel laughing)
190 |
191 | 00:05:01.108 --> 00:05:03.183
192 | Yeah!
193 |
194 | 00:05:04.125 --> 00:05:05.175
195 | Yeah!
196 |
197 | 00:05:06.100 --> 00:05:07.150
198 | Come on!
199 |
200 | 00:05:08.008 --> 00:05:10.008
201 | Whoo!
202 |
203 | 00:05:14.075 --> 00:05:15.125
204 | (screeching)
205 |
206 | 00:05:15.142 --> 00:05:16.167
207 | (thud)
208 |
209 | 00:05:21.067 --> 00:05:22.067
210 | (snarls)
211 |
212 | 00:05:25.192 --> 00:05:27.067
213 | (crunching)
214 |
215 | 00:05:33.133 --> 00:05:34.100
216 | (grunts)
217 |
218 | 00:05:35.092 --> 00:05:37.117
219 | (screeching)
220 |
221 | 00:05:38.092 --> 00:05:39.092
222 | Scales!
223 |
224 | 00:05:48.058 --> 00:05:49.175
225 | (wind whistling softly)
226 |
227 | 00:05:51.125 --> 00:05:52.175
228 | (breathing hard)
229 |
230 | 00:05:53.100 --> 00:05:56.050
231 | (lyrical oboe playing over orchestra)
232 |
233 | 00:06:07.100 --> 00:06:13.050
234 | (ethereal chorus singing)
235 |
236 | 00:06:26.092 --> 00:06:28.050
237 | (beast growling)
238 |
239 | 00:06:30.017 --> 00:06:31.133
240 | (cries out in pain)
241 |
242 | 00:06:35.192 --> 00:06:38.142
243 | (wind roaring)
244 |
245 | 00:06:39.150 --> 00:06:41.025
246 | (groans)
247 |
248 | 00:06:42.133 --> 00:06:44.100
249 | (gasps)
250 |
251 | 00:06:57.058 --> 00:06:59.150
252 | (panting and gasping)
253 |
254 | 00:07:03.142 --> 00:07:06.017
255 | (wind whistling)
256 |
257 | 00:07:15.050 --> 00:07:16.083
258 | (weapons clash)
259 |
260 | 00:07:18.083 --> 00:07:22.117
261 | (panting)
262 |
263 | 00:07:25.133 --> 00:07:26.183
264 | I have failed.
265 |
266 | 00:07:27.150 --> 00:07:29.158
267 | Mmm...
268 |
269 | 00:07:32.133 --> 00:07:34.133
270 | You've only failed to see.
271 |
272 | 00:07:37.100 --> 00:07:38.175
273 | These are dragon lands, Sintel.
274 |
275 | 00:07:40.133 --> 00:07:42.083
276 | You are closer than you know.
277 |
278 | 00:07:51.192 --> 00:07:55.042
279 | (quiet music playing)
280 |
281 | 00:08:07.158 --> 00:08:11.042
282 | (footsteps crunching softly)
283 |
284 | 00:08:19.117 --> 00:08:20.192
285 | (growling softly)
286 |
287 | 00:08:22.150 --> 00:08:26.008
288 | (crunching loudly)
289 |
290 | 00:08:38.050 --> 00:08:39.192
291 | (meat ripping)
292 |
293 | 00:08:45.142 --> 00:08:46.158
294 | (soft thud)
295 |
296 | 00:08:58.108 --> 00:09:01.083
297 | (squealing)
298 |
299 | 00:09:02.050 --> 00:09:03.083
300 | (growls)
301 |
302 | 00:09:15.183 --> 00:09:17.033
303 | (growling)
304 |
305 | 00:09:17.100 --> 00:09:18.175
306 | Scales!
307 |
308 | 00:09:30.017 --> 00:09:31.067
309 | (bellowing)
310 |
311 | 00:09:31.125 --> 00:09:33.000
312 | (shards tinkling as they fall)
313 |
314 | 00:09:34.117 --> 00:09:37.175
315 | (suspenseful music playing)
316 |
317 | 00:09:39.033 --> 00:09:41.075
318 | (growling and grunting)
319 |
320 | 00:09:49.092 --> 00:09:53.008
321 | (growling)
322 |
323 | 00:09:56.033 --> 00:09:58.067
324 | (growls and sniffs)
325 |
326 | 00:10:00.183 --> 00:10:02.017
327 | (shrieks)
328 |
329 | 00:10:02.025 --> 00:10:06.108
330 | (bellowing)
331 |
332 | 00:10:07.033 --> 00:10:08.058
333 | (growling)
334 |
335 | 00:10:20.183 --> 00:10:21.192
336 | Scales?
337 |
338 | 00:10:26.033 --> 00:10:27.175
339 | Scales...
340 |
341 | 00:10:47.142 --> 00:10:49.025
342 | (moaning softly)
343 |
344 | 00:10:59.125 --> 00:11:01.083
345 | (rumbling and cracking)
346 |
347 | 00:11:12.142 --> 00:11:15.050
348 | (boulders crashing)
349 |
350 | 00:11:21.017 --> 00:11:23.000
351 | (silence)
352 |
353 | 00:11:33.033 --> 00:11:34.083
354 | (sobbing softly)
355 |
356 | 00:11:35.167 --> 00:11:37.192
357 | (flock squawking)
358 |
359 | 00:11:40.117 --> 00:11:42.000
360 | (sniffles)
361 |
362 | 00:11:57.158 --> 00:11:59.017
363 | (blade clanks)
364 |
365 | 00:12:02.017 --> 00:12:05.042
366 | (quiet music begins playing)
367 |
368 | 00:12:10.083 --> 00:12:12.092
369 | (scuffling)
370 |
371 | 00:12:27.175 --> 00:12:32.008
372 | ♪ Come take my journey into night ♪
373 |
374 | 00:12:34.117 --> 00:12:39.058
375 | ♪ Come be my shadow, walk at my side ♪
376 |
377 | 00:12:41.050 --> 00:12:46.050
378 | ♪ And when you see all that I have seen ♪
379 |
380 | 00:12:47.150 --> 00:12:52.042
381 | ♪ Can you tell me love from pride? ♪
382 |
383 | 00:12:54.117 --> 00:12:59.008
384 | ♪ I have been waiting all this time ♪
385 |
386 | 00:13:01.092 --> 00:13:06.092
387 | ♪ For one to wake me, one to call mine ♪
388 |
389 | 00:13:07.158 --> 00:13:12.158
390 | ♪ So when you're near all that you hold dear ♪
391 |
392 | 00:13:14.008 --> 00:13:18.100
393 | ♪ Do you fear what you will find? ♪
394 |
395 | 00:13:20.067 --> 00:13:24.158
396 | ♪ As the dawn breaks through the night ♪
397 |
398 | 00:13:27.025 --> 00:13:31.008
399 | ♪ I move on, forever longing ♪
400 |
401 | 00:13:33.025 --> 00:13:44.150
402 | ♪ For the home I found in your eyes. ♪
403 |
404 | 00:13:48.042 --> 00:13:52.133
405 | ♪ I will be listening for the drum ♪
406 |
407 | 00:13:54.108 --> 00:13:59.000
408 | ♪ To call me over, far away from... ♪
409 |
410 | 00:14:01.108 --> 00:14:06.000
411 | ♪ My tender youth and the very truth ♪
412 |
413 | 00:14:07.075 --> 00:14:11.058
414 | ♪ Showing me what I've become. ♪
415 |
416 | 00:14:13.133 --> 00:14:18.025
417 | ♪ As the dawn breaks through the night ♪
418 |
419 | 00:14:20.033 --> 00:14:24.017
420 | ♪ I move on, forever longing ♪
421 |
422 | 00:14:25.100 --> 00:14:30.042
423 | ♪ For the home I found in your eyes ♪
424 |
425 | 00:14:32.150 --> 00:14:40.000
426 | ♪ Your voice saw me through the night. ♪
--------------------------------------------------------------------------------
/public/video/sintel/thumbs.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janumedia/vue-storybook-example/c22ac54c00a11a54df085be1e0723262f93a742b/public/video/sintel/thumbs.jpg
--------------------------------------------------------------------------------
/public/video/sintel/thumbs.vtt:
--------------------------------------------------------------------------------
1 | WEBVTT
2 |
3 | 00:00.000 --> 00:11.100
4 | thumbs.jpg#xywh=0,0,160,68
5 |
6 | 00:11.100 --> 00:22.200
7 | thumbs.jpg#xywh=160,0,160,68
8 |
9 | 00:22.200 --> 00:33.300
10 | thumbs.jpg#xywh=320,0,160,68
11 |
12 | 00:33.300 --> 00:44.400
13 | thumbs.jpg#xywh=480,0,160,68
14 |
15 | 00:44.400 --> 00:55.500
16 | thumbs.jpg#xywh=0,68,160,68
17 |
18 | 00:55.500 --> 01:06.600
19 | thumbs.jpg#xywh=160,68,160,68
20 |
21 | 01:06.600 --> 01:17.700
22 | thumbs.jpg#xywh=320,68,160,68
23 |
24 | 01:17.700 --> 01:28.800
25 | thumbs.jpg#xywh=480,68,160,68
26 |
27 | 01:28.800 --> 01:39.900
28 | thumbs.jpg#xywh=0,136,160,68
29 |
30 | 01:39.900 --> 01:51.000
31 | thumbs.jpg#xywh=160,136,160,68
32 |
33 | 01:51.000 --> 02:02.100
34 | thumbs.jpg#xywh=320,136,160,68
35 |
36 | 02:02.100 --> 02:13.200
37 | thumbs.jpg#xywh=480,136,160,68
38 |
39 | 02:13.200 --> 02:24.300
40 | thumbs.jpg#xywh=0,204,160,68
41 |
42 | 02:24.300 --> 02:35.400
43 | thumbs.jpg#xywh=160,204,160,68
44 |
45 | 02:35.400 --> 02:46.500
46 | thumbs.jpg#xywh=320,204,160,68
47 |
48 | 02:46.500 --> 02:57.600
49 | thumbs.jpg#xywh=480,204,160,68
50 |
51 | 02:57.600 --> 03:08.700
52 | thumbs.jpg#xywh=0,272,160,68
53 |
54 | 03:08.700 --> 03:19.800
55 | thumbs.jpg#xywh=160,272,160,68
56 |
57 | 03:19.800 --> 03:30.900
58 | thumbs.jpg#xywh=320,272,160,68
59 |
60 | 03:30.900 --> 03:42.000
61 | thumbs.jpg#xywh=480,272,160,68
62 |
63 | 03:42.000 --> 03:53.100
64 | thumbs.jpg#xywh=0,340,160,68
65 |
66 | 03:53.100 --> 04:04.200
67 | thumbs.jpg#xywh=160,340,160,68
68 |
69 | 04:04.200 --> 04:15.300
70 | thumbs.jpg#xywh=320,340,160,68
71 |
72 | 04:15.300 --> 04:26.400
73 | thumbs.jpg#xywh=480,340,160,68
74 |
75 | 04:26.400 --> 04:37.500
76 | thumbs.jpg#xywh=0,408,160,68
77 |
78 | 04:37.500 --> 04:48.600
79 | thumbs.jpg#xywh=160,408,160,68
80 |
81 | 04:48.600 --> 04:59.700
82 | thumbs.jpg#xywh=320,408,160,68
83 |
84 | 04:59.700 --> 05:10.800
85 | thumbs.jpg#xywh=480,408,160,68
86 |
87 | 05:10.800 --> 05:21.900
88 | thumbs.jpg#xywh=0,476,160,68
89 |
90 | 05:21.900 --> 05:33.000
91 | thumbs.jpg#xywh=160,476,160,68
92 |
93 | 05:33.000 --> 05:44.100
94 | thumbs.jpg#xywh=320,476,160,68
95 |
96 | 05:44.100 --> 05:55.200
97 | thumbs.jpg#xywh=480,476,160,68
98 |
99 | 05:55.200 --> 06:06.300
100 | thumbs.jpg#xywh=0,544,160,68
101 |
102 | 06:06.300 --> 06:17.400
103 | thumbs.jpg#xywh=160,544,160,68
104 |
105 | 06:17.400 --> 06:28.500
106 | thumbs.jpg#xywh=320,544,160,68
107 |
108 | 06:28.500 --> 06:39.600
109 | thumbs.jpg#xywh=480,544,160,68
110 |
111 | 06:39.600 --> 06:50.700
112 | thumbs.jpg#xywh=0,612,160,68
113 |
114 | 06:50.700 --> 07:01.800
115 | thumbs.jpg#xywh=160,612,160,68
116 |
117 | 07:01.800 --> 07:12.900
118 | thumbs.jpg#xywh=320,612,160,68
119 |
120 | 07:12.900 --> 07:24.000
121 | thumbs.jpg#xywh=480,612,160,68
122 |
123 | 07:24.000 --> 07:35.100
124 | thumbs.jpg#xywh=0,680,160,68
125 |
126 | 07:35.100 --> 07:46.200
127 | thumbs.jpg#xywh=160,680,160,68
128 |
129 | 07:46.200 --> 07:57.300
130 | thumbs.jpg#xywh=320,680,160,68
131 |
132 | 07:57.300 --> 08:08.400
133 | thumbs.jpg#xywh=480,680,160,68
134 |
135 | 08:08.400 --> 08:19.500
136 | thumbs.jpg#xywh=0,748,160,68
137 |
138 | 08:19.500 --> 08:30.600
139 | thumbs.jpg#xywh=160,748,160,68
140 |
141 | 08:30.600 --> 08:41.700
142 | thumbs.jpg#xywh=320,748,160,68
143 |
144 | 08:41.700 --> 08:52.800
145 | thumbs.jpg#xywh=480,748,160,68
146 |
147 | 08:52.800 --> 09:03.900
148 | thumbs.jpg#xywh=0,816,160,68
149 |
150 | 09:03.900 --> 09:15.000
151 | thumbs.jpg#xywh=160,816,160,68
152 |
153 | 09:15.000 --> 09:26.100
154 | thumbs.jpg#xywh=320,816,160,68
155 |
156 | 09:26.100 --> 09:37.200
157 | thumbs.jpg#xywh=480,816,160,68
158 |
159 | 09:37.200 --> 09:48.300
160 | thumbs.jpg#xywh=0,884,160,68
161 |
162 | 09:48.300 --> 09:59.400
163 | thumbs.jpg#xywh=160,884,160,68
164 |
165 | 09:59.400 --> 10:10.500
166 | thumbs.jpg#xywh=320,884,160,68
167 |
168 | 10:10.500 --> 10:21.600
169 | thumbs.jpg#xywh=480,884,160,68
170 |
171 | 10:21.600 --> 10:32.700
172 | thumbs.jpg#xywh=0,952,160,68
173 |
174 | 10:32.700 --> 10:43.800
175 | thumbs.jpg#xywh=160,952,160,68
176 |
177 | 10:43.800 --> 10:54.900
178 | thumbs.jpg#xywh=320,952,160,68
179 |
180 | 10:54.900 --> 11:06.000
181 | thumbs.jpg#xywh=480,952,160,68
182 |
183 | 11:06.000 --> 11:17.100
184 | thumbs.jpg#xywh=0,1020,160,68
185 |
186 | 11:17.100 --> 11:28.200
187 | thumbs.jpg#xywh=160,1020,160,68
188 |
189 | 11:28.200 --> 11:39.300
190 | thumbs.jpg#xywh=320,1020,160,68
191 |
192 | 11:39.300 --> 11:50.400
193 | thumbs.jpg#xywh=480,1020,160,68
194 |
195 | 11:50.400 --> 12:01.500
196 | thumbs.jpg#xywh=0,1088,160,68
197 |
198 | 12:01.500 --> 12:12.600
199 | thumbs.jpg#xywh=160,1088,160,68
200 |
201 | 12:12.600 --> 12:23.700
202 | thumbs.jpg#xywh=320,1088,160,68
203 |
204 | 12:23.700 --> 12:34.800
205 | thumbs.jpg#xywh=480,1088,160,68
206 |
207 | 12:34.800 --> 12:45.900
208 | thumbs.jpg#xywh=0,1156,160,68
209 |
210 | 12:45.900 --> 12:57.000
211 | thumbs.jpg#xywh=160,1156,160,68
212 |
213 | 12:57.000 --> 13:08.100
214 | thumbs.jpg#xywh=320,1156,160,68
215 |
216 | 13:08.100 --> 13:19.200
217 | thumbs.jpg#xywh=480,1156,160,68
218 |
219 | 13:19.200 --> 13:30.300
220 | thumbs.jpg#xywh=0,1224,160,68
221 |
222 | 13:30.300 --> 13:41.400
223 | thumbs.jpg#xywh=160,1224,160,68
224 |
225 | 13:41.400 --> 13:52.500
226 | thumbs.jpg#xywh=320,1224,160,68
227 |
228 | 13:52.500 --> 14:03.600
229 | thumbs.jpg#xywh=480,1224,160,68
230 |
231 | 14:03.600 --> 14:14.700
232 | thumbs.jpg#xywh=0,1292,160,68
233 |
234 | 14:14.700 --> 14:25.800
235 | thumbs.jpg#xywh=160,1292,160,68
236 |
237 | 14:25.800 --> 14:36.900
238 | thumbs.jpg#xywh=320,1292,160,68
239 |
240 | 14:36.900 --> 14:48.000
241 | thumbs.jpg#xywh=480,1292,160,68
242 |
243 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
19 |
45 |
--------------------------------------------------------------------------------
/src/assets/css/_anim.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janumedia/vue-storybook-example/c22ac54c00a11a54df085be1e0723262f93a742b/src/assets/css/_anim.scss
--------------------------------------------------------------------------------
/src/assets/css/_color.scss:
--------------------------------------------------------------------------------
1 | $primary: #102E5A;
2 | $primary-text: #F3F2F3;
3 | $secondary: #6D9FB5;
4 | $secondary-text: #FFF;//#102E5A;
5 | $border-color: #6D9FB5;
6 | $error: red;
7 | $error-text: #FFF;
8 | $disabled: rgb(218, 218, 218);
9 | $disabled-text: rgb(187, 186, 186);
10 | $background: #fff;
11 | $font-color: #102E5A;
--------------------------------------------------------------------------------
/src/assets/css/_mixin.scss:
--------------------------------------------------------------------------------
1 | @mixin translate($valueX, $valueY) {
2 | -webkit-transform:translate($valueX, $valueY);
3 | -moz-transform:translate($valueX, $valueY);
4 | -ms-transform:translate($valueX, $valueY);
5 | -o-transform:translate($valueX, $valueY);
6 | transform:translate($valueX, $valueY);
7 | }
8 | @mixin translateX($value) {
9 | -webkit-transform:translateX($value);
10 | -moz-transform:translateX($value);
11 | -ms-transform:translateX($value);
12 | -o-transform:translateX($value);
13 | transform:translateX($value);
14 | }
15 | @mixin translateY($value) {
16 | -webkit-transform:translateY($value);
17 | -moz-transform:translateY($value);
18 | -o-transform:translateY($value);
19 | -ms-transform:translateY($value);
20 | transform:translateY($value);
21 | }
22 | @mixin rotate($value) {
23 | -webkit-transform: rotate($value);
24 | -moz-transform: rotate($value);
25 | -o-transform: rotate($value);
26 | transform: rotate($value);
27 | }
28 | @mixin transition($properties...) {
29 | -webkit-transition: $properties;
30 | -moz-transition: $properties;
31 | -ms-transition: $properties;
32 | transition: $properties;
33 | //fix flickring issue https://goo.gl/7yCcm7
34 | //CoreAnimation issue on safari https://stackoverflow.com/a/24469750/1578100
35 | //-webkit-transform-style: preserve-3d;
36 | //-webkit-transform: translateZ(0);
37 | //-webkit-backface-visibility: hidden;
38 | }
39 | @mixin transition-duration($value) {
40 | -webkit-transition-duration: $value;
41 | -moz-transition-duration: $value;
42 | -ms-transition-duration:$value;
43 | transition-duration: $value;
44 | }
45 | @mixin transition-delay($value) {
46 | -webkit-transition-delay: $value;
47 | -moz-transition-delay: $value;
48 | -ms-transition-delay: $value;
49 | transition-delay: $value;
50 | }
51 | @mixin transition-timing-function($value) {
52 | -webkit-transition-timing-function: $value;
53 | -moz-transition-timing-function: $value;
54 | -ms-transition-timing-function: $value;
55 | transition-timing-function: $value;
56 | }
57 | @mixin animation($properties...) {
58 | -webkit-animation: $properties;
59 | -moz-animation: $properties;
60 | -ms-animation: $properties;
61 | -o-animation: $properties;
62 | animation: $properties;
63 | }
64 | /*
65 | @mixin border-radius($properties...) {
66 | border-radius: $properties;
67 | -webkit-border-radius: $properties;
68 | -moz-border-radius: $properties;
69 | }*/
--------------------------------------------------------------------------------
/src/assets/css/_normalize.scss:
--------------------------------------------------------------------------------
1 | @import '_reset.scss';
2 | @import '_color.scss';
3 |
4 | body, html {
5 | font-family: 'Avenir', Helvetica, Arial, sans-serif;
6 | font-size: 16px;
7 | color: $font-color;
8 | -webkit-font-smoothing: antialiased;
9 | -moz-osx-font-smoothing: grayscale;
10 | padding: 0;
11 | margin: 10px;
12 | }
--------------------------------------------------------------------------------
/src/assets/css/_reset.scss:
--------------------------------------------------------------------------------
1 | //reset box-size
2 | //https://css-tricks.com/box-sizing/
3 | *, *:after, *:before { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; }
4 |
5 | ul { padding: 0; margin: 0; }
6 | li { list-style: none; }
7 | :focus { outline: none; }
8 | a { text-decoration: none; outline: none; }
9 | a img { border: 0; }
10 |
11 | // iOS shadow removed
12 | input {
13 | -webkit-appearance: none;
14 | -moz-appearance: none;
15 | box-shadow: none;
16 | }
17 |
18 | // avoid zoom in iOS mobile device when entering input
19 | @media screen and (-webkit-min-device-pixel-ratio:0) {
20 | select,
21 | textarea,
22 | input,
23 | label,
24 | button {
25 | font-size: 16px;
26 | -webkit-tap-highlight-color: rgba(0,0,0,0); //remove tap highlight color
27 | }
28 | }
--------------------------------------------------------------------------------
/src/assets/css/_utils.scss:
--------------------------------------------------------------------------------
1 | .text--center {
2 | text-align: center;
3 | }
4 | .text--left {
5 | text-align: left;
6 | }
7 | .text--right {
8 | text-align: right;
9 | }
10 | .font--bold {
11 | font-weight: bold;
12 | }
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janumedia/vue-storybook-example/c22ac54c00a11a54df085be1e0723262f93a742b/src/assets/logo.png
--------------------------------------------------------------------------------
/src/assets/storybook+vue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/janumedia/vue-storybook-example/c22ac54c00a11a54df085be1e0723262f93a742b/src/assets/storybook+vue.png
--------------------------------------------------------------------------------
/src/components/HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ msg }}
4 |
5 | For a guide and recipes on how to configure / customize this project,
6 | check out the
7 | vue-cli documentation.
8 |
9 |
Installed CLI Plugins
10 |
15 |
Essential Links
16 |
23 |
Ecosystem
24 |
31 |
32 |
33 |
34 |
42 |
43 |
44 |
60 |
--------------------------------------------------------------------------------
/src/components/core/Button.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
22 |
102 |
--------------------------------------------------------------------------------
/src/components/core/ButtonWrapper.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
15 |
40 |
--------------------------------------------------------------------------------
/src/components/core/Checkbox.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
41 |
114 |
--------------------------------------------------------------------------------
/src/components/core/Input.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
14 |
15 |
16 |
17 |
18 |
83 |
125 |
126 |
--------------------------------------------------------------------------------
/src/components/core/RadioButton.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
26 |
95 |
96 |
--------------------------------------------------------------------------------
/src/components/core/SwitchButton.vue:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
58 |
174 |
--------------------------------------------------------------------------------
/src/components/core/ToggleButton.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
17 |
18 |
19 |
60 |
--------------------------------------------------------------------------------
/src/components/media/Icon.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/media/LazyImage.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
![]()
4 |
5 |
6 |
111 |
120 |
--------------------------------------------------------------------------------
/src/components/media/VideoPlayer.vue:
--------------------------------------------------------------------------------
1 |
204 |
205 |
206 |
218 |
219 |
220 |
223 |
226 |
229 |
232 |
235 |
236 |
237 |
238 |
{{videoSeek}}
239 |
240 |
243 |
246 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 | {{videoCurrentTime}} / {{videoDuration}}
257 |
258 |
261 |
264 |
265 |
266 |
267 |
268 |
269 |
399 |
--------------------------------------------------------------------------------
/src/layouts/default.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Home
5 | Setup
6 | Media
7 | 404
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/layouts/no-navigation.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
21 |
22 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import router from './router'
4 |
5 | import DefaultLayout from './layouts/default'
6 | import NoNavigationLayout from './layouts/no-navigation'
7 |
8 | Vue.config.productionTip = false
9 |
10 | //register layouts
11 | Vue.component('default-layout', DefaultLayout);
12 | Vue.component('no-nav-layout', NoNavigationLayout);
13 |
14 | //register async components
15 | Vue.component('custom-button', () => import(/* webpackChunkName: "custom-button" */ '@/components/core/Button'));
16 | Vue.component('input-text', () => import(/* webpackChunkName: "input-text" */ '@/components/core/Input'));
17 | Vue.component('checkbox', () => import(/* webpackChunkName: "checkbox" */ '@/components/core/Checkbox'));
18 | Vue.component('radio-button', () => import(/* webpackChunkName: "radio-button" */ '@/components/core/RadioButton'));
19 | Vue.component('switch-button', () => import(/* webpackChunkName: "switch-button" */ '@/components/core/SwitchButton'));
20 |
21 | new Vue({
22 | router,
23 | render: h => h(App),
24 | }).$mount('#app')
25 |
--------------------------------------------------------------------------------
/src/router.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 | import Home from '@/views/Home.vue'
4 |
5 | Vue.use(Router);
6 |
7 | export default new Router({
8 | mode: 'history',
9 | base: process.env.BASE_URL,
10 | routes: [
11 | {
12 | path: '/',
13 | name: 'home',
14 | component: Home
15 | },
16 | {
17 | path: '/setup',
18 | name: 'setup',
19 | component: () => import(/* webpackChunkName: "setup" */ '@/views/Setup.vue')
20 | },
21 | {
22 | path: '/media',
23 | name: 'media',
24 | component: () => import(/* webpackChunkName: "setup" */ '@/views/Media.vue')
25 | },
26 | {
27 | path: '*',
28 | name: '404',
29 | meta: { layout: 'no-nav' },
30 | component: () => import(/* webpackChunkName: "404" */ '@/views/404.vue')
31 | }
32 | ]
33 | })
--------------------------------------------------------------------------------
/src/stories/AppDecorator.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
26 |
--------------------------------------------------------------------------------
/src/stories/Welcome.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
Welcome to Storybook + Vue Example
5 |
6 | For a guide and recipes on how to configure / customize Storybook Vue,
7 | check the following links or refer to
8 | this source.
9 |
10 |
Step by Step Guides
11 |
17 |
Essential Links
18 |
24 |
25 |
26 |
27 |
35 |
36 |
37 |
69 |
--------------------------------------------------------------------------------
/src/stories/index.js:
--------------------------------------------------------------------------------
1 | import { storiesOf } from '@storybook/vue'
2 | //import addons
3 | import { linkTo } from '@storybook/addon-links'
4 | import { action, decorate } from '@storybook/addon-actions'
5 | import { configureViewport, INITIAL_VIEWPORTS } from '@storybook/addon-viewport'
6 | import { withKnobs, text, boolean, number, select, color } from '@storybook/addon-knobs';
7 | //
8 | import StoryRouter from 'storybook-vue-router'
9 |
10 | import App from '@/App'
11 | import Welcome from './Welcome'
12 |
13 | import * as Icons from '@/components/media/Icon'
14 |
15 | import router from '@/router'
16 |
17 | configureViewport({
18 | viewports: {
19 | ...INITIAL_VIEWPORTS
20 | }
21 | });
22 |
23 | storiesOf('Page|Welcome', module)
24 | .addParameters({
25 | options: {
26 | selectedAddonPanel: 'storybook-addon-viewport/addon-panel'
27 | }
28 | })
29 | .add('welcome', () => ({
30 | render: h => h(Welcome)
31 | }));
32 |
33 | storiesOf('Page|App', module)
34 | .addDecorator(StoryRouter({}, router.options))
35 | .addParameters({
36 | options: {
37 | selectedAddonPanel: 'storybook-addon-viewport/addon-panel'
38 | }
39 | })
40 | .add('app with router', () => ({
41 | render: h => h(App)
42 | }));
43 |
44 | storiesOf('Components|Button', module)
45 | .add('default', () => ({
46 | template: 'Default Button'
47 | }))
48 | .add('rounded', () => ({
49 | template: 'Rounded Button'
50 | }))
51 | .add('uppercase', () => ({
52 | template: 'Uppercase Button'
53 | }))
54 | .add('primary', () => ({
55 | template: 'Primary Button'
56 | }))
57 | .add('disabled', () => ({
58 | template: 'Disabled Button'
59 | }))
60 | .add('emoji & symbol', () => ({
61 | template: '😎🌍🍺💯'
62 | }))
63 | .add('custom font size', () => ({
64 | template: '30px
40px
'
65 | }));
66 |
67 | storiesOf('Components|Input', module)
68 | .add('default', () => ({
69 | template: ''
70 | }))
71 | .add('placeholder', () => ({
72 | template: ''
73 | }))
74 | .add('prefix', () => ({
75 | template: ''
76 | }))
77 | .add('suffix', () => ({
78 | template: ''
79 | }))
80 | .add('emoji & symbol', () => ({
81 | template: `
82 |
83 |
84 |
85 |
86 | `
87 | }))
88 | .add('custom width', () => ({
89 | template: ''
90 | }));
91 |
92 | storiesOf('Components|Checkbox', module)
93 | .add('default', () => ({
94 | template: `
95 |
96 | Default One
97 | Default Two
98 |
`
99 | }))
100 | .add('fill', () => ({
101 | template: `
102 |
103 | Fill One
104 | Fill Two
105 |
`
106 | }))
107 | .add('custom font size', () => ({
108 | template: `
109 |
110 | 30px
111 | 40px
112 |
`
113 | }));
114 |
115 | storiesOf('Components|RadioButton', module)
116 | .add('default', () => ({
117 | template: `
118 |
119 | Default One
120 | Default Two
121 |
122 | `
123 | }))
124 | .add('fill', () => ({
125 | template: `
126 |
127 | Fill One
128 | Fill Two
129 |
130 | `
131 | }))
132 | .add('custom font size', () => ({
133 | template: `
134 |
135 | 30px
136 | 40px
137 |
138 | `
139 | }))
140 |
141 | storiesOf('Components|SwitchButton', module)
142 | .add('default', () => ({
143 | template: ``
144 | }))
145 | .add('rounded', () => ({
146 | template: ``
147 | }))
148 | .add('rounded + label', () => ({
149 | template: `My Label`
150 | }))
151 | .add('rounded + on + off', () => ({
152 | template: ``
153 | }))
154 | .add('rounded + disabled', () => ({
155 | template: `Disabled`
156 | }))
157 | .add('custom font size', () => ({
158 | template: `
159 |
160 | 20px
161 | 40px
162 |
163 | `
164 | }));
165 |
166 | storiesOf('Components|LazyImage', module)
167 | .addParameters({
168 | options: {
169 | selectedAddonPanel: 'storybook-addon-viewport/addon-panel'
170 | }
171 | })
172 | .add('default', () => ({
173 | template: `
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 | `
182 | }))
183 | .add('custom placeHolder', () => ({
184 | template: `
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 | `
193 | }));
194 |
195 | storiesOf('Components|Icon', module)
196 | .addDecorator(withKnobs)
197 | .addParameters({
198 | options: {
199 | addonPanelInRight: true,
200 | selectedAddonPanel: 'storybooks/storybook-addon-knobs'
201 | }
202 | })
203 | .add('Icon List', () => ({
204 | props: {
205 | color: {
206 | type: String,
207 | default: color('color', '#F8E71C')
208 | },
209 | width: {
210 | type: Number,
211 | default: number('width', 80, {
212 | range: true,
213 | min: 80,
214 | max: 200,
215 | step: 10
216 | })
217 | },
218 | height: {
219 | type: Number,
220 | default: number('height', 80, {
221 | range: true,
222 | min: 80,
223 | max: 200,
224 | step: 10
225 | })
226 | }
227 | },
228 | render(h) {
229 | return (
230 |
231 | {Object.keys(Icons).map(iconName => {
232 | if(iconName !== 'default') return(
233 |
234 | {h(Icons[iconName], {props:{width:this.width, height:this.height, color:this.color}})}
235 |
{iconName}
236 |
237 |
238 | )
239 | })}
240 |
241 | )
242 | }
243 | }));
244 |
245 | storiesOf('Components|VideoPlayer', module)
246 | .addParameters({
247 | options: {
248 | selectedAddonPanel: 'storybook-addon-viewport/addon-panel'
249 | }
250 | })
251 | .add('Video default', () => ({
252 | template:`
253 |
254 |
255 |
259 | `
260 | }))
261 |
262 | // decorate return first argument as new value
263 | const firstArg = decorate([args => {
264 | return Array.isArray(args[0]) ? args[0] : [args[0]]
265 | }]);
266 |
267 | storiesOf('Addons|Actions', module)
268 | .addParameters({
269 | options: {
270 | addonPanelInRight: true,
271 | selectedAddonPanel: 'storybook/actions/actions-panel'
272 | }
273 | })
274 | .add('Button: click', () => ({
275 | template: 'Click Me!',
276 | methods: {
277 | handleClick: action('click')
278 | }
279 | }))
280 | .add('Checkbox: v-model', () => ({
281 | template: `
282 |
283 | Select your favorite fruit:
284 | Manggo
285 | Orange
286 |
`,
287 | data() {
288 | return {
289 | listValues: ["Orange"]
290 | }
291 | },
292 | watch: firstArg.actions('listValues')
293 | }))
294 | .add('RadioButton: v-model', () => ({
295 | template: `
296 |
297 | Select the best browser:
298 | Chrome
299 | Safari
300 | Firefox
301 |
`,
302 | data() {
303 | return {
304 | value: null
305 | }
306 | },
307 | watch: {
308 | value: firstArg.action('value')
309 | }
310 | }))
311 | .add('SwitchButton: input', () => ({
312 | template: '',
313 | methods: {
314 | handleInput: action('input')
315 | }
316 | }))
317 | .add('SwitchButton: v-model', () => ({
318 | template: '',
319 | data() {
320 | return {
321 | value: null
322 | }
323 | },
324 | watch: {
325 | value: firstArg.action('value')
326 | }
327 | }));
328 |
329 | storiesOf('Addons|Knobs', module)
330 | .addDecorator(withKnobs)
331 | .addParameters({
332 | options: {
333 | addonPanelInRight: true,
334 | selectedAddonPanel: 'storybooks/storybook-addon-knobs'
335 | }
336 | })
337 | .add('Button', () => ({
338 | props: {
339 | label: {
340 | type: String,
341 | default: text('label', 'Button Label 💯')
342 | },
343 | rounded: {
344 | type: Boolean,
345 | default: boolean('rounded', true)
346 | },
347 | primary: {
348 | type: Boolean,
349 | default: boolean('primary', false)
350 | },
351 | disabled: {
352 | type: Boolean,
353 | default: boolean('disabled', false)
354 | },
355 | fontSize: {
356 | type: String,
357 | default: `${number('font-size', 16, {
358 | range: true,
359 | min: 0,
360 | max: 60,
361 | step: 5
362 | })}px`
363 | }
364 | },
365 | template: `{{ label }}`
366 | }))
367 | .add('SwitchButton', () => ({
368 | props: {
369 | on: {
370 | type: String,
371 | default: text('on', 'ON')
372 | },
373 | off: {
374 | type: String,
375 | default: text('off', 'OFF')
376 | },
377 | rounded: {
378 | type: Boolean,
379 | default: boolean('rounded', true)
380 | },
381 | disabled: {
382 | type: Boolean,
383 | default: boolean('disabled', false)
384 | },
385 | fontSize: {
386 | type: String,
387 | default: `${number('font-size', 16, {
388 | range: true,
389 | min: 0,
390 | max: 60,
391 | step: 5
392 | })}px`
393 | }
394 | },
395 | template: ``
396 | }))
397 | .add('Input', () => ({
398 | props: {
399 | placeholder: {
400 | type: String,
401 | default: text('placeholder', 'Place Holder')
402 | },
403 | prefix: {
404 | type: String,
405 | default: text('prefix', '💲')
406 | },
407 | suffix: {
408 | type: String,
409 | default: text('suffix', '℉')
410 | },
411 | fontSize: {
412 | type: String,
413 | default: `${number('font-size', 16, {
414 | range: true,
415 | min: 0,
416 | max: 60,
417 | step: 5
418 | })}px`
419 | }
420 | },
421 | template: ''
422 | }));
423 |
424 | storiesOf("Addons|Links", module)
425 | .add('linkTo', () => ({
426 | template: 'Go to Welcome',
427 | methods: {
428 | handleClick: linkTo('Welcome', 'welcome')
429 | }
430 | }));
431 |
432 | // Writing Stories using Decorators
433 | // https://storybook.js.org/basics/writing-stories/#using-decorators
434 | // custom styles
435 | const centerWrapper = {
436 | position: 'absolute',
437 | top: 0,
438 | bottom: 0,
439 | left: 0,
440 | right: 0,
441 | display: 'table',
442 | width: '100%',
443 | height: '100vh',
444 | textAlign: 'center',
445 | padding: '0.5em'
446 | }
447 | const center = {
448 | position: 'relative',
449 | display: 'table-cell',
450 | verticalAlign: 'middle',
451 | }
452 |
453 | //custom decorator using story function
454 | const storyFunction = (storyFn) => {
455 | const storyFnWrapper = storyFn();
456 | return {
457 | components: {storyFnWrapper},
458 | data(){
459 | return {
460 | centerWrapper,
461 | center
462 | }
463 | },
464 | template: ''
465 | }
466 | };
467 | //custom decorator using story component
468 | const storyComponent = () => {
469 | return {
470 | data(){
471 | return {
472 | centerWrapper: {...centerWrapper, backgroundColor: '#eef'},
473 | center
474 | }
475 | },
476 | template: ''
477 | }
478 | };
479 | //custom decorator using custom vue component
480 | import AppDecorator from './AppDecorator';
481 | const vueComponent = () => ({
482 | components: {AppDecorator},
483 | template: ''
484 | });
485 |
486 | storiesOf('Customs|Decorator/with story function', module)
487 | .addDecorator(storyFunction)
488 | .add('Button', () => ({
489 | template: 'Centered Button'
490 | }))
491 | .add('SwitchButton', () => ({
492 | template: `Centered`
493 | }));
494 |
495 | storiesOf('Customs|Decorator/with story component', module)
496 | .addDecorator(storyComponent)
497 | .add('Button', () => ({
498 | template: 'Centered Button'
499 | }))
500 | .add('SwitchButton', () => ({
501 | template: `Centered`
502 | }));
503 |
504 | storiesOf('Customs|Decorator/with vue component', module)
505 | .addDecorator(vueComponent)
506 | .add('Button', () => ({
507 | template: 'Centered Button'
508 | }))
509 | .add('SwitchButton', () => ({
510 | template: `Centered`
511 | }))
512 |
--------------------------------------------------------------------------------
/src/utils/utils.js:
--------------------------------------------------------------------------------
1 | let intervalData = {};
2 |
3 | export const iOSDevice = () => /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
4 | export const isMobile = () => {
5 | //https://stackoverflow.com/a/21742107/1578100
6 | const userAgent = navigator.userAgent || navigator.vendor || window.opera;
7 | return /android/i.test(userAgent) || /iPad|iPhone|iPhone/.test(userAgent) && !window.MSStream
8 | }
9 |
10 | export const addClass = (el, className) => {
11 | el.className += ` ${className}`;
12 | }
13 | export const removeClass = (el, className) => {
14 | el.className = el.className.replace(new RegExp(`(?:^|\\s)${className}(?!\\S)`),'');
15 | }
16 |
17 | export default {
18 |
19 | hide(el) {
20 | el.style.display = "none";
21 | return new Promise((resolve) => resolve);
22 | },
23 | show(el) {
24 | el.style.opacity = 1;
25 | el.style.display = "block";
26 | return new Promise((resolve) => resolve);
27 | },
28 | setOpacity(el, value) {
29 | if(el) el.style.opacity = value;
30 | },
31 | fadeOut(el, doneRemoveAfterDone, duration) {
32 | el.style.opacity = el.style.opacity || 1;
33 | clearTimeout(intervalData[el.innerHTML]);
34 | return new Promise((resolve) => {
35 | (function fade() {
36 | if((el.style.opacity -= .1) < 0)
37 | {
38 | if(!doneRemoveAfterDone) el.style.display = "none";
39 | resolve();
40 | } else
41 | {
42 | intervalData[el.innerHTML] = setTimeout(fade, duration || 20);
43 | }
44 | })();
45 | })
46 | },
47 | fadeIn(el, duration) {
48 | if(!el.style.display || el.style.display == "none") el.style.display = "block";
49 | el.style.opacity = el.style.opacity || 0;
50 | clearTimeout(intervalData[el.innerHTML]);
51 | let opacity = 0;
52 | return new Promise((resolve) => {
53 | (function fade() {
54 | opacity = parseFloat(el.style.opacity);
55 | if((opacity += .1) > 1)
56 | {
57 | resolve();
58 | } else
59 | {
60 | el.style.opacity = opacity;
61 | intervalData[el.innerHTML] = setTimeout(fade, duration || 20);
62 | }
63 | })();
64 | })
65 | },
66 | clearFade() {
67 | Object.keys(intervalData).map(key => {
68 | clearTimeout(intervalData[key]);
69 | intervalData[key] = null;
70 | })
71 | },
72 | delay(duration) {
73 | return new Promise((resolve) => setTimeout(resolve , duration));
74 | },
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/src/views/404.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Error {{ statusCode }}
4 | {{ message }}
5 | Go to Home
6 |
7 |
8 |
24 |
--------------------------------------------------------------------------------
/src/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
5 |
6 |
7 |
15 |
--------------------------------------------------------------------------------
/src/views/Media.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Video Type Not Supported!!!
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
38 |
--------------------------------------------------------------------------------
/src/views/Setup.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Setup Page
4 |
5 |
Your favorite fruits
6 |
9 |
The best browser
10 |
13 |
Allow cookies
14 |
15 |
Annual tax
16 |
17 |
18 |
19 |
Save Setup
20 |
21 |
22 |
23 |
24 |
25 |
35 |
50 |
51 |
--------------------------------------------------------------------------------
/tests/unit/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | jest: true
4 | }
5 | }
--------------------------------------------------------------------------------
/tests/unit/example.spec.js:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------