🎉
18
.eslintrc.js
@@ -4,17 +4,19 @@ module.exports = {
|
||||
node: true
|
||||
},
|
||||
extends: [
|
||||
"plugin:vue/essential",
|
||||
"eslint:recommended",
|
||||
"@vue/typescript/recommended",
|
||||
"@vue/prettier",
|
||||
"@vue/prettier/@typescript-eslint"
|
||||
'plugin:vue/essential',
|
||||
'eslint:recommended',
|
||||
'@vue/typescript/recommended',
|
||||
'@vue/prettier',
|
||||
'@vue/prettier/@typescript-eslint'
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 2020
|
||||
},
|
||||
rules: {
|
||||
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
|
||||
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off"
|
||||
'@typescript-eslint/camelcase': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
1
.node-version
Normal file
@@ -0,0 +1 @@
|
||||
v14.4.0
|
||||
5
.prettierrc
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"arrowParens": "always"
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
module.exports = {
|
||||
presets: ["@vue/cli-plugin-babel/preset"]
|
||||
};
|
||||
presets: ['@vue/cli-plugin-babel/preset']
|
||||
}
|
||||
|
||||
4
netlify.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[[redirects]]
|
||||
from = "/*"
|
||||
to = "/"
|
||||
status = 200
|
||||
@@ -8,11 +8,13 @@
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vue/composition-api": "^1.0.0-beta.1",
|
||||
"core-js": "^3.6.5",
|
||||
"register-service-worker": "^1.7.1",
|
||||
"vue": "^2.6.11",
|
||||
"vue-router": "^3.2.0",
|
||||
"vuex": "^3.4.0"
|
||||
"vuex": "^3.4.0",
|
||||
"youtube-video-js": "^3.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^2.33.0",
|
||||
|
||||
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 799 B After Width: | Height: | Size: 433 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 781 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.0 KiB |
@@ -1,3 +1,8 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.00251 14.9297L0 1.07422H6.14651L8.00251 4.27503L9.84583 1.07422H16L8.00251 14.9297Z" fill="black"/>
|
||||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="512" height="512" fill="#F8EFBA"/>
|
||||
<path d="M305.042 343.875V324.458C305.042 314.159 300.95 304.282 293.668 296.999C286.385 289.716 276.508 285.625 266.208 285.625H188.542C178.242 285.625 168.365 289.716 161.082 296.999C153.8 304.282 149.708 314.159 149.708 324.458V343.875" stroke="black" stroke-width="12" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M227.375 246.792C248.822 246.792 266.208 229.405 266.208 207.958C266.208 186.511 248.822 169.125 227.375 169.125C205.928 169.125 188.542 186.511 188.542 207.958C188.542 229.405 205.928 246.792 227.375 246.792Z" stroke="black" stroke-width="12" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M363.292 343.875V324.458C363.285 315.854 360.421 307.496 355.15 300.695C349.878 293.895 342.498 289.038 334.167 286.887" stroke="black" stroke-width="12" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M295.333 170.387C303.687 172.526 311.09 177.384 316.378 184.195C321.665 191.007 324.534 199.384 324.534 208.007C324.534 216.63 321.665 225.007 316.378 231.818C311.09 238.63 303.687 243.488 295.333 245.627" stroke="black" stroke-width="12" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<rect x="140" y="140" width="233" height="233" stroke="white"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 215 B After Width: | Height: | Size: 1.3 KiB |
8
public/logo.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="512" height="512" fill="#F8EFBA"/>
|
||||
<path d="M305.042 343.875V324.458C305.042 314.159 300.95 304.282 293.668 296.999C286.385 289.716 276.508 285.625 266.208 285.625H188.542C178.242 285.625 168.365 289.716 161.082 296.999C153.8 304.282 149.708 314.159 149.708 324.458V343.875" stroke="black" stroke-width="12" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M227.375 246.792C248.822 246.792 266.208 229.405 266.208 207.958C266.208 186.511 248.822 169.125 227.375 169.125C205.928 169.125 188.542 186.511 188.542 207.958C188.542 229.405 205.928 246.792 227.375 246.792Z" stroke="black" stroke-width="12" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M363.292 343.875V324.458C363.285 315.854 360.421 307.496 355.15 300.695C349.878 293.895 342.498 289.038 334.167 286.887" stroke="black" stroke-width="12" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M295.333 170.387C303.687 172.526 311.09 177.384 316.378 184.195C321.665 191.007 324.534 199.384 324.534 208.007C324.534 216.63 321.665 225.007 316.378 231.818C311.09 238.63 303.687 243.488 295.333 245.627" stroke="black" stroke-width="12" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<rect x="140" y="140" width="233" height="233" stroke="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
28
src/App.vue
@@ -1,32 +1,16 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<div id="nav">
|
||||
<router-link to="/">Home</router-link> |
|
||||
<router-link to="/about">About</router-link>
|
||||
</div>
|
||||
<h1>Bons programmeurs</h1>
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import '@/styles/app';
|
||||
|
||||
#app {
|
||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
#nav {
|
||||
padding: 30px;
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
color: #2c3e50;
|
||||
|
||||
&.router-link-exact-active {
|
||||
color: #42b983;
|
||||
}
|
||||
}
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
Before Width: | Height: | Size: 6.7 KiB |
BIN
src/assets/sounds/move.mp3
Normal file
27
src/components/DreamMaker.vue
Normal file
@@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<div class="dream-maker">
|
||||
<h2>Coder {{ position }}</h2>
|
||||
<h4 v-show="isTurn">{{ session }}</h4>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from '@vue/composition-api'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'DreamMaker',
|
||||
props: {
|
||||
position: { type: String, required: true },
|
||||
isTurn: { type: Boolean, required: true },
|
||||
session: { type: String, required: true }
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dream-maker {
|
||||
h4 {
|
||||
font-size: 24pt;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,148 +0,0 @@
|
||||
<template>
|
||||
<div class="hello">
|
||||
<h1>{{ msg }}</h1>
|
||||
<p>
|
||||
For a guide and recipes on how to configure / customize this project,<br />
|
||||
check out the
|
||||
<a href="https://cli.vuejs.org" target="_blank" rel="noopener"
|
||||
>vue-cli documentation</a
|
||||
>.
|
||||
</p>
|
||||
<h3>Installed CLI Plugins</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<a
|
||||
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>babel</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-typescript"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>typescript</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>pwa</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>router</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>vuex</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>eslint</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Essential Links</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://forum.vuejs.org" target="_blank" rel="noopener"
|
||||
>Forum</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://chat.vuejs.org" target="_blank" rel="noopener"
|
||||
>Community Chat</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://twitter.com/vuejs" target="_blank" rel="noopener"
|
||||
>Twitter</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Ecosystem</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://router.vuejs.org" target="_blank" rel="noopener"
|
||||
>vue-router</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://github.com/vuejs/vue-devtools#vue-devtools"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>vue-devtools</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener"
|
||||
>vue-loader</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://github.com/vuejs/awesome-vue"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>awesome-vue</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
export default Vue.extend({
|
||||
name: "HelloWorld",
|
||||
props: {
|
||||
msg: String
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped lang="scss">
|
||||
h3 {
|
||||
margin: 40px 0 0;
|
||||
}
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
li {
|
||||
display: inline-block;
|
||||
margin: 0 10px;
|
||||
}
|
||||
a {
|
||||
color: #42b983;
|
||||
}
|
||||
</style>
|
||||
19
src/main.ts
@@ -1,13 +1,16 @@
|
||||
import Vue from "vue";
|
||||
import App from "./App.vue";
|
||||
import "./registerServiceWorker";
|
||||
import router from "./router";
|
||||
import store from "./store";
|
||||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
import './registerServiceWorker'
|
||||
import router from './router'
|
||||
import store from './store'
|
||||
import VueCompositionAPI from '@vue/composition-api'
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
Vue.use(VueCompositionAPI)
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
new Vue({
|
||||
router,
|
||||
store,
|
||||
render: h => h(App)
|
||||
}).$mount("#app");
|
||||
render: (h) => h(App)
|
||||
}).$mount('#app')
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
/* eslint-disable no-console */
|
||||
|
||||
import { register } from "register-service-worker";
|
||||
import { register } from 'register-service-worker'
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
register(`${process.env.BASE_URL}service-worker.js`, {
|
||||
ready() {
|
||||
console.log(
|
||||
"App is being served from cache by a service worker.\n" +
|
||||
"For more details, visit https://goo.gl/AFskqB"
|
||||
);
|
||||
'App is being served from cache by a service worker.\n' +
|
||||
'For more details, visit https://goo.gl/AFskqB'
|
||||
)
|
||||
},
|
||||
registered() {
|
||||
console.log("Service worker has been registered.");
|
||||
console.log('Service worker has been registered.')
|
||||
},
|
||||
cached() {
|
||||
console.log("Content has been cached for offline use.");
|
||||
console.log('Content has been cached for offline use.')
|
||||
},
|
||||
updatefound() {
|
||||
console.log("New content is downloading.");
|
||||
console.log('New content is downloading.')
|
||||
},
|
||||
updated() {
|
||||
console.log("New content is available; please refresh.");
|
||||
console.log('New content is available; please refresh.')
|
||||
},
|
||||
offline() {
|
||||
console.log(
|
||||
"No internet connection found. App is running in offline mode."
|
||||
);
|
||||
'No internet connection found. App is running in offline mode.'
|
||||
)
|
||||
},
|
||||
error(error) {
|
||||
console.error("Error during service worker registration:", error);
|
||||
console.error('Error during service worker registration:', error)
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,30 +1,21 @@
|
||||
import Vue from "vue";
|
||||
import VueRouter, { RouteConfig } from "vue-router";
|
||||
import Home from "../views/Home.vue";
|
||||
import Vue from 'vue'
|
||||
import VueRouter, { RouteConfig } from 'vue-router'
|
||||
import Home from '../views/Home.vue'
|
||||
|
||||
Vue.use(VueRouter);
|
||||
Vue.use(VueRouter)
|
||||
|
||||
const routes: Array<RouteConfig> = [
|
||||
{
|
||||
path: "/",
|
||||
name: "Home",
|
||||
path: '/',
|
||||
name: 'Home',
|
||||
component: Home
|
||||
},
|
||||
{
|
||||
path: "/about",
|
||||
name: "About",
|
||||
// route level code-splitting
|
||||
// this generates a separate chunk (about.[hash].js) for this route
|
||||
// which is lazy-loaded when the route is visited.
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "about" */ "../views/About.vue")
|
||||
}
|
||||
];
|
||||
]
|
||||
|
||||
const router = new VueRouter({
|
||||
mode: "history",
|
||||
mode: 'history',
|
||||
base: process.env.BASE_URL,
|
||||
routes
|
||||
});
|
||||
})
|
||||
|
||||
export default router;
|
||||
export default router
|
||||
|
||||
4
src/shims-tsx.d.ts
vendored
@@ -1,4 +1,4 @@
|
||||
import Vue, { VNode } from "vue";
|
||||
import Vue, { VNode } from 'vue'
|
||||
|
||||
declare global {
|
||||
namespace JSX {
|
||||
@@ -7,7 +7,7 @@ declare global {
|
||||
// tslint:disable no-empty-interface
|
||||
interface ElementClass extends Vue {}
|
||||
interface IntrinsicElements {
|
||||
[elem: string]: any;
|
||||
[elem: string]: any
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
6
src/shims-vue.d.ts
vendored
@@ -1,4 +1,4 @@
|
||||
declare module "*.vue" {
|
||||
import Vue from "vue";
|
||||
export default Vue;
|
||||
declare module '*.vue' {
|
||||
import Vue from 'vue'
|
||||
export default Vue
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import Vue from "vue";
|
||||
import Vuex from "vuex";
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
Vue.use(Vuex);
|
||||
Vue.use(Vuex)
|
||||
|
||||
export default new Vuex.Store({
|
||||
state: {},
|
||||
mutations: {},
|
||||
actions: {},
|
||||
modules: {}
|
||||
});
|
||||
})
|
||||
|
||||
31
src/styles/app.scss
Normal file
@@ -0,0 +1,31 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Anonymous+Pro&display=swap');
|
||||
|
||||
$color: #f8efba;
|
||||
|
||||
body {
|
||||
text-align: center;
|
||||
font-family: 'Anonymous Pro', monospace;
|
||||
background-color: #2c3a47;
|
||||
color: $color;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
font-family: 'Anonymous Pro', monospace;
|
||||
border: none;
|
||||
padding: 1rem;
|
||||
text-decoration: none;
|
||||
background: #0069ed;
|
||||
color: $color;
|
||||
cursor: pointer;
|
||||
transition: background 250ms ease-in-out, transform 150ms ease;
|
||||
}
|
||||
|
||||
button:hover,
|
||||
button:focus {
|
||||
background: #0053ba;
|
||||
}
|
||||
|
||||
button:active {
|
||||
transform: scale(0.99);
|
||||
}
|
||||
19
src/utils/notification.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
declare const Notification: any
|
||||
|
||||
export const notify = (message: string) => {
|
||||
if (!('Notification' in window)) {
|
||||
return
|
||||
} else if (Notification.permission === 'granted') {
|
||||
new Notification(message)
|
||||
} else if (Notification.permission !== 'denied') {
|
||||
Notification.requestPermission((permission: any) => {
|
||||
if (!('permission' in Notification)) {
|
||||
Notification.permission = permission
|
||||
}
|
||||
|
||||
if (permission === 'granted') {
|
||||
new Notification(message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,156 @@
|
||||
<template>
|
||||
<div class="home">
|
||||
<img alt="Vue logo" src="../assets/logo.png" />
|
||||
<HelloWorld msg="Welcome to Your Vue.js App" />
|
||||
<section class="brogrammers">
|
||||
<DreamMaker
|
||||
position="1"
|
||||
:is-turn="isProgrammer1Turn"
|
||||
:session="session"
|
||||
/>
|
||||
<DreamMaker
|
||||
position="2"
|
||||
:is-turn="!isProgrammer1Turn"
|
||||
:session="session"
|
||||
/>
|
||||
</section>
|
||||
<div class="global-time">{{ time }}</div>
|
||||
<div class="actions">
|
||||
<button v-if="timeState === 'stopped'" @click="start">play</button>
|
||||
<button v-if="timeState === 'started'" @click="stop">stop</button>
|
||||
</div>
|
||||
<youtube-video
|
||||
v-show="false"
|
||||
src="https://www.youtube-nocookie.com/embed/5qap5aO4i9A"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// @ is an alias to /src
|
||||
import HelloWorld from "@/components/HelloWorld.vue";
|
||||
<script lang="ts">
|
||||
import 'youtube-video-js'
|
||||
import {
|
||||
ref,
|
||||
watchEffect,
|
||||
defineComponent,
|
||||
onMounted,
|
||||
computed,
|
||||
onUnmounted
|
||||
} from '@vue/composition-api'
|
||||
import DreamMaker from '@/components/DreamMaker.vue'
|
||||
import { notify } from '@/utils/notification'
|
||||
|
||||
export default {
|
||||
name: "Home",
|
||||
const moveSound = new Audio(require('@/assets/sounds/move.mp3'))
|
||||
type Stopwatch = 'stopped' | 'started'
|
||||
const INTERVAL = 120
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Home',
|
||||
components: {
|
||||
HelloWorld
|
||||
DreamMaker
|
||||
},
|
||||
setup() {
|
||||
let chilledcow: HTMLVideoElement | null = null
|
||||
let stopwatchId: number | null = null
|
||||
const isProgrammer1Turn = ref(true)
|
||||
let stopWatchSessionId: number | null = null
|
||||
const seconds = ref(0)
|
||||
const time = computed(() => {
|
||||
const m = Math.floor(seconds.value / 60)
|
||||
const s = seconds.value % 60
|
||||
|
||||
return `${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`
|
||||
})
|
||||
const sessionSeconds = ref(INTERVAL)
|
||||
const session = computed(() => {
|
||||
const m = Math.floor(sessionSeconds.value / 60)
|
||||
const s = sessionSeconds.value % 60
|
||||
|
||||
return `${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`
|
||||
})
|
||||
const timeState = ref<Stopwatch>('stopped')
|
||||
const start = () => {
|
||||
timeState.value = 'started'
|
||||
notify('Session started!')
|
||||
|
||||
stopwatchId = setInterval(() => {
|
||||
seconds.value++
|
||||
if (seconds.value % INTERVAL === 0) {
|
||||
sessionSeconds.value = INTERVAL
|
||||
isProgrammer1Turn.value = !isProgrammer1Turn.value
|
||||
|
||||
const programmer = isProgrammer1Turn.value
|
||||
? 'Programmer 1'
|
||||
: 'Programmer 2'
|
||||
|
||||
notify(`Time to change, ${programmer}, your turn!`)
|
||||
moveSound.play()
|
||||
}
|
||||
}, 1000)
|
||||
stopWatchSessionId = setInterval(() => {
|
||||
sessionSeconds.value--
|
||||
}, 1000)
|
||||
}
|
||||
const stop = () => {
|
||||
timeState.value = 'stopped'
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
chilledcow = document.querySelector('youtube-video')
|
||||
})
|
||||
|
||||
const clear = () => {
|
||||
if (stopwatchId) {
|
||||
clearInterval(stopwatchId)
|
||||
}
|
||||
if (stopWatchSessionId) {
|
||||
clearInterval(stopWatchSessionId)
|
||||
}
|
||||
seconds.value = 0
|
||||
sessionSeconds.value = INTERVAL
|
||||
}
|
||||
|
||||
onUnmounted(clear)
|
||||
|
||||
watchEffect(() => {
|
||||
switch (timeState.value) {
|
||||
case 'started':
|
||||
if (chilledcow) {
|
||||
chilledcow.play()
|
||||
}
|
||||
break
|
||||
case 'stopped':
|
||||
if (chilledcow) {
|
||||
chilledcow.pause()
|
||||
}
|
||||
clear()
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
start,
|
||||
stop,
|
||||
timeState,
|
||||
time,
|
||||
session,
|
||||
isProgrammer1Turn
|
||||
}
|
||||
}
|
||||
};
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.home {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
}
|
||||
.brogrammers {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.global-time {
|
||||
font-size: 80pt;
|
||||
padding: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
91
vue.config.js
Normal file
@@ -0,0 +1,91 @@
|
||||
const mainColor = '#3f4fa6'
|
||||
|
||||
module.exports = {
|
||||
pwa: {
|
||||
themeColor: mainColor,
|
||||
msTileColor: mainColor,
|
||||
workboxOptions: {
|
||||
skipWaiting: true,
|
||||
clientsClaim: true
|
||||
},
|
||||
name: '',
|
||||
manifestOptions: {
|
||||
background_color: mainColor,
|
||||
theme_color: mainColor,
|
||||
icons: [
|
||||
{
|
||||
src: './img/icons/android-chrome-192x192.png',
|
||||
sizes: '192x192',
|
||||
type: 'image/png'
|
||||
},
|
||||
{
|
||||
src: './img/icons/android-chrome-512x512.png',
|
||||
sizes: '512x512',
|
||||
type: 'image/png'
|
||||
},
|
||||
{
|
||||
src: './img/icons/android-chrome-maskable-192x192.png',
|
||||
sizes: '192x192',
|
||||
type: 'image/png',
|
||||
purpose: 'maskable'
|
||||
},
|
||||
{
|
||||
src: './img/icons/android-chrome-maskable-512x512.png',
|
||||
sizes: '512x512',
|
||||
type: 'image/png',
|
||||
purpose: 'maskable'
|
||||
},
|
||||
{
|
||||
src: './img/icons/apple-touch-icon-60x60.png',
|
||||
sizes: '60x60',
|
||||
type: 'image/png'
|
||||
},
|
||||
{
|
||||
src: './img/icons/apple-touch-icon-76x76.png',
|
||||
sizes: '76x76',
|
||||
type: 'image/png'
|
||||
},
|
||||
{
|
||||
src: './img/icons/apple-touch-icon-120x120.png',
|
||||
sizes: '120x120',
|
||||
type: 'image/png'
|
||||
},
|
||||
{
|
||||
src: './img/icons/apple-touch-icon-152x152.png',
|
||||
sizes: '152x152',
|
||||
type: 'image/png'
|
||||
},
|
||||
{
|
||||
src: './img/icons/apple-touch-icon-180x180.png',
|
||||
sizes: '180x180',
|
||||
type: 'image/png'
|
||||
},
|
||||
{
|
||||
src: './img/icons/apple-touch-icon.png',
|
||||
sizes: '180x180',
|
||||
type: 'image/png'
|
||||
},
|
||||
{
|
||||
src: './img/icons/favicon-16x16.png',
|
||||
sizes: '16x16',
|
||||
type: 'image/png'
|
||||
},
|
||||
{
|
||||
src: './img/icons/favicon-32x32.png',
|
||||
sizes: '32x32',
|
||||
type: 'image/png'
|
||||
},
|
||||
{
|
||||
src: './img/icons/msapplication-icon-144x144.png',
|
||||
sizes: '144x144',
|
||||
type: 'image/png'
|
||||
},
|
||||
{
|
||||
src: './img/icons/mstile-150x150.png',
|
||||
sizes: '150x150',
|
||||
type: 'image/png'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
24
yarn.lock
@@ -1225,6 +1225,13 @@
|
||||
optionalDependencies:
|
||||
prettier "^1.18.2"
|
||||
|
||||
"@vue/composition-api@^1.0.0-beta.1":
|
||||
version "1.0.0-beta.1"
|
||||
resolved "https://registry.yarnpkg.com/@vue/composition-api/-/composition-api-1.0.0-beta.1.tgz#bd5c3fc902f8bd75c3bd9180974572a51a416447"
|
||||
integrity sha512-QByO16Ij9QR/JK0XWZh6cSs76nMlcEpr67enklteiDWvJesO5ziS22rRILr3HAwV3pBnGqZszeNfwEEWx1vCHw==
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
"@vue/eslint-config-prettier@^6.0.0":
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@vue/eslint-config-prettier/-/eslint-config-prettier-6.0.0.tgz#ad5912b308f4ae468458e02a2b05db0b9d246700"
|
||||
@@ -7258,6 +7265,11 @@ resolve@^1.10.0, resolve@^1.3.2, resolve@^1.8.1:
|
||||
dependencies:
|
||||
path-parse "^1.0.6"
|
||||
|
||||
resource-manager-js@^5.0.7:
|
||||
version "5.0.7"
|
||||
resolved "https://registry.yarnpkg.com/resource-manager-js/-/resource-manager-js-5.0.7.tgz#df2a4e65be234e2e846354ca31421fb0ae1c27c6"
|
||||
integrity sha512-MCx8XHSonLhBeC6FvMyWJZ73g9Rk4NkLIOguxrS9Q6IFqY/GBnv75UCwj0gv3GQRWz8ei4X3A6VLFNfLLYddMg==
|
||||
|
||||
restore-cursor@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
|
||||
@@ -8296,6 +8308,11 @@ tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0:
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
|
||||
integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
|
||||
|
||||
tslib@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.0.tgz#18d13fc2dce04051e20f074cc8387fd8089ce4f3"
|
||||
integrity sha512-lTqkx847PI7xEDYJntxZH89L2/aXInsyF2luSafe/+0fHOMjlBNXdH6th7f70qxLDhul7KZK0zC8V5ZIyHl0/g==
|
||||
|
||||
tslint@^5.20.1:
|
||||
version "5.20.1"
|
||||
resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.20.1.tgz#e401e8aeda0152bc44dd07e614034f3f80c67b7d"
|
||||
@@ -9161,3 +9178,10 @@ yorkie@^2.0.0:
|
||||
is-ci "^1.0.10"
|
||||
normalize-path "^1.0.0"
|
||||
strip-indent "^2.0.0"
|
||||
|
||||
youtube-video-js@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/youtube-video-js/-/youtube-video-js-3.2.0.tgz#f9873ac92812e3ce443dd0856f909936c3dafc9b"
|
||||
integrity sha512-6ePqvcZ2FUgz1ueaI2Mr9e9P6utBmBlGHAJstVSjKrAKEQiiTsZNPaQ2tQM2dNogPKnEM2jZp/YKiJWhoJT7gw==
|
||||
dependencies:
|
||||
resource-manager-js "^5.0.7"
|
||||
|
||||