🎉
18
.eslintrc.js
@@ -4,17 +4,19 @@ module.exports = {
|
|||||||
node: true
|
node: true
|
||||||
},
|
},
|
||||||
extends: [
|
extends: [
|
||||||
"plugin:vue/essential",
|
'plugin:vue/essential',
|
||||||
"eslint:recommended",
|
'eslint:recommended',
|
||||||
"@vue/typescript/recommended",
|
'@vue/typescript/recommended',
|
||||||
"@vue/prettier",
|
'@vue/prettier',
|
||||||
"@vue/prettier/@typescript-eslint"
|
'@vue/prettier/@typescript-eslint'
|
||||||
],
|
],
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
ecmaVersion: 2020
|
ecmaVersion: 2020
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
|
'@typescript-eslint/camelcase': 'off',
|
||||||
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "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 = {
|
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"
|
"lint": "vue-cli-service lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@vue/composition-api": "^1.0.0-beta.1",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
"register-service-worker": "^1.7.1",
|
"register-service-worker": "^1.7.1",
|
||||||
"vue": "^2.6.11",
|
"vue": "^2.6.11",
|
||||||
"vue-router": "^3.2.0",
|
"vue-router": "^3.2.0",
|
||||||
"vuex": "^3.4.0"
|
"vuex": "^3.4.0",
|
||||||
|
"youtube-video-js": "^3.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "^2.33.0",
|
"@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">
|
<svg width="512" height="512" viewBox="0 0 512 512" 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"/>
|
<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>
|
</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>
|
<template>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<div id="nav">
|
<h1>Bons programmeurs</h1>
|
||||||
<router-link to="/">Home</router-link> |
|
|
||||||
<router-link to="/about">About</router-link>
|
|
||||||
</div>
|
|
||||||
<router-view />
|
<router-view />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@import '@/styles/app';
|
||||||
|
|
||||||
#app {
|
#app {
|
||||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
display: flex;
|
||||||
-webkit-font-smoothing: antialiased;
|
flex-direction: column;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
min-height: 100vh;
|
||||||
text-align: center;
|
|
||||||
color: #2c3e50;
|
|
||||||
}
|
|
||||||
|
|
||||||
#nav {
|
|
||||||
padding: 30px;
|
|
||||||
|
|
||||||
a {
|
|
||||||
font-weight: bold;
|
|
||||||
color: #2c3e50;
|
|
||||||
|
|
||||||
&.router-link-exact-active {
|
|
||||||
color: #42b983;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</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 Vue from 'vue'
|
||||||
import App from "./App.vue";
|
import App from './App.vue'
|
||||||
import "./registerServiceWorker";
|
import './registerServiceWorker'
|
||||||
import router from "./router";
|
import router from './router'
|
||||||
import store from "./store";
|
import store from './store'
|
||||||
|
import VueCompositionAPI from '@vue/composition-api'
|
||||||
|
|
||||||
Vue.config.productionTip = false;
|
Vue.use(VueCompositionAPI)
|
||||||
|
|
||||||
|
Vue.config.productionTip = false
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
router,
|
router,
|
||||||
store,
|
store,
|
||||||
render: h => h(App)
|
render: (h) => h(App)
|
||||||
}).$mount("#app");
|
}).$mount('#app')
|
||||||
|
|||||||
@@ -1,34 +1,34 @@
|
|||||||
/* eslint-disable no-console */
|
/* 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`, {
|
register(`${process.env.BASE_URL}service-worker.js`, {
|
||||||
ready() {
|
ready() {
|
||||||
console.log(
|
console.log(
|
||||||
"App is being served from cache by a service worker.\n" +
|
'App is being served from cache by a service worker.\n' +
|
||||||
"For more details, visit https://goo.gl/AFskqB"
|
'For more details, visit https://goo.gl/AFskqB'
|
||||||
);
|
)
|
||||||
},
|
},
|
||||||
registered() {
|
registered() {
|
||||||
console.log("Service worker has been registered.");
|
console.log('Service worker has been registered.')
|
||||||
},
|
},
|
||||||
cached() {
|
cached() {
|
||||||
console.log("Content has been cached for offline use.");
|
console.log('Content has been cached for offline use.')
|
||||||
},
|
},
|
||||||
updatefound() {
|
updatefound() {
|
||||||
console.log("New content is downloading.");
|
console.log('New content is downloading.')
|
||||||
},
|
},
|
||||||
updated() {
|
updated() {
|
||||||
console.log("New content is available; please refresh.");
|
console.log('New content is available; please refresh.')
|
||||||
},
|
},
|
||||||
offline() {
|
offline() {
|
||||||
console.log(
|
console.log(
|
||||||
"No internet connection found. App is running in offline mode."
|
'No internet connection found. App is running in offline mode.'
|
||||||
);
|
)
|
||||||
},
|
},
|
||||||
error(error) {
|
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 Vue from 'vue'
|
||||||
import VueRouter, { RouteConfig } from "vue-router";
|
import VueRouter, { RouteConfig } from 'vue-router'
|
||||||
import Home from "../views/Home.vue";
|
import Home from '../views/Home.vue'
|
||||||
|
|
||||||
Vue.use(VueRouter);
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
const routes: Array<RouteConfig> = [
|
const routes: Array<RouteConfig> = [
|
||||||
{
|
{
|
||||||
path: "/",
|
path: '/',
|
||||||
name: "Home",
|
name: 'Home',
|
||||||
component: 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({
|
const router = new VueRouter({
|
||||||
mode: "history",
|
mode: 'history',
|
||||||
base: process.env.BASE_URL,
|
base: process.env.BASE_URL,
|
||||||
routes
|
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 {
|
declare global {
|
||||||
namespace JSX {
|
namespace JSX {
|
||||||
@@ -7,7 +7,7 @@ declare global {
|
|||||||
// tslint:disable no-empty-interface
|
// tslint:disable no-empty-interface
|
||||||
interface ElementClass extends Vue {}
|
interface ElementClass extends Vue {}
|
||||||
interface IntrinsicElements {
|
interface IntrinsicElements {
|
||||||
[elem: string]: any;
|
[elem: string]: any
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
6
src/shims-vue.d.ts
vendored
@@ -1,4 +1,4 @@
|
|||||||
declare module "*.vue" {
|
declare module '*.vue' {
|
||||||
import Vue from "vue";
|
import Vue from 'vue'
|
||||||
export default Vue;
|
export default Vue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import Vue from "vue";
|
import Vue from 'vue'
|
||||||
import Vuex from "vuex";
|
import Vuex from 'vuex'
|
||||||
|
|
||||||
Vue.use(Vuex);
|
Vue.use(Vuex)
|
||||||
|
|
||||||
export default new Vuex.Store({
|
export default new Vuex.Store({
|
||||||
state: {},
|
state: {},
|
||||||
mutations: {},
|
mutations: {},
|
||||||
actions: {},
|
actions: {},
|
||||||
modules: {}
|
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>
|
<template>
|
||||||
<div class="home">
|
<div class="home">
|
||||||
<img alt="Vue logo" src="../assets/logo.png" />
|
<section class="brogrammers">
|
||||||
<HelloWorld msg="Welcome to Your Vue.js App" />
|
<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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
// @ is an alias to /src
|
import 'youtube-video-js'
|
||||||
import HelloWorld from "@/components/HelloWorld.vue";
|
import {
|
||||||
|
ref,
|
||||||
|
watchEffect,
|
||||||
|
defineComponent,
|
||||||
|
onMounted,
|
||||||
|
computed,
|
||||||
|
onUnmounted
|
||||||
|
} from '@vue/composition-api'
|
||||||
|
import DreamMaker from '@/components/DreamMaker.vue'
|
||||||
|
import { notify } from '@/utils/notification'
|
||||||
|
|
||||||
export default {
|
const moveSound = new Audio(require('@/assets/sounds/move.mp3'))
|
||||||
name: "Home",
|
type Stopwatch = 'stopped' | 'started'
|
||||||
|
const INTERVAL = 120
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Home',
|
||||||
components: {
|
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>
|
</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:
|
optionalDependencies:
|
||||||
prettier "^1.18.2"
|
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":
|
"@vue/eslint-config-prettier@^6.0.0":
|
||||||
version "6.0.0"
|
version "6.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@vue/eslint-config-prettier/-/eslint-config-prettier-6.0.0.tgz#ad5912b308f4ae468458e02a2b05db0b9d246700"
|
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:
|
dependencies:
|
||||||
path-parse "^1.0.6"
|
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:
|
restore-cursor@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
|
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"
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
|
||||||
integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
|
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:
|
tslint@^5.20.1:
|
||||||
version "5.20.1"
|
version "5.20.1"
|
||||||
resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.20.1.tgz#e401e8aeda0152bc44dd07e614034f3f80c67b7d"
|
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"
|
is-ci "^1.0.10"
|
||||||
normalize-path "^1.0.0"
|
normalize-path "^1.0.0"
|
||||||
strip-indent "^2.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"
|
||||||
|
|||||||